diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 0b718747d9d..a51284e3a1f 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,4 +1,5 @@ { + "image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04", "extensions": [ "rust-lang.rust-analyzer", "bungcip.better-toml", diff --git a/.github/workflows/compile-queries.yml b/.github/workflows/compile-queries.yml index 38452f97d36..945515c0c53 100644 --- a/.github/workflows/compile-queries.yml +++ b/.github/workflows/compile-queries.yml @@ -7,6 +7,11 @@ on: - "rc/*" - "codeql-cli-*" pull_request: + paths: + - '**.ql' + - '**.qll' + - '**/qlpack.yml' + - '**.dbscheme' permissions: contents: read @@ -33,9 +38,9 @@ jobs: # run with --check-only if running in a PR (github.sha != main) if : ${{ github.event_name == 'pull_request' }} shell: bash - run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500 + run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500 --ram=56000 - name: compile queries - full # do full compile if running on main - this populates the cache if : ${{ github.event_name != 'pull_request' }} shell: bash - run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500 + run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500 --ram=56000 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2b677468025..c0bd4abd0d0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -72,7 +72,7 @@ repos: - id: rust-codegen name: Run Rust checked in code generation - files: ^misc/codegen/|^rust/(schema.py$|codegen/|.*/generated/|ql/lib/(rust\.dbscheme$|codeql/rust/elements)|\.generated.list) + files: ^misc/codegen/|^rust/(prefix\.dbscheme|schema/|codegen/|.*/generated/|ql/lib/(rust\.dbscheme$|codeql/rust/elements)|\.generated.list) language: system entry: bazel run //rust/codegen -- --quiet pass_filenames: false diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 68df2f6f498..5d9a735d379 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -38,6 +38,93 @@ "command": "${config:python.pythonPath}", }, "problemMatcher": [] + }, + { + "label": "Create query change note", + "type": "process", + "command": "python3", + "args": [ + "misc/scripts/create-change-note.py", + "${input:language}", + "src", + "${input:name}", + "${input:categoryQuery}" + ], + "presentation": { + "reveal": "never", + "close": true + }, + "problemMatcher": [] + }, + { + "label": "Create library change note", + "type": "process", + "command": "python3", + "args": [ + "misc/scripts/create-change-note.py", + "${input:language}", + "lib", + "${input:name}", + "${input:categoryLibrary}" + ], + "presentation": { + "reveal": "never", + "close": true + }, + "problemMatcher": [] + } + ], + "inputs": [ + { + "type": "pickString", + "id": "language", + "description": "Language", + "options": + [ + "go", + "java", + "javascript", + "cpp", + "csharp", + "python", + "ruby", + "rust", + "swift", + ] + }, + { + "type": "promptString", + "id": "name", + "description": "Short name (kebab-case)" + }, + { + "type": "pickString", + "id": "categoryQuery", + "description": "Category (query change)", + "options": + [ + "breaking", + "deprecated", + "newQuery", + "queryMetadata", + "majorAnalysis", + "minorAnalysis", + "fix", + ] + }, + { + "type": "pickString", + "id": "categoryLibrary", + "description": "Category (library change)", + "options": + [ + "breaking", + "deprecated", + "feature", + "majorAnalysis", + "minorAnalysis", + "fix", + ] } ] } diff --git a/2024-11-25-ts57.md b/2024-11-25-ts57.md new file mode 100644 index 00000000000..3a92872d6d6 --- /dev/null +++ b/2024-11-25-ts57.md @@ -0,0 +1,4 @@ +--- +category: majorAnalysis +--- +* Added support for TypeScript 5.7. diff --git a/CODEOWNERS b/CODEOWNERS index 6e1c975ace7..1912a138758 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -42,3 +42,6 @@ MODULE.bazel @github/codeql-ci-reviewers # Misc /misc/scripts/accept-expected-changes-from-ci.py @RasmusWL /misc/scripts/generate-code-scanning-query-list.py @RasmusWL + +# .devcontainer +/.devcontainer/ @github/codeql-ci-reviewers diff --git a/Cargo.lock b/Cargo.lock index 1d5b8824c84..65a77b316c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -381,8 +381,10 @@ version = "0.1.0" dependencies = [ "anyhow", "argfile", + "chrono", "clap", "codeql-extractor", + "dunce", "figment", "glob", "itertools 0.13.0", @@ -404,6 +406,7 @@ dependencies = [ "ra_ap_vfs", "rust-extractor-macros", "serde", + "serde_json", "serde_with", "stderrlog", "triomphe", @@ -540,6 +543,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1" +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + [[package]] name = "either" version = "1.13.0" @@ -2034,9 +2043,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.132" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", "memchr", diff --git a/MODULE.bazel b/MODULE.bazel index 13c801520b0..08a4aaa78af 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -68,7 +68,7 @@ use_repo(py_deps, "vendor__anyhow-1.0.44", "vendor__cc-1.0.70", "vendor__clap-2. # deps for ruby+rust # keep in sync by running `misc/bazel/3rdparty/update_cargo_deps.sh` tree_sitter_extractors_deps = use_extension("//misc/bazel/3rdparty:tree_sitter_extractors_extension.bzl", "r") -use_repo(tree_sitter_extractors_deps, "vendor__anyhow-1.0.93", "vendor__argfile-0.2.1", "vendor__chrono-0.4.38", "vendor__clap-4.5.20", "vendor__encoding-0.2.33", "vendor__figment-0.10.19", "vendor__flate2-1.0.34", "vendor__glob-0.3.1", "vendor__globset-0.4.15", "vendor__itertools-0.10.5", "vendor__itertools-0.13.0", "vendor__lazy_static-1.5.0", "vendor__log-0.4.22", "vendor__num-traits-0.2.19", "vendor__num_cpus-1.16.0", "vendor__proc-macro2-1.0.89", "vendor__quote-1.0.37", "vendor__ra_ap_base_db-0.0.232", "vendor__ra_ap_cfg-0.0.232", "vendor__ra_ap_hir-0.0.232", "vendor__ra_ap_hir_def-0.0.232", "vendor__ra_ap_hir_expand-0.0.232", "vendor__ra_ap_ide_db-0.0.232", "vendor__ra_ap_intern-0.0.232", "vendor__ra_ap_load-cargo-0.0.232", "vendor__ra_ap_parser-0.0.232", "vendor__ra_ap_paths-0.0.232", "vendor__ra_ap_project_model-0.0.232", "vendor__ra_ap_span-0.0.232", "vendor__ra_ap_syntax-0.0.232", "vendor__ra_ap_vfs-0.0.232", "vendor__rand-0.8.5", "vendor__rayon-1.10.0", "vendor__regex-1.11.1", "vendor__serde-1.0.214", "vendor__serde_json-1.0.132", "vendor__serde_with-3.11.0", "vendor__stderrlog-0.6.0", "vendor__syn-2.0.87", "vendor__tracing-0.1.40", "vendor__tracing-subscriber-0.3.18", "vendor__tree-sitter-0.24.4", "vendor__tree-sitter-embedded-template-0.23.2", "vendor__tree-sitter-json-0.24.8", "vendor__tree-sitter-ql-0.23.1", "vendor__tree-sitter-ruby-0.23.1", "vendor__triomphe-0.1.14", "vendor__ungrammar-1.16.1") +use_repo(tree_sitter_extractors_deps, "vendor__anyhow-1.0.93", "vendor__argfile-0.2.1", "vendor__chrono-0.4.38", "vendor__clap-4.5.20", "vendor__dunce-1.0.5", "vendor__encoding-0.2.33", "vendor__figment-0.10.19", "vendor__flate2-1.0.34", "vendor__glob-0.3.1", "vendor__globset-0.4.15", "vendor__itertools-0.10.5", "vendor__itertools-0.13.0", "vendor__lazy_static-1.5.0", "vendor__log-0.4.22", "vendor__num-traits-0.2.19", "vendor__num_cpus-1.16.0", "vendor__proc-macro2-1.0.89", "vendor__quote-1.0.37", "vendor__ra_ap_base_db-0.0.232", "vendor__ra_ap_cfg-0.0.232", "vendor__ra_ap_hir-0.0.232", "vendor__ra_ap_hir_def-0.0.232", "vendor__ra_ap_hir_expand-0.0.232", "vendor__ra_ap_ide_db-0.0.232", "vendor__ra_ap_intern-0.0.232", "vendor__ra_ap_load-cargo-0.0.232", "vendor__ra_ap_parser-0.0.232", "vendor__ra_ap_paths-0.0.232", "vendor__ra_ap_project_model-0.0.232", "vendor__ra_ap_span-0.0.232", "vendor__ra_ap_syntax-0.0.232", "vendor__ra_ap_vfs-0.0.232", "vendor__rand-0.8.5", "vendor__rayon-1.10.0", "vendor__regex-1.11.1", "vendor__serde-1.0.214", "vendor__serde_json-1.0.133", "vendor__serde_with-3.11.0", "vendor__stderrlog-0.6.0", "vendor__syn-2.0.87", "vendor__tracing-0.1.40", "vendor__tracing-subscriber-0.3.18", "vendor__tree-sitter-0.24.4", "vendor__tree-sitter-embedded-template-0.23.2", "vendor__tree-sitter-json-0.24.8", "vendor__tree-sitter-ql-0.23.1", "vendor__tree-sitter-ruby-0.23.1", "vendor__triomphe-0.1.14", "vendor__ungrammar-1.16.1") dotnet = use_extension("@rules_dotnet//dotnet:extensions.bzl", "dotnet") dotnet.toolchain(dotnet_version = "9.0.100") diff --git a/config/identical-files.json b/config/identical-files.json index c4436872b9a..579a22379e8 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -1,58 +1,4 @@ { - "DataFlow Java/C++/C#/Go/Python/Ruby/Swift Legacy Configuration": [ - "java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl1.qll", - "java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll", - "java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll", - "java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll", - "java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll", - "java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll", - "cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl1.qll", - "cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll", - "cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll", - "cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll", - "cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll", - "cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl1.qll", - "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", - "csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl1.qll", - "csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll", - "csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll", - "csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll", - "csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll", - "go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl1.qll", - "go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl2.qll", - "python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl1.qll", - "python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll", - "python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll", - "python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll", - "ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl1.qll", - "ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll", - "swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl1.qll" - ], - "TaintTracking Legacy Configuration Java/C++/C#/Go/Python/Ruby/Swift": [ - "cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll", - "cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll", - "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", - "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", - "csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll", - "csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll", - "go/ql/lib/semmle/go/dataflow/internal/tainttracking1/TaintTrackingImpl.qll", - "go/ql/lib/semmle/go/dataflow/internal/tainttracking2/TaintTrackingImpl.qll", - "java/ql/lib/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll", - "java/ql/lib/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll", - "java/ql/lib/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingImpl.qll", - "python/ql/lib/semmle/python/dataflow/new/internal/tainttracking1/TaintTrackingImpl.qll", - "python/ql/lib/semmle/python/dataflow/new/internal/tainttracking2/TaintTrackingImpl.qll", - "python/ql/lib/semmle/python/dataflow/new/internal/tainttracking3/TaintTrackingImpl.qll", - "python/ql/lib/semmle/python/dataflow/new/internal/tainttracking4/TaintTrackingImpl.qll", - "ruby/ql/lib/codeql/ruby/dataflow/internal/tainttracking1/TaintTrackingImpl.qll", - "swift/ql/lib/codeql/swift/dataflow/internal/tainttracking1/TaintTrackingImpl.qll" - ], "SsaReadPosition Java/C#": [ "java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll", "csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll" diff --git a/cpp/downgrades/f0156f5f88ab5967c79162012c20f30600ca5ebf/old.dbscheme b/cpp/downgrades/f0156f5f88ab5967c79162012c20f30600ca5ebf/old.dbscheme new file mode 100644 index 00000000000..f0156f5f88a --- /dev/null +++ b/cpp/downgrades/f0156f5f88ab5967c79162012c20f30600ca5ebf/old.dbscheme @@ -0,0 +1,2339 @@ + +/** + * 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 +); + +/** + * Optionally, record the build mode for each compilation. + */ +compilation_build_mode( + unique int id : @compilation ref, + int mode : int ref +); + +/* +case @compilation_build_mode.mode of + 0 = @build_mode_none +| 1 = @build_mode_manual +| 2 = @build_mode_auto +; +*/ + +/** + * 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 + */ + +extractor_version( + string codeql_version: string ref, + string frontend_version: string ref +) + +@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 @macroinvocation.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_function +| 2 = @constructor +| 3 = @destructor +| 4 = @conversion_function +| 5 = @operator +| 6 = @builtin_function // GCC built-in functions, e.g. __builtin___memcpy_chk +| 7 = @user_defined_literal +| 8 = @deduction_guide +; +*/ + +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 +); + +/* +case @coroutine_placeholder_variable.kind of + 1 = @handle +| 2 = @promise +| 3 = @init_await_resume +; +*/ + +coroutine_placeholder_variable( + unique int placeholder_variable: @variable ref, + int kind: int ref, + int function: @function 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); + +function_prototyped(unique int id: @function ref) + +deduction_guide_for_class( + int id: @function ref, + int class_template: @usertype 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 +); + +case @using.kind of + 1 = @using_declaration +| 2 = @using_directive +| 3 = @using_enum_declaration +; + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref, + int kind: int 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: @parameterized_element 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 = @errortype +| 2 = @unknowntype +| 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 Microsoft-specific __int8 +// ... 21 Microsoft-specific __int16 +// ... 22 Microsoft-specific __int32 +// ... 23 Microsoft-specific __int64 +| 24 = @float +| 25 = @double +| 26 = @long_double +| 27 = @complex_float // C99-specific _Complex float +| 28 = @complex_double // C99-specific _Complex double +| 29 = @complex_long_double // C99-specific _Complex long double +| 30 = @imaginary_float // C99-specific _Imaginary float +| 31 = @imaginary_double // C99-specific _Imaginary double +| 32 = @imaginary_long_double // C99-specific _Imaginary long double +| 33 = @wchar_t // Microsoft-specific +| 34 = @decltype_nullptr // C++11 +| 35 = @int128 // __int128 +| 36 = @unsigned_int128 // unsigned __int128 +| 37 = @signed_int128 // signed __int128 +| 38 = @float128 // __float128 +| 39 = @complex_float128 // _Complex __float128 +| 40 = @decimal32 // _Decimal32 +| 41 = @decimal64 // _Decimal64 +| 42 = @decimal128 // _Decimal128 +| 43 = @char16_t +| 44 = @char32_t +| 45 = @std_float32 // _Float32 +| 46 = @float32x // _Float32x +| 47 = @std_float64 // _Float64 +| 48 = @float64x // _Float64x +| 49 = @std_float128 // _Float128 +// ... 50 _Float128x +| 51 = @char8_t +| 52 = @float16 // _Float16 +| 53 = @complex_float16 // _Complex _Float16 +| 54 = @fp16 // __fp16 +| 55 = @std_bfloat16 // __bf16 +| 56 = @std_float16 // std::float16_t +| 57 = @complex_std_float32 // _Complex _Float32 +| 58 = @complex_float32x // _Complex _Float32x +| 59 = @complex_std_float64 // _Complex _Float64 +| 60 = @complex_float64x // _Complex _Float64x +| 61 = @complex_std_float128 // _Complex _Float128 +; + +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, + boolean is_complete: boolean ref +); + +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 +); + +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 +); + +explicit_specifier_exprs( + unique int func_id: @function ref, + int constant: @expr 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 +| 5 = @attribute_arg_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_expr( + unique int arg: @attribute_arg ref, + int expr: @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 + | @c11_generic + ; + +/* +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 + ; + +@assign_pointer_expr = @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr + | @assign_bitwise_expr + | @assign_pointer_expr + ; + +@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr + +/* + Binary encoding of the allocator form. + + 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 +); + +/* + Binary encoding of the deallocator form. + + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 4 = destroying_delete + ; +*/ + +/** + * 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 +); + +expr_reuse( + int reuse: @expr ref, + int original: @expr ref, + int value_category: int 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 +| 363 = @reuseexpr +| 364 = @istriviallycopyassignable +| 365 = @isassignablenopreconditioncheck +| 366 = @referencebindstotemporary +| 367 = @issameas +| 368 = @builtinhasattribute +| 369 = @ispointerinterconvertiblewithclass +| 370 = @builtinispointerinterconvertiblewithclass +| 371 = @iscorrespondingmember +| 372 = @builtiniscorrespondingmember +| 373 = @isboundedarray +| 374 = @isunboundedarray +| 375 = @isreferenceable +| 378 = @isnothrowconvertible +| 379 = @referenceconstructsfromtemporary +| 380 = @referenceconvertsfromtemporary +| 381 = @isconvertible +| 382 = @isvalidwinrttype +| 383 = @iswinclass +| 384 = @iswininterface +| 385 = @istriviallyequalitycomparable +| 386 = @isscopedenum +| 387 = @istriviallyrelocatable +| 388 = @datasizeof +| 389 = @c11_generic +| 390 = @requires_expr +| 391 = @nested_requirement +| 392 = @compound_requirement +| 393 = @concept_id +; + +@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 + | @istrivialexpr + | @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 + | @istriviallycopyassignable + | @isassignablenopreconditioncheck + | @referencebindstotemporary + | @issameas + | @builtinhasattribute + | @ispointerinterconvertiblewithclass + | @builtinispointerinterconvertiblewithclass + | @iscorrespondingmember + | @builtiniscorrespondingmember + | @isboundedarray + | @isunboundedarray + | @isreferenceable + | @isnothrowconvertible + | @referenceconstructsfromtemporary + | @referenceconvertsfromtemporary + | @isconvertible + | @isvalidwinrttype + | @iswinclass + | @iswininterface + | @istriviallyequalitycomparable + | @isscopedenum + | @istriviallyrelocatable + ; + +compound_requirement_is_noexcept( + int expr: @compound_requirement ref +); + +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. Position is used to sort repeated initializers. + */ +#keyset[aggregate, position] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref, + int position: int ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. Position is used to sort repeated initializers. + */ +#keyset[aggregate, position] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref, + int position: 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 | @datasizeof; + +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 +); + +@stmt_for_or_range_based_for = @stmt_for + | @stmt_range_based_for; + +for_initialization( + unique int for_stmt: @stmt_for_or_range_based_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 +); + +@parameterized_element = @function | @stmt_block | @requires_expr; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @parameterized_element 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( + 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/f0156f5f88ab5967c79162012c20f30600ca5ebf/semmlecode.cpp.dbscheme b/cpp/downgrades/f0156f5f88ab5967c79162012c20f30600ca5ebf/semmlecode.cpp.dbscheme new file mode 100644 index 00000000000..e51fad7a243 --- /dev/null +++ b/cpp/downgrades/f0156f5f88ab5967c79162012c20f30600ca5ebf/semmlecode.cpp.dbscheme @@ -0,0 +1,2323 @@ + +/** + * 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 + */ + +extractor_version( + string codeql_version: string ref, + string frontend_version: string ref +) + +@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 @macroinvocation.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_function +| 2 = @constructor +| 3 = @destructor +| 4 = @conversion_function +| 5 = @operator +| 6 = @builtin_function // GCC built-in functions, e.g. __builtin___memcpy_chk +| 7 = @user_defined_literal +| 8 = @deduction_guide +; +*/ + +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 +); + +/* +case @coroutine_placeholder_variable.kind of + 1 = @handle +| 2 = @promise +| 3 = @init_await_resume +; +*/ + +coroutine_placeholder_variable( + unique int placeholder_variable: @variable ref, + int kind: int ref, + int function: @function 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); + +function_prototyped(unique int id: @function ref) + +deduction_guide_for_class( + int id: @function ref, + int class_template: @usertype 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 +); + +case @using.kind of + 1 = @using_declaration +| 2 = @using_directive +| 3 = @using_enum_declaration +; + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref, + int kind: int 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: @parameterized_element 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 = @errortype +| 2 = @unknowntype +| 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 Microsoft-specific __int8 +// ... 21 Microsoft-specific __int16 +// ... 22 Microsoft-specific __int32 +// ... 23 Microsoft-specific __int64 +| 24 = @float +| 25 = @double +| 26 = @long_double +| 27 = @complex_float // C99-specific _Complex float +| 28 = @complex_double // C99-specific _Complex double +| 29 = @complex_long_double // C99-specific _Complex long double +| 30 = @imaginary_float // C99-specific _Imaginary float +| 31 = @imaginary_double // C99-specific _Imaginary double +| 32 = @imaginary_long_double // C99-specific _Imaginary long double +| 33 = @wchar_t // Microsoft-specific +| 34 = @decltype_nullptr // C++11 +| 35 = @int128 // __int128 +| 36 = @unsigned_int128 // unsigned __int128 +| 37 = @signed_int128 // signed __int128 +| 38 = @float128 // __float128 +| 39 = @complex_float128 // _Complex __float128 +| 40 = @decimal32 // _Decimal32 +| 41 = @decimal64 // _Decimal64 +| 42 = @decimal128 // _Decimal128 +| 43 = @char16_t +| 44 = @char32_t +| 45 = @std_float32 // _Float32 +| 46 = @float32x // _Float32x +| 47 = @std_float64 // _Float64 +| 48 = @float64x // _Float64x +| 49 = @std_float128 // _Float128 +// ... 50 _Float128x +| 51 = @char8_t +| 52 = @float16 // _Float16 +| 53 = @complex_float16 // _Complex _Float16 +| 54 = @fp16 // __fp16 +| 55 = @std_bfloat16 // __bf16 +| 56 = @std_float16 // std::float16_t +| 57 = @complex_std_float32 // _Complex _Float32 +| 58 = @complex_float32x // _Complex _Float32x +| 59 = @complex_std_float64 // _Complex _Float64 +| 60 = @complex_float64x // _Complex _Float64x +| 61 = @complex_std_float128 // _Complex _Float128 +; + +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, + boolean is_complete: boolean ref +); + +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 +); + +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 +); + +explicit_specifier_exprs( + unique int func_id: @function ref, + int constant: @expr 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 +| 5 = @attribute_arg_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_expr( + unique int arg: @attribute_arg ref, + int expr: @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 + | @c11_generic + ; + +/* +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 + ; + +@assign_pointer_expr = @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr + | @assign_bitwise_expr + | @assign_pointer_expr + ; + +@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr + +/* + Binary encoding of the allocator form. + + 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 +); + +/* + Binary encoding of the deallocator form. + + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 4 = destroying_delete + ; +*/ + +/** + * 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 +); + +expr_reuse( + int reuse: @expr ref, + int original: @expr ref, + int value_category: int 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 +| 363 = @reuseexpr +| 364 = @istriviallycopyassignable +| 365 = @isassignablenopreconditioncheck +| 366 = @referencebindstotemporary +| 367 = @issameas +| 368 = @builtinhasattribute +| 369 = @ispointerinterconvertiblewithclass +| 370 = @builtinispointerinterconvertiblewithclass +| 371 = @iscorrespondingmember +| 372 = @builtiniscorrespondingmember +| 373 = @isboundedarray +| 374 = @isunboundedarray +| 375 = @isreferenceable +| 378 = @isnothrowconvertible +| 379 = @referenceconstructsfromtemporary +| 380 = @referenceconvertsfromtemporary +| 381 = @isconvertible +| 382 = @isvalidwinrttype +| 383 = @iswinclass +| 384 = @iswininterface +| 385 = @istriviallyequalitycomparable +| 386 = @isscopedenum +| 387 = @istriviallyrelocatable +| 388 = @datasizeof +| 389 = @c11_generic +| 390 = @requires_expr +| 391 = @nested_requirement +| 392 = @compound_requirement +| 393 = @concept_id +; + +@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 + | @istrivialexpr + | @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 + | @istriviallycopyassignable + | @isassignablenopreconditioncheck + | @referencebindstotemporary + | @issameas + | @builtinhasattribute + | @ispointerinterconvertiblewithclass + | @builtinispointerinterconvertiblewithclass + | @iscorrespondingmember + | @builtiniscorrespondingmember + | @isboundedarray + | @isunboundedarray + | @isreferenceable + | @isnothrowconvertible + | @referenceconstructsfromtemporary + | @referenceconvertsfromtemporary + | @isconvertible + | @isvalidwinrttype + | @iswinclass + | @iswininterface + | @istriviallyequalitycomparable + | @isscopedenum + | @istriviallyrelocatable + ; + +compound_requirement_is_noexcept( + int expr: @compound_requirement ref +); + +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. Position is used to sort repeated initializers. + */ +#keyset[aggregate, position] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref, + int position: int ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. Position is used to sort repeated initializers. + */ +#keyset[aggregate, position] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref, + int position: 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 | @datasizeof; + +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 +); + +@stmt_for_or_range_based_for = @stmt_for + | @stmt_range_based_for; + +for_initialization( + unique int for_stmt: @stmt_for_or_range_based_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 +); + +@parameterized_element = @function | @stmt_block | @requires_expr; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @parameterized_element 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( + 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/f0156f5f88ab5967c79162012c20f30600ca5ebf/upgrade.properties b/cpp/downgrades/f0156f5f88ab5967c79162012c20f30600ca5ebf/upgrade.properties new file mode 100644 index 00000000000..cf362f384da --- /dev/null +++ b/cpp/downgrades/f0156f5f88ab5967c79162012c20f30600ca5ebf/upgrade.properties @@ -0,0 +1,3 @@ +description: Implement compilation_build_mode/2 +compatibility: full +compilation_build_mode.rel: delete diff --git a/cpp/ql/lib/change-notes/2024-11-18-throwing-functions.md b/cpp/ql/lib/change-notes/2024-11-18-throwing-functions.md new file mode 100644 index 00000000000..73b358a0e1f --- /dev/null +++ b/cpp/ql/lib/change-notes/2024-11-18-throwing-functions.md @@ -0,0 +1,4 @@ +--- +category: deprecated +--- +* The `NonThrowing` class (`semmle.code.cpp.models.interfaces.NonThrowing`) has been deprecated. Please use the `NonCppThrowingFunction` class instead. \ No newline at end of file diff --git a/cpp/ql/lib/change-notes/2024-12-03-remove-dataflow-config-class-api.md b/cpp/ql/lib/change-notes/2024-12-03-remove-dataflow-config-class-api.md new file mode 100644 index 00000000000..d09ec528c99 --- /dev/null +++ b/cpp/ql/lib/change-notes/2024-12-03-remove-dataflow-config-class-api.md @@ -0,0 +1,4 @@ +--- +category: breaking +--- +* Deleted the old deprecated data flow API that was based on extending a configuration class. See https://github.blog/changelog/2023-08-14-new-dataflow-api-for-writing-custom-codeql-queries for instructions on migrating your queries to use the new API. diff --git a/cpp/ql/lib/semmle/code/cpp/Compilation.qll b/cpp/ql/lib/semmle/code/cpp/Compilation.qll index 1a8d90f991c..407dc31e05f 100644 --- a/cpp/ql/lib/semmle/code/cpp/Compilation.qll +++ b/cpp/ql/lib/semmle/code/cpp/Compilation.qll @@ -112,4 +112,7 @@ class Compilation extends @compilation { * termination, but crashing due to something like a segfault is not. */ predicate normalTermination() { compilation_finished(this, _, _) } + + /** Holds if this compilation was compiled using the "none" build mode. */ + predicate buildModeNone() { compilation_build_mode(this, 0) } } diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/DataFlow.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/DataFlow.qll index 505b2e190e5..a478da5193e 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/DataFlow.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/DataFlow.qll @@ -29,5 +29,5 @@ deprecated module DataFlow { private import semmle.code.cpp.dataflow.internal.DataFlowImplSpecific private import codeql.dataflow.DataFlow import DataFlowMake - import semmle.code.cpp.dataflow.internal.DataFlowImpl1 + import Public } diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/DataFlow2.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/DataFlow2.qll deleted file mode 100644 index 19ffa16b76c..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/DataFlow2.qll +++ /dev/null @@ -1,22 +0,0 @@ -/** - * 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.dataflow.DataFlow` for the full documentation. - */ - -import cpp - -/** - * DEPRECATED: Use `semmle.code.cpp.dataflow.new.DataFlow2` instead. - * - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) data flow analyses. - */ -deprecated module DataFlow2 { - import semmle.code.cpp.dataflow.internal.DataFlowImpl2 -} diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/DataFlow3.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/DataFlow3.qll deleted file mode 100644 index 554b2e155b4..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/DataFlow3.qll +++ /dev/null @@ -1,22 +0,0 @@ -/** - * 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.dataflow.DataFlow` for the full documentation. - */ - -import cpp - -/** - * DEPRECATED: Use `semmle.code.cpp.dataflow.new.DataFlow3` instead. - * - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) data flow analyses. - */ -deprecated module DataFlow3 { - import semmle.code.cpp.dataflow.internal.DataFlowImpl3 -} diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/DataFlow4.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/DataFlow4.qll deleted file mode 100644 index fdd4e8ab7ae..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/DataFlow4.qll +++ /dev/null @@ -1,22 +0,0 @@ -/** - * 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.dataflow.DataFlow` for the full documentation. - */ - -import cpp - -/** - * DEPRECATED: Use `semmle.code.cpp.dataflow.new.DataFlow4` instead. - * - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) data flow analyses. - */ -deprecated module DataFlow4 { - import semmle.code.cpp.dataflow.internal.DataFlowImpl4 -} diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll index 07cb2670858..49610b7c85b 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll @@ -793,28 +793,27 @@ private Element interpretElement0( ) { ( // Non-member functions - elementSpec(namespace, type, subtypes, name, signature, _) and + funcHasQualifiedName(result, namespace, name) and subtypes = false and type = "" and ( elementSpecMatchesSignature(result, namespace, type, subtypes, name, signature) or signature = "" and - elementSpec(namespace, type, subtypes, name, "", _) and - funcHasQualifiedName(result, namespace, name) + elementSpec(namespace, type, subtypes, name, signature, _) ) or // Member functions exists(Class namedClass, Class classWithMethod | + hasClassAndName(classWithMethod, result, name) and + classHasQualifiedName(namedClass, namespace, type) + | ( - elementSpecMatchesSignature(result, namespace, type, subtypes, name, signature) and - hasClassAndName(classWithMethod, result, name) + elementSpecMatchesSignature(result, namespace, type, subtypes, name, signature) or signature = "" and - elementSpec(namespace, type, subtypes, name, "", _) and - hasClassAndName(classWithMethod, result, name) + elementSpec(namespace, type, subtypes, name, "", _) ) and - classHasQualifiedName(namedClass, namespace, type) and ( // member declared in the named type or a subtype of it subtypes = true and diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/RecursionPrevention.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/RecursionPrevention.qll deleted file mode 100644 index 2d8b52f8622..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/RecursionPrevention.qll +++ /dev/null @@ -1,39 +0,0 @@ -/** - * DEPRECATED: Recursion through `DataFlow::Configuration` is impossible in - * any supported tooling. There is no need for this module because it's - * impossible to accidentally depend on recursion through - * `DataFlow::Configuration` in current releases. - * - * When this module is imported, recursive use of `DataFlow::Configuration` is - * disallowed. Importing this module will guarantee the absence of such - * recursion, which is unsupported and will be unconditionally disallowed in a - * future release. - * - * Recursive use of `DataFlow{2..4}::Configuration` is always disallowed, so no - * import is needed for those. - */ - -import cpp -private import semmle.code.cpp.dataflow.DataFlow - -/** - * 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. - * Four copies are available: `DataFlow` through `DataFlow4`. - */ -abstract private class ConfigurationRecursionPrevention extends DataFlow::Configuration { - bindingset[this] - ConfigurationRecursionPrevention() { any() } - - override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) { - strictcount(DataFlow::Node n | this.isSource(n)) < 0 - or - strictcount(DataFlow::Node n | this.isSink(n)) < 0 - or - strictcount(DataFlow::Node n1, DataFlow::Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0 - or - super.hasFlow(source, sink) - } -} diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/TaintTracking.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/TaintTracking.qll index 1f93e2a74df..36af8d9660b 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/TaintTracking.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/TaintTracking.qll @@ -16,7 +16,6 @@ */ import semmle.code.cpp.dataflow.DataFlow -import semmle.code.cpp.dataflow.DataFlow2 /** * DEPRECATED: Use `semmle.code.cpp.dataflow.new.TaintTracking` instead. @@ -25,10 +24,9 @@ import semmle.code.cpp.dataflow.DataFlow2 * global (inter-procedural) taint-tracking analyses. */ deprecated module TaintTracking { - import semmle.code.cpp.dataflow.internal.tainttracking1.TaintTrackingParameter::Public + import semmle.code.cpp.dataflow.internal.TaintTrackingUtil private import semmle.code.cpp.dataflow.internal.DataFlowImplSpecific private import semmle.code.cpp.dataflow.internal.TaintTrackingImplSpecific private import codeql.dataflow.TaintTracking import TaintFlowMake - import semmle.code.cpp.dataflow.internal.tainttracking1.TaintTrackingImpl } diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/TaintTracking2.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/TaintTracking2.qll deleted file mode 100644 index dce00316cbb..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/TaintTracking2.qll +++ /dev/null @@ -1,22 +0,0 @@ -/** - * 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.dataflow.TaintTracking` for the full documentation. - */ - -/** - * DEPRECATED: Use `semmle.code.cpp.dataflow.new.TaintTracking2` instead. - * - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) taint-tracking analyses. - */ -deprecated module TaintTracking2 { - import semmle.code.cpp.dataflow.internal.tainttracking2.TaintTrackingImpl -} diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl1.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl1.qll deleted file mode 100644 index 17def0c431d..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl1.qll +++ /dev/null @@ -1,361 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * Provides a `Configuration` class backwards-compatible interface to the data - * flow library. - */ - -private import DataFlowImplCommon -private import DataFlowImplSpecific::Private -import DataFlowImplSpecific::Public -private import DataFlowImpl -import DataFlowImplCommonPublic -deprecated import FlowStateString -private import codeql.util.Unit - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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 sink, 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() } - - /** - * 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. - * - * These features are generally not relevant for typical end-to-end data flow - * queries, but should only be used for constructing paths that need to - * somehow be pluggable in another path context. - */ - FlowFeature getAFeature() { none() } - - /** Holds if sources should be grouped in the result of `hasFlowPath`. */ - predicate sourceGrouping(Node source, string sourceGroup) { none() } - - /** Holds if sinks should be grouped in the result of `hasFlowPath`. */ - predicate sinkGrouping(Node sink, string sinkGroup) { none() } - - /** - * Holds if data may flow from `source` to `sink` for this configuration. - */ - predicate hasFlow(Node source, Node sink) { hasFlow(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) { hasFlowPath(source, sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } - - /** - * 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() } -} - -/** - * 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 deprecated 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) - } -} - -deprecated private FlowState relevantState(Configuration config) { - config.isSource(_, result) or - config.isSink(_, result) or - config.isBarrier(_, result) or - config.isAdditionalFlowStep(_, result, _, _) or - config.isAdditionalFlowStep(_, _, _, result) -} - -private newtype TConfigState = - deprecated TMkConfigState(Configuration config, FlowState state) { - state = relevantState(config) or state instanceof FlowStateEmpty - } - -deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) } - -deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) } - -deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) } - -deprecated private module Config implements FullStateConfigSig { - class FlowState = TConfigState; - - predicate isSource(Node source, FlowState state) { - getConfig(state).isSource(source, getState(state)) - or - getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty - } - - predicate isSink(Node sink) { none() } - - predicate isSink(Node sink, FlowState state) { - getConfig(state).isSink(sink, getState(state)) - or - getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty - } - - predicate isBarrier(Node node) { none() } - - predicate isBarrier(Node node, FlowState state) { - getConfig(state).isBarrier(node, getState(state)) or - getConfig(state).isBarrier(node) - } - - predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) } - - predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) } - - predicate isBarrierIn(Node node, FlowState state) { none() } - - predicate isBarrierOut(Node node, FlowState state) { none() } - - predicate isAdditionalFlowStep(Node node1, Node node2, string model) { - singleConfiguration() and - any(Configuration config).isAdditionalFlowStep(node1, node2) and - model = "" - } - - predicate isAdditionalFlowStep( - Node node1, FlowState state1, Node node2, FlowState state2, string model - ) { - getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and - getConfig(state2) = getConfig(state1) and - model = "" - or - not singleConfiguration() and - getConfig(state1).isAdditionalFlowStep(node1, node2) and - state2 = state1 and - model = "" - } - - predicate allowImplicitRead(Node node, ContentSet c) { - any(Configuration config).allowImplicitRead(node, c) - } - - predicate neverSkip(Node node) { none() } - - int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) } - - int accessPathLimit() { result = 5 } - - FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } - - predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } - - predicate observeDiffInformedIncrementalMode() { none() } -} - -deprecated private import Impl as I - -/** - * 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, and which can reach a sink, are generated. - */ -deprecated class PathNode instanceof I::PathNode { - /** Gets a textual representation of this element. */ - final string toString() { result = super.toString() } - - /** - * Gets a textual representation of this element, including a textual - * representation of the call context. - */ - final string toStringWithContext() { result = super.toStringWithContext() } - - /** - * 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/). - */ - final predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - /** Gets the underlying `Node`. */ - final Node getNode() { result = super.getNode() } - - /** Gets the `FlowState` of this node. */ - deprecated final FlowState getState() { result = getState(super.getState()) } - - /** Gets the associated configuration. */ - deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) } - - /** Gets a successor of this node, if any. */ - final PathNode getASuccessor() { result = super.getASuccessor() } - - /** Holds if this node is a source. */ - final predicate isSource() { super.isSource() } - - /** Holds if this node is a grouping of source nodes. */ - final predicate isSourceGroup(string group) { super.isSourceGroup(group) } - - /** Holds if this node is a grouping of sink nodes. */ - final predicate isSinkGroup(string group) { super.isSinkGroup(group) } -} - -deprecated module PathGraph = I::PathGraph; - -deprecated private predicate hasFlow(Node source, Node sink, Configuration config) { - exists(PathNode source0, PathNode sink0 | - hasFlowPath(source0, sink0, config) and - source0.getNode() = source and - sink0.getNode() = sink - ) -} - -deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) { - I::flowPath(source, sink) and source.getConfiguration() = config -} - -deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) } - -deprecated predicate flowsTo = hasFlow/3; diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll deleted file mode 100644 index 17def0c431d..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ /dev/null @@ -1,361 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * Provides a `Configuration` class backwards-compatible interface to the data - * flow library. - */ - -private import DataFlowImplCommon -private import DataFlowImplSpecific::Private -import DataFlowImplSpecific::Public -private import DataFlowImpl -import DataFlowImplCommonPublic -deprecated import FlowStateString -private import codeql.util.Unit - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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 sink, 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() } - - /** - * 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. - * - * These features are generally not relevant for typical end-to-end data flow - * queries, but should only be used for constructing paths that need to - * somehow be pluggable in another path context. - */ - FlowFeature getAFeature() { none() } - - /** Holds if sources should be grouped in the result of `hasFlowPath`. */ - predicate sourceGrouping(Node source, string sourceGroup) { none() } - - /** Holds if sinks should be grouped in the result of `hasFlowPath`. */ - predicate sinkGrouping(Node sink, string sinkGroup) { none() } - - /** - * Holds if data may flow from `source` to `sink` for this configuration. - */ - predicate hasFlow(Node source, Node sink) { hasFlow(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) { hasFlowPath(source, sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } - - /** - * 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() } -} - -/** - * 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 deprecated 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) - } -} - -deprecated private FlowState relevantState(Configuration config) { - config.isSource(_, result) or - config.isSink(_, result) or - config.isBarrier(_, result) or - config.isAdditionalFlowStep(_, result, _, _) or - config.isAdditionalFlowStep(_, _, _, result) -} - -private newtype TConfigState = - deprecated TMkConfigState(Configuration config, FlowState state) { - state = relevantState(config) or state instanceof FlowStateEmpty - } - -deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) } - -deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) } - -deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) } - -deprecated private module Config implements FullStateConfigSig { - class FlowState = TConfigState; - - predicate isSource(Node source, FlowState state) { - getConfig(state).isSource(source, getState(state)) - or - getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty - } - - predicate isSink(Node sink) { none() } - - predicate isSink(Node sink, FlowState state) { - getConfig(state).isSink(sink, getState(state)) - or - getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty - } - - predicate isBarrier(Node node) { none() } - - predicate isBarrier(Node node, FlowState state) { - getConfig(state).isBarrier(node, getState(state)) or - getConfig(state).isBarrier(node) - } - - predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) } - - predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) } - - predicate isBarrierIn(Node node, FlowState state) { none() } - - predicate isBarrierOut(Node node, FlowState state) { none() } - - predicate isAdditionalFlowStep(Node node1, Node node2, string model) { - singleConfiguration() and - any(Configuration config).isAdditionalFlowStep(node1, node2) and - model = "" - } - - predicate isAdditionalFlowStep( - Node node1, FlowState state1, Node node2, FlowState state2, string model - ) { - getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and - getConfig(state2) = getConfig(state1) and - model = "" - or - not singleConfiguration() and - getConfig(state1).isAdditionalFlowStep(node1, node2) and - state2 = state1 and - model = "" - } - - predicate allowImplicitRead(Node node, ContentSet c) { - any(Configuration config).allowImplicitRead(node, c) - } - - predicate neverSkip(Node node) { none() } - - int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) } - - int accessPathLimit() { result = 5 } - - FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } - - predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } - - predicate observeDiffInformedIncrementalMode() { none() } -} - -deprecated private import Impl as I - -/** - * 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, and which can reach a sink, are generated. - */ -deprecated class PathNode instanceof I::PathNode { - /** Gets a textual representation of this element. */ - final string toString() { result = super.toString() } - - /** - * Gets a textual representation of this element, including a textual - * representation of the call context. - */ - final string toStringWithContext() { result = super.toStringWithContext() } - - /** - * 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/). - */ - final predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - /** Gets the underlying `Node`. */ - final Node getNode() { result = super.getNode() } - - /** Gets the `FlowState` of this node. */ - deprecated final FlowState getState() { result = getState(super.getState()) } - - /** Gets the associated configuration. */ - deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) } - - /** Gets a successor of this node, if any. */ - final PathNode getASuccessor() { result = super.getASuccessor() } - - /** Holds if this node is a source. */ - final predicate isSource() { super.isSource() } - - /** Holds if this node is a grouping of source nodes. */ - final predicate isSourceGroup(string group) { super.isSourceGroup(group) } - - /** Holds if this node is a grouping of sink nodes. */ - final predicate isSinkGroup(string group) { super.isSinkGroup(group) } -} - -deprecated module PathGraph = I::PathGraph; - -deprecated private predicate hasFlow(Node source, Node sink, Configuration config) { - exists(PathNode source0, PathNode sink0 | - hasFlowPath(source0, sink0, config) and - source0.getNode() = source and - sink0.getNode() = sink - ) -} - -deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) { - I::flowPath(source, sink) and source.getConfiguration() = config -} - -deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) } - -deprecated predicate flowsTo = hasFlow/3; diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll deleted file mode 100644 index 17def0c431d..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ /dev/null @@ -1,361 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * Provides a `Configuration` class backwards-compatible interface to the data - * flow library. - */ - -private import DataFlowImplCommon -private import DataFlowImplSpecific::Private -import DataFlowImplSpecific::Public -private import DataFlowImpl -import DataFlowImplCommonPublic -deprecated import FlowStateString -private import codeql.util.Unit - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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 sink, 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() } - - /** - * 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. - * - * These features are generally not relevant for typical end-to-end data flow - * queries, but should only be used for constructing paths that need to - * somehow be pluggable in another path context. - */ - FlowFeature getAFeature() { none() } - - /** Holds if sources should be grouped in the result of `hasFlowPath`. */ - predicate sourceGrouping(Node source, string sourceGroup) { none() } - - /** Holds if sinks should be grouped in the result of `hasFlowPath`. */ - predicate sinkGrouping(Node sink, string sinkGroup) { none() } - - /** - * Holds if data may flow from `source` to `sink` for this configuration. - */ - predicate hasFlow(Node source, Node sink) { hasFlow(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) { hasFlowPath(source, sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } - - /** - * 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() } -} - -/** - * 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 deprecated 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) - } -} - -deprecated private FlowState relevantState(Configuration config) { - config.isSource(_, result) or - config.isSink(_, result) or - config.isBarrier(_, result) or - config.isAdditionalFlowStep(_, result, _, _) or - config.isAdditionalFlowStep(_, _, _, result) -} - -private newtype TConfigState = - deprecated TMkConfigState(Configuration config, FlowState state) { - state = relevantState(config) or state instanceof FlowStateEmpty - } - -deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) } - -deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) } - -deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) } - -deprecated private module Config implements FullStateConfigSig { - class FlowState = TConfigState; - - predicate isSource(Node source, FlowState state) { - getConfig(state).isSource(source, getState(state)) - or - getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty - } - - predicate isSink(Node sink) { none() } - - predicate isSink(Node sink, FlowState state) { - getConfig(state).isSink(sink, getState(state)) - or - getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty - } - - predicate isBarrier(Node node) { none() } - - predicate isBarrier(Node node, FlowState state) { - getConfig(state).isBarrier(node, getState(state)) or - getConfig(state).isBarrier(node) - } - - predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) } - - predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) } - - predicate isBarrierIn(Node node, FlowState state) { none() } - - predicate isBarrierOut(Node node, FlowState state) { none() } - - predicate isAdditionalFlowStep(Node node1, Node node2, string model) { - singleConfiguration() and - any(Configuration config).isAdditionalFlowStep(node1, node2) and - model = "" - } - - predicate isAdditionalFlowStep( - Node node1, FlowState state1, Node node2, FlowState state2, string model - ) { - getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and - getConfig(state2) = getConfig(state1) and - model = "" - or - not singleConfiguration() and - getConfig(state1).isAdditionalFlowStep(node1, node2) and - state2 = state1 and - model = "" - } - - predicate allowImplicitRead(Node node, ContentSet c) { - any(Configuration config).allowImplicitRead(node, c) - } - - predicate neverSkip(Node node) { none() } - - int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) } - - int accessPathLimit() { result = 5 } - - FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } - - predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } - - predicate observeDiffInformedIncrementalMode() { none() } -} - -deprecated private import Impl as I - -/** - * 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, and which can reach a sink, are generated. - */ -deprecated class PathNode instanceof I::PathNode { - /** Gets a textual representation of this element. */ - final string toString() { result = super.toString() } - - /** - * Gets a textual representation of this element, including a textual - * representation of the call context. - */ - final string toStringWithContext() { result = super.toStringWithContext() } - - /** - * 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/). - */ - final predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - /** Gets the underlying `Node`. */ - final Node getNode() { result = super.getNode() } - - /** Gets the `FlowState` of this node. */ - deprecated final FlowState getState() { result = getState(super.getState()) } - - /** Gets the associated configuration. */ - deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) } - - /** Gets a successor of this node, if any. */ - final PathNode getASuccessor() { result = super.getASuccessor() } - - /** Holds if this node is a source. */ - final predicate isSource() { super.isSource() } - - /** Holds if this node is a grouping of source nodes. */ - final predicate isSourceGroup(string group) { super.isSourceGroup(group) } - - /** Holds if this node is a grouping of sink nodes. */ - final predicate isSinkGroup(string group) { super.isSinkGroup(group) } -} - -deprecated module PathGraph = I::PathGraph; - -deprecated private predicate hasFlow(Node source, Node sink, Configuration config) { - exists(PathNode source0, PathNode sink0 | - hasFlowPath(source0, sink0, config) and - source0.getNode() = source and - sink0.getNode() = sink - ) -} - -deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) { - I::flowPath(source, sink) and source.getConfiguration() = config -} - -deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) } - -deprecated predicate flowsTo = hasFlow/3; diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll deleted file mode 100644 index 17def0c431d..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ /dev/null @@ -1,361 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * Provides a `Configuration` class backwards-compatible interface to the data - * flow library. - */ - -private import DataFlowImplCommon -private import DataFlowImplSpecific::Private -import DataFlowImplSpecific::Public -private import DataFlowImpl -import DataFlowImplCommonPublic -deprecated import FlowStateString -private import codeql.util.Unit - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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 sink, 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() } - - /** - * 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. - * - * These features are generally not relevant for typical end-to-end data flow - * queries, but should only be used for constructing paths that need to - * somehow be pluggable in another path context. - */ - FlowFeature getAFeature() { none() } - - /** Holds if sources should be grouped in the result of `hasFlowPath`. */ - predicate sourceGrouping(Node source, string sourceGroup) { none() } - - /** Holds if sinks should be grouped in the result of `hasFlowPath`. */ - predicate sinkGrouping(Node sink, string sinkGroup) { none() } - - /** - * Holds if data may flow from `source` to `sink` for this configuration. - */ - predicate hasFlow(Node source, Node sink) { hasFlow(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) { hasFlowPath(source, sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } - - /** - * 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() } -} - -/** - * 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 deprecated 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) - } -} - -deprecated private FlowState relevantState(Configuration config) { - config.isSource(_, result) or - config.isSink(_, result) or - config.isBarrier(_, result) or - config.isAdditionalFlowStep(_, result, _, _) or - config.isAdditionalFlowStep(_, _, _, result) -} - -private newtype TConfigState = - deprecated TMkConfigState(Configuration config, FlowState state) { - state = relevantState(config) or state instanceof FlowStateEmpty - } - -deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) } - -deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) } - -deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) } - -deprecated private module Config implements FullStateConfigSig { - class FlowState = TConfigState; - - predicate isSource(Node source, FlowState state) { - getConfig(state).isSource(source, getState(state)) - or - getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty - } - - predicate isSink(Node sink) { none() } - - predicate isSink(Node sink, FlowState state) { - getConfig(state).isSink(sink, getState(state)) - or - getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty - } - - predicate isBarrier(Node node) { none() } - - predicate isBarrier(Node node, FlowState state) { - getConfig(state).isBarrier(node, getState(state)) or - getConfig(state).isBarrier(node) - } - - predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) } - - predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) } - - predicate isBarrierIn(Node node, FlowState state) { none() } - - predicate isBarrierOut(Node node, FlowState state) { none() } - - predicate isAdditionalFlowStep(Node node1, Node node2, string model) { - singleConfiguration() and - any(Configuration config).isAdditionalFlowStep(node1, node2) and - model = "" - } - - predicate isAdditionalFlowStep( - Node node1, FlowState state1, Node node2, FlowState state2, string model - ) { - getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and - getConfig(state2) = getConfig(state1) and - model = "" - or - not singleConfiguration() and - getConfig(state1).isAdditionalFlowStep(node1, node2) and - state2 = state1 and - model = "" - } - - predicate allowImplicitRead(Node node, ContentSet c) { - any(Configuration config).allowImplicitRead(node, c) - } - - predicate neverSkip(Node node) { none() } - - int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) } - - int accessPathLimit() { result = 5 } - - FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } - - predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } - - predicate observeDiffInformedIncrementalMode() { none() } -} - -deprecated private import Impl as I - -/** - * 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, and which can reach a sink, are generated. - */ -deprecated class PathNode instanceof I::PathNode { - /** Gets a textual representation of this element. */ - final string toString() { result = super.toString() } - - /** - * Gets a textual representation of this element, including a textual - * representation of the call context. - */ - final string toStringWithContext() { result = super.toStringWithContext() } - - /** - * 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/). - */ - final predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - /** Gets the underlying `Node`. */ - final Node getNode() { result = super.getNode() } - - /** Gets the `FlowState` of this node. */ - deprecated final FlowState getState() { result = getState(super.getState()) } - - /** Gets the associated configuration. */ - deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) } - - /** Gets a successor of this node, if any. */ - final PathNode getASuccessor() { result = super.getASuccessor() } - - /** Holds if this node is a source. */ - final predicate isSource() { super.isSource() } - - /** Holds if this node is a grouping of source nodes. */ - final predicate isSourceGroup(string group) { super.isSourceGroup(group) } - - /** Holds if this node is a grouping of sink nodes. */ - final predicate isSinkGroup(string group) { super.isSinkGroup(group) } -} - -deprecated module PathGraph = I::PathGraph; - -deprecated private predicate hasFlow(Node source, Node sink, Configuration config) { - exists(PathNode source0, PathNode sink0 | - hasFlowPath(source0, sink0, config) and - source0.getNode() = source and - sink0.getNode() = sink - ) -} - -deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) { - I::flowPath(source, sink) and source.getConfiguration() = config -} - -deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) } - -deprecated predicate flowsTo = hasFlow/3; diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll deleted file mode 100644 index 17def0c431d..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ /dev/null @@ -1,361 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * Provides a `Configuration` class backwards-compatible interface to the data - * flow library. - */ - -private import DataFlowImplCommon -private import DataFlowImplSpecific::Private -import DataFlowImplSpecific::Public -private import DataFlowImpl -import DataFlowImplCommonPublic -deprecated import FlowStateString -private import codeql.util.Unit - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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 sink, 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() } - - /** - * 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. - * - * These features are generally not relevant for typical end-to-end data flow - * queries, but should only be used for constructing paths that need to - * somehow be pluggable in another path context. - */ - FlowFeature getAFeature() { none() } - - /** Holds if sources should be grouped in the result of `hasFlowPath`. */ - predicate sourceGrouping(Node source, string sourceGroup) { none() } - - /** Holds if sinks should be grouped in the result of `hasFlowPath`. */ - predicate sinkGrouping(Node sink, string sinkGroup) { none() } - - /** - * Holds if data may flow from `source` to `sink` for this configuration. - */ - predicate hasFlow(Node source, Node sink) { hasFlow(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) { hasFlowPath(source, sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } - - /** - * 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() } -} - -/** - * 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 deprecated 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) - } -} - -deprecated private FlowState relevantState(Configuration config) { - config.isSource(_, result) or - config.isSink(_, result) or - config.isBarrier(_, result) or - config.isAdditionalFlowStep(_, result, _, _) or - config.isAdditionalFlowStep(_, _, _, result) -} - -private newtype TConfigState = - deprecated TMkConfigState(Configuration config, FlowState state) { - state = relevantState(config) or state instanceof FlowStateEmpty - } - -deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) } - -deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) } - -deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) } - -deprecated private module Config implements FullStateConfigSig { - class FlowState = TConfigState; - - predicate isSource(Node source, FlowState state) { - getConfig(state).isSource(source, getState(state)) - or - getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty - } - - predicate isSink(Node sink) { none() } - - predicate isSink(Node sink, FlowState state) { - getConfig(state).isSink(sink, getState(state)) - or - getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty - } - - predicate isBarrier(Node node) { none() } - - predicate isBarrier(Node node, FlowState state) { - getConfig(state).isBarrier(node, getState(state)) or - getConfig(state).isBarrier(node) - } - - predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) } - - predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) } - - predicate isBarrierIn(Node node, FlowState state) { none() } - - predicate isBarrierOut(Node node, FlowState state) { none() } - - predicate isAdditionalFlowStep(Node node1, Node node2, string model) { - singleConfiguration() and - any(Configuration config).isAdditionalFlowStep(node1, node2) and - model = "" - } - - predicate isAdditionalFlowStep( - Node node1, FlowState state1, Node node2, FlowState state2, string model - ) { - getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and - getConfig(state2) = getConfig(state1) and - model = "" - or - not singleConfiguration() and - getConfig(state1).isAdditionalFlowStep(node1, node2) and - state2 = state1 and - model = "" - } - - predicate allowImplicitRead(Node node, ContentSet c) { - any(Configuration config).allowImplicitRead(node, c) - } - - predicate neverSkip(Node node) { none() } - - int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) } - - int accessPathLimit() { result = 5 } - - FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } - - predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } - - predicate observeDiffInformedIncrementalMode() { none() } -} - -deprecated private import Impl as I - -/** - * 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, and which can reach a sink, are generated. - */ -deprecated class PathNode instanceof I::PathNode { - /** Gets a textual representation of this element. */ - final string toString() { result = super.toString() } - - /** - * Gets a textual representation of this element, including a textual - * representation of the call context. - */ - final string toStringWithContext() { result = super.toStringWithContext() } - - /** - * 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/). - */ - final predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - /** Gets the underlying `Node`. */ - final Node getNode() { result = super.getNode() } - - /** Gets the `FlowState` of this node. */ - deprecated final FlowState getState() { result = getState(super.getState()) } - - /** Gets the associated configuration. */ - deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) } - - /** Gets a successor of this node, if any. */ - final PathNode getASuccessor() { result = super.getASuccessor() } - - /** Holds if this node is a source. */ - final predicate isSource() { super.isSource() } - - /** Holds if this node is a grouping of source nodes. */ - final predicate isSourceGroup(string group) { super.isSourceGroup(group) } - - /** Holds if this node is a grouping of sink nodes. */ - final predicate isSinkGroup(string group) { super.isSinkGroup(group) } -} - -deprecated module PathGraph = I::PathGraph; - -deprecated private predicate hasFlow(Node source, Node sink, Configuration config) { - exists(PathNode source0, PathNode sink0 | - hasFlowPath(source0, sink0, config) and - source0.getNode() = source and - sink0.getNode() = sink - ) -} - -deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) { - I::flowPath(source, sink) and source.getConfiguration() = config -} - -deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) } - -deprecated predicate flowsTo = hasFlow/3; diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll index b4f325e01df..4a8ea4ebd43 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll @@ -729,41 +729,39 @@ private predicate exprToDefinitionByReferenceStep(Expr exprIn, Expr argOut) { private module FieldFlow { private import DataFlowImplCommon - private import DataFlowImplLocal private import DataFlowPrivate + private import semmle.code.cpp.dataflow.DataFlow /** - * A configuration for finding local-only flow through fields. This uses the - * `Configuration` class in the dedicated `DataFlowImplLocal` copy of the - * shared library that's not user-exposed directly. + * A configuration for finding local-only flow through fields. * * To keep the flow local to a single function, we put barriers on parameters * and return statements. Sources and sinks are the values that go into and * out of fields, respectively. */ - private class FieldConfiguration extends Configuration { - FieldConfiguration() { this = "FieldConfiguration" } - - override predicate isSource(Node source) { + private module FieldConfig implements DataFlow::ConfigSig { + predicate isSource(Node source) { storeStep(source, _, _) or // Also mark `foo(a.b);` as a source when `a.b` may be overwritten by `foo`. readStep(_, _, any(Node node | node.asExpr() = source.asDefiningArgument())) } - override predicate isSink(Node sink) { readStep(_, _, sink) } + predicate isSink(Node sink) { readStep(_, _, sink) } - override predicate isBarrier(Node node) { node instanceof ParameterNode } + predicate isBarrier(Node node) { node instanceof ParameterNode } - override predicate isBarrierOut(Node node) { + predicate isBarrierOut(Node node) { node.asExpr().getParent() instanceof ReturnStmt or node.asExpr().getParent() instanceof ThrowExpr } } + private module Flow = DataFlow::Global; + predicate fieldFlow(Node node1, Node node2) { - exists(FieldConfiguration cfg | cfg.hasFlow(node1, node2)) and + Flow::flow(node1, node2) and // This configuration should not be able to cross function boundaries, but // we double-check here just to be sure. getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) 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 deleted file mode 100644 index 75e7856fd26..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ /dev/null @@ -1,168 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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) } - - /** - * 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/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingParameter.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingParameter.qll deleted file mode 100644 index f9346e28434..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingParameter.qll +++ /dev/null @@ -1,10 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - */ - -import semmle.code.cpp.dataflow.internal.TaintTrackingUtil as Public - -module Private { - import semmle.code.cpp.dataflow.DataFlow::DataFlow as DataFlow - import semmle.code.cpp.dataflow.internal.DataFlowImpl as DataFlowInternal -} 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 deleted file mode 100644 index 75e7856fd26..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ /dev/null @@ -1,168 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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) } - - /** - * 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/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingParameter.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingParameter.qll deleted file mode 100644 index e935b8d4d08..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingParameter.qll +++ /dev/null @@ -1,9 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - */ - -import semmle.code.cpp.dataflow.internal.TaintTrackingUtil as Public - -module Private { - import semmle.code.cpp.dataflow.DataFlow2::DataFlow2 as DataFlow -} diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/new/DataFlow.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/new/DataFlow.qll index bcbebd0de1e..2067dc8aac0 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/new/DataFlow.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/new/DataFlow.qll @@ -29,5 +29,5 @@ module DataFlow { private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific private import codeql.dataflow.DataFlow import DataFlowMake - import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl1 + import Public } diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/new/DataFlow2.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/new/DataFlow2.qll deleted file mode 100644 index 35c5a34a656..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/new/DataFlow2.qll +++ /dev/null @@ -1,20 +0,0 @@ -/** - * 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.dataflow.new.DataFlow` for the full documentation. - */ - -import cpp - -/** - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) data flow analyses. - */ -module DataFlow2 { - import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl2 -} diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/new/DataFlow3.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/new/DataFlow3.qll deleted file mode 100644 index e2e402835f2..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/new/DataFlow3.qll +++ /dev/null @@ -1,20 +0,0 @@ -/** - * 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.dataflow.new.DataFlow` for the full documentation. - */ - -import cpp - -/** - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) data flow analyses. - */ -module DataFlow3 { - import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl3 -} diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/new/DataFlow4.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/new/DataFlow4.qll deleted file mode 100644 index f9209abe1e1..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/new/DataFlow4.qll +++ /dev/null @@ -1,20 +0,0 @@ -/** - * 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.dataflow.new.DataFlow` for the full documentation. - */ - -import cpp - -/** - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) data flow analyses. - */ -module DataFlow4 { - import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl4 -} diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/new/TaintTracking.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/new/TaintTracking.qll index d28a389203f..ecc927ecad7 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/new/TaintTracking.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/new/TaintTracking.qll @@ -16,18 +16,16 @@ */ import semmle.code.cpp.dataflow.new.DataFlow -import semmle.code.cpp.dataflow.new.DataFlow2 /** * Provides classes for performing local (intra-procedural) and * global (inter-procedural) taint-tracking analyses. */ module TaintTracking { - import semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTrackingParameter::Public + import semmle.code.cpp.ir.dataflow.internal.TaintTrackingUtil private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific private import semmle.code.cpp.ir.dataflow.internal.TaintTrackingImplSpecific private import codeql.dataflow.TaintTracking private import semmle.code.cpp.Location import TaintFlowMake - import semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTrackingImpl } diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/new/TaintTracking2.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/new/TaintTracking2.qll deleted file mode 100644 index 2da049cefaf..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/new/TaintTracking2.qll +++ /dev/null @@ -1,20 +0,0 @@ -/** - * 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.dataflow.new.TaintTracking` for the full documentation. - */ - -/** - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) taint-tracking analyses. - */ -module TaintTracking2 { - import semmle.code.cpp.ir.dataflow.internal.tainttracking2.TaintTrackingImpl -} diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/new/TaintTracking3.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/new/TaintTracking3.qll deleted file mode 100644 index 113175d8369..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/new/TaintTracking3.qll +++ /dev/null @@ -1,20 +0,0 @@ -/** - * 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.dataflow.new.TaintTracking` for the full documentation. - */ - -/** - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) taint-tracking analyses. - */ -module TaintTracking3 { - import semmle.code.cpp.ir.dataflow.internal.tainttracking3.TaintTrackingImpl -} diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/DataFlow.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/DataFlow.qll index 671d82c74ef..ecd474d64b2 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/DataFlow.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/DataFlow.qll @@ -25,5 +25,5 @@ module DataFlow { private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific private import codeql.dataflow.DataFlow import DataFlowMake - import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl1 + import Public } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/DataFlow2.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/DataFlow2.qll deleted file mode 100644 index 95eb979192d..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/DataFlow2.qll +++ /dev/null @@ -1,16 +0,0 @@ -/** - * 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 semmle.code.cpp.ir.dataflow.internal.DataFlowImpl2 -} diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/DataFlow3.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/DataFlow3.qll deleted file mode 100644 index 42529f78e5b..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/DataFlow3.qll +++ /dev/null @@ -1,16 +0,0 @@ -/** - * 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 semmle.code.cpp.ir.dataflow.internal.DataFlowImpl3 -} diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/DataFlow4.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/DataFlow4.qll deleted file mode 100644 index 6cd49e39e71..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/DataFlow4.qll +++ /dev/null @@ -1,16 +0,0 @@ -/** - * 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 semmle.code.cpp.ir.dataflow.internal.DataFlowImpl4 -} diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/TaintTracking.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/TaintTracking.qll index 9ca1315ec3e..69bb1978cf6 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/TaintTracking.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/TaintTracking.qll @@ -16,13 +16,11 @@ */ import semmle.code.cpp.ir.dataflow.DataFlow -import semmle.code.cpp.ir.dataflow.DataFlow2 module TaintTracking { - import semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTrackingParameter::Public + import semmle.code.cpp.ir.dataflow.internal.TaintTrackingUtil private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific private import semmle.code.cpp.ir.dataflow.internal.TaintTrackingImplSpecific private import codeql.dataflow.TaintTracking import TaintFlowMake - import semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTrackingImpl } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/TaintTracking2.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/TaintTracking2.qll deleted file mode 100644 index 3ef03a3bd2c..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/TaintTracking2.qll +++ /dev/null @@ -1,15 +0,0 @@ -/** - * 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 semmle.code.cpp.ir.dataflow.internal.tainttracking2.TaintTrackingImpl -} diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/TaintTracking3.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/TaintTracking3.qll deleted file mode 100644 index 98e1caebf38..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/TaintTracking3.qll +++ /dev/null @@ -1,15 +0,0 @@ -/** - * 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 semmle.code.cpp.ir.dataflow.internal.tainttracking3.TaintTrackingImpl -} diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl1.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl1.qll deleted file mode 100644 index 17def0c431d..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl1.qll +++ /dev/null @@ -1,361 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * Provides a `Configuration` class backwards-compatible interface to the data - * flow library. - */ - -private import DataFlowImplCommon -private import DataFlowImplSpecific::Private -import DataFlowImplSpecific::Public -private import DataFlowImpl -import DataFlowImplCommonPublic -deprecated import FlowStateString -private import codeql.util.Unit - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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 sink, 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() } - - /** - * 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. - * - * These features are generally not relevant for typical end-to-end data flow - * queries, but should only be used for constructing paths that need to - * somehow be pluggable in another path context. - */ - FlowFeature getAFeature() { none() } - - /** Holds if sources should be grouped in the result of `hasFlowPath`. */ - predicate sourceGrouping(Node source, string sourceGroup) { none() } - - /** Holds if sinks should be grouped in the result of `hasFlowPath`. */ - predicate sinkGrouping(Node sink, string sinkGroup) { none() } - - /** - * Holds if data may flow from `source` to `sink` for this configuration. - */ - predicate hasFlow(Node source, Node sink) { hasFlow(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) { hasFlowPath(source, sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } - - /** - * 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() } -} - -/** - * 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 deprecated 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) - } -} - -deprecated private FlowState relevantState(Configuration config) { - config.isSource(_, result) or - config.isSink(_, result) or - config.isBarrier(_, result) or - config.isAdditionalFlowStep(_, result, _, _) or - config.isAdditionalFlowStep(_, _, _, result) -} - -private newtype TConfigState = - deprecated TMkConfigState(Configuration config, FlowState state) { - state = relevantState(config) or state instanceof FlowStateEmpty - } - -deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) } - -deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) } - -deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) } - -deprecated private module Config implements FullStateConfigSig { - class FlowState = TConfigState; - - predicate isSource(Node source, FlowState state) { - getConfig(state).isSource(source, getState(state)) - or - getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty - } - - predicate isSink(Node sink) { none() } - - predicate isSink(Node sink, FlowState state) { - getConfig(state).isSink(sink, getState(state)) - or - getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty - } - - predicate isBarrier(Node node) { none() } - - predicate isBarrier(Node node, FlowState state) { - getConfig(state).isBarrier(node, getState(state)) or - getConfig(state).isBarrier(node) - } - - predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) } - - predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) } - - predicate isBarrierIn(Node node, FlowState state) { none() } - - predicate isBarrierOut(Node node, FlowState state) { none() } - - predicate isAdditionalFlowStep(Node node1, Node node2, string model) { - singleConfiguration() and - any(Configuration config).isAdditionalFlowStep(node1, node2) and - model = "" - } - - predicate isAdditionalFlowStep( - Node node1, FlowState state1, Node node2, FlowState state2, string model - ) { - getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and - getConfig(state2) = getConfig(state1) and - model = "" - or - not singleConfiguration() and - getConfig(state1).isAdditionalFlowStep(node1, node2) and - state2 = state1 and - model = "" - } - - predicate allowImplicitRead(Node node, ContentSet c) { - any(Configuration config).allowImplicitRead(node, c) - } - - predicate neverSkip(Node node) { none() } - - int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) } - - int accessPathLimit() { result = 5 } - - FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } - - predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } - - predicate observeDiffInformedIncrementalMode() { none() } -} - -deprecated private import Impl as I - -/** - * 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, and which can reach a sink, are generated. - */ -deprecated class PathNode instanceof I::PathNode { - /** Gets a textual representation of this element. */ - final string toString() { result = super.toString() } - - /** - * Gets a textual representation of this element, including a textual - * representation of the call context. - */ - final string toStringWithContext() { result = super.toStringWithContext() } - - /** - * 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/). - */ - final predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - /** Gets the underlying `Node`. */ - final Node getNode() { result = super.getNode() } - - /** Gets the `FlowState` of this node. */ - deprecated final FlowState getState() { result = getState(super.getState()) } - - /** Gets the associated configuration. */ - deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) } - - /** Gets a successor of this node, if any. */ - final PathNode getASuccessor() { result = super.getASuccessor() } - - /** Holds if this node is a source. */ - final predicate isSource() { super.isSource() } - - /** Holds if this node is a grouping of source nodes. */ - final predicate isSourceGroup(string group) { super.isSourceGroup(group) } - - /** Holds if this node is a grouping of sink nodes. */ - final predicate isSinkGroup(string group) { super.isSinkGroup(group) } -} - -deprecated module PathGraph = I::PathGraph; - -deprecated private predicate hasFlow(Node source, Node sink, Configuration config) { - exists(PathNode source0, PathNode sink0 | - hasFlowPath(source0, sink0, config) and - source0.getNode() = source and - sink0.getNode() = sink - ) -} - -deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) { - I::flowPath(source, sink) and source.getConfiguration() = config -} - -deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) } - -deprecated predicate flowsTo = hasFlow/3; diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll deleted file mode 100644 index 17def0c431d..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ /dev/null @@ -1,361 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * Provides a `Configuration` class backwards-compatible interface to the data - * flow library. - */ - -private import DataFlowImplCommon -private import DataFlowImplSpecific::Private -import DataFlowImplSpecific::Public -private import DataFlowImpl -import DataFlowImplCommonPublic -deprecated import FlowStateString -private import codeql.util.Unit - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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 sink, 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() } - - /** - * 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. - * - * These features are generally not relevant for typical end-to-end data flow - * queries, but should only be used for constructing paths that need to - * somehow be pluggable in another path context. - */ - FlowFeature getAFeature() { none() } - - /** Holds if sources should be grouped in the result of `hasFlowPath`. */ - predicate sourceGrouping(Node source, string sourceGroup) { none() } - - /** Holds if sinks should be grouped in the result of `hasFlowPath`. */ - predicate sinkGrouping(Node sink, string sinkGroup) { none() } - - /** - * Holds if data may flow from `source` to `sink` for this configuration. - */ - predicate hasFlow(Node source, Node sink) { hasFlow(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) { hasFlowPath(source, sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } - - /** - * 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() } -} - -/** - * 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 deprecated 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) - } -} - -deprecated private FlowState relevantState(Configuration config) { - config.isSource(_, result) or - config.isSink(_, result) or - config.isBarrier(_, result) or - config.isAdditionalFlowStep(_, result, _, _) or - config.isAdditionalFlowStep(_, _, _, result) -} - -private newtype TConfigState = - deprecated TMkConfigState(Configuration config, FlowState state) { - state = relevantState(config) or state instanceof FlowStateEmpty - } - -deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) } - -deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) } - -deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) } - -deprecated private module Config implements FullStateConfigSig { - class FlowState = TConfigState; - - predicate isSource(Node source, FlowState state) { - getConfig(state).isSource(source, getState(state)) - or - getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty - } - - predicate isSink(Node sink) { none() } - - predicate isSink(Node sink, FlowState state) { - getConfig(state).isSink(sink, getState(state)) - or - getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty - } - - predicate isBarrier(Node node) { none() } - - predicate isBarrier(Node node, FlowState state) { - getConfig(state).isBarrier(node, getState(state)) or - getConfig(state).isBarrier(node) - } - - predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) } - - predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) } - - predicate isBarrierIn(Node node, FlowState state) { none() } - - predicate isBarrierOut(Node node, FlowState state) { none() } - - predicate isAdditionalFlowStep(Node node1, Node node2, string model) { - singleConfiguration() and - any(Configuration config).isAdditionalFlowStep(node1, node2) and - model = "" - } - - predicate isAdditionalFlowStep( - Node node1, FlowState state1, Node node2, FlowState state2, string model - ) { - getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and - getConfig(state2) = getConfig(state1) and - model = "" - or - not singleConfiguration() and - getConfig(state1).isAdditionalFlowStep(node1, node2) and - state2 = state1 and - model = "" - } - - predicate allowImplicitRead(Node node, ContentSet c) { - any(Configuration config).allowImplicitRead(node, c) - } - - predicate neverSkip(Node node) { none() } - - int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) } - - int accessPathLimit() { result = 5 } - - FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } - - predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } - - predicate observeDiffInformedIncrementalMode() { none() } -} - -deprecated private import Impl as I - -/** - * 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, and which can reach a sink, are generated. - */ -deprecated class PathNode instanceof I::PathNode { - /** Gets a textual representation of this element. */ - final string toString() { result = super.toString() } - - /** - * Gets a textual representation of this element, including a textual - * representation of the call context. - */ - final string toStringWithContext() { result = super.toStringWithContext() } - - /** - * 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/). - */ - final predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - /** Gets the underlying `Node`. */ - final Node getNode() { result = super.getNode() } - - /** Gets the `FlowState` of this node. */ - deprecated final FlowState getState() { result = getState(super.getState()) } - - /** Gets the associated configuration. */ - deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) } - - /** Gets a successor of this node, if any. */ - final PathNode getASuccessor() { result = super.getASuccessor() } - - /** Holds if this node is a source. */ - final predicate isSource() { super.isSource() } - - /** Holds if this node is a grouping of source nodes. */ - final predicate isSourceGroup(string group) { super.isSourceGroup(group) } - - /** Holds if this node is a grouping of sink nodes. */ - final predicate isSinkGroup(string group) { super.isSinkGroup(group) } -} - -deprecated module PathGraph = I::PathGraph; - -deprecated private predicate hasFlow(Node source, Node sink, Configuration config) { - exists(PathNode source0, PathNode sink0 | - hasFlowPath(source0, sink0, config) and - source0.getNode() = source and - sink0.getNode() = sink - ) -} - -deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) { - I::flowPath(source, sink) and source.getConfiguration() = config -} - -deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) } - -deprecated predicate flowsTo = hasFlow/3; diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll deleted file mode 100644 index 17def0c431d..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ /dev/null @@ -1,361 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * Provides a `Configuration` class backwards-compatible interface to the data - * flow library. - */ - -private import DataFlowImplCommon -private import DataFlowImplSpecific::Private -import DataFlowImplSpecific::Public -private import DataFlowImpl -import DataFlowImplCommonPublic -deprecated import FlowStateString -private import codeql.util.Unit - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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 sink, 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() } - - /** - * 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. - * - * These features are generally not relevant for typical end-to-end data flow - * queries, but should only be used for constructing paths that need to - * somehow be pluggable in another path context. - */ - FlowFeature getAFeature() { none() } - - /** Holds if sources should be grouped in the result of `hasFlowPath`. */ - predicate sourceGrouping(Node source, string sourceGroup) { none() } - - /** Holds if sinks should be grouped in the result of `hasFlowPath`. */ - predicate sinkGrouping(Node sink, string sinkGroup) { none() } - - /** - * Holds if data may flow from `source` to `sink` for this configuration. - */ - predicate hasFlow(Node source, Node sink) { hasFlow(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) { hasFlowPath(source, sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } - - /** - * 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() } -} - -/** - * 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 deprecated 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) - } -} - -deprecated private FlowState relevantState(Configuration config) { - config.isSource(_, result) or - config.isSink(_, result) or - config.isBarrier(_, result) or - config.isAdditionalFlowStep(_, result, _, _) or - config.isAdditionalFlowStep(_, _, _, result) -} - -private newtype TConfigState = - deprecated TMkConfigState(Configuration config, FlowState state) { - state = relevantState(config) or state instanceof FlowStateEmpty - } - -deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) } - -deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) } - -deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) } - -deprecated private module Config implements FullStateConfigSig { - class FlowState = TConfigState; - - predicate isSource(Node source, FlowState state) { - getConfig(state).isSource(source, getState(state)) - or - getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty - } - - predicate isSink(Node sink) { none() } - - predicate isSink(Node sink, FlowState state) { - getConfig(state).isSink(sink, getState(state)) - or - getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty - } - - predicate isBarrier(Node node) { none() } - - predicate isBarrier(Node node, FlowState state) { - getConfig(state).isBarrier(node, getState(state)) or - getConfig(state).isBarrier(node) - } - - predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) } - - predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) } - - predicate isBarrierIn(Node node, FlowState state) { none() } - - predicate isBarrierOut(Node node, FlowState state) { none() } - - predicate isAdditionalFlowStep(Node node1, Node node2, string model) { - singleConfiguration() and - any(Configuration config).isAdditionalFlowStep(node1, node2) and - model = "" - } - - predicate isAdditionalFlowStep( - Node node1, FlowState state1, Node node2, FlowState state2, string model - ) { - getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and - getConfig(state2) = getConfig(state1) and - model = "" - or - not singleConfiguration() and - getConfig(state1).isAdditionalFlowStep(node1, node2) and - state2 = state1 and - model = "" - } - - predicate allowImplicitRead(Node node, ContentSet c) { - any(Configuration config).allowImplicitRead(node, c) - } - - predicate neverSkip(Node node) { none() } - - int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) } - - int accessPathLimit() { result = 5 } - - FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } - - predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } - - predicate observeDiffInformedIncrementalMode() { none() } -} - -deprecated private import Impl as I - -/** - * 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, and which can reach a sink, are generated. - */ -deprecated class PathNode instanceof I::PathNode { - /** Gets a textual representation of this element. */ - final string toString() { result = super.toString() } - - /** - * Gets a textual representation of this element, including a textual - * representation of the call context. - */ - final string toStringWithContext() { result = super.toStringWithContext() } - - /** - * 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/). - */ - final predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - /** Gets the underlying `Node`. */ - final Node getNode() { result = super.getNode() } - - /** Gets the `FlowState` of this node. */ - deprecated final FlowState getState() { result = getState(super.getState()) } - - /** Gets the associated configuration. */ - deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) } - - /** Gets a successor of this node, if any. */ - final PathNode getASuccessor() { result = super.getASuccessor() } - - /** Holds if this node is a source. */ - final predicate isSource() { super.isSource() } - - /** Holds if this node is a grouping of source nodes. */ - final predicate isSourceGroup(string group) { super.isSourceGroup(group) } - - /** Holds if this node is a grouping of sink nodes. */ - final predicate isSinkGroup(string group) { super.isSinkGroup(group) } -} - -deprecated module PathGraph = I::PathGraph; - -deprecated private predicate hasFlow(Node source, Node sink, Configuration config) { - exists(PathNode source0, PathNode sink0 | - hasFlowPath(source0, sink0, config) and - source0.getNode() = source and - sink0.getNode() = sink - ) -} - -deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) { - I::flowPath(source, sink) and source.getConfiguration() = config -} - -deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) } - -deprecated predicate flowsTo = hasFlow/3; diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll deleted file mode 100644 index 17def0c431d..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ /dev/null @@ -1,361 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * Provides a `Configuration` class backwards-compatible interface to the data - * flow library. - */ - -private import DataFlowImplCommon -private import DataFlowImplSpecific::Private -import DataFlowImplSpecific::Public -private import DataFlowImpl -import DataFlowImplCommonPublic -deprecated import FlowStateString -private import codeql.util.Unit - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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 sink, 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() } - - /** - * 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. - * - * These features are generally not relevant for typical end-to-end data flow - * queries, but should only be used for constructing paths that need to - * somehow be pluggable in another path context. - */ - FlowFeature getAFeature() { none() } - - /** Holds if sources should be grouped in the result of `hasFlowPath`. */ - predicate sourceGrouping(Node source, string sourceGroup) { none() } - - /** Holds if sinks should be grouped in the result of `hasFlowPath`. */ - predicate sinkGrouping(Node sink, string sinkGroup) { none() } - - /** - * Holds if data may flow from `source` to `sink` for this configuration. - */ - predicate hasFlow(Node source, Node sink) { hasFlow(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) { hasFlowPath(source, sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } - - /** - * 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() } -} - -/** - * 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 deprecated 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) - } -} - -deprecated private FlowState relevantState(Configuration config) { - config.isSource(_, result) or - config.isSink(_, result) or - config.isBarrier(_, result) or - config.isAdditionalFlowStep(_, result, _, _) or - config.isAdditionalFlowStep(_, _, _, result) -} - -private newtype TConfigState = - deprecated TMkConfigState(Configuration config, FlowState state) { - state = relevantState(config) or state instanceof FlowStateEmpty - } - -deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) } - -deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) } - -deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) } - -deprecated private module Config implements FullStateConfigSig { - class FlowState = TConfigState; - - predicate isSource(Node source, FlowState state) { - getConfig(state).isSource(source, getState(state)) - or - getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty - } - - predicate isSink(Node sink) { none() } - - predicate isSink(Node sink, FlowState state) { - getConfig(state).isSink(sink, getState(state)) - or - getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty - } - - predicate isBarrier(Node node) { none() } - - predicate isBarrier(Node node, FlowState state) { - getConfig(state).isBarrier(node, getState(state)) or - getConfig(state).isBarrier(node) - } - - predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) } - - predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) } - - predicate isBarrierIn(Node node, FlowState state) { none() } - - predicate isBarrierOut(Node node, FlowState state) { none() } - - predicate isAdditionalFlowStep(Node node1, Node node2, string model) { - singleConfiguration() and - any(Configuration config).isAdditionalFlowStep(node1, node2) and - model = "" - } - - predicate isAdditionalFlowStep( - Node node1, FlowState state1, Node node2, FlowState state2, string model - ) { - getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and - getConfig(state2) = getConfig(state1) and - model = "" - or - not singleConfiguration() and - getConfig(state1).isAdditionalFlowStep(node1, node2) and - state2 = state1 and - model = "" - } - - predicate allowImplicitRead(Node node, ContentSet c) { - any(Configuration config).allowImplicitRead(node, c) - } - - predicate neverSkip(Node node) { none() } - - int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) } - - int accessPathLimit() { result = 5 } - - FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } - - predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } - - predicate observeDiffInformedIncrementalMode() { none() } -} - -deprecated private import Impl as I - -/** - * 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, and which can reach a sink, are generated. - */ -deprecated class PathNode instanceof I::PathNode { - /** Gets a textual representation of this element. */ - final string toString() { result = super.toString() } - - /** - * Gets a textual representation of this element, including a textual - * representation of the call context. - */ - final string toStringWithContext() { result = super.toStringWithContext() } - - /** - * 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/). - */ - final predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - /** Gets the underlying `Node`. */ - final Node getNode() { result = super.getNode() } - - /** Gets the `FlowState` of this node. */ - deprecated final FlowState getState() { result = getState(super.getState()) } - - /** Gets the associated configuration. */ - deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) } - - /** Gets a successor of this node, if any. */ - final PathNode getASuccessor() { result = super.getASuccessor() } - - /** Holds if this node is a source. */ - final predicate isSource() { super.isSource() } - - /** Holds if this node is a grouping of source nodes. */ - final predicate isSourceGroup(string group) { super.isSourceGroup(group) } - - /** Holds if this node is a grouping of sink nodes. */ - final predicate isSinkGroup(string group) { super.isSinkGroup(group) } -} - -deprecated module PathGraph = I::PathGraph; - -deprecated private predicate hasFlow(Node source, Node sink, Configuration config) { - exists(PathNode source0, PathNode sink0 | - hasFlowPath(source0, sink0, config) and - source0.getNode() = source and - sink0.getNode() = sink - ) -} - -deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) { - I::flowPath(source, sink) and source.getConfiguration() = config -} - -deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) } - -deprecated predicate flowsTo = hasFlow/3; diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ProductFlow.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ProductFlow.qll index 0c474b0e75d..ff5f3e46e64 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ProductFlow.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ProductFlow.qll @@ -545,7 +545,7 @@ module ProductFlow { private predicate outImpl1(Flow1::PathNode pred1, Flow1::PathNode succ1, DataFlowCall call) { Flow1::PathGraph::edges(pred1, succ1, _, _) and exists(ReturnKindExt returnKind | - succ1.getNode() = returnKind.getAnOutNode(call) and + succ1.getNode() = getAnOutNodeExt(call, returnKind) and returnKind = getParamReturnPosition(_, pred1.asParameterReturnNode()).getKind() ) } @@ -573,7 +573,7 @@ module ProductFlow { private predicate outImpl2(Flow2::PathNode pred2, Flow2::PathNode succ2, DataFlowCall call) { Flow2::PathGraph::edges(pred2, succ2, _, _) and exists(ReturnKindExt returnKind | - succ2.getNode() = returnKind.getAnOutNode(call) and + succ2.getNode() = getAnOutNodeExt(call, returnKind) and returnKind = getParamReturnPosition(_, pred2.asParameterReturnNode()).getKind() ) } 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 deleted file mode 100644 index 75e7856fd26..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ /dev/null @@ -1,168 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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) } - - /** - * 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/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingParameter.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingParameter.qll deleted file mode 100644 index 19e10871a78..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingParameter.qll +++ /dev/null @@ -1,6 +0,0 @@ -import semmle.code.cpp.ir.dataflow.internal.TaintTrackingUtil as Public - -module Private { - import semmle.code.cpp.ir.dataflow.DataFlow::DataFlow as DataFlow - import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl as DataFlowInternal -} 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 deleted file mode 100644 index 75e7856fd26..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ /dev/null @@ -1,168 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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) } - - /** - * 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/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingParameter.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingParameter.qll deleted file mode 100644 index ac0b79d067e..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingParameter.qll +++ /dev/null @@ -1,5 +0,0 @@ -import semmle.code.cpp.ir.dataflow.internal.TaintTrackingUtil as Public - -module Private { - import semmle.code.cpp.ir.dataflow.DataFlow2::DataFlow2 as DataFlow -} 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 deleted file mode 100644 index 75e7856fd26..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll +++ /dev/null @@ -1,168 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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) } - - /** - * 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/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingParameter.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingParameter.qll deleted file mode 100644 index 2a3b69f55cd..00000000000 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingParameter.qll +++ /dev/null @@ -1,5 +0,0 @@ -import semmle.code.cpp.ir.dataflow.internal.TaintTrackingUtil as Public - -module Private { - import semmle.code.cpp.ir.dataflow.DataFlow3::DataFlow3 as DataFlow -} diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll index daa6bdaafcf..2ddc55f91f5 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll @@ -364,10 +364,14 @@ class TranslatedFunctionCall extends TranslatedCallExpr, TranslatedDirectCall { final override predicate mayThrowException() { expr.getTarget().(ThrowingFunction).mayThrowException(_) + or + expr.getTarget() instanceof AlwaysSehThrowingFunction } final override predicate mustThrowException() { expr.getTarget().(ThrowingFunction).mayThrowException(true) + or + expr.getTarget() instanceof AlwaysSehThrowingFunction } } diff --git a/cpp/ql/lib/semmle/code/cpp/models/Models.qll b/cpp/ql/lib/semmle/code/cpp/models/Models.qll index 1e0b6cd33ed..f6776a623ff 100644 --- a/cpp/ql/lib/semmle/code/cpp/models/Models.qll +++ b/cpp/ql/lib/semmle/code/cpp/models/Models.qll @@ -49,3 +49,4 @@ private import implementations.PostgreSql private import implementations.System private import implementations.StructuredExceptionHandling private import implementations.ZMQ +private import implementations.Win32CommandExecution diff --git a/cpp/ql/lib/semmle/code/cpp/models/implementations/Memcpy.qll b/cpp/ql/lib/semmle/code/cpp/models/implementations/Memcpy.qll index 0bf2dd31fe4..311847e8aec 100644 --- a/cpp/ql/lib/semmle/code/cpp/models/implementations/Memcpy.qll +++ b/cpp/ql/lib/semmle/code/cpp/models/implementations/Memcpy.qll @@ -16,7 +16,7 @@ import semmle.code.cpp.models.interfaces.NonThrowing * `__builtin___memcpy_chk`. */ private class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffectFunction, - AliasFunction, NonThrowingFunction + AliasFunction, NonCppThrowingFunction { MemcpyFunction() { // memcpy(dest, src, num) diff --git a/cpp/ql/lib/semmle/code/cpp/models/implementations/Memset.qll b/cpp/ql/lib/semmle/code/cpp/models/implementations/Memset.qll index ab2e0af99f3..51234e50f94 100644 --- a/cpp/ql/lib/semmle/code/cpp/models/implementations/Memset.qll +++ b/cpp/ql/lib/semmle/code/cpp/models/implementations/Memset.qll @@ -11,7 +11,7 @@ import semmle.code.cpp.models.interfaces.SideEffect import semmle.code.cpp.models.interfaces.NonThrowing private class MemsetFunctionModel extends ArrayFunction, DataFlowFunction, AliasFunction, - SideEffectFunction, NonThrowingFunction + SideEffectFunction, NonCppThrowingFunction { MemsetFunctionModel() { this.hasGlobalOrStdOrBslName("memset") diff --git a/cpp/ql/lib/semmle/code/cpp/models/implementations/NoexceptFunction.qll b/cpp/ql/lib/semmle/code/cpp/models/implementations/NoexceptFunction.qll index b0f76ee6538..22f860bc593 100644 --- a/cpp/ql/lib/semmle/code/cpp/models/implementations/NoexceptFunction.qll +++ b/cpp/ql/lib/semmle/code/cpp/models/implementations/NoexceptFunction.qll @@ -6,6 +6,6 @@ import semmle.code.cpp.models.interfaces.NonThrowing * * Note: The `throw` specifier was deprecated in C++11 and removed in C++17. */ -class NoexceptFunction extends NonThrowingFunction { +class NoexceptFunction extends NonCppThrowingFunction { NoexceptFunction() { this.isNoExcept() or this.isNoThrow() } } diff --git a/cpp/ql/lib/semmle/code/cpp/models/implementations/Printf.qll b/cpp/ql/lib/semmle/code/cpp/models/implementations/Printf.qll index 9c3bfb4f35e..d4b054ea0b5 100644 --- a/cpp/ql/lib/semmle/code/cpp/models/implementations/Printf.qll +++ b/cpp/ql/lib/semmle/code/cpp/models/implementations/Printf.qll @@ -13,7 +13,7 @@ import semmle.code.cpp.models.interfaces.NonThrowing /** * The standard functions `printf`, `wprintf` and their glib variants. */ -private class Printf extends FormattingFunction, AliasFunction, NonThrowingFunction { +private class Printf extends FormattingFunction, AliasFunction, NonCppThrowingFunction { Printf() { this instanceof TopLevelFunction and ( @@ -37,7 +37,7 @@ private class Printf extends FormattingFunction, AliasFunction, NonThrowingFunct /** * The standard functions `fprintf`, `fwprintf` and their glib variants. */ -private class Fprintf extends FormattingFunction, NonThrowingFunction { +private class Fprintf extends FormattingFunction, NonCppThrowingFunction { Fprintf() { this instanceof TopLevelFunction and ( @@ -55,7 +55,7 @@ private class Fprintf extends FormattingFunction, NonThrowingFunction { /** * The standard function `sprintf` and its Microsoft and glib variants. */ -private class Sprintf extends FormattingFunction, NonThrowingFunction { +private class Sprintf extends FormattingFunction, NonCppThrowingFunction { Sprintf() { this instanceof TopLevelFunction and ( @@ -98,7 +98,9 @@ private class Sprintf extends FormattingFunction, NonThrowingFunction { /** * Implements `Snprintf`. */ -private class SnprintfImpl extends Snprintf, AliasFunction, SideEffectFunction, NonThrowingFunction { +private class SnprintfImpl extends Snprintf, AliasFunction, SideEffectFunction, + NonCppThrowingFunction +{ SnprintfImpl() { this instanceof TopLevelFunction and ( @@ -205,7 +207,7 @@ private class StringCchPrintf extends FormattingFunction { /** * The standard function `syslog`. */ -private class Syslog extends FormattingFunction, NonThrowingFunction { +private class Syslog extends FormattingFunction, NonCppThrowingFunction { Syslog() { this instanceof TopLevelFunction and this.hasGlobalName("syslog") and 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 9b11ed0af15..966c7425dc4 100644 --- a/cpp/ql/lib/semmle/code/cpp/models/implementations/Strcat.qll +++ b/cpp/ql/lib/semmle/code/cpp/models/implementations/Strcat.qll @@ -15,7 +15,7 @@ import semmle.code.cpp.models.interfaces.NonThrowing * Does not include `strlcat`, which is covered by `StrlcatFunction` */ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, SideEffectFunction, - NonThrowingFunction + NonCppThrowingFunction { StrcatFunction() { this.hasGlobalOrStdOrBslName([ diff --git a/cpp/ql/lib/semmle/code/cpp/models/implementations/Strcpy.qll b/cpp/ql/lib/semmle/code/cpp/models/implementations/Strcpy.qll index b7f06f0cebf..b7ed20f1bab 100644 --- a/cpp/ql/lib/semmle/code/cpp/models/implementations/Strcpy.qll +++ b/cpp/ql/lib/semmle/code/cpp/models/implementations/Strcpy.qll @@ -13,7 +13,7 @@ import semmle.code.cpp.models.interfaces.NonThrowing * The standard function `strcpy` and its wide, sized, and Microsoft variants. */ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, SideEffectFunction, - NonThrowingFunction + NonCppThrowingFunction { StrcpyFunction() { this.hasGlobalOrStdOrBslName([ diff --git a/cpp/ql/lib/semmle/code/cpp/models/implementations/StructuredExceptionHandling.qll b/cpp/ql/lib/semmle/code/cpp/models/implementations/StructuredExceptionHandling.qll index af8f3088f25..e561bfadee6 100644 --- a/cpp/ql/lib/semmle/code/cpp/models/implementations/StructuredExceptionHandling.qll +++ b/cpp/ql/lib/semmle/code/cpp/models/implementations/StructuredExceptionHandling.qll @@ -1,9 +1,7 @@ import semmle.code.cpp.models.interfaces.Throwing -class WindowsDriverFunction extends ThrowingFunction { - WindowsDriverFunction() { +class WindowsDriverExceptionAnnotation extends AlwaysSehThrowingFunction { + WindowsDriverExceptionAnnotation() { this.hasGlobalName(["RaiseException", "ExRaiseAccessViolation", "ExRaiseDatatypeMisalignment"]) } - - final override predicate mayThrowException(boolean unconditional) { unconditional = true } } diff --git a/cpp/ql/lib/semmle/code/cpp/models/implementations/Win32CommandExecution.qll b/cpp/ql/lib/semmle/code/cpp/models/implementations/Win32CommandExecution.qll new file mode 100644 index 00000000000..13d7ffae807 --- /dev/null +++ b/cpp/ql/lib/semmle/code/cpp/models/implementations/Win32CommandExecution.qll @@ -0,0 +1,56 @@ +private import semmle.code.cpp.models.interfaces.CommandExecution + +/** The `ShellExecute` family of functions from Win32. */ +class ShellExecute extends Function { + ShellExecute() { this.hasGlobalName("ShellExecute" + ["", "A", "W"]) } +} + +private class ShellExecuteModel extends ShellExecute, CommandExecutionFunction { + override predicate hasCommandArgument(FunctionInput input) { input.isParameterDeref(2) } +} + +/** The `WinExec` function from Win32. */ +class WinExec extends Function { + WinExec() { this.hasGlobalName("WinExec") } +} + +private class WinExecModel extends WinExec, CommandExecutionFunction { + override predicate hasCommandArgument(FunctionInput input) { input.isParameterDeref(0) } +} + +/** The `CreateProcess` family of functions from Win32. */ +class CreateProcess extends Function { + CreateProcess() { this.hasGlobalName("CreateProcess" + ["", "A", "W"]) } +} + +private class CreateProcessModel extends CreateProcess, CommandExecutionFunction { + override predicate hasCommandArgument(FunctionInput input) { input.isParameterDeref(0) } +} + +/** The `CreateProcessAsUser` family of functions from Win32. */ +class CreateProcessAsUser extends Function { + CreateProcessAsUser() { this.hasGlobalName("CreateProcessAsUser" + ["", "A", "W"]) } +} + +private class CreateProcessAsUserModel extends CreateProcessAsUser, CommandExecutionFunction { + override predicate hasCommandArgument(FunctionInput input) { input.isParameterDeref(1) } +} + +/** The `CreateProcessWithLogonW` function from Win32. */ +class CreateProcessWithLogonW extends Function { + CreateProcessWithLogonW() { this.hasGlobalName("CreateProcessWithLogonW") } +} + +private class CreateProcessWithLogonModel extends CreateProcessWithLogonW, CommandExecutionFunction { + override predicate hasCommandArgument(FunctionInput input) { input.isParameterDeref(4) } +} + +/** The `CreateProcessWithTokenW` function from Win32. */ +class CreateProcessWithTokenW extends Function { + CreateProcessWithTokenW() { this.hasGlobalName("CreateProcessWithTokenW") } +} + +private class CreateProcessWithTokenWModel extends CreateProcessWithTokenW, CommandExecutionFunction +{ + override predicate hasCommandArgument(FunctionInput input) { input.isParameterDeref(2) } +} diff --git a/cpp/ql/lib/semmle/code/cpp/models/interfaces/NonThrowing.qll b/cpp/ql/lib/semmle/code/cpp/models/interfaces/NonThrowing.qll index 64901d39ad3..85b9b66cd66 100644 --- a/cpp/ql/lib/semmle/code/cpp/models/interfaces/NonThrowing.qll +++ b/cpp/ql/lib/semmle/code/cpp/models/interfaces/NonThrowing.qll @@ -6,6 +6,15 @@ import semmle.code.cpp.Function import semmle.code.cpp.models.Models /** - * A function that is guaranteed to never throw. + * A function that is guaranteed to never throw a C++ exception + * + * The function may still raise a structured exception handling (SEH) exception. */ -abstract class NonThrowingFunction extends Function { } +abstract class NonCppThrowingFunction extends Function { } + +/** + * A function that is guaranteed to never throw. + * + * DEPRECATED: use `NonCppThrowingFunction` instead. + */ +deprecated class NonThrowingFunction = NonCppThrowingFunction; diff --git a/cpp/ql/lib/semmle/code/cpp/models/interfaces/Throwing.qll b/cpp/ql/lib/semmle/code/cpp/models/interfaces/Throwing.qll index 79b7523f1d9..cc294806709 100644 --- a/cpp/ql/lib/semmle/code/cpp/models/interfaces/Throwing.qll +++ b/cpp/ql/lib/semmle/code/cpp/models/interfaces/Throwing.qll @@ -11,7 +11,7 @@ import semmle.code.cpp.models.Models import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs /** - * A class that models the exceptional behavior of a function. + * A function that is known to raise an exception. */ abstract class ThrowingFunction extends Function { /** @@ -20,3 +20,8 @@ abstract class ThrowingFunction extends Function { */ abstract predicate mayThrowException(boolean unconditional); } + +/** + * A function that unconditionally raises a structured exception handling (SEH) exception. + */ +abstract class AlwaysSehThrowingFunction extends Function { } diff --git a/cpp/ql/lib/semmlecode.cpp.dbscheme b/cpp/ql/lib/semmlecode.cpp.dbscheme index e51fad7a243..f0156f5f88a 100644 --- a/cpp/ql/lib/semmlecode.cpp.dbscheme +++ b/cpp/ql/lib/semmlecode.cpp.dbscheme @@ -46,6 +46,22 @@ compilation_args( string arg : string ref ); +/** + * Optionally, record the build mode for each compilation. + */ +compilation_build_mode( + unique int id : @compilation ref, + int mode : int ref +); + +/* +case @compilation_build_mode.mode of + 0 = @build_mode_none +| 1 = @build_mode_manual +| 2 = @build_mode_auto +; +*/ + /** * The source files that are compiled by a compiler invocation. * If `id` is for the compiler invocation diff --git a/cpp/ql/lib/semmlecode.cpp.dbscheme.stats b/cpp/ql/lib/semmlecode.cpp.dbscheme.stats index 7f0d99272e7..758aba34608 100644 --- a/cpp/ql/lib/semmlecode.cpp.dbscheme.stats +++ b/cpp/ql/lib/semmlecode.cpp.dbscheme.stats @@ -18,7 +18,7 @@ @location_default - 29764890 + 29746763 @location_stmt @@ -34,11 +34,11 @@ @file - 123251 + 123176 @folder - 16340 + 16330 @macro_expansion @@ -46,23 +46,23 @@ @other_macro_reference - 859029 + 858505 @function - 4179363 + 4176817 @fun_decl - 4543516 + 4541216 @var_decl - 8039391 + 8034962 @type_decl - 3283451 + 3281452 @namespace_decl @@ -70,11 +70,11 @@ @using_declaration - 363219 + 362998 @using_directive - 6536 + 6532 @using_enum_declaration @@ -86,7 +86,7 @@ @parameter - 6190611 + 6186841 @membervariable @@ -98,7 +98,7 @@ @localvariable - 576945 + 576952 @enumconstant @@ -330,15 +330,15 @@ @pointer - 568173 + 567827 @type_with_specifiers - 852026 + 851507 @array - 110179 + 110112 @routineptr @@ -346,7 +346,7 @@ @reference - 1276405 + 1275627 @gnu_vector @@ -358,7 +358,7 @@ @rvalue_reference - 333340 + 333137 @block @@ -366,15 +366,15 @@ @decltype - 27078 + 27061 @usertype - 5234008 + 5230820 @mangledname - 6061757 + 6058065 @type_mention @@ -386,15 +386,15 @@ @ptrtomember - 37815 + 37792 @specifier - 24743 + 24728 @gnuattribute - 553700 + 553363 @stdattribute @@ -410,15 +410,15 @@ @alignas - 4668 + 4665 @attribute_arg_token - 25210 + 25195 @attribute_arg_constant_expr - 318400 + 318207 @attribute_arg_empty @@ -450,7 +450,7 @@ @namespace - 12138 + 12131 @specialnamequalifyingelement @@ -482,7 +482,7 @@ @parexpr - 3587463 + 3587464 @arithnegexpr @@ -582,11 +582,11 @@ @gtexpr - 104110 + 104047 @ltexpr - 101776 + 101714 @geexpr @@ -634,7 +634,7 @@ @assignorexpr - 23627 + 23628 @assignxorexpr @@ -662,11 +662,11 @@ @subscriptexpr - 364477 + 364481 @callexpr - 316533 + 316340 @vastartexpr @@ -678,7 +678,7 @@ @vaendexpr - 2801 + 2799 @vacopyexpr @@ -830,7 +830,7 @@ @sizeof_pack - 5602 + 5598 @hasassignexpr @@ -978,7 +978,7 @@ @lambdaexpr - 21475 + 21462 @param_ref @@ -1022,7 +1022,7 @@ @istriviallycopyableexpr - 3734 + 3732 @isliteraltypeexpr @@ -1374,7 +1374,7 @@ @lambdacapture - 28011 + 27994 @stmt_expr @@ -1398,11 +1398,11 @@ @stmt_return - 1280140 + 1279827 @stmt_block - 1419265 + 1418867 @stmt_end_test_while @@ -1430,7 +1430,7 @@ @stmt_empty - 192682 + 192685 @stmt_continue @@ -1462,7 +1462,7 @@ @stmt_range_based_for - 8403 + 8398 @stmt_handler @@ -1478,31 +1478,31 @@ @ppd_if - 667148 + 666741 @ppd_ifdef - 263311 + 263150 @ppd_ifndef - 266579 + 266416 @ppd_elif - 25210 + 25195 @ppd_else - 209154 + 209027 @ppd_endif - 1197038 + 1196309 @ppd_plain_include - 311398 + 311208 @ppd_define @@ -1510,15 +1510,15 @@ @ppd_undef - 258642 + 258484 @ppd_include_next - 1867 + 1866 @ppd_line - 27520 + 27521 @ppd_error @@ -1900,6 +1900,54 @@ + + compilation_build_mode + 9742 + + + id + 9742 + + + mode + 11 + + + + + id + mode + + + 12 + + + 1 + 2 + 9742 + + + + + + + mode + id + + + 12 + + + 863 + 864 + 11 + + + + + + + compilation_compiling_files 11546 @@ -2164,7 +2212,7 @@ seconds - 8429 + 8030 @@ -2245,47 +2293,52 @@ 3 4 - 639 + 799 4 5 - 359 + 199 - 6 + 5 7 119 8 + 9 + 79 + + + 9 10 - 159 + 119 10 - 11 + 12 + 159 + + + 12 + 16 119 - 11 - 15 + 17 + 20 159 - 16 - 19 + 21 + 42 159 - 19 - 24 - 159 - - - 40 - 89 - 119 + 55 + 90 + 79 @@ -2368,7 +2421,7 @@ 6 7 - 439 + 399 7 @@ -2377,19 +2430,19 @@ 8 - 10 + 9 + 239 + + + 9 + 24 279 - 10 - 26 + 25 + 85 279 - - 28 - 81 - 199 - @@ -2439,8 +2492,8 @@ 79 - 125 - 126 + 124 + 125 39 @@ -2462,27 +2515,37 @@ 1 2 - 3635 + 3755 2 3 - 1917 + 1398 3 4 - 1558 + 998 4 + 5 + 759 + + + 5 6 - 719 + 439 6 - 48 - 599 + 25 + 639 + + + 46 + 47 + 39 @@ -2498,27 +2561,27 @@ 1 2 - 3595 + 3515 2 3 - 1438 + 1278 3 4 - 1358 + 599 4 5 - 639 + 878 5 6 - 479 + 759 6 @@ -2527,8 +2590,8 @@ 8 - 73 - 239 + 76 + 319 @@ -2544,12 +2607,12 @@ 1 2 - 6512 + 5753 2 3 - 1917 + 2277 @@ -2893,7 +2956,7 @@ cpu_seconds - 7507 + 7292 elapsed_seconds @@ -2943,17 +3006,17 @@ 1 2 - 6242 + 5937 2 3 - 835 + 846 3 - 15 - 428 + 16 + 507 @@ -2969,12 +3032,12 @@ 1 2 - 6976 + 6682 2 3 - 530 + 609 @@ -3003,48 +3066,48 @@ 11 - 6 - 7 + 7 + 8 11 - 9 - 10 + 8 + 9 11 - 11 - 12 + 12 + 13 11 - 16 - 17 + 13 + 14 11 - 49 - 50 + 51 + 52 11 - 154 - 155 + 163 + 164 11 - 160 - 161 + 167 + 168 11 - 204 - 205 + 187 + 188 11 - 248 - 249 + 249 + 250 11 @@ -3074,48 +3137,48 @@ 11 - 6 - 7 + 7 + 8 11 - 9 - 10 + 8 + 9 11 - 11 - 12 + 12 + 13 11 - 16 - 17 + 13 + 14 11 - 47 - 48 + 49 + 50 11 - 118 - 119 + 120 + 121 11 - 128 - 129 + 123 + 124 11 - 149 - 150 + 138 + 139 11 - 222 - 223 + 224 + 225 11 @@ -4888,31 +4951,31 @@ locations_default - 29764890 + 29746763 id - 29764890 + 29746763 container - 123251 + 123176 startLine - 2095283 + 2094007 startColumn - 36882 + 36859 endLine - 2099485 + 2098207 endColumn - 48086 + 48057 @@ -4926,7 +4989,7 @@ 1 2 - 29764890 + 29746763 @@ -4942,7 +5005,7 @@ 1 2 - 29764890 + 29746763 @@ -4958,7 +5021,7 @@ 1 2 - 29764890 + 29746763 @@ -4974,7 +5037,7 @@ 1 2 - 29764890 + 29746763 @@ -4990,7 +5053,7 @@ 1 2 - 29764890 + 29746763 @@ -5006,67 +5069,67 @@ 1 11 - 9804 + 9798 11 18 - 10270 + 10264 18 30 - 9337 + 9331 30 42 - 9804 + 9798 43 61 - 9804 + 9798 61 79 - 9337 + 9331 80 106 - 9804 + 9798 108 149 - 9337 + 9331 149 199 - 9337 + 9331 206 291 - 9337 + 9331 304 469 - 9337 + 9331 482 850 - 9337 + 9331 936 2380 - 8403 + 8398 @@ -5082,67 +5145,67 @@ 1 8 - 9337 + 9331 8 13 - 9337 + 9331 13 20 - 9804 + 9798 20 32 - 9337 + 9331 32 43 - 9804 + 9798 44 61 - 9337 + 9331 62 72 - 9337 + 9331 73 93 - 9337 + 9331 97 128 - 9337 + 9331 128 180 - 9337 + 9331 180 267 - 9337 + 9331 277 414 - 9337 + 9331 439 1465 - 9337 + 9331 1557 @@ -5163,67 +5226,67 @@ 1 4 - 8870 + 8865 4 5 - 7936 + 7931 5 6 - 7469 + 7465 6 8 - 11204 + 11197 8 10 - 9337 + 9331 10 15 - 10737 + 10731 15 23 - 9804 + 9798 23 28 - 11204 + 11197 28 34 - 9804 + 9798 34 44 - 9337 + 9331 44 55 - 9337 + 9331 55 66 - 9804 + 9798 66 77 - 8403 + 8398 @@ -5239,67 +5302,67 @@ 1 8 - 9337 + 9331 8 13 - 9337 + 9331 13 20 - 9804 + 9798 20 32 - 9337 + 9331 32 43 - 9804 + 9798 43 60 - 9337 + 9331 61 71 - 9337 + 9331 72 93 - 9337 + 9331 94 127 - 9337 + 9331 128 179 - 9337 + 9331 180 268 - 9337 + 9331 278 413 - 9337 + 9331 437 1465 - 9337 + 9331 1554 @@ -5320,67 +5383,67 @@ 1 9 - 9804 + 9798 9 13 - 9337 + 9331 13 18 - 9337 + 9331 18 26 - 10270 + 10264 27 33 - 9337 + 9331 33 39 - 9337 + 9331 39 47 - 10270 + 10264 47 53 - 9337 + 9331 53 60 - 10270 + 10264 60 66 - 9337 + 9331 66 74 - 9804 + 9798 74 78 - 9804 + 9798 78 90 - 7002 + 6998 @@ -5396,52 +5459,52 @@ 1 2 - 583112 + 582757 2 3 - 314199 + 314007 3 4 - 195615 + 195496 4 6 - 162001 + 161903 6 10 - 183010 + 182899 10 16 - 162935 + 162836 16 25 - 169004 + 168901 25 46 - 161067 + 160969 46 169 - 157333 + 157237 169 265 - 7002 + 6998 @@ -5457,42 +5520,42 @@ 1 2 - 871167 + 870636 2 3 - 273582 + 273415 3 5 - 193748 + 193630 5 8 - 173673 + 173567 8 13 - 188146 + 188031 13 20 - 161067 + 160969 20 51 - 159667 + 159570 51 265 - 74231 + 74186 @@ -5508,47 +5571,47 @@ 1 2 - 612058 + 611685 2 3 - 313265 + 313074 3 4 - 198417 + 198296 4 6 - 183010 + 182899 6 9 - 173206 + 173100 9 13 - 163402 + 163302 13 19 - 174606 + 174500 19 29 - 164802 + 164702 29 52 - 112514 + 112445 @@ -5564,22 +5627,22 @@ 1 2 - 1531779 + 1530846 2 3 - 348747 + 348534 3 5 - 162001 + 161903 5 16 - 52755 + 52723 @@ -5595,47 +5658,47 @@ 1 2 - 587781 + 587423 2 3 - 316066 + 315874 3 4 - 197483 + 197363 4 6 - 168537 + 168435 6 9 - 158266 + 158170 9 14 - 170872 + 170768 14 21 - 175073 + 174967 21 32 - 162468 + 162369 32 63 - 157799 + 157703 64 @@ -5656,67 +5719,67 @@ 1 31 - 2801 + 2799 42 85 - 2801 + 2799 86 128 - 2801 + 2799 129 229 - 2801 + 2799 247 286 - 2801 + 2799 291 360 - 2801 + 2799 373 457 - 2801 + 2799 473 565 - 2801 + 2799 566 619 - 2801 + 2799 619 689 - 2801 + 2799 696 807 - 2801 + 2799 819 1563 - 2801 + 2799 1634 5631 - 2801 + 2799 15295 @@ -5737,67 +5800,67 @@ 1 18 - 2801 + 2799 23 35 - 3268 + 3266 38 43 - 2801 + 2799 44 61 - 2801 + 2799 65 73 - 2801 + 2799 73 84 - 3268 + 3266 84 96 - 2801 + 2799 96 101 - 3268 + 3266 101 105 - 3268 + 3266 107 112 - 2801 + 2799 112 126 - 2801 + 2799 137 170 - 2801 + 2799 195 265 - 1400 + 1399 @@ -5813,67 +5876,67 @@ 1 19 - 2801 + 2799 30 72 - 2801 + 2799 83 122 - 2801 + 2799 122 205 - 2801 + 2799 214 261 - 2801 + 2799 265 322 - 2801 + 2799 322 379 - 2801 + 2799 404 430 - 2801 + 2799 453 474 - 2801 + 2799 478 505 - 2801 + 2799 511 583 - 2801 + 2799 585 836 - 2801 + 2799 1104 2196 - 2801 + 2799 2387 @@ -5894,67 +5957,67 @@ 1 19 - 2801 + 2799 30 72 - 2801 + 2799 83 122 - 2801 + 2799 122 205 - 2801 + 2799 214 261 - 2801 + 2799 265 322 - 2801 + 2799 322 380 - 2801 + 2799 404 430 - 2801 + 2799 453 474 - 2801 + 2799 477 504 - 2801 + 2799 514 582 - 2801 + 2799 585 835 - 2801 + 2799 1109 2203 - 2801 + 2799 2382 @@ -5975,67 +6038,67 @@ 1 7 - 2801 + 2799 7 11 - 3268 + 3266 11 16 - 3268 + 3266 16 22 - 2801 + 2799 22 24 - 3268 + 3266 24 28 - 2801 + 2799 29 34 - 3268 + 3266 34 41 - 3268 + 3266 41 46 - 2801 + 2799 47 49 - 1867 + 1866 49 54 - 2801 + 2799 54 74 - 2801 + 2799 75 86 - 1867 + 1866 @@ -6051,52 +6114,52 @@ 1 2 - 593383 + 593022 2 3 - 306262 + 306076 3 4 - 198417 + 198296 4 6 - 159667 + 159570 6 10 - 182543 + 182432 10 16 - 162001 + 161903 16 25 - 171338 + 171234 25 46 - 158733 + 158636 46 161 - 158266 + 158170 162 265 - 8870 + 8865 @@ -6112,47 +6175,47 @@ 1 2 - 886574 + 886034 2 3 - 260043 + 259884 3 4 - 125119 + 125043 4 6 - 140992 + 140906 6 10 - 184877 + 184765 10 15 - 168537 + 168435 15 26 - 163402 + 163302 26 120 - 158266 + 158170 121 265 - 11671 + 11664 @@ -6168,22 +6231,22 @@ 1 2 - 1529445 + 1528513 2 3 - 341744 + 341536 3 5 - 170872 + 170768 5 10 - 57424 + 57389 @@ -6199,47 +6262,47 @@ 1 2 - 623262 + 622883 2 3 - 303461 + 303276 3 4 - 201685 + 201562 4 6 - 183944 + 183832 6 9 - 169938 + 169834 9 13 - 166670 + 166568 13 19 - 175073 + 174967 19 29 - 161067 + 160969 29 52 - 114381 + 114311 @@ -6255,52 +6318,52 @@ 1 2 - 599919 + 599554 2 3 - 306262 + 306076 3 4 - 197016 + 196896 4 6 - 169004 + 168901 6 9 - 156399 + 156304 9 14 - 169004 + 168901 14 21 - 177875 + 177766 21 32 - 162001 + 161903 32 60 - 158266 + 158170 60 65 - 3734 + 3732 @@ -6316,67 +6379,67 @@ 1 2 - 5135 + 5132 2 8 - 3734 + 3732 9 186 - 3734 + 3732 193 288 - 3734 + 3732 294 495 - 3734 + 3732 503 555 - 3734 + 3732 561 633 - 3734 + 3732 640 758 - 3734 + 3732 758 869 - 3734 + 3732 875 1074 - 3734 + 3732 1074 1281 - 3734 + 3732 1289 1590 - 3734 + 3732 1685 2418 - 1867 + 1866 @@ -6392,62 +6455,62 @@ 1 2 - 5602 + 5598 2 5 - 3734 + 3732 5 65 - 3734 + 3732 70 100 - 3734 + 3732 100 111 - 3734 + 3732 112 122 - 4201 + 4199 122 140 - 3734 + 3732 143 153 - 3734 + 3732 153 161 - 4201 + 4199 161 173 - 4201 + 4199 173 178 - 3734 + 3732 188 265 - 3734 + 3732 @@ -6463,62 +6526,62 @@ 1 2 - 5602 + 5598 2 8 - 3734 + 3732 9 105 - 3734 + 3732 155 241 - 3734 + 3732 253 336 - 3734 + 3732 340 426 - 3734 + 3732 434 488 - 3734 + 3732 489 572 - 3734 + 3732 573 623 - 3734 + 3732 626 696 - 4201 + 4199 701 813 - 3734 + 3732 818 1095 - 3734 + 3732 1172 @@ -6539,67 +6602,67 @@ 1 2 - 6069 + 6065 2 4 - 3734 + 3732 4 8 - 4201 + 4199 8 15 - 3734 + 3732 15 23 - 3734 + 3732 23 29 - 3734 + 3732 29 35 - 4201 + 4199 35 39 - 3268 + 3266 39 42 - 3268 + 3266 42 44 - 3268 + 3266 44 46 - 3734 + 3732 46 49 - 3734 + 3732 49 53 - 1400 + 1399 @@ -6615,67 +6678,67 @@ 1 2 - 5602 + 5598 2 8 - 3734 + 3732 9 156 - 3734 + 3732 159 240 - 3734 + 3732 251 335 - 3734 + 3732 342 430 - 3734 + 3732 432 490 - 3734 + 3732 490 573 - 3734 + 3732 574 622 - 3734 + 3732 626 698 - 3734 + 3732 700 798 - 3734 + 3732 811 987 - 3734 + 3732 1096 1180 - 1400 + 1399 @@ -10599,23 +10662,23 @@ numlines - 1383783 + 1382941 element_id - 1376780 + 1375942 num_lines - 101776 + 101714 num_code - 84969 + 84917 num_comment - 59758 + 59722 @@ -10629,12 +10692,12 @@ 1 2 - 1369777 + 1368943 2 3 - 7002 + 6998 @@ -10650,12 +10713,12 @@ 1 2 - 1370711 + 1369876 2 3 - 6069 + 6065 @@ -10671,7 +10734,7 @@ 1 2 - 1376780 + 1375942 @@ -10687,27 +10750,27 @@ 1 2 - 68162 + 68120 2 3 - 12138 + 12131 3 4 - 7469 + 7465 4 21 - 7936 + 7931 29 921 - 6069 + 6065 @@ -10723,27 +10786,27 @@ 1 2 - 70496 + 70453 2 3 - 12138 + 12131 3 4 - 8403 + 8398 4 6 - 9337 + 9331 6 7 - 1400 + 1399 @@ -10759,22 +10822,22 @@ 1 2 - 69562 + 69520 2 3 - 14939 + 14930 3 4 - 10737 + 10731 4 7 - 6536 + 6532 @@ -10790,27 +10853,27 @@ 1 2 - 52755 + 52723 2 3 - 14472 + 14463 3 5 - 6536 + 6532 5 42 - 6536 + 6532 44 922 - 4668 + 4665 @@ -10826,27 +10889,27 @@ 1 2 - 52755 + 52723 2 3 - 16807 + 16796 3 5 - 6069 + 6065 5 8 - 6536 + 6532 8 12 - 2801 + 2799 @@ -10862,27 +10925,27 @@ 1 2 - 53222 + 53190 2 3 - 15873 + 15863 3 5 - 7469 + 7465 5 7 - 5135 + 5132 7 10 - 3268 + 3266 @@ -10898,32 +10961,32 @@ 1 2 - 34547 + 34526 2 3 - 9337 + 9331 3 4 - 4201 + 4199 4 6 - 4668 + 4665 6 11 - 5135 + 5132 17 2596 - 1867 + 1866 @@ -10939,32 +11002,32 @@ 1 2 - 34547 + 34526 2 3 - 9337 + 9331 3 4 - 4201 + 4199 4 6 - 4668 + 4665 6 8 - 4668 + 4665 10 38 - 2334 + 2332 @@ -10980,32 +11043,32 @@ 1 2 - 34547 + 34526 2 3 - 9337 + 9331 3 4 - 4201 + 4199 4 6 - 4668 + 4665 6 10 - 4668 + 4665 10 37 - 2334 + 2332 @@ -11647,15 +11710,15 @@ files - 123251 + 123176 id - 123251 + 123176 name - 123251 + 123176 @@ -11669,7 +11732,7 @@ 1 2 - 123251 + 123176 @@ -11685,7 +11748,7 @@ 1 2 - 123251 + 123176 @@ -11695,15 +11758,15 @@ folders - 16340 + 16330 id - 16340 + 16330 name - 16340 + 16330 @@ -11717,7 +11780,7 @@ 1 2 - 16340 + 16330 @@ -11733,7 +11796,7 @@ 1 2 - 16340 + 16330 @@ -11743,15 +11806,15 @@ containerparent - 138658 + 138574 parent - 16340 + 16330 child - 138658 + 138574 @@ -11765,32 +11828,32 @@ 1 2 - 7469 + 7465 2 3 - 3268 + 3266 3 4 - 1400 + 1399 4 12 - 1400 + 1399 23 28 - 1400 + 1399 40 67 - 1400 + 1399 @@ -11806,7 +11869,7 @@ 1 2 - 138658 + 138574 @@ -12392,15 +12455,15 @@ inmacroexpansion - 109779080 + 109779103 id - 18027694 + 18027697 inv - 2700160 + 2700159 @@ -12414,12 +12477,12 @@ 1 3 - 1582361 + 1582360 3 5 - 1077793 + 1077794 5 @@ -12429,17 +12492,17 @@ 6 7 - 4819903 + 4819904 7 8 - 6385932 + 6385934 8 9 - 2605242 + 2605243 9 @@ -12460,12 +12523,12 @@ 1 2 - 378424 + 378422 2 3 - 544104 + 544105 3 @@ -12500,7 +12563,7 @@ 11 337 - 224847 + 224845 339 @@ -12520,15 +12583,15 @@ affectedbymacroexpansion - 35689251 + 35689257 id - 5156949 + 5156948 inv - 2784762 + 2784761 @@ -12542,7 +12605,7 @@ 1 2 - 2816079 + 2816078 2 @@ -12588,7 +12651,7 @@ 1 4 - 229116 + 229115 4 @@ -12603,12 +12666,12 @@ 9 12 - 251119 + 251120 12 13 - 333984 + 333985 13 @@ -12628,7 +12691,7 @@ 16 17 - 276608 + 276609 17 @@ -13607,19 +13670,19 @@ functions - 4179363 + 4176817 id - 4179363 + 4176817 name - 1895466 + 1894311 kind - 3268 + 3266 @@ -13633,7 +13696,7 @@ 1 2 - 4179363 + 4176817 @@ -13649,7 +13712,7 @@ 1 2 - 4179363 + 4176817 @@ -13665,22 +13728,22 @@ 1 2 - 1498165 + 1497253 2 3 - 153131 + 153038 3 5 - 142860 + 142773 5 952 - 101309 + 101247 @@ -13696,7 +13759,7 @@ 1 2 - 1894999 + 1893845 2 @@ -13798,15 +13861,15 @@ function_entry_point - 1151752 + 1151517 id - 1141948 + 1141719 entry_point - 1151752 + 1151517 @@ -13820,12 +13883,12 @@ 1 2 - 1132144 + 1131921 2 3 - 9804 + 9798 @@ -13841,7 +13904,7 @@ 1 2 - 1151752 + 1151517 @@ -13851,15 +13914,15 @@ function_return_type - 4184498 + 4181950 id - 4179363 + 4176817 return_type - 817945 + 817446 @@ -13873,12 +13936,12 @@ 1 2 - 4174227 + 4171685 2 3 - 5135 + 5132 @@ -13894,22 +13957,22 @@ 1 2 - 506080 + 505771 2 3 - 211489 + 211360 3 7 - 66294 + 66254 7 2231 - 34081 + 34060 @@ -14200,33 +14263,33 @@ function_deleted - 96173 + 96115 id - 96173 + 96115 function_defaulted - 73764 + 73719 id - 73764 + 73719 function_prototyped - 4087391 + 4084901 id - 4087391 + 4084901 @@ -14379,27 +14442,27 @@ fun_decls - 4548652 + 4546348 id - 4543516 + 4541216 function - 4035569 + 4033111 type_id - 816544 + 816047 name - 1797891 + 1796796 location - 3370755 + 3368702 @@ -14413,7 +14476,7 @@ 1 2 - 4543516 + 4541216 @@ -14429,12 +14492,12 @@ 1 2 - 4538381 + 4536084 2 3 - 5135 + 5132 @@ -14450,7 +14513,7 @@ 1 2 - 4543516 + 4541216 @@ -14466,7 +14529,7 @@ 1 2 - 4543516 + 4541216 @@ -14482,17 +14545,17 @@ 1 2 - 3606521 + 3603858 2 3 - 356216 + 356466 3 7 - 72830 + 72786 @@ -14508,12 +14571,12 @@ 1 2 - 3995885 + 3993452 2 3 - 39683 + 39659 @@ -14529,7 +14592,7 @@ 1 2 - 4035569 + 4033111 @@ -14545,17 +14608,17 @@ 1 2 - 3663012 + 3660781 2 3 - 311864 + 311674 3 6 - 60692 + 60655 @@ -14571,22 +14634,22 @@ 1 2 - 431381 + 431119 2 3 - 274048 + 273882 3 6 - 63493 + 63454 6 - 2476 - 47620 + 2477 + 47591 @@ -14602,22 +14665,22 @@ 1 2 - 515417 + 515103 2 3 - 203085 + 202961 3 7 - 63026 + 62988 7 2192 - 35014 + 34993 @@ -14633,17 +14696,17 @@ 1 2 - 690024 + 689604 2 4 - 67228 + 67187 4 773 - 59291 + 59255 @@ -14659,22 +14722,22 @@ 1 2 - 595251 + 594888 2 3 - 121384 + 121310 3 7 - 63493 + 63454 7 1959 - 36415 + 36393 @@ -14690,27 +14753,27 @@ 1 2 - 1228318 + 1227570 2 3 - 267045 + 266883 3 4 - 77966 + 77918 4 7 - 146128 + 146039 7 986 - 78433 + 78385 @@ -14726,22 +14789,22 @@ 1 2 - 1407593 + 1406736 2 3 - 152197 + 152104 3 5 - 136791 + 136707 5 936 - 101309 + 101247 @@ -14757,17 +14820,17 @@ 1 2 - 1579399 + 1578437 2 4 - 134923 + 134841 4 562 - 83568 + 83517 @@ -14783,27 +14846,27 @@ 1 2 - 1236254 + 1235502 2 3 - 293190 + 293011 3 4 - 78899 + 78851 4 8 - 137257 + 137174 8 542 - 52288 + 52256 @@ -14819,17 +14882,17 @@ 1 2 - 2966451 + 2964644 2 4 - 277783 + 277614 4 55 - 126520 + 126442 @@ -14845,17 +14908,17 @@ 1 2 - 3033679 + 3031832 2 7 - 244169 + 244020 7 55 - 92905 + 92849 @@ -14871,12 +14934,12 @@ 1 2 - 3207353 + 3205399 2 18 - 163402 + 163302 @@ -14892,12 +14955,12 @@ 1 2 - 3232563 + 3230595 2 13 - 138191 + 138107 @@ -14907,22 +14970,22 @@ fun_def - 1888930 + 1888246 id - 1888930 + 1888246 fun_specialized - 26144 + 26128 id - 26144 + 26128 @@ -14940,15 +15003,15 @@ fun_decl_specifiers - 2906692 + 2904922 id - 1689579 + 1688550 name - 2801 + 2799 @@ -14962,17 +15025,17 @@ 1 2 - 491140 + 490841 2 3 - 1179764 + 1179045 3 4 - 18674 + 18663 @@ -15144,11 +15207,11 @@ fun_decl_empty_throws - 1472021 + 1471124 fun_decl - 1472021 + 1471124 @@ -15208,11 +15271,11 @@ fun_decl_empty_noexcept - 863230 + 863171 fun_decl - 863230 + 863171 @@ -15317,19 +15380,19 @@ param_decl_bind - 6995017 + 6991224 id - 6995017 + 6991224 index - 7936 + 7931 fun_decl - 3835284 + 3833415 @@ -15343,7 +15406,7 @@ 1 2 - 6995017 + 6991224 @@ -15359,7 +15422,7 @@ 1 2 - 6995017 + 6991224 @@ -15438,8 +15501,8 @@ 466 - 8215 - 8216 + 8216 + 8217 466 @@ -15519,8 +15582,8 @@ 466 - 8215 - 8216 + 8216 + 8217 466 @@ -15537,27 +15600,27 @@ 1 2 - 1973899 + 1973163 2 3 - 1061647 + 1061001 3 4 - 502812 + 502505 4 8 - 290856 + 290678 8 18 - 6069 + 6065 @@ -15573,27 +15636,27 @@ 1 2 - 1973899 + 1973163 2 3 - 1061647 + 1061001 3 4 - 502812 + 502505 4 8 - 290856 + 290678 8 18 - 6069 + 6065 @@ -15603,27 +15666,27 @@ var_decls - 8110354 + 8105882 id - 8039391 + 8034962 variable - 7027231 + 7022951 type_id - 2043462 + 2042217 name - 667614 + 667208 location - 5311974 + 5308739 @@ -15637,7 +15700,7 @@ 1 2 - 8039391 + 8034962 @@ -15653,12 +15716,12 @@ 1 2 - 7971229 + 7966841 2 3 - 68162 + 68120 @@ -15674,7 +15737,7 @@ 1 2 - 8039391 + 8034962 @@ -15690,12 +15753,12 @@ 1 2 - 8036590 + 8032162 2 3 - 2801 + 2799 @@ -15711,17 +15774,17 @@ 1 2 - 6175205 + 6170977 2 3 - 698427 + 698469 3 7 - 153598 + 153504 @@ -15737,12 +15800,12 @@ 1 2 - 6855892 + 6851717 2 4 - 171338 + 171234 @@ -15758,12 +15821,12 @@ 1 2 - 6911916 + 6907706 2 3 - 115315 + 115245 @@ -15779,17 +15842,17 @@ 1 2 - 6481934 + 6477987 2 3 - 542962 + 542631 3 4 - 2334 + 2332 @@ -15805,27 +15868,27 @@ 1 2 - 1165758 + 1165048 2 3 - 477134 + 476377 3 4 - 94773 + 95182 4 7 - 184877 + 184765 7 762 - 120917 + 120844 @@ -15841,22 +15904,22 @@ 1 2 - 1299281 + 1298490 2 3 - 452390 + 452115 3 6 - 155932 + 155837 6 724 - 135857 + 135774 @@ -15872,17 +15935,17 @@ 1 2 - 1539249 + 1538311 2 3 - 383295 + 383061 3 128 - 120917 + 120844 @@ -15898,22 +15961,22 @@ 1 2 - 1365576 + 1364744 2 3 - 404303 + 404057 3 7 - 173206 + 173100 7 592 - 100375 + 100314 @@ -15929,37 +15992,37 @@ 1 2 - 341277 + 341069 2 3 - 86836 + 86783 3 4 - 48553 + 48524 4 6 - 51821 + 51790 6 12 - 52288 + 52256 12 33 - 50421 + 50390 34 - 2384 - 36415 + 2385 + 36393 @@ -15975,37 +16038,37 @@ 1 2 - 368822 + 368597 2 3 - 77966 + 77918 3 4 - 45285 + 45258 4 6 - 49487 + 49457 6 14 - 53222 + 53190 14 56 - 50888 + 50857 56 2301 - 21942 + 21929 @@ -16021,27 +16084,27 @@ 1 2 - 457059 + 456781 2 3 - 93839 + 93782 3 5 - 46686 + 46657 5 19 - 50888 + 50857 19 1182 - 19141 + 19129 @@ -16057,32 +16120,32 @@ 1 2 - 379093 + 378862 2 3 - 90571 + 90516 3 5 - 59758 + 59722 5 9 - 51354 + 51323 9 21 - 50421 + 50390 21 1010 - 36415 + 36393 @@ -16098,17 +16161,17 @@ 1 2 - 4496363 + 4493625 2 3 - 531757 + 531433 3 - 896 - 283853 + 897 + 283680 @@ -16124,17 +16187,17 @@ 1 2 - 4885727 + 4882752 2 17 - 415508 + 415255 17 892 - 10737 + 10731 @@ -16150,12 +16213,12 @@ 1 2 - 4961826 + 4958804 2 759 - 350147 + 349934 @@ -16171,12 +16234,12 @@ 1 2 - 5302637 + 5299407 2 6 - 9337 + 9331 @@ -16186,26 +16249,26 @@ var_def - 3994952 + 3992985 id - 3994952 + 3992985 var_decl_specifiers - 378626 + 378395 id - 378626 + 378395 name - 1867 + 1866 @@ -16219,7 +16282,7 @@ 1 2 - 378626 + 378395 @@ -16271,19 +16334,19 @@ type_decls - 3283451 + 3281452 id - 3283451 + 3281452 type_id - 3233030 + 3231061 location - 3166269 + 3164340 @@ -16297,7 +16360,7 @@ 1 2 - 3283451 + 3281452 @@ -16313,7 +16376,7 @@ 1 2 - 3283451 + 3281452 @@ -16329,12 +16392,12 @@ 1 2 - 3191479 + 3189536 2 5 - 41550 + 41525 @@ -16350,12 +16413,12 @@ 1 2 - 3191479 + 3189536 2 5 - 41550 + 41525 @@ -16371,12 +16434,12 @@ 1 2 - 3113980 + 3112083 2 20 - 52288 + 52256 @@ -16392,12 +16455,12 @@ 1 2 - 3113980 + 3112083 2 20 - 52288 + 52256 @@ -16407,22 +16470,22 @@ type_def - 2641981 + 2640372 id - 2641981 + 2640372 type_decl_top - 743713 + 743260 type_decl - 743713 + 743260 @@ -16795,19 +16858,19 @@ usings - 369755 + 369530 id - 369755 + 369530 element_id - 315599 + 315407 location - 247904 + 247753 kind @@ -16825,7 +16888,7 @@ 1 2 - 369755 + 369530 @@ -16841,7 +16904,7 @@ 1 2 - 369755 + 369530 @@ -16857,7 +16920,7 @@ 1 2 - 369755 + 369530 @@ -16873,17 +16936,17 @@ 1 2 - 263311 + 263150 2 3 - 50888 + 50857 3 5 - 1400 + 1399 @@ -16899,17 +16962,17 @@ 1 2 - 263311 + 263150 2 3 - 50888 + 50857 3 5 - 1400 + 1399 @@ -16925,7 +16988,7 @@ 1 2 - 315599 + 315407 @@ -16941,22 +17004,22 @@ 1 2 - 202618 + 202495 2 4 - 10737 + 10731 4 5 - 31279 + 31260 5 11 - 3268 + 3266 @@ -16972,22 +17035,22 @@ 1 2 - 202618 + 202495 2 4 - 10737 + 10731 4 5 - 31279 + 31260 5 11 - 3268 + 3266 @@ -17003,7 +17066,7 @@ 1 2 - 247904 + 247753 @@ -17787,23 +17850,23 @@ params - 6354480 + 6350610 id - 6190611 + 6186841 function - 3491673 + 3489546 index - 7936 + 7931 type_id - 1846445 + 1845321 @@ -17817,7 +17880,7 @@ 1 2 - 6190611 + 6186841 @@ -17833,7 +17896,7 @@ 1 2 - 6190611 + 6186841 @@ -17849,12 +17912,12 @@ 1 2 - 6066892 + 6063198 2 4 - 123718 + 123643 @@ -17870,22 +17933,22 @@ 1 2 - 1867454 + 1866317 2 3 - 952868 + 952288 3 4 - 429981 + 429719 4 18 - 241368 + 241221 @@ -17901,22 +17964,22 @@ 1 2 - 1867454 + 1866317 2 3 - 952868 + 952288 3 4 - 429981 + 429719 4 18 - 241368 + 241221 @@ -17932,22 +17995,22 @@ 1 2 - 2165780 + 2164461 2 3 - 826815 + 826311 3 4 - 346412 + 346201 4 12 - 152664 + 152571 @@ -18145,7 +18208,7 @@ 6 7 - 1400 + 1399 7 @@ -18201,22 +18264,22 @@ 1 2 - 1183966 + 1183245 2 3 - 406171 + 405923 3 7 - 154064 + 153971 7 518 - 102243 + 102180 @@ -18232,22 +18295,22 @@ 1 2 - 1404792 + 1403937 2 3 - 212422 + 212293 3 7 - 147528 + 147439 7 502 - 81701 + 81651 @@ -18263,17 +18326,17 @@ 1 2 - 1420199 + 1419334 2 3 - 347346 + 347135 3 13 - 78899 + 78851 @@ -18283,11 +18346,11 @@ overrides - 125725 + 125735 new - 122752 + 122762 old @@ -18305,7 +18368,7 @@ 1 2 - 119788 + 119797 2 @@ -18713,11 +18776,11 @@ localvariables - 576945 + 576952 id - 576945 + 576952 type_id @@ -18725,7 +18788,7 @@ name - 90547 + 90549 @@ -18739,7 +18802,7 @@ 1 2 - 576945 + 576952 @@ -18755,7 +18818,7 @@ 1 2 - 576945 + 576952 @@ -18812,7 +18875,7 @@ 1 2 - 26912 + 26913 2 @@ -18848,12 +18911,12 @@ 1 2 - 57031 + 57032 2 3 - 14284 + 14285 3 @@ -18884,7 +18947,7 @@ 1 2 - 76491 + 76492 2 @@ -18894,7 +18957,7 @@ 3 1486 - 6644 + 6645 @@ -19922,31 +19985,31 @@ builtintypes - 26144 + 26128 id - 26144 + 26128 name - 26144 + 26128 kind - 26144 + 26128 size - 3268 + 3266 sign - 1400 + 1399 alignment - 2334 + 2332 @@ -19960,7 +20023,7 @@ 1 2 - 26144 + 26128 @@ -19976,7 +20039,7 @@ 1 2 - 26144 + 26128 @@ -19992,7 +20055,7 @@ 1 2 - 26144 + 26128 @@ -20008,7 +20071,7 @@ 1 2 - 26144 + 26128 @@ -20024,7 +20087,7 @@ 1 2 - 26144 + 26128 @@ -20040,7 +20103,7 @@ 1 2 - 26144 + 26128 @@ -20056,7 +20119,7 @@ 1 2 - 26144 + 26128 @@ -20072,7 +20135,7 @@ 1 2 - 26144 + 26128 @@ -20088,7 +20151,7 @@ 1 2 - 26144 + 26128 @@ -20104,7 +20167,7 @@ 1 2 - 26144 + 26128 @@ -20120,7 +20183,7 @@ 1 2 - 26144 + 26128 @@ -20136,7 +20199,7 @@ 1 2 - 26144 + 26128 @@ -20152,7 +20215,7 @@ 1 2 - 26144 + 26128 @@ -20168,7 +20231,7 @@ 1 2 - 26144 + 26128 @@ -20184,7 +20247,7 @@ 1 2 - 26144 + 26128 @@ -20343,7 +20406,7 @@ 3 4 - 2334 + 2332 @@ -20359,12 +20422,12 @@ 1 2 - 1867 + 1866 2 3 - 1400 + 1399 @@ -20479,7 +20542,7 @@ 5 6 - 1400 + 1399 @@ -20603,7 +20666,7 @@ 2 3 - 2334 + 2332 @@ -20619,7 +20682,7 @@ 3 4 - 2334 + 2332 @@ -20629,23 +20692,23 @@ derivedtypes - 3669548 + 3667313 id - 3669548 + 3667313 name - 1552788 + 1551842 kind - 2801 + 2799 type_id - 2362796 + 2361357 @@ -20659,7 +20722,7 @@ 1 2 - 3669548 + 3667313 @@ -20675,7 +20738,7 @@ 1 2 - 3669548 + 3667313 @@ -20691,7 +20754,7 @@ 1 2 - 3669548 + 3667313 @@ -20707,17 +20770,17 @@ 1 2 - 1324025 + 1323218 2 4 - 120450 + 120377 4 1153 - 108312 + 108246 @@ -20733,7 +20796,7 @@ 1 2 - 1551854 + 1550909 2 @@ -20754,17 +20817,17 @@ 1 2 - 1324025 + 1323218 2 4 - 120450 + 120377 4 1135 - 108312 + 108246 @@ -20903,22 +20966,22 @@ 1 2 - 1515439 + 1514516 2 3 - 546230 + 545897 3 4 - 218492 + 218359 4 72 - 82634 + 82584 @@ -20934,22 +20997,22 @@ 1 2 - 1526644 + 1525714 2 3 - 538760 + 538432 3 4 - 215690 + 215559 4 72 - 81701 + 81651 @@ -20965,22 +21028,22 @@ 1 2 - 1519641 + 1518715 2 3 - 549965 + 549630 3 4 - 217558 + 217425 4 6 - 75631 + 75585 @@ -20990,11 +21053,11 @@ pointerishsize - 2707342 + 2705693 id - 2707342 + 2705693 size @@ -21016,7 +21079,7 @@ 1 2 - 2707342 + 2705693 @@ -21032,7 +21095,7 @@ 1 2 - 2707342 + 2705693 @@ -21106,23 +21169,23 @@ arraysizes - 88237 + 88183 id - 88237 + 88183 num_elements - 31746 + 31727 bytesize - 33147 + 33127 alignment - 1867 + 1866 @@ -21136,7 +21199,7 @@ 1 2 - 88237 + 88183 @@ -21152,7 +21215,7 @@ 1 2 - 88237 + 88183 @@ -21168,7 +21231,7 @@ 1 2 - 88237 + 88183 @@ -21184,22 +21247,22 @@ 1 2 - 1867 + 1866 2 3 - 23810 + 23795 3 5 - 2801 + 2799 5 13 - 2801 + 2799 13 @@ -21220,17 +21283,17 @@ 1 2 - 26611 + 26595 2 3 - 2334 + 2332 3 7 - 2801 + 2799 @@ -21246,17 +21309,17 @@ 1 2 - 26611 + 26595 2 3 - 2801 + 2799 3 5 - 2334 + 2332 @@ -21272,27 +21335,27 @@ 1 2 - 1867 + 1866 2 3 - 23810 + 23795 3 4 - 3268 + 3266 4 6 - 2334 + 2332 7 16 - 1867 + 1866 @@ -21308,17 +21371,17 @@ 1 2 - 27544 + 27528 2 3 - 3734 + 3732 3 5 - 1867 + 1866 @@ -21334,12 +21397,12 @@ 1 2 - 27544 + 27528 2 3 - 4668 + 4665 4 @@ -21791,19 +21854,19 @@ usertypes - 5234008 + 5230820 id - 5234008 + 5230820 name - 1352503 + 1351680 kind - 5135 + 5132 @@ -21817,7 +21880,7 @@ 1 2 - 5234008 + 5230820 @@ -21833,7 +21896,7 @@ 1 2 - 5234008 + 5230820 @@ -21849,27 +21912,27 @@ 1 2 - 983681 + 983082 2 3 - 153598 + 153504 3 7 - 104577 + 104513 7 61 - 101776 + 101714 65 874 - 8870 + 8865 @@ -21885,17 +21948,17 @@ 1 2 - 1211977 + 1211239 2 3 - 125586 + 125509 3 7 - 14939 + 14930 @@ -22037,19 +22100,19 @@ usertypesize - 1706386 + 1705347 id - 1706386 + 1705347 size - 13539 + 13530 alignment - 2334 + 2332 @@ -22063,7 +22126,7 @@ 1 2 - 1706386 + 1705347 @@ -22079,7 +22142,7 @@ 1 2 - 1706386 + 1705347 @@ -22095,12 +22158,12 @@ 1 2 - 3268 + 3266 2 3 - 4201 + 4199 3 @@ -22151,12 +22214,12 @@ 1 2 - 10270 + 10264 2 3 - 2801 + 2799 3 @@ -22307,15 +22370,15 @@ mangled_name - 9019338 + 9013845 id - 9019338 + 9013845 mangled_name - 6061757 + 6058065 is_complete @@ -22333,7 +22396,7 @@ 1 2 - 9019338 + 9013845 @@ -22349,7 +22412,7 @@ 1 2 - 9019338 + 9013845 @@ -22365,12 +22428,12 @@ 1 2 - 5789108 + 5785583 2 874 - 272648 + 272482 @@ -22386,7 +22449,7 @@ 1 2 - 6061757 + 6058065 @@ -22439,48 +22502,48 @@ is_standard_layout_class - 1253995 + 1253232 id - 1253995 + 1253232 is_complete - 1645694 + 1644692 id - 1645694 + 1644692 is_class_template - 398234 + 397992 id - 398234 + 397992 class_instantiation - 1089659 + 1088996 to - 1089659 + 1088996 from - 168537 + 168435 @@ -22494,7 +22557,7 @@ 1 2 - 1089659 + 1088996 @@ -22510,47 +22573,47 @@ 1 2 - 59758 + 59722 2 3 - 29412 + 29394 3 4 - 15873 + 15863 4 5 - 13072 + 13064 5 6 - 9804 + 9798 6 10 - 12605 + 12597 10 16 - 13072 + 13064 16 70 - 13539 + 13530 70 84 - 1400 + 1399 @@ -22801,19 +22864,19 @@ class_template_argument_value - 495342 + 495040 type_id - 304861 + 304676 index - 1867 + 1866 arg_value - 495342 + 495040 @@ -22827,17 +22890,17 @@ 1 2 - 249772 + 249619 2 3 - 53222 + 53190 3 4 - 1867 + 1866 @@ -22853,22 +22916,22 @@ 1 2 - 189546 + 189431 2 3 - 81234 + 81184 3 4 - 12138 + 12131 4 9 - 21942 + 21929 @@ -22946,7 +23009,7 @@ 1 2 - 495342 + 495040 @@ -22962,7 +23025,7 @@ 1 2 - 495342 + 495040 @@ -22972,15 +23035,15 @@ is_proxy_class_for - 62092 + 62055 id - 62092 + 62055 templ_param_id - 62092 + 62055 @@ -22994,7 +23057,7 @@ 1 2 - 62092 + 62055 @@ -23010,7 +23073,7 @@ 1 2 - 62092 + 62055 @@ -23316,11 +23379,11 @@ is_function_template - 1402925 + 1402070 id - 1402925 + 1402070 @@ -24451,19 +24514,19 @@ routinetypeargs - 983214 + 982616 routine - 423445 + 423187 index - 7936 + 7931 type_id - 226895 + 226757 @@ -24477,27 +24540,27 @@ 1 2 - 152664 + 152571 2 3 - 133989 + 133908 3 4 - 63493 + 63454 4 5 - 45752 + 45724 5 18 - 27544 + 27528 @@ -24513,27 +24576,27 @@ 1 2 - 182543 + 182432 2 3 - 133522 + 133441 3 4 - 58824 + 58788 4 5 - 33614 + 33593 5 11 - 14939 + 14930 @@ -24574,7 +24637,7 @@ 10 11 - 1400 + 1399 13 @@ -24635,7 +24698,7 @@ 4 5 - 1400 + 1399 5 @@ -24691,27 +24754,27 @@ 1 2 - 146595 + 146505 2 3 - 30812 + 30794 3 5 - 16807 + 16796 5 12 - 18207 + 18196 12 110 - 14472 + 14463 @@ -24727,22 +24790,22 @@ 1 2 - 172739 + 172634 2 3 - 30812 + 30794 3 6 - 18674 + 18663 6 14 - 4668 + 4665 @@ -24752,19 +24815,19 @@ ptrtomembers - 37815 + 37792 id - 37815 + 37792 type_id - 37815 + 37792 class_id - 15406 + 15397 @@ -24778,7 +24841,7 @@ 1 2 - 37815 + 37792 @@ -24794,7 +24857,7 @@ 1 2 - 37815 + 37792 @@ -24810,7 +24873,7 @@ 1 2 - 37815 + 37792 @@ -24826,7 +24889,7 @@ 1 2 - 37815 + 37792 @@ -24842,12 +24905,12 @@ 1 2 - 13539 + 13530 8 9 - 1400 + 1399 28 @@ -24868,12 +24931,12 @@ 1 2 - 13539 + 13530 8 9 - 1400 + 1399 28 @@ -24888,15 +24951,15 @@ specifiers - 24743 + 24728 id - 24743 + 24728 str - 24743 + 24728 @@ -24910,7 +24973,7 @@ 1 2 - 24743 + 24728 @@ -24926,7 +24989,7 @@ 1 2 - 24743 + 24728 @@ -24936,15 +24999,15 @@ typespecifiers - 1132144 + 1131454 type_id - 1113936 + 1113258 spec_id - 3734 + 3732 @@ -24958,12 +25021,12 @@ 1 2 - 1095728 + 1095061 2 3 - 18207 + 18196 @@ -25019,15 +25082,15 @@ funspecifiers - 10305080 + 10298338 func_id - 4068249 + 4065772 spec_id - 8403 + 8398 @@ -25041,27 +25104,27 @@ 1 2 - 1357639 + 1356812 2 3 - 640536 + 640613 3 4 - 985549 + 984482 4 5 - 780129 + 779654 5 8 - 304395 + 304209 @@ -25160,8 +25223,8 @@ 466 - 6435 - 6436 + 6434 + 6435 466 @@ -25172,15 +25235,15 @@ varspecifiers - 2246080 + 2244713 var_id - 1225050 + 1224304 spec_id - 3734 + 3732 @@ -25194,22 +25257,22 @@ 1 2 - 730174 + 729730 2 3 - 202618 + 202495 3 4 - 58357 + 58322 4 5 - 233898 + 233756 @@ -25318,19 +25381,19 @@ attributes - 561636 + 561294 id - 561636 + 561294 kind - 1400 + 1399 name - 11204 + 11197 name_space @@ -25338,7 +25401,7 @@ location - 481336 + 481043 @@ -25352,7 +25415,7 @@ 1 2 - 561636 + 561294 @@ -25368,7 +25431,7 @@ 1 2 - 561636 + 561294 @@ -25384,7 +25447,7 @@ 1 2 - 561636 + 561294 @@ -25400,7 +25463,7 @@ 1 2 - 561636 + 561294 @@ -25591,7 +25654,7 @@ 1 2 - 10270 + 10264 2 @@ -25612,7 +25675,7 @@ 1 2 - 11204 + 11197 @@ -25783,17 +25846,17 @@ 1 2 - 431848 + 431585 2 3 - 20075 + 20062 3 7 - 29412 + 29394 @@ -25809,7 +25872,7 @@ 1 2 - 481336 + 481043 @@ -25825,17 +25888,17 @@ 1 2 - 433249 + 432985 2 3 - 19608 + 19596 3 4 - 28478 + 28461 @@ -25851,7 +25914,7 @@ 1 2 - 481336 + 481043 @@ -25861,27 +25924,27 @@ attribute_args - 344078 + 343868 id - 344078 + 343868 kind - 1400 + 1399 attribute - 262844 + 262684 index - 1400 + 1399 location - 327738 + 327538 @@ -25895,7 +25958,7 @@ 1 2 - 344078 + 343868 @@ -25911,7 +25974,7 @@ 1 2 - 344078 + 343868 @@ -25927,7 +25990,7 @@ 1 2 - 344078 + 343868 @@ -25943,7 +26006,7 @@ 1 2 - 344078 + 343868 @@ -26058,17 +26121,17 @@ 1 2 - 197483 + 197363 2 3 - 49487 + 49457 3 4 - 15873 + 15863 @@ -26084,12 +26147,12 @@ 1 2 - 252573 + 252419 2 3 - 10270 + 10264 @@ -26105,17 +26168,17 @@ 1 2 - 197483 + 197363 2 3 - 49487 + 49457 3 4 - 15873 + 15863 @@ -26131,17 +26194,17 @@ 1 2 - 197483 + 197363 2 3 - 49487 + 49457 3 4 - 15873 + 15863 @@ -26256,12 +26319,12 @@ 1 2 - 313732 + 313541 2 7 - 14005 + 13997 @@ -26277,12 +26340,12 @@ 1 2 - 315132 + 314941 2 3 - 12605 + 12597 @@ -26298,12 +26361,12 @@ 1 2 - 313732 + 313541 2 7 - 14005 + 13997 @@ -26319,7 +26382,7 @@ 1 2 - 327738 + 327538 @@ -26329,15 +26392,15 @@ attribute_arg_value - 25210 + 25195 arg - 25210 + 25195 value - 15873 + 15863 @@ -26351,7 +26414,7 @@ 1 2 - 25210 + 25195 @@ -26367,12 +26430,12 @@ 1 2 - 14472 + 14463 2 16 - 1400 + 1399 @@ -26430,15 +26493,15 @@ attribute_arg_constant - 318400 + 318207 arg - 318400 + 318207 constant - 318400 + 318207 @@ -26452,7 +26515,7 @@ 1 2 - 318400 + 318207 @@ -26468,7 +26531,7 @@ 1 2 - 318400 + 318207 @@ -26647,15 +26710,15 @@ funcattributes - 630265 + 629882 func_id - 443520 + 443250 spec_id - 524754 + 524435 @@ -26669,17 +26732,17 @@ 1 2 - 338476 + 338269 2 3 - 64427 + 64387 3 6 - 39683 + 39659 6 @@ -26700,12 +26763,12 @@ 1 2 - 506080 + 505771 2 17 - 18674 + 18663 @@ -26841,15 +26904,15 @@ unspecifiedtype - 9488069 + 9482291 type_id - 9488069 + 9482291 unspecified_type_id - 6490338 + 6486385 @@ -26863,7 +26926,7 @@ 1 2 - 9488069 + 9482291 @@ -26879,17 +26942,17 @@ 1 2 - 4558923 + 4556146 2 3 - 1715723 + 1714678 3 145 - 215690 + 215559 @@ -26899,19 +26962,19 @@ member - 3881037 + 3878673 parent - 545763 + 545431 index - 92905 + 92849 child - 3809607 + 3807287 @@ -26925,47 +26988,47 @@ 1 2 - 129788 + 129709 2 3 - 64894 + 64854 3 4 - 73297 + 73252 4 5 - 75165 + 75119 5 6 - 40617 + 40592 6 8 - 46686 + 46657 8 14 - 45752 + 45724 14 30 - 41550 + 41525 30 200 - 28011 + 27994 @@ -26981,52 +27044,52 @@ 1 2 - 129788 + 129709 2 3 - 64894 + 64854 3 4 - 73297 + 73252 4 5 - 76098 + 76052 5 6 - 39683 + 39659 6 7 - 24276 + 24262 7 9 - 42017 + 41992 9 17 - 43885 + 43858 17 41 - 41550 + 41525 41 200 - 10270 + 10264 @@ -27042,62 +27105,62 @@ 1 2 - 26144 + 26128 2 3 - 7002 + 6998 3 4 - 3734 + 3732 4 5 - 7936 + 7931 5 6 - 5602 + 5598 6 7 - 5602 + 5598 7 9 - 7469 + 7465 9 16 - 7002 + 6998 16 52 - 7002 + 6998 52 107 - 7002 + 6998 108 577 - 7002 + 6998 737 1162 - 1400 + 1399 @@ -27113,62 +27176,62 @@ 1 2 - 26144 + 26128 2 3 - 7002 + 6998 3 4 - 3734 + 3732 4 5 - 7936 + 7931 5 6 - 5602 + 5598 6 7 - 5602 + 5598 7 9 - 7469 + 7465 9 16 - 7002 + 6998 16 52 - 7002 + 6998 52 107 - 7002 + 6998 108 577 - 7002 + 6998 738 1163 - 1400 + 1399 @@ -27184,7 +27247,7 @@ 1 2 - 3809607 + 3807287 @@ -27200,12 +27263,12 @@ 1 2 - 3738177 + 3735900 2 3 - 71430 + 71386 @@ -28735,15 +28798,15 @@ commentbinding - 3091104 + 3089221 id - 2445431 + 2443942 element - 3014538 + 3012702 @@ -28757,12 +28820,12 @@ 1 2 - 2368399 + 2366956 2 97 - 77032 + 76985 @@ -28778,12 +28841,12 @@ 1 2 - 2937972 + 2936183 2 3 - 76565 + 76519 @@ -28793,15 +28856,15 @@ exprconv - 7032991 + 7032993 converted - 7032991 + 7032993 conversion - 7032991 + 7032993 @@ -28815,7 +28878,7 @@ 1 2 - 7032991 + 7032993 @@ -28831,7 +28894,7 @@ 1 2 - 7032991 + 7032993 @@ -29188,15 +29251,15 @@ namespaces - 12138 + 12131 id - 12138 + 12131 name - 9804 + 9798 @@ -29210,7 +29273,7 @@ 1 2 - 12138 + 12131 @@ -29226,7 +29289,7 @@ 1 2 - 8403 + 8398 2 @@ -29246,26 +29309,26 @@ namespace_inline - 1400 + 1399 id - 1400 + 1399 namespacembrs - 2388007 + 2386553 parentid - 10270 + 10264 memberid - 2388007 + 2386553 @@ -29279,7 +29342,7 @@ 1 2 - 1867 + 1866 2 @@ -29340,7 +29403,7 @@ 1 2 - 2388007 + 2386553 @@ -29836,7 +29899,7 @@ qualifyingelement - 97518 + 97537 location @@ -29950,7 +30013,7 @@ 1 2 - 58401 + 58420 2 @@ -29986,7 +30049,7 @@ 1 2 - 58401 + 58420 2 @@ -30022,7 +30085,7 @@ 1 2 - 63815 + 63834 2 @@ -30135,12 +30198,12 @@ 1 2 - 137073 + 137054 2 3 - 55684 + 55703 3 @@ -32081,7 +32144,7 @@ expr_types - 18451442 + 18451397 id @@ -32107,12 +32170,12 @@ 1 2 - 18188121 + 18188166 2 3 - 131660 + 131615 @@ -32149,17 +32212,17 @@ 2 3 - 249334 + 249345 3 4 - 102840 + 102817 4 5 - 81865 + 81877 5 @@ -32174,12 +32237,12 @@ 14 41 - 91664 + 91653 41 125325 - 44579 + 44590 @@ -33706,11 +33769,11 @@ lambdas - 21475 + 21462 expr - 21475 + 21462 default_capture @@ -33732,7 +33795,7 @@ 1 2 - 21475 + 21462 @@ -33748,7 +33811,7 @@ 1 2 - 21475 + 21462 @@ -33822,15 +33885,15 @@ lambda_capture - 28011 + 27994 id - 28011 + 27994 lambda - 20541 + 20529 index @@ -33838,7 +33901,7 @@ field - 28011 + 27994 captured_by_reference @@ -33850,7 +33913,7 @@ location - 2801 + 2799 @@ -33864,7 +33927,7 @@ 1 2 - 28011 + 27994 @@ -33880,7 +33943,7 @@ 1 2 - 28011 + 27994 @@ -33896,7 +33959,7 @@ 1 2 - 28011 + 27994 @@ -33912,7 +33975,7 @@ 1 2 - 28011 + 27994 @@ -33928,7 +33991,7 @@ 1 2 - 28011 + 27994 @@ -33944,7 +34007,7 @@ 1 2 - 28011 + 27994 @@ -33960,12 +34023,12 @@ 1 2 - 13072 + 13064 2 3 - 7469 + 7465 @@ -33981,12 +34044,12 @@ 1 2 - 13072 + 13064 2 3 - 7469 + 7465 @@ -34002,12 +34065,12 @@ 1 2 - 13072 + 13064 2 3 - 7469 + 7465 @@ -34023,7 +34086,7 @@ 1 2 - 20541 + 20529 @@ -34039,7 +34102,7 @@ 1 2 - 20541 + 20529 @@ -34055,12 +34118,12 @@ 1 2 - 13072 + 13064 2 3 - 7469 + 7465 @@ -34192,7 +34255,7 @@ 1 2 - 28011 + 27994 @@ -34208,7 +34271,7 @@ 1 2 - 28011 + 27994 @@ -34224,7 +34287,7 @@ 1 2 - 28011 + 27994 @@ -34240,7 +34303,7 @@ 1 2 - 28011 + 27994 @@ -34256,7 +34319,7 @@ 1 2 - 28011 + 27994 @@ -34272,7 +34335,7 @@ 1 2 - 28011 + 27994 @@ -34480,7 +34543,7 @@ 8 9 - 1867 + 1866 14 @@ -34501,7 +34564,7 @@ 8 9 - 1867 + 1866 14 @@ -34522,7 +34585,7 @@ 1 2 - 2801 + 2799 @@ -34538,7 +34601,7 @@ 8 9 - 1867 + 1866 14 @@ -34559,7 +34622,7 @@ 1 2 - 2801 + 2799 @@ -34575,7 +34638,7 @@ 1 2 - 2801 + 2799 @@ -36318,11 +36381,11 @@ stmt_decl_bind - 580842 + 580849 stmt - 541060 + 541066 num @@ -36330,7 +36393,7 @@ decl - 580738 + 580745 @@ -36344,7 +36407,7 @@ 1 2 - 520371 + 520377 2 @@ -36365,7 +36428,7 @@ 1 2 - 520371 + 520377 2 @@ -36568,7 +36631,7 @@ 1 2 - 580700 + 580707 2 @@ -36589,7 +36652,7 @@ 1 2 - 580738 + 580745 @@ -36599,11 +36662,11 @@ stmt_decl_entry_bind - 580842 + 580849 stmt - 541060 + 541066 num @@ -36611,7 +36674,7 @@ decl_entry - 580784 + 580791 @@ -36625,7 +36688,7 @@ 1 2 - 520371 + 520377 2 @@ -36646,7 +36709,7 @@ 1 2 - 520371 + 520377 2 @@ -36849,7 +36912,7 @@ 1 2 - 580763 + 580770 3 @@ -36870,7 +36933,7 @@ 1 2 - 580784 + 580791 @@ -36880,15 +36943,15 @@ blockscope - 1410861 + 1410469 block - 1410861 + 1410469 enclosing - 1295546 + 1295224 @@ -36902,7 +36965,7 @@ 1 2 - 1410861 + 1410469 @@ -36918,12 +36981,12 @@ 1 2 - 1230185 + 1229903 2 13 - 65360 + 65321 @@ -37119,19 +37182,19 @@ preprocdirects - 4190567 + 4188015 id - 4190567 + 4188015 kind - 5135 + 5132 location - 4149950 + 4147423 @@ -37145,7 +37208,7 @@ 1 2 - 4190567 + 4188015 @@ -37161,7 +37224,7 @@ 1 2 - 4190567 + 4188015 @@ -37309,7 +37372,7 @@ 1 2 - 4149483 + 4146956 88 @@ -37330,7 +37393,7 @@ 1 2 - 4149950 + 4147423 @@ -37340,15 +37403,15 @@ preprocpair - 1431403 + 1430532 begin - 1197038 + 1196309 elseelifend - 1431403 + 1430532 @@ -37362,17 +37425,17 @@ 1 2 - 978546 + 977950 2 3 - 208221 + 208094 3 11 - 10270 + 10264 @@ -37388,7 +37451,7 @@ 1 2 - 1431403 + 1430532 @@ -37398,22 +37461,22 @@ preproctrue - 767056 + 766589 branch - 767056 + 766589 preprocfalse - 331473 + 331271 branch - 331473 + 331271 @@ -37566,15 +37629,15 @@ includes - 313265 + 313074 id - 313265 + 313074 included - 117182 + 117111 @@ -37588,7 +37651,7 @@ 1 2 - 313265 + 313074 @@ -37604,32 +37667,32 @@ 1 2 - 61159 + 61121 2 3 - 21942 + 21929 3 4 - 12605 + 12597 4 6 - 10270 + 10264 6 14 - 8870 + 8865 14 47 - 2334 + 2332 diff --git a/cpp/ql/lib/upgrades/e51fad7a2436caefab0c6bd52f05e28e7cce4d92/old.dbscheme b/cpp/ql/lib/upgrades/e51fad7a2436caefab0c6bd52f05e28e7cce4d92/old.dbscheme new file mode 100644 index 00000000000..e51fad7a243 --- /dev/null +++ b/cpp/ql/lib/upgrades/e51fad7a2436caefab0c6bd52f05e28e7cce4d92/old.dbscheme @@ -0,0 +1,2323 @@ + +/** + * 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 + */ + +extractor_version( + string codeql_version: string ref, + string frontend_version: string ref +) + +@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 @macroinvocation.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_function +| 2 = @constructor +| 3 = @destructor +| 4 = @conversion_function +| 5 = @operator +| 6 = @builtin_function // GCC built-in functions, e.g. __builtin___memcpy_chk +| 7 = @user_defined_literal +| 8 = @deduction_guide +; +*/ + +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 +); + +/* +case @coroutine_placeholder_variable.kind of + 1 = @handle +| 2 = @promise +| 3 = @init_await_resume +; +*/ + +coroutine_placeholder_variable( + unique int placeholder_variable: @variable ref, + int kind: int ref, + int function: @function 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); + +function_prototyped(unique int id: @function ref) + +deduction_guide_for_class( + int id: @function ref, + int class_template: @usertype 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 +); + +case @using.kind of + 1 = @using_declaration +| 2 = @using_directive +| 3 = @using_enum_declaration +; + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref, + int kind: int 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: @parameterized_element 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 = @errortype +| 2 = @unknowntype +| 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 Microsoft-specific __int8 +// ... 21 Microsoft-specific __int16 +// ... 22 Microsoft-specific __int32 +// ... 23 Microsoft-specific __int64 +| 24 = @float +| 25 = @double +| 26 = @long_double +| 27 = @complex_float // C99-specific _Complex float +| 28 = @complex_double // C99-specific _Complex double +| 29 = @complex_long_double // C99-specific _Complex long double +| 30 = @imaginary_float // C99-specific _Imaginary float +| 31 = @imaginary_double // C99-specific _Imaginary double +| 32 = @imaginary_long_double // C99-specific _Imaginary long double +| 33 = @wchar_t // Microsoft-specific +| 34 = @decltype_nullptr // C++11 +| 35 = @int128 // __int128 +| 36 = @unsigned_int128 // unsigned __int128 +| 37 = @signed_int128 // signed __int128 +| 38 = @float128 // __float128 +| 39 = @complex_float128 // _Complex __float128 +| 40 = @decimal32 // _Decimal32 +| 41 = @decimal64 // _Decimal64 +| 42 = @decimal128 // _Decimal128 +| 43 = @char16_t +| 44 = @char32_t +| 45 = @std_float32 // _Float32 +| 46 = @float32x // _Float32x +| 47 = @std_float64 // _Float64 +| 48 = @float64x // _Float64x +| 49 = @std_float128 // _Float128 +// ... 50 _Float128x +| 51 = @char8_t +| 52 = @float16 // _Float16 +| 53 = @complex_float16 // _Complex _Float16 +| 54 = @fp16 // __fp16 +| 55 = @std_bfloat16 // __bf16 +| 56 = @std_float16 // std::float16_t +| 57 = @complex_std_float32 // _Complex _Float32 +| 58 = @complex_float32x // _Complex _Float32x +| 59 = @complex_std_float64 // _Complex _Float64 +| 60 = @complex_float64x // _Complex _Float64x +| 61 = @complex_std_float128 // _Complex _Float128 +; + +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, + boolean is_complete: boolean ref +); + +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 +); + +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 +); + +explicit_specifier_exprs( + unique int func_id: @function ref, + int constant: @expr 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 +| 5 = @attribute_arg_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_expr( + unique int arg: @attribute_arg ref, + int expr: @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 + | @c11_generic + ; + +/* +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 + ; + +@assign_pointer_expr = @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr + | @assign_bitwise_expr + | @assign_pointer_expr + ; + +@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr + +/* + Binary encoding of the allocator form. + + 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 +); + +/* + Binary encoding of the deallocator form. + + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 4 = destroying_delete + ; +*/ + +/** + * 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 +); + +expr_reuse( + int reuse: @expr ref, + int original: @expr ref, + int value_category: int 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 +| 363 = @reuseexpr +| 364 = @istriviallycopyassignable +| 365 = @isassignablenopreconditioncheck +| 366 = @referencebindstotemporary +| 367 = @issameas +| 368 = @builtinhasattribute +| 369 = @ispointerinterconvertiblewithclass +| 370 = @builtinispointerinterconvertiblewithclass +| 371 = @iscorrespondingmember +| 372 = @builtiniscorrespondingmember +| 373 = @isboundedarray +| 374 = @isunboundedarray +| 375 = @isreferenceable +| 378 = @isnothrowconvertible +| 379 = @referenceconstructsfromtemporary +| 380 = @referenceconvertsfromtemporary +| 381 = @isconvertible +| 382 = @isvalidwinrttype +| 383 = @iswinclass +| 384 = @iswininterface +| 385 = @istriviallyequalitycomparable +| 386 = @isscopedenum +| 387 = @istriviallyrelocatable +| 388 = @datasizeof +| 389 = @c11_generic +| 390 = @requires_expr +| 391 = @nested_requirement +| 392 = @compound_requirement +| 393 = @concept_id +; + +@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 + | @istrivialexpr + | @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 + | @istriviallycopyassignable + | @isassignablenopreconditioncheck + | @referencebindstotemporary + | @issameas + | @builtinhasattribute + | @ispointerinterconvertiblewithclass + | @builtinispointerinterconvertiblewithclass + | @iscorrespondingmember + | @builtiniscorrespondingmember + | @isboundedarray + | @isunboundedarray + | @isreferenceable + | @isnothrowconvertible + | @referenceconstructsfromtemporary + | @referenceconvertsfromtemporary + | @isconvertible + | @isvalidwinrttype + | @iswinclass + | @iswininterface + | @istriviallyequalitycomparable + | @isscopedenum + | @istriviallyrelocatable + ; + +compound_requirement_is_noexcept( + int expr: @compound_requirement ref +); + +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. Position is used to sort repeated initializers. + */ +#keyset[aggregate, position] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref, + int position: int ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. Position is used to sort repeated initializers. + */ +#keyset[aggregate, position] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref, + int position: 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 | @datasizeof; + +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 +); + +@stmt_for_or_range_based_for = @stmt_for + | @stmt_range_based_for; + +for_initialization( + unique int for_stmt: @stmt_for_or_range_based_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 +); + +@parameterized_element = @function | @stmt_block | @requires_expr; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @parameterized_element 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( + 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/e51fad7a2436caefab0c6bd52f05e28e7cce4d92/semmlecode.cpp.dbscheme b/cpp/ql/lib/upgrades/e51fad7a2436caefab0c6bd52f05e28e7cce4d92/semmlecode.cpp.dbscheme new file mode 100644 index 00000000000..f0156f5f88a --- /dev/null +++ b/cpp/ql/lib/upgrades/e51fad7a2436caefab0c6bd52f05e28e7cce4d92/semmlecode.cpp.dbscheme @@ -0,0 +1,2339 @@ + +/** + * 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 +); + +/** + * Optionally, record the build mode for each compilation. + */ +compilation_build_mode( + unique int id : @compilation ref, + int mode : int ref +); + +/* +case @compilation_build_mode.mode of + 0 = @build_mode_none +| 1 = @build_mode_manual +| 2 = @build_mode_auto +; +*/ + +/** + * 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 + */ + +extractor_version( + string codeql_version: string ref, + string frontend_version: string ref +) + +@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 @macroinvocation.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_function +| 2 = @constructor +| 3 = @destructor +| 4 = @conversion_function +| 5 = @operator +| 6 = @builtin_function // GCC built-in functions, e.g. __builtin___memcpy_chk +| 7 = @user_defined_literal +| 8 = @deduction_guide +; +*/ + +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 +); + +/* +case @coroutine_placeholder_variable.kind of + 1 = @handle +| 2 = @promise +| 3 = @init_await_resume +; +*/ + +coroutine_placeholder_variable( + unique int placeholder_variable: @variable ref, + int kind: int ref, + int function: @function 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); + +function_prototyped(unique int id: @function ref) + +deduction_guide_for_class( + int id: @function ref, + int class_template: @usertype 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 +); + +case @using.kind of + 1 = @using_declaration +| 2 = @using_directive +| 3 = @using_enum_declaration +; + +usings( + unique int id: @using, + int element_id: @element ref, + int location: @location_default ref, + int kind: int 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: @parameterized_element 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 = @errortype +| 2 = @unknowntype +| 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 Microsoft-specific __int8 +// ... 21 Microsoft-specific __int16 +// ... 22 Microsoft-specific __int32 +// ... 23 Microsoft-specific __int64 +| 24 = @float +| 25 = @double +| 26 = @long_double +| 27 = @complex_float // C99-specific _Complex float +| 28 = @complex_double // C99-specific _Complex double +| 29 = @complex_long_double // C99-specific _Complex long double +| 30 = @imaginary_float // C99-specific _Imaginary float +| 31 = @imaginary_double // C99-specific _Imaginary double +| 32 = @imaginary_long_double // C99-specific _Imaginary long double +| 33 = @wchar_t // Microsoft-specific +| 34 = @decltype_nullptr // C++11 +| 35 = @int128 // __int128 +| 36 = @unsigned_int128 // unsigned __int128 +| 37 = @signed_int128 // signed __int128 +| 38 = @float128 // __float128 +| 39 = @complex_float128 // _Complex __float128 +| 40 = @decimal32 // _Decimal32 +| 41 = @decimal64 // _Decimal64 +| 42 = @decimal128 // _Decimal128 +| 43 = @char16_t +| 44 = @char32_t +| 45 = @std_float32 // _Float32 +| 46 = @float32x // _Float32x +| 47 = @std_float64 // _Float64 +| 48 = @float64x // _Float64x +| 49 = @std_float128 // _Float128 +// ... 50 _Float128x +| 51 = @char8_t +| 52 = @float16 // _Float16 +| 53 = @complex_float16 // _Complex _Float16 +| 54 = @fp16 // __fp16 +| 55 = @std_bfloat16 // __bf16 +| 56 = @std_float16 // std::float16_t +| 57 = @complex_std_float32 // _Complex _Float32 +| 58 = @complex_float32x // _Complex _Float32x +| 59 = @complex_std_float64 // _Complex _Float64 +| 60 = @complex_float64x // _Complex _Float64x +| 61 = @complex_std_float128 // _Complex _Float128 +; + +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, + boolean is_complete: boolean ref +); + +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 +); + +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 +); + +explicit_specifier_exprs( + unique int func_id: @function ref, + int constant: @expr 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 +| 5 = @attribute_arg_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_expr( + unique int arg: @attribute_arg ref, + int expr: @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 + | @c11_generic + ; + +/* +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 + ; + +@assign_pointer_expr = @assignpaddexpr + | @assignpsubexpr + ; + +@assign_op_expr = @assign_arith_expr + | @assign_bitwise_expr + | @assign_pointer_expr + ; + +@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr + +/* + Binary encoding of the allocator form. + + 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 +); + +/* + Binary encoding of the deallocator form. + + case @deallocator.form of + 0 = plain + | 1 = size + | 2 = alignment + | 4 = destroying_delete + ; +*/ + +/** + * 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 +); + +expr_reuse( + int reuse: @expr ref, + int original: @expr ref, + int value_category: int 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 +| 363 = @reuseexpr +| 364 = @istriviallycopyassignable +| 365 = @isassignablenopreconditioncheck +| 366 = @referencebindstotemporary +| 367 = @issameas +| 368 = @builtinhasattribute +| 369 = @ispointerinterconvertiblewithclass +| 370 = @builtinispointerinterconvertiblewithclass +| 371 = @iscorrespondingmember +| 372 = @builtiniscorrespondingmember +| 373 = @isboundedarray +| 374 = @isunboundedarray +| 375 = @isreferenceable +| 378 = @isnothrowconvertible +| 379 = @referenceconstructsfromtemporary +| 380 = @referenceconvertsfromtemporary +| 381 = @isconvertible +| 382 = @isvalidwinrttype +| 383 = @iswinclass +| 384 = @iswininterface +| 385 = @istriviallyequalitycomparable +| 386 = @isscopedenum +| 387 = @istriviallyrelocatable +| 388 = @datasizeof +| 389 = @c11_generic +| 390 = @requires_expr +| 391 = @nested_requirement +| 392 = @compound_requirement +| 393 = @concept_id +; + +@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 + | @istrivialexpr + | @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 + | @istriviallycopyassignable + | @isassignablenopreconditioncheck + | @referencebindstotemporary + | @issameas + | @builtinhasattribute + | @ispointerinterconvertiblewithclass + | @builtinispointerinterconvertiblewithclass + | @iscorrespondingmember + | @builtiniscorrespondingmember + | @isboundedarray + | @isunboundedarray + | @isreferenceable + | @isnothrowconvertible + | @referenceconstructsfromtemporary + | @referenceconvertsfromtemporary + | @isconvertible + | @isvalidwinrttype + | @iswinclass + | @iswininterface + | @istriviallyequalitycomparable + | @isscopedenum + | @istriviallyrelocatable + ; + +compound_requirement_is_noexcept( + int expr: @compound_requirement ref +); + +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. Position is used to sort repeated initializers. + */ +#keyset[aggregate, position] +aggregate_field_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int field: @membervariable ref, + int position: int ref +); + +/** + * The index of the element being initialized by an initializer expression + * within an aggregate initializer for an array. Position is used to sort repeated initializers. + */ +#keyset[aggregate, position] +aggregate_array_init( + int aggregate: @aggregateliteral ref, + int initializer: @expr ref, + int element_index: int ref, + int position: 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 | @datasizeof; + +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 +); + +@stmt_for_or_range_based_for = @stmt_for + | @stmt_range_based_for; + +for_initialization( + unique int for_stmt: @stmt_for_or_range_based_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 +); + +@parameterized_element = @function | @stmt_block | @requires_expr; + +blockscope( + unique int block: @stmt_block ref, + int enclosing: @parameterized_element 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( + 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/e51fad7a2436caefab0c6bd52f05e28e7cce4d92/upgrade.properties b/cpp/ql/lib/upgrades/e51fad7a2436caefab0c6bd52f05e28e7cce4d92/upgrade.properties new file mode 100644 index 00000000000..08e1dc42eb2 --- /dev/null +++ b/cpp/ql/lib/upgrades/e51fad7a2436caefab0c6bd52f05e28e7cce4d92/upgrade.properties @@ -0,0 +1,2 @@ +description: Implement compilation_build_mode/2 +compatibility: backwards diff --git a/cpp/ql/src/experimental/Best Practices/GuardedFree.cpp b/cpp/ql/src/Best Practices/GuardedFree.cpp similarity index 100% rename from cpp/ql/src/experimental/Best Practices/GuardedFree.cpp rename to cpp/ql/src/Best Practices/GuardedFree.cpp diff --git a/cpp/ql/src/experimental/Best Practices/GuardedFree.qhelp b/cpp/ql/src/Best Practices/GuardedFree.qhelp similarity index 55% rename from cpp/ql/src/experimental/Best Practices/GuardedFree.qhelp rename to cpp/ql/src/Best Practices/GuardedFree.qhelp index 77fdd467000..c2dc5cb36d7 100644 --- a/cpp/ql/src/experimental/Best Practices/GuardedFree.qhelp +++ b/cpp/ql/src/Best Practices/GuardedFree.qhelp @@ -1,18 +1,28 @@ - + + -

The free function, which deallocates heap memory, may accept a NULL pointer and take no action. Therefore, it is unnecessary to check its argument for the value of NULL before a function call to free. As such, these guards may hinder performance and readability.

+

The free function, which deallocates heap memory, may accept a NULL pointer and take no action. Therefore, it is unnecessary to check the argument for the value of NULL before a function call to free. As such, these guards may hinder performance and readability.

+ -

A function call to free should not depend upon the value of its argument. Delete the if condition preceeding a function call to free when its only purpose is to check the value of the pointer to be freed.

+

A function call to free should not depend upon the value of its argument. Delete the condition preceding a function call to free when its only purpose is to check the value of the pointer to be freed.

+ + +

In this example, the condition checking the value of foo can be deleted.

+
+
  • The Open Group Base Specifications Issue 7, 2018 Edition: - free - free allocated memory + free - free allocated memory.
  • -
    \ No newline at end of file + + diff --git a/cpp/ql/src/Best Practices/GuardedFree.ql b/cpp/ql/src/Best Practices/GuardedFree.ql new file mode 100644 index 00000000000..ea81a715828 --- /dev/null +++ b/cpp/ql/src/Best Practices/GuardedFree.ql @@ -0,0 +1,47 @@ +/** + * @name Guarded Free + * @description NULL-condition guards before function calls to the memory-deallocation + * function free(3) are unnecessary, because passing NULL to free(3) is a no-op. + * @kind problem + * @problem.severity recommendation + * @precision very-high + * @id cpp/guarded-free + * @tags maintainability + * readability + */ + +import cpp +import semmle.code.cpp.controlflow.Guards + +class FreeCall extends FunctionCall { + FreeCall() { this.getTarget().hasGlobalName("free") } +} + +predicate blockContainsPreprocessorBranches(BasicBlock bb) { + exists(PreprocessorBranch ppb, Location bbLoc, Location ppbLoc | + bbLoc = bb.(Stmt).getLocation() and ppbLoc = ppb.getLocation() + | + bbLoc.getFile() = ppb.getFile() and + bbLoc.getStartLine() < ppbLoc.getStartLine() and + ppbLoc.getEndLine() < bbLoc.getEndLine() + ) +} + +from GuardCondition gc, FreeCall fc, Variable v, BasicBlock bb +where + gc.ensuresEq(v.getAnAccess(), 0, bb, false) and + fc.getArgument(0) = v.getAnAccess() and + bb = fc.getBasicBlock() and + ( + // No block statement: if (x) free(x); + bb = fc.getEnclosingStmt() + or + // Block statement with a single nested statement: if (x) { free(x); } + strictcount(bb.(BlockStmt).getAStmt()) = 1 + ) and + strictcount(BasicBlock bb2 | gc.ensuresEq(_, 0, bb2, _) | bb2) = 1 and + not fc.isInMacroExpansion() and + not blockContainsPreprocessorBranches(bb) and + not (gc instanceof BinaryOperation and not gc instanceof ComparisonOperation) and + not exists(CommaExpr c | c.getAChild*() = fc) +select gc, "unnecessary NULL check before call to $@", fc, "free" diff --git a/cpp/ql/src/Critical/UseAfterFree.qhelp b/cpp/ql/src/Critical/UseAfterFree.qhelp index 6a532ed4d35..60dd1a6690e 100644 --- a/cpp/ql/src/Critical/UseAfterFree.qhelp +++ b/cpp/ql/src/Critical/UseAfterFree.qhelp @@ -8,7 +8,7 @@

    This rule finds accesses through a pointer of a memory location that has already been freed (i.e. through a dangling pointer). Such memory blocks have already been released to the dynamic memory manager, and modifying them can lead to anything -from a segfault to memory corruption that would cause subsequent calls to the dynamic memory manger to behave +from a segfault to memory corruption that would cause subsequent calls to the dynamic memory manager to behave erratically, to a possible security vulnerability.

    diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll index 6f3f4d43e9a..218a54b36c5 100644 --- a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qll @@ -51,5 +51,7 @@ predicate tooFewArguments(FunctionCall fc, Function f) { hasDefiniteNumberOfParameters(fde) | fde.getNumberOfParameters() > fc.getNumberOfArguments() - ) + ) and + // Don't report on implicit function declarations, as these are likely extraction errors. + not f.getADeclarationEntry().isImplicit() } diff --git a/cpp/ql/src/Security/CWE/CWE-078/ExecTainted.ql b/cpp/ql/src/Security/CWE/CWE-078/ExecTainted.ql index 0686c4a707c..f6dd3b6f212 100644 --- a/cpp/ql/src/Security/CWE/CWE-078/ExecTainted.ql +++ b/cpp/ql/src/Security/CWE/CWE-078/ExecTainted.ql @@ -19,7 +19,6 @@ import semmle.code.cpp.security.Security import semmle.code.cpp.valuenumbering.GlobalValueNumbering import semmle.code.cpp.ir.IR import semmle.code.cpp.ir.dataflow.TaintTracking -import semmle.code.cpp.ir.dataflow.TaintTracking2 import semmle.code.cpp.security.FlowSources import semmle.code.cpp.models.implementations.Strcat import ExecTaint::PathGraph diff --git a/cpp/ql/src/Security/CWE/CWE-570/IncorrectAllocationErrorHandling.ql b/cpp/ql/src/Security/CWE/CWE-570/IncorrectAllocationErrorHandling.ql index 92daf31b057..d4d908f8474 100644 --- a/cpp/ql/src/Security/CWE/CWE-570/IncorrectAllocationErrorHandling.ql +++ b/cpp/ql/src/Security/CWE/CWE-570/IncorrectAllocationErrorHandling.ql @@ -45,7 +45,7 @@ predicate deleteMayThrow(DeleteOrDeleteArrayExpr deleteExpr) { * like it might throw an exception, and the function does not have a `noexcept` or `throw()` specifier. */ predicate functionMayThrow(Function f) { - not f instanceof NonThrowingFunction and + not f instanceof NonCppThrowingFunction and (not exists(f.getBlock()) or stmtMayThrow(f.getBlock())) } diff --git a/cpp/ql/src/change-notes/2014-11-26-guarded-free.md b/cpp/ql/src/change-notes/2014-11-26-guarded-free.md new file mode 100644 index 00000000000..4280025a04f --- /dev/null +++ b/cpp/ql/src/change-notes/2014-11-26-guarded-free.md @@ -0,0 +1,4 @@ +--- +category: newQuery +--- +* Added a new high-precision quality query, `cpp/guarded-free`, which detects useless NULL pointer checks before calls to `free`. A variation of this query was originally contributed as an [experimental query by @mario-campos](https://github.com/github/codeql/pull/16331). diff --git a/cpp/ql/src/change-notes/2024-11-22-too-few-arguments.md b/cpp/ql/src/change-notes/2024-11-22-too-few-arguments.md new file mode 100644 index 00000000000..116df08838a --- /dev/null +++ b/cpp/ql/src/change-notes/2024-11-22-too-few-arguments.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The "Call to function with fewer arguments than declared parameters" query (`cpp/too-few-arguments`) query no longer produces results if the function has been implicitly declared. diff --git a/cpp/ql/src/experimental/Best Practices/GuardedFree.ql b/cpp/ql/src/experimental/Best Practices/GuardedFree.ql deleted file mode 100644 index 2d504d9bc05..00000000000 --- a/cpp/ql/src/experimental/Best Practices/GuardedFree.ql +++ /dev/null @@ -1,26 +0,0 @@ -/** - * @name Guarded Free - * @description NULL-condition guards before function calls to the memory-deallocation - * function free(3) are unnecessary, because passing NULL to free(3) is a no-op. - * @kind problem - * @problem.severity recommendation - * @precision very-high - * @id cpp/guarded-free - * @tags maintainability - * readability - * experimental - */ - -import cpp -import semmle.code.cpp.controlflow.Guards - -class FreeCall extends FunctionCall { - FreeCall() { this.getTarget().hasGlobalName("free") } -} - -from GuardCondition gc, FreeCall fc, Variable v, BasicBlock bb -where - gc.ensuresEq(v.getAnAccess(), 0, bb, false) and - fc.getArgument(0) = v.getAnAccess() and - bb = fc.getEnclosingStmt() -select gc, "unnecessary NULL check before call to $@", fc, "free" diff --git a/cpp/ql/test/experimental/query-tests/Best Practices/GuardedFree/GuardedFree.expected b/cpp/ql/test/experimental/query-tests/Best Practices/GuardedFree/GuardedFree.expected deleted file mode 100644 index 209bae407b8..00000000000 --- a/cpp/ql/test/experimental/query-tests/Best Practices/GuardedFree/GuardedFree.expected +++ /dev/null @@ -1,10 +0,0 @@ -| test.cpp:5:7:5:7 | x | unnecessary NULL check before call to $@ | test.cpp:6:5:6:8 | call to free | free | -| test.cpp:23:7:23:7 | x | unnecessary NULL check before call to $@ | test.cpp:26:5:26:8 | call to free | free | -| test.cpp:31:7:31:8 | ! ... | unnecessary NULL check before call to $@ | test.cpp:35:3:35:6 | call to free | free | -| test.cpp:31:7:31:24 | ... \|\| ... | unnecessary NULL check before call to $@ | test.cpp:35:3:35:6 | call to free | free | -| test.cpp:31:8:31:8 | x | unnecessary NULL check before call to $@ | test.cpp:35:3:35:6 | call to free | free | -| test.cpp:94:12:94:12 | x | unnecessary NULL check before call to $@ | test.cpp:94:3:94:13 | call to free | free | -| test.cpp:98:7:98:8 | ! ... | unnecessary NULL check before call to $@ | test.cpp:101:3:101:6 | call to free | free | -| test.cpp:98:8:98:8 | x | unnecessary NULL check before call to $@ | test.cpp:101:3:101:6 | call to free | free | -| test.cpp:106:7:106:18 | ... != ... | unnecessary NULL check before call to $@ | test.cpp:107:5:107:8 | call to free | free | -| test.cpp:113:7:113:18 | ... != ... | unnecessary NULL check before call to $@ | test.cpp:114:17:114:20 | call to free | free | diff --git a/cpp/ql/test/experimental/query-tests/Best Practices/GuardedFree/GuardedFree.qlref b/cpp/ql/test/experimental/query-tests/Best Practices/GuardedFree/GuardedFree.qlref deleted file mode 100644 index e28bdae3991..00000000000 --- a/cpp/ql/test/experimental/query-tests/Best Practices/GuardedFree/GuardedFree.qlref +++ /dev/null @@ -1 +0,0 @@ -experimental/Best Practices/GuardedFree.ql diff --git a/cpp/ql/test/library-tests/dataflow/asExpr/test-indirect.expected b/cpp/ql/test/library-tests/dataflow/asExpr/test-indirect.expected index 8ec8033d086..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/dataflow/asExpr/test-indirect.expected +++ b/cpp/ql/test/library-tests/dataflow/asExpr/test-indirect.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/cpp/ql/test/library-tests/dataflow/asExpr/test.expected b/cpp/ql/test/library-tests/dataflow/asExpr/test.expected index 8ec8033d086..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/dataflow/asExpr/test.expected +++ b/cpp/ql/test/library-tests/dataflow/asExpr/test.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/guard-condition-regression-test.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/guard-condition-regression-test.expected index 8ec8033d086..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/guard-condition-regression-test.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/guard-condition-regression-test.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/has-parameter-flow-out.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/has-parameter-flow-out.expected index 22f278d41ae..5711cec229d 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/has-parameter-flow-out.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/has-parameter-flow-out.expected @@ -1,3 +1 @@ WARNING: module 'DataFlow' has been deprecated and may be removed in future (has-parameter-flow-out.ql:5,18-61) -testFailures -failures diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test-number-of-outnodes.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test-number-of-outnodes.expected index a32c8f7af91..316ac213731 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test-number-of-outnodes.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test-number-of-outnodes.expected @@ -1,3 +1 @@ WARNING: module 'DataFlow' has been deprecated and may be removed in future (test-number-of-outnodes.ql:5,18-61) -failures -testFailures diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.expected index 8ec8033d086..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_self_argument_flow.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_self_argument_flow.expected index 8ec8033d086..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_self_argument_flow.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_self_argument_flow.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_self_parameter_flow.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_self_parameter_flow.expected index 48de9172b36..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_self_parameter_flow.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test_self_parameter_flow.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/type-bugs.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/type-bugs.expected index 02f5544fe14..87ebdc9e83a 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/type-bugs.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/type-bugs.expected @@ -52,4 +52,3 @@ incorrectBaseType | test.cpp:854:10:854:36 | * ... | Expected 'Node.getType()' to be const int, but it was int | | test.cpp:867:10:867:30 | * ... | Expected 'Node.getType()' to be const int, but it was int | | test.cpp:1098:52:1098:53 | *& ... | Expected 'Node.getType()' to be char, but it was char * | -failures diff --git a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected index a3d09178f2c..8a954e9235a 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected @@ -1,5 +1,4 @@ testFailures -failures edges | asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | provenance | MaD:10 | | asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:2 | diff --git a/cpp/ql/test/library-tests/dataflow/fields/flow.expected b/cpp/ql/test/library-tests/dataflow/fields/flow.expected index 8ec8033d086..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/flow.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/cpp/ql/test/library-tests/dataflow/models-as-data/interpretElement.expected b/cpp/ql/test/library-tests/dataflow/models-as-data/interpretElement.expected index 8ec8033d086..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/dataflow/models-as-data/interpretElement.expected +++ b/cpp/ql/test/library-tests/dataflow/models-as-data/interpretElement.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/cpp/ql/test/library-tests/dataflow/models-as-data/taint.expected b/cpp/ql/test/library-tests/dataflow/models-as-data/taint.expected index 8ec8033d086..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/dataflow/models-as-data/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/models-as-data/taint.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/cpp/ql/test/library-tests/dataflow/parameters-without-defs/test.expected b/cpp/ql/test/library-tests/dataflow/parameters-without-defs/test.expected index 8ec8033d086..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/dataflow/parameters-without-defs/test.expected +++ b/cpp/ql/test/library-tests/dataflow/parameters-without-defs/test.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/cpp/ql/test/library-tests/dataflow/smart-pointers-taint/taint.expected b/cpp/ql/test/library-tests/dataflow/smart-pointers-taint/taint.expected index dfa7c56f90b..a3e8b75f996 100644 --- a/cpp/ql/test/library-tests/dataflow/smart-pointers-taint/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/smart-pointers-taint/taint.expected @@ -2,5 +2,3 @@ WARNING: module 'DataFlow' has been deprecated and may be removed in future (tai WARNING: module 'DataFlow' has been deprecated and may be removed in future (taint.ql:7,24-32) WARNING: module 'DataFlow' has been deprecated and may be removed in future (taint.ql:11,22-30) WARNING: module 'TaintTracking' has been deprecated and may be removed in future (taint.ql:19,20-33) -failures -testFailures diff --git a/cpp/ql/test/library-tests/dataflow/source-sink-tests/local-flow.expected b/cpp/ql/test/library-tests/dataflow/source-sink-tests/local-flow.expected index 8ec8033d086..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/dataflow/source-sink-tests/local-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/source-sink-tests/local-flow.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/cpp/ql/test/library-tests/dataflow/source-sink-tests/remote-flow.expected b/cpp/ql/test/library-tests/dataflow/source-sink-tests/remote-flow.expected index 8ec8033d086..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/dataflow/source-sink-tests/remote-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/source-sink-tests/remote-flow.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp index d123ed5cc15..b69a0b3d58f 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp @@ -164,4 +164,10 @@ void test_format() { auto s2 = std::format(string::source()); sink(s2); // $ ir MISSING: ast +} + +void test(std::format_string s) { + int x = source(); + int y = std::same_signature_as_format_but_different_name(s, x); + sink(y); // clean } \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected index 7de6914e8aa..b5ddf84747a 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -451,6 +451,9 @@ WARNING: module 'TaintTracking' has been deprecated and may be removed in future | format.cpp:162:24:162:27 | {} | format.cpp:162:24:162:27 | call to basic_format_string | TAINT | | format.cpp:165:13:165:23 | call to format | format.cpp:166:8:166:9 | s2 | | | format.cpp:165:25:165:38 | call to source | format.cpp:165:25:165:40 | call to basic_format_string | TAINT | +| format.cpp:169:30:169:30 | s | format.cpp:171:60:171:60 | s | | +| format.cpp:170:11:170:16 | call to source | format.cpp:171:63:171:63 | x | | +| format.cpp:171:11:171:58 | call to same_signature_as_format_but_different_name | format.cpp:172:8:172:8 | y | | | map.cpp:21:28:21:28 | call to pair | map.cpp:23:2:23:2 | a | | | map.cpp:21:28:21:28 | call to pair | map.cpp:24:7:24:7 | a | | | map.cpp:21:28:21:28 | call to pair | map.cpp:25:7:25:7 | a | | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/stl.h b/cpp/ql/test/library-tests/dataflow/taint-tests/stl.h index 9647f41cb7c..01e5f3b929b 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/stl.h +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/stl.h @@ -676,4 +676,9 @@ namespace std { using format_string = basic_format_string; // simplified from `char, std::type_identity_t...` template string format( format_string fmt, Args&&... args ); + + // This function has the same signature as `format`, but a different name. It should NOT be able to use + // the model for `format`. + template + int same_signature_as_format_but_different_name(format_string, Args &&...args); } \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected index 299f1413878..444be256516 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -3,5 +3,3 @@ WARNING: module 'DataFlow' has been deprecated and may be removed in future (tai WARNING: module 'DataFlow' has been deprecated and may be removed in future (taint.ql:61,22-30) WARNING: module 'DataFlow' has been deprecated and may be removed in future (taint.ql:68,25-33) WARNING: module 'TaintTracking' has been deprecated and may be removed in future (taint.ql:73,20-33) -testFailures -failures diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_mad-signatures.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_mad-signatures.expected index 0d27fdaf0fd..26031f42c0a 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_mad-signatures.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_mad-signatures.expected @@ -265,6 +265,8 @@ signatureMatches | stl.h:678:33:678:38 | format | (format_string,Args &&) | | format | 0 | | stl.h:678:33:678:38 | format | (format_string,Args &&) | | format | 1 | | stl.h:678:33:678:38 | format | (format_string,Args &&) | | format | 1 | +| stl.h:683:6:683:48 | same_signature_as_format_but_different_name | (format_string,Args &&) | | format | 0 | +| stl.h:683:6:683:48 | same_signature_as_format_but_different_name | (format_string,Args &&) | | format | 1 | getSignatureParameterName | (InputIt,InputIt) | deque | assign | 0 | func:0 | | (InputIt,InputIt) | deque | assign | 1 | func:0 | @@ -729,6 +731,8 @@ getParameterTypeName | stl.h:678:33:678:38 | format | 0 | format_string | | stl.h:678:33:678:38 | format | 1 | func:0 && | | stl.h:678:33:678:38 | format | 1 | func:0 && | +| stl.h:683:6:683:48 | same_signature_as_format_but_different_name | 0 | format_string | +| stl.h:683:6:683:48 | same_signature_as_format_but_different_name | 1 | func:0 && | | stringstream.cpp:18:6:18:9 | sink | 0 | const basic_ostream> & | | stringstream.cpp:21:6:21:9 | sink | 0 | const basic_istream> & | | stringstream.cpp:24:6:24:9 | sink | 0 | const basic_iostream> & | diff --git a/cpp/ql/test/library-tests/ir/modulus-analysis/ModulusAnalysis.expected b/cpp/ql/test/library-tests/ir/modulus-analysis/ModulusAnalysis.expected index 8ec8033d086..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/ir/modulus-analysis/ModulusAnalysis.expected +++ b/cpp/ql/test/library-tests/ir/modulus-analysis/ModulusAnalysis.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/cpp/ql/test/library-tests/ir/range-analysis/Overflow.expected b/cpp/ql/test/library-tests/ir/range-analysis/Overflow.expected index 8ec8033d086..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/ir/range-analysis/Overflow.expected +++ b/cpp/ql/test/library-tests/ir/range-analysis/Overflow.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/cpp/ql/test/library-tests/ir/range-analysis/RangeAnalysis.expected b/cpp/ql/test/library-tests/ir/range-analysis/RangeAnalysis.expected index 8ec8033d086..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/ir/range-analysis/RangeAnalysis.expected +++ b/cpp/ql/test/library-tests/ir/range-analysis/RangeAnalysis.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/cpp/ql/test/library-tests/ir/sign-analysis/SignAnalysis.expected b/cpp/ql/test/library-tests/ir/sign-analysis/SignAnalysis.expected index 8ec8033d086..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/ir/sign-analysis/SignAnalysis.expected +++ b/cpp/ql/test/library-tests/ir/sign-analysis/SignAnalysis.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/cpp/ql/test/library-tests/ir/types/irtypes.expected b/cpp/ql/test/library-tests/ir/types/irtypes.expected index 8ec8033d086..e69de29bb2d 100644 --- a/cpp/ql/test/library-tests/ir/types/irtypes.expected +++ b/cpp/ql/test/library-tests/ir/types/irtypes.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/cpp/ql/test/query-tests/Best Practices/GuardedFree/GuardedFree.expected b/cpp/ql/test/query-tests/Best Practices/GuardedFree/GuardedFree.expected new file mode 100644 index 00000000000..a9a189218c6 --- /dev/null +++ b/cpp/ql/test/query-tests/Best Practices/GuardedFree/GuardedFree.expected @@ -0,0 +1,5 @@ +| test.cpp:5:7:5:7 | x | unnecessary NULL check before call to $@ | test.cpp:6:5:6:8 | call to free | free | +| test.cpp:10:7:10:7 | x | unnecessary NULL check before call to $@ | test.cpp:11:5:11:8 | call to free | free | +| test.cpp:42:7:42:7 | x | unnecessary NULL check before call to $@ | test.cpp:43:5:43:8 | call to free | free | +| test.cpp:49:7:49:7 | x | unnecessary NULL check before call to $@ | test.cpp:50:5:50:8 | call to free | free | +| test.cpp:106:7:106:18 | ... != ... | unnecessary NULL check before call to $@ | test.cpp:107:5:107:8 | call to free | free | diff --git a/cpp/ql/test/query-tests/Best Practices/GuardedFree/GuardedFree.qlref b/cpp/ql/test/query-tests/Best Practices/GuardedFree/GuardedFree.qlref new file mode 100644 index 00000000000..d64671f08c3 --- /dev/null +++ b/cpp/ql/test/query-tests/Best Practices/GuardedFree/GuardedFree.qlref @@ -0,0 +1 @@ +Best Practices/GuardedFree.ql diff --git a/cpp/ql/test/experimental/query-tests/Best Practices/GuardedFree/test.cpp b/cpp/ql/test/query-tests/Best Practices/GuardedFree/test.cpp similarity index 79% rename from cpp/ql/test/experimental/query-tests/Best Practices/GuardedFree/test.cpp rename to cpp/ql/test/query-tests/Best Practices/GuardedFree/test.cpp index 12b1fb2364e..d52bcef72d1 100644 --- a/cpp/ql/test/experimental/query-tests/Best Practices/GuardedFree/test.cpp +++ b/cpp/ql/test/query-tests/Best Practices/GuardedFree/test.cpp @@ -20,7 +20,7 @@ void test2(int *x) { } void test3(int *x, bool b) { - if (x) { // GOOD [FALSE POSITIVE]: x is being accessed in the body of the if + if (x) { // GOOD: x is being accessed in the body of the if if (b) *x = 42; free(x); @@ -28,7 +28,7 @@ void test3(int *x, bool b) { } bool test4(char *x, char *y) { - if (!x || strcmp(x, y)) { // GOOD [FALSE POSITIVE]: x is being accessed in the guard and return value depends on x + if (!x || strcmp(x, y)) { // GOOD: x is being accessed in the guard and return value depends on x free(x); return true; } @@ -91,11 +91,11 @@ void test10(char *x) { if (x) free(x); void test11(char *x) { - TRY_FREE(x) // BAD + TRY_FREE(x) // BAD [NOT DETECTED] } bool test12(char *x) { - if (!x) // GOOD [FALSE POSITIVE]: return value depends on x + if (!x) // GOOD: return value depends on x return false; free(x); @@ -110,6 +110,6 @@ void test13(char *x) { void inspect(char *x); void test14(char *x) { - if (x != nullptr) // GOOD [FALSE POSITIVE]: x might be accessed in the first operand of the comma operator + if (x != nullptr) // GOOD: x might be accessed in the first operand of the comma operator inspect(x), free(x); } diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.expected index 8547894e769..d3e0ecbd591 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.expected @@ -1,9 +1,9 @@ | test.c:28:3:28:12 | call to undeclared | Function call implicitly declares 'undeclared'. | | test.c:31:3:31:19 | call to not_yet_declared1 | Function call implicitly declares 'not_yet_declared1'. | | test.c:32:3:32:19 | call to not_yet_declared2 | Function call implicitly declares 'not_yet_declared2'. | -| test.c:43:3:43:27 | call to not_declared_defined_with | Function call implicitly declares 'not_declared_defined_with'. | -| test.c:54:3:54:21 | call to defined_with_double | Function call implicitly declares 'defined_with_double'. | -| test.c:66:3:66:22 | call to defined_with_ptr_ptr | Function call implicitly declares 'defined_with_ptr_ptr'. | -| test.c:68:3:68:22 | call to defined_with_ptr_arr | Function call implicitly declares 'defined_with_ptr_arr'. | -| test.c:132:3:132:22 | call to implicit_declaration | Function call implicitly declares 'implicit_declaration'. | -| test.c:133:3:133:30 | call to implicit_declaration_k_and_r | Function call implicitly declares 'implicit_declaration_k_and_r'. | +| test.c:44:3:44:27 | call to not_declared_defined_with | Function call implicitly declares 'not_declared_defined_with'. | +| test.c:55:3:55:21 | call to defined_with_double | Function call implicitly declares 'defined_with_double'. | +| test.c:67:3:67:22 | call to defined_with_ptr_ptr | Function call implicitly declares 'defined_with_ptr_ptr'. | +| test.c:69:3:69:22 | call to defined_with_ptr_arr | Function call implicitly declares 'defined_with_ptr_arr'. | +| test.c:133:3:133:22 | call to implicit_declaration | Function call implicitly declares 'implicit_declaration'. | +| test.c:134:3:134:30 | call to implicit_declaration_k_and_r | Function call implicitly declares 'implicit_declaration_k_and_r'. | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected index b6015dad456..d067430aba9 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected @@ -1,18 +1,18 @@ -| test.c:33:3:33:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:32:3:32:3 | not_yet_declared2 | not_yet_declared2 | test.c:33:21:33:22 | ca | ca | file://:0:0:0:0 | int[4] | int[4] | test.c:76:24:76:26 | (unnamed parameter 0) | int (unnamed parameter 0) | -| test.c:33:3:33:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:76:6:76:22 | not_yet_declared2 | not_yet_declared2 | test.c:33:21:33:22 | ca | ca | file://:0:0:0:0 | int[4] | int[4] | test.c:76:24:76:26 | (unnamed parameter 0) | int (unnamed parameter 0) | -| test.c:40:3:40:29 | call to declared_empty_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:77:6:77:32 | declared_empty_defined_with | declared_empty_defined_with | test.c:40:31:40:32 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:77:38:77:38 | x | int x | -| test.c:44:3:44:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:80:6:80:30 | not_declared_defined_with | not_declared_defined_with | test.c:44:29:44:31 | 4 | 4 | file://:0:0:0:0 | long long | long long | test.c:80:36:80:36 | x | int x | -| test.c:44:3:44:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:80:6:80:30 | not_declared_defined_with | not_declared_defined_with | test.c:44:37:44:42 | 2500000000.0 | 2500000000.0 | file://:0:0:0:0 | float | float | test.c:80:50:80:50 | z | int z | -| test.c:47:3:47:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:47:26:47:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:92:34:92:34 | x | int * x | -| test.c:47:3:47:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:47:34:47:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:92:43:92:43 | y | void * y | -| test.c:47:3:47:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:92:6:92:27 | declared_with_pointers | declared_with_pointers | test.c:47:26:47:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:92:34:92:34 | x | int * x | -| test.c:47:3:47:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:92:6:92:27 | declared_with_pointers | declared_with_pointers | test.c:47:34:47:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:92:43:92:43 | y | void * y | -| test.c:49:3:49:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:6:6:6:24 | declared_with_array | declared_with_array | test.c:49:23:49:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:93:31:93:31 | a | char[6] a | -| test.c:49:3:49:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:93:6:93:24 | declared_with_array | declared_with_array | test.c:49:23:49:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:93:31:93:31 | a | char[6] a | -| test.c:51:3:51:20 | call to defined_with_float | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:95:7:95:24 | defined_with_float | defined_with_float | test.c:51:22:51:24 | 2.0 | 2.0 | file://:0:0:0:0 | float | float | test.c:95:32:95:32 | f | float f | -| test.c:52:3:52:20 | call to defined_with_float | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:95:7:95:24 | defined_with_float | defined_with_float | test.c:52:22:52:24 | 2.0 | 2.0 | file://:0:0:0:0 | double | double | test.c:95:32:95:32 | f | float f | -| test.c:55:3:55:21 | call to defined_with_double | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:99:8:99:26 | defined_with_double | defined_with_double | test.c:55:23:55:25 | 99 | 99 | file://:0:0:0:0 | int | int | test.c:99:35:99:35 | d | double d | -| test.c:57:3:57:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:103:11:103:32 | defined_with_long_long | defined_with_long_long | test.c:57:26:57:28 | 99 | 99 | file://:0:0:0:0 | int | int | test.c:103:44:103:45 | ll | long long ll | -| test.c:58:3:58:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:103:11:103:32 | defined_with_long_long | defined_with_long_long | test.c:58:26:58:26 | 3 | 3 | file://:0:0:0:0 | int | int | test.c:103:44:103:45 | ll | long long ll | -| test.c:60:3:60:21 | call to defined_with_double | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:99:8:99:26 | defined_with_double | defined_with_double | test.c:60:23:60:25 | 2 | 2 | file://:0:0:0:0 | long long | long long | test.c:99:35:99:35 | d | double d | -| test.c:61:3:61:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:103:11:103:32 | defined_with_long_long | defined_with_long_long | test.c:61:26:61:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:103:44:103:45 | ll | long long ll | +| test.c:33:3:33:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:32:3:32:3 | not_yet_declared2 | not_yet_declared2 | test.c:33:21:33:22 | ca | ca | file://:0:0:0:0 | int[4] | int[4] | test.c:77:24:77:26 | (unnamed parameter 0) | int (unnamed parameter 0) | +| test.c:33:3:33:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:77:6:77:22 | not_yet_declared2 | not_yet_declared2 | test.c:33:21:33:22 | ca | ca | file://:0:0:0:0 | int[4] | int[4] | test.c:77:24:77:26 | (unnamed parameter 0) | int (unnamed parameter 0) | +| test.c:41:3:41:29 | call to declared_empty_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:78:6:78:32 | declared_empty_defined_with | declared_empty_defined_with | test.c:41:31:41:32 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:78:38:78:38 | x | int x | +| test.c:45:3:45:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:81:6:81:30 | not_declared_defined_with | not_declared_defined_with | test.c:45:29:45:31 | 4 | 4 | file://:0:0:0:0 | long long | long long | test.c:81:36:81:36 | x | int x | +| test.c:45:3:45:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:81:6:81:30 | not_declared_defined_with | not_declared_defined_with | test.c:45:37:45:42 | 2500000000.0 | 2500000000.0 | file://:0:0:0:0 | float | float | test.c:81:50:81:50 | z | int z | +| test.c:48:3:48:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:48:26:48:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:93:34:93:34 | x | int * x | +| test.c:48:3:48:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:48:34:48:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:93:43:93:43 | y | void * y | +| test.c:48:3:48:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:93:6:93:27 | declared_with_pointers | declared_with_pointers | test.c:48:26:48:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:93:34:93:34 | x | int * x | +| test.c:48:3:48:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:93:6:93:27 | declared_with_pointers | declared_with_pointers | test.c:48:34:48:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:93:43:93:43 | y | void * y | +| test.c:50:3:50:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:6:6:6:24 | declared_with_array | declared_with_array | test.c:50:23:50:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:94:31:94:31 | a | char[6] a | +| test.c:50:3:50:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:94:6:94:24 | declared_with_array | declared_with_array | test.c:50:23:50:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:94:31:94:31 | a | char[6] a | +| test.c:52:3:52:20 | call to defined_with_float | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:96:7:96:24 | defined_with_float | defined_with_float | test.c:52:22:52:24 | 2.0 | 2.0 | file://:0:0:0:0 | float | float | test.c:96:32:96:32 | f | float f | +| test.c:53:3:53:20 | call to defined_with_float | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:96:7:96:24 | defined_with_float | defined_with_float | test.c:53:22:53:24 | 2.0 | 2.0 | file://:0:0:0:0 | double | double | test.c:96:32:96:32 | f | float f | +| test.c:56:3:56:21 | call to defined_with_double | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:100:8:100:26 | defined_with_double | defined_with_double | test.c:56:23:56:25 | 99 | 99 | file://:0:0:0:0 | int | int | test.c:100:35:100:35 | d | double d | +| test.c:58:3:58:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:104:11:104:32 | defined_with_long_long | defined_with_long_long | test.c:58:26:58:28 | 99 | 99 | file://:0:0:0:0 | int | int | test.c:104:44:104:45 | ll | long long ll | +| test.c:59:3:59:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:104:11:104:32 | defined_with_long_long | defined_with_long_long | test.c:59:26:59:26 | 3 | 3 | file://:0:0:0:0 | int | int | test.c:104:44:104:45 | ll | long long ll | +| test.c:61:3:61:21 | call to defined_with_double | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:100:8:100:26 | defined_with_double | defined_with_double | test.c:61:23:61:25 | 2 | 2 | file://:0:0:0:0 | long long | long long | test.c:100:35:100:35 | d | double d | +| test.c:62:3:62:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:104:11:104:32 | defined_with_long_long | defined_with_long_long | test.c:62:26:62:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:104:44:104:45 | ll | long long ll | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected index 42c4f7f9455..90468d3a9bf 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected @@ -1,4 +1,2 @@ -| test.c:34:3:34:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:32:3:32:3 | not_yet_declared2 | not_yet_declared2 | -| test.c:34:3:34:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:76:6:76:22 | not_yet_declared2 | not_yet_declared2 | -| test.c:36:3:36:29 | call to declared_empty_defined_with | This call has fewer arguments than required by $@. | test.c:77:6:77:32 | declared_empty_defined_with | declared_empty_defined_with | -| test.c:87:10:87:20 | call to dereference | This call has fewer arguments than required by $@. | test.c:90:5:90:15 | dereference | dereference | +| test.c:37:3:37:29 | call to declared_empty_defined_with | This call has fewer arguments than required by $@. | test.c:78:6:78:32 | declared_empty_defined_with | declared_empty_defined_with | +| test.c:88:10:88:20 | call to dereference | This call has fewer arguments than required by $@. | test.c:91:5:91:15 | dereference | dereference | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected index bc64434578b..6eff27c3adb 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected @@ -1,2 +1,2 @@ -| test.c:41:3:41:29 | call to declared_empty_defined_with | This call has more arguments than required by $@. | test.c:77:6:77:32 | declared_empty_defined_with | declared_empty_defined_with | -| test.c:72:3:72:28 | call to declared_and_defined_empty | This call has more arguments than required by $@. | test.c:114:6:114:31 | declared_and_defined_empty | declared_and_defined_empty | +| test.c:42:3:42:29 | call to declared_empty_defined_with | This call has more arguments than required by $@. | test.c:78:6:78:32 | declared_empty_defined_with | declared_empty_defined_with | +| test.c:73:3:73:28 | call to declared_and_defined_empty | This call has more arguments than required by $@. | test.c:115:6:115:31 | declared_and_defined_empty | declared_and_defined_empty | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c index 86e940a8e28..d77c16683ed 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c @@ -30,8 +30,9 @@ void test(int *argv[]) { not_yet_declared1(1); // BAD (GOOD for everything except for cpp/implicit-function-declaration) not_yet_declared2(1); // BAD (GOOD for everything except for cpp/implicit-function-declaration) - not_yet_declared2(ca); // BAD - not_yet_declared2(); // BAD + not_yet_declared2(ca); // BAD (GOOD for everything except for cpp/mistyped-function-arguments + // and cpp/too-few-arguments. Not detected in the case of cpp/too-few-arguments.) + not_yet_declared2(); // BAD [NOT DETECTED] (GOOD for everything except for cpp/too-few-arguments) declared_empty_defined_with(); // BAD declared_empty_defined_with(1); // GOOD diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-193/AllocationToInvalidPointer.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-193/AllocationToInvalidPointer.expected index 8ec8033d086..e69de29bb2d 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-193/AllocationToInvalidPointer.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-193/AllocationToInvalidPointer.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-193/InvalidPointerToDereference.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-193/InvalidPointerToDereference.expected index 8ec8033d086..e69de29bb2d 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-193/InvalidPointerToDereference.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-193/InvalidPointerToDereference.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/csharp/.vscode/launch.json b/csharp/.vscode/launch.json index 46858861047..f5b4aa79cc1 100644 --- a/csharp/.vscode/launch.json +++ b/csharp/.vscode/launch.json @@ -6,7 +6,7 @@ "type": "coreclr", "request": "launch", "preLaunchTask": "dotnet: build", - "program": "${workspaceFolder}/extractor/Semmle.Extraction.CSharp.Standalone/bin/Debug/net8.0/Semmle.Extraction.CSharp.Standalone.dll", + "program": "${workspaceFolder}/extractor/Semmle.Extraction.CSharp.Standalone/bin/Debug/net9.0/Semmle.Extraction.CSharp.Standalone.dll", "args": [], // Set the path to the folder that should be extracted: "cwd": "${workspaceFolder}/ql/test/library-tests/standalone/standalonemode", @@ -35,7 +35,7 @@ "type": "coreclr", "request": "launch", "preLaunchTask": "dotnet: build", - "program": "${workspaceFolder}/autobuilder/Semmle.Autobuild.CSharp/bin/Debug/net8.0/Semmle.Autobuild.CSharp.dll", + "program": "${workspaceFolder}/autobuilder/Semmle.Autobuild.CSharp/bin/Debug/net9.0/Semmle.Autobuild.CSharp.dll", // Set the path to the folder that should be extracted: "cwd": "${workspaceFolder}/ql/integration-tests/all-platforms/autobuild", "stopAtEntry": true, @@ -53,7 +53,7 @@ "type": "coreclr", "request": "launch", "preLaunchTask": "dotnet: build", - "program": "${workspaceFolder}/extractor/Semmle.Extraction.CSharp.Driver/bin/Debug/net8.0/Semmle.Extraction.CSharp.Driver.dll", + "program": "${workspaceFolder}/extractor/Semmle.Extraction.CSharp.Driver/bin/Debug/net9.0/Semmle.Extraction.CSharp.Driver.dll", "stopAtEntry": true, "args": [ "--binlog", @@ -61,5 +61,21 @@ ], "env": {} }, + { + "name": "C#: Tracing Debug", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "dotnet: build", + "program": "${workspaceFolder}/extractor/Semmle.Extraction.CSharp.Driver/bin/Debug/net9.0/Semmle.Extraction.CSharp.Driver.dll", + // Set the path to the folder that should be extracted: + "cwd": "${workspaceFolder}/ql/test/library-tests/dataflow/local", + "args": [ + "LocalDataFlow.cs" + ], + "env": {}, + "stopAtEntry": true, + "justMyCode": false, + "suppressJITOptimizations": true + }, ] } diff --git a/csharp/autobuilder/Semmle.Autobuild.CSharp/AutoBuildRule.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp/AutoBuildRule.cs index e58c8ddccd9..b3efe64b7e9 100644 --- a/csharp/autobuilder/Semmle.Autobuild.CSharp/AutoBuildRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/AutoBuildRule.cs @@ -49,11 +49,9 @@ namespace Semmle.Autobuild.CSharp tryCleanExtractorArgsLogs & BuildScript.DeleteFile(Extractor.GetCSharpLogPath()); - /// - /// Execute script `s` and check that the C# extractor has been executed. - /// If either fails, attempt to cleanup any artifacts produced by the extractor, - /// and exit with code 1, in order to proceed to the next attempt. - /// + // Execute script `s` and check that the C# extractor has been executed. + // If either fails, attempt to cleanup any artifacts produced by the extractor, + // and exit with code 1, in order to proceed to the next attempt. BuildScript IntermediateAttempt(BuildScript s) => (s & this.autobuilder.CheckExtractorRun(false)) | (attemptExtractorCleanup & BuildScript.Failure); diff --git a/csharp/autobuilder/Semmle.Autobuild.Shared/Autobuilder.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/Autobuilder.cs index 371352cf5e2..919e3821750 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Shared/Autobuilder.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Autobuilder.cs @@ -195,7 +195,7 @@ namespace Semmle.Autobuild.Shared } /// - /// Retrieves the value of an environment variable named or throws + /// Retrieves the value of an environment variable named or throws /// an exception if no such environment variable has been set. /// /// The name of the environment variable. @@ -228,7 +228,7 @@ namespace Semmle.Autobuild.Shared private readonly IDiagnosticsWriter diagnostics; /// - /// Makes relative to the root source directory. + /// Makes relative to the root source directory. /// /// The path which to make relative. /// The relative path. diff --git a/csharp/autobuilder/Semmle.Autobuild.Shared/MarkdownUtil.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/MarkdownUtil.cs index 13a3533eb31..f5721910a96 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Shared/MarkdownUtil.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/MarkdownUtil.cs @@ -22,7 +22,7 @@ namespace Semmle.Autobuild.Shared public static string ToMarkdownLink(this string link, string title) => $"[{title}]({link})"; /// - /// Renders as a markdown list of the project paths. + /// Renders as a markdown list of the project paths. /// /// /// The list of projects whose paths should be rendered as a markdown list. @@ -35,7 +35,7 @@ namespace Semmle.Autobuild.Shared } /// - /// Renders as a markdown list. + /// Renders as a markdown list. /// /// The item type. /// The list that should be formatted as a markdown list. diff --git a/csharp/documentation/library-coverage/coverage.csv b/csharp/documentation/library-coverage/coverage.csv index 10b1c58ef31..39646702a8c 100644 --- a/csharp/documentation/library-coverage/coverage.csv +++ b/csharp/documentation/library-coverage/coverage.csv @@ -8,39 +8,43 @@ ILLink.Shared,,,31,,,,,,,,,,,,,,,,,,,11,20 ILLink.Tasks,,,5,,,,,,,,,,,,,,,,,,,4,1 Internal.IL,,,54,,,,,,,,,,,,,,,,,,,28,26 Internal.Pgo,,,9,,,,,,,,,,,,,,,,,,,2,7 -Internal.TypeSystem,,,328,,,,,,,,,,,,,,,,,,,201,127 +Internal.TypeSystem,,,329,,,,,,,,,,,,,,,,,,,201,128 JsonToItemsTaskFactory,,,11,,,,,,,,,,,,,,,,,,,1,10 Microsoft.Android.Build,,1,14,,,,,,,,,,,,,1,,,,,,12,2 Microsoft.Apple.Build,,,7,,,,,,,,,,,,,,,,,,,7, Microsoft.ApplicationBlocks.Data,28,,,,,,,,,,,,28,,,,,,,,,, +Microsoft.AspNetCore.Components,,2,1,,,,,,,,,,,,,,,,2,,,1, +Microsoft.AspNetCore.WebUtilities,,,2,,,,,,,,,,,,,,,,,,,2, Microsoft.CSharp,,,2,,,,,,,,,,,,,,,,,,,2, -Microsoft.Diagnostics.Tools.Pgo,,,23,,,,,,,,,,,,,,,,,,,2,21 +Microsoft.Diagnostics.Tools.Pgo,,,25,,,,,,,,,,,,,,,,,,,2,23 Microsoft.DotNet.Build.Tasks,,,10,,,,,,,,,,,,,,,,,,,8,2 +Microsoft.DotNet.PlatformAbstractions,,,1,,,,,,,,,,,,,,,,,,,1, Microsoft.EntityFrameworkCore,6,,12,,,,,,,,,,6,,,,,,,,,,12 Microsoft.Extensions.Caching.Distributed,,,3,,,,,,,,,,,,,,,,,,,,3 -Microsoft.Extensions.Caching.Memory,,,31,,,,,,,,,,,,,,,,,,,5,26 -Microsoft.Extensions.Configuration,,3,91,,,,,,,,,,,,,3,,,,,,25,66 -Microsoft.Extensions.DependencyInjection,,,130,,,,,,,,,,,,,,,,,,,17,113 +Microsoft.Extensions.Caching.Memory,,,37,,,,,,,,,,,,,,,,,,,5,32 +Microsoft.Extensions.Configuration,,3,101,,,,,,,,,,,,,3,,,,,,29,72 +Microsoft.Extensions.DependencyInjection,,,202,,,,,,,,,,,,,,,,,,,15,187 Microsoft.Extensions.DependencyModel,,1,16,,,,,,,,,,,,,1,,,,,,14,2 Microsoft.Extensions.Diagnostics.Metrics,,,14,,,,,,,,,,,,,,,,,,,1,13 Microsoft.Extensions.FileProviders,,,17,,,,,,,,,,,,,,,,,,,7,10 -Microsoft.Extensions.FileSystemGlobbing,,,22,,,,,,,,,,,,,,,,,,,11,11 -Microsoft.Extensions.Hosting,,,39,,,,,,,,,,,,,,,,,,,29,10 +Microsoft.Extensions.FileSystemGlobbing,,,21,,,,,,,,,,,,,,,,,,,10,11 +Microsoft.Extensions.Hosting,,,58,,,,,,,,,,,,,,,,,,,29,29 Microsoft.Extensions.Http,,,9,,,,,,,,,,,,,,,,,,,7,2 -Microsoft.Extensions.Logging,,,64,,,,,,,,,,,,,,,,,,,25,39 -Microsoft.Extensions.Options,,,14,,,,,,,,,,,,,,,,,,,14, -Microsoft.Extensions.Primitives,,,72,,,,,,,,,,,,,,,,,,,67,5 -Microsoft.Interop,,,137,,,,,,,,,,,,,,,,,,,70,67 +Microsoft.Extensions.Logging,,,91,,,,,,,,,,,,,,,,,,,25,66 +Microsoft.Extensions.Options,,,68,,,,,,,,,,,,,,,,,,,44,24 +Microsoft.Extensions.Primitives,,,73,,,,,,,,,,,,,,,,,,,67,6 +Microsoft.Interop,,,159,,,,,,,,,,,,,,,,,,,75,84 +Microsoft.JSInterop,2,,,,,,,,,,2,,,,,,,,,,,, Microsoft.NET.Build.Tasks,,,5,,,,,,,,,,,,,,,,,,,3,2 Microsoft.NET.Sdk.WebAssembly,,,2,,,,,,,,,,,,,,,,,,,1,1 Microsoft.NET.WebAssembly.Webcil,,,6,,,,,,,,,,,,,,,,,,,6, Microsoft.VisualBasic,,,13,,,,,,,,,,,,,,,,,,,1,12 Microsoft.WebAssembly.Build.Tasks,,,9,,,,,,,,,,,,,,,,,,,8,1 Microsoft.Win32,,4,2,,,,,,,,,,,,,,,,,,4,,2 -Mono.Linker,,,287,,,,,,,,,,,,,,,,,,,145,142 +Mono.Linker,,,293,,,,,,,,,,,,,,,,,,,145,148 MySql.Data.MySqlClient,48,,,,,,,,,,,,48,,,,,,,,,, Newtonsoft.Json,,,91,,,,,,,,,,,,,,,,,,,73,18 ServiceStack,194,,7,27,,,,,75,,,,92,,,,,,,,,7, SourceGenerators,,,5,,,,,,,,,,,,,,,,,,,,5 -System,54,47,10313,,6,5,5,,,4,1,,33,2,,6,15,17,4,3,,5351,4962 +System,54,47,10819,,6,5,5,,,4,1,,33,2,,6,15,17,4,3,,5512,5307 Windows.Security.Cryptography.Core,1,,,,,,,1,,,,,,,,,,,,,,, diff --git a/csharp/documentation/library-coverage/coverage.rst b/csharp/documentation/library-coverage/coverage.rst index 5eaaad17457..7023de4a356 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``",47,10313,54,5 - Others,"``Amazon.Lambda.APIGatewayEvents``, ``Amazon.Lambda.Core``, ``Dapper``, ``ILCompiler``, ``ILLink.RoslynAnalyzer``, ``ILLink.Shared``, ``ILLink.Tasks``, ``Internal.IL``, ``Internal.Pgo``, ``Internal.TypeSystem``, ``JsonToItemsTaskFactory``, ``Microsoft.Android.Build``, ``Microsoft.Apple.Build``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.CSharp``, ``Microsoft.Diagnostics.Tools.Pgo``, ``Microsoft.DotNet.Build.Tasks``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.Diagnostics.Metrics``, ``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.NET.Sdk.WebAssembly``, ``Microsoft.NET.WebAssembly.Webcil``, ``Microsoft.VisualBasic``, ``Microsoft.WebAssembly.Build.Tasks``, ``Microsoft.Win32``, ``Mono.Linker``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``, ``SourceGenerators``, ``Windows.Security.Cryptography.Core``",57,1848,148, - Totals,,104,12168,396,5 + System,"``System.*``, ``System``",47,10819,54,5 + Others,"``Amazon.Lambda.APIGatewayEvents``, ``Amazon.Lambda.Core``, ``Dapper``, ``ILCompiler``, ``ILLink.RoslynAnalyzer``, ``ILLink.Shared``, ``ILLink.Tasks``, ``Internal.IL``, ``Internal.Pgo``, ``Internal.TypeSystem``, ``JsonToItemsTaskFactory``, ``Microsoft.Android.Build``, ``Microsoft.Apple.Build``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.AspNetCore.Components``, ``Microsoft.AspNetCore.WebUtilities``, ``Microsoft.CSharp``, ``Microsoft.Diagnostics.Tools.Pgo``, ``Microsoft.DotNet.Build.Tasks``, ``Microsoft.DotNet.PlatformAbstractions``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.Diagnostics.Metrics``, ``Microsoft.Extensions.FileProviders``, ``Microsoft.Extensions.FileSystemGlobbing``, ``Microsoft.Extensions.Hosting``, ``Microsoft.Extensions.Http``, ``Microsoft.Extensions.Logging``, ``Microsoft.Extensions.Options``, ``Microsoft.Extensions.Primitives``, ``Microsoft.Interop``, ``Microsoft.JSInterop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.NET.Sdk.WebAssembly``, ``Microsoft.NET.WebAssembly.Webcil``, ``Microsoft.VisualBasic``, ``Microsoft.WebAssembly.Build.Tasks``, ``Microsoft.Win32``, ``Mono.Linker``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``, ``SourceGenerators``, ``Windows.Security.Cryptography.Core``",59,2071,150,2 + Totals,,106,12897,398,7 diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/Assets.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/Assets.cs index 4a6b401038e..13235ba1988 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/Assets.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/Assets.cs @@ -127,21 +127,21 @@ namespace Semmle.Extraction.CSharp.DependencyFetching /// /// Example: /// "project": { - // "version": "1.0.0", - // "frameworks": { - // "net7.0": { - // "frameworkReferences": { - // "Microsoft.AspNetCore.App": { - // "privateAssets": "none" - // }, - // "Microsoft.NETCore.App": { - // "privateAssets": "all" - // } - // } - // } - // } - // } - // + /// "version": "1.0.0", + /// "frameworks": { + /// "net7.0": { + /// "frameworkReferences": { + /// "Microsoft.AspNetCore.App": { + /// "privateAssets": "none" + /// }, + /// "Microsoft.NETCore.App": { + /// "privateAssets": "all" + /// } + /// } + /// } + /// } + /// } + /// /// Adds the following dependencies /// Paths: { /// "microsoft.aspnetcore.app.ref", diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DotNetVersion.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DotNetVersion.cs index f62c279d240..b4273d02b77 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DotNetVersion.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DotNetVersion.cs @@ -27,7 +27,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching * This is the same as FullPath, except that we assume that the * reference assemblies are in a directory called "packs" and * the reference assemblies themselves are in a directory called - * ".Ref/ref". + * "[Framework].Ref/ref". * Example: * FullPath: /usr/share/dotnet/shared/Microsoft.NETCore.App/7.0.2 * FullPathReferenceAssemblies: /usr/share/dotnet/packs/Microsoft.NETCore.App.Ref/7.0.2/ref diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/FileContent.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/FileContent.cs index f33329046cf..f5199de1c13 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/FileContent.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/FileContent.cs @@ -38,8 +38,8 @@ namespace Semmle.Extraction.CSharp.DependencyFetching /// True if any file in the source directory indicates that ASP.NET Core is used. /// The following heuristic is used to decide, if ASP.NET Core is used: /// If any file in the source directory contains something like (this will most like be a .csproj file) - /// - /// + /// <Project Sdk="Microsoft.NET.Sdk.Web"> + /// <FrameworkReference Include="Microsoft.AspNetCore.App"/> /// public bool UseAspNetCoreDlls { diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/IDotNetCliInvoker.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/IDotNetCliInvoker.cs index bfc8b44ee56..89631ffa861 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/IDotNetCliInvoker.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/IDotNetCliInvoker.cs @@ -10,20 +10,20 @@ namespace Semmle.Extraction.CSharp.DependencyFetching string Exec { get; } /// - /// Execute `dotnet ` and return true if the command succeeded, otherwise false. + /// Execute `dotnet ` and return true if the command succeeded, otherwise false. /// If `silent` is true the output of the command is logged as `debug` otherwise as `info`. /// bool RunCommand(string args, bool silent = true); /// - /// Execute `dotnet ` and return true if the command succeeded, otherwise false. + /// Execute `dotnet ` and return true if the command succeeded, otherwise false. /// The output of the command is returned in `output`. /// If `silent` is true the output of the command is logged as `debug` otherwise as `info`. /// bool RunCommand(string args, out IList output, bool silent = true); /// - /// Execute `dotnet ` in `` and return true if the command succeeded, otherwise false. + /// Execute `dotnet ` in `` and return true if the command succeeded, otherwise false. /// The output of the command is returned in `output`. /// If `silent` is true the output of the command is logged as `debug` otherwise as `info`. /// diff --git a/csharp/extractor/Semmle.Extraction.CSharp/CodeAnalysisExtensions/SymbolExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp/CodeAnalysisExtensions/SymbolExtensions.cs index 2ffdd9dbcd6..bb61efe332c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/CodeAnalysisExtensions/SymbolExtensions.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/CodeAnalysisExtensions/SymbolExtensions.cs @@ -133,9 +133,6 @@ namespace Semmle.Extraction.CSharp /// /// Constructs a unique string for this type symbol. - /// - /// The supplied action is applied to the - /// syntactic sub terms of this type (if any). /// /// The extraction context. /// The trap builder used to store the result. @@ -495,31 +492,31 @@ namespace Semmle.Extraction.CSharp /// /// Holds if this type is of the form int? or - /// System.Nullable. + /// System.Nullable<int>. /// public static bool IsBoundNullable(this ITypeSymbol type) => type.SpecialType == SpecialType.None && type.OriginalDefinition.IsUnboundNullable(); /// - /// Holds if this type is System.Nullable. + /// Holds if this type is System.Nullable<T>. /// public static bool IsUnboundNullable(this ITypeSymbol type) => type.SpecialType == SpecialType.System_Nullable_T; /// - /// Holds if this type is System.Span. + /// Holds if this type is System.Span<T>. /// public static bool IsUnboundSpan(this ITypeSymbol type) => type.ToString() == "System.Span"; /// - /// Holds if this type is of the form System.Span. + /// Holds if this type is of the form System.Span<byte>. /// public static bool IsBoundSpan(this ITypeSymbol type) => type.SpecialType == SpecialType.None && type.OriginalDefinition.IsUnboundSpan(); /// - /// Holds if this type is System.ReadOnlySpan. + /// Holds if this type is System.ReadOnlySpan<T>. /// public static bool IsUnboundReadOnlySpan(this ITypeSymbol type) => type.ToString() == "System.ReadOnlySpan"; @@ -536,7 +533,7 @@ namespace Semmle.Extraction.CSharp } /// - /// Holds if this type is of the form System.ReadOnlySpan. + /// Holds if this type is of the form System.ReadOnlySpan<byte>. /// public static bool IsBoundReadOnlySpan(this ITypeSymbol type) => type.SpecialType == SpecialType.None && type.OriginalDefinition.IsUnboundReadOnlySpan(); @@ -645,5 +642,40 @@ namespace Semmle.Extraction.CSharp /// public static IEnumerable GetAnnotatedTypeArguments(this INamedTypeSymbol symbol) => symbol.TypeArguments.Zip(symbol.TypeArgumentNullableAnnotations, (t, a) => new AnnotatedTypeSymbol(t, a)); + + /// + /// Returns true if the symbol is public, protected or protected internal. + /// + public static bool IsPublicOrProtected(this ISymbol symbol) => + symbol.DeclaredAccessibility == Accessibility.Public + || symbol.DeclaredAccessibility == Accessibility.Protected + || symbol.DeclaredAccessibility == Accessibility.ProtectedOrInternal; + + /// + /// Returns true if the given symbol should be extracted. + /// + public static bool ShouldExtractSymbol(this ISymbol symbol) + { + // Extract all source symbols and public/protected metadata symbols. + if (symbol.Locations.Any(x => !x.IsInMetadata) || symbol.IsPublicOrProtected()) + { + return true; + } + if (symbol is IMethodSymbol method) + { + return method.ExplicitInterfaceImplementations.Any(m => m.ContainingType.ShouldExtractSymbol()); + } + if (symbol is IPropertySymbol property) + { + return property.ExplicitInterfaceImplementations.Any(m => m.ContainingType.ShouldExtractSymbol()); + } + return false; + } + + /// + /// Returns the symbols that should be extracted. + /// + public static IEnumerable ExtractionCandidates(this IEnumerable symbols) where T : ISymbol => + symbols.Where(symbol => symbol.ShouldExtractSymbol()); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/CachedEntity.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/CachedEntity.cs index ed0a21bc083..96bef973211 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/CachedEntity.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/CachedEntity.cs @@ -7,7 +7,7 @@ namespace Semmle.Extraction.CSharp.Entities /// /// A cached entity. /// - /// The property is used as label in caching. + /// The property is used as label in caching. /// public abstract class CachedEntity : LabelledEntity { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/IEntity.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/IEntity.cs index d8d3c538e42..f6f60ff9146 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/IEntity.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/IEntity.cs @@ -9,12 +9,12 @@ namespace Semmle.Extraction.CSharp /// Entities are divided into two types: normal entities and cached /// entities. /// - /// Normal entities implement directly, and they + /// Normal entities implement directly, and they /// (may) emit contents to the trap file during object construction. /// - /// Cached entities implement , and they - /// emit contents to the trap file when - /// is called. Caching prevents + /// Cached entities implement , and they + /// emit contents to the trap file when + /// is called. Caching prevents /// from being called on entities that have already been emitted. /// public interface IEntity diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs index f5021d38eeb..9241528eb75 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs @@ -77,7 +77,7 @@ namespace Semmle.Extraction.CSharp.Entities /// /// Gets a string representation of a constant value. /// - /// The value. + /// The value. /// The string representation. public static string ValueAsString(object? value) { @@ -98,7 +98,6 @@ namespace Semmle.Extraction.CSharp.Entities /// The node to extract. /// The parent entity. /// The child index. - /// A type hint. /// The new expression. public static Expression Create(Context cx, ExpressionSyntax node, IExpressionParentEntity parent, int child, Boolean isCompilerGenerated = false) { @@ -120,7 +119,6 @@ namespace Semmle.Extraction.CSharp.Entities /// The node to extract. /// The parent entity. /// The child index. - /// A type hint. public static void CreateDeferred(Context cx, ExpressionSyntax node, IExpressionParentEntity parent, int child) { if (ContainsPattern(node)) @@ -244,7 +242,6 @@ namespace Semmle.Extraction.CSharp.Entities /// to show the target of the call. Also note the dynamic method /// name if available. /// - /// Context /// The expression. public void OperatorCall(TextWriter trapFile, ExpressionSyntax node) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression`1.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression`1.cs index 6386e43a9b4..4c2670369e0 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression`1.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression`1.cs @@ -20,7 +20,7 @@ namespace Semmle.Extraction.CSharp.Entities /// expressions and expr_location are populated by the constructor /// (should not fail), so even if expression-type specific population fails (e.g., in /// standalone extraction), the expression created via - /// will + /// will /// still be valid. /// protected abstract void PopulateExpression(TextWriter trapFile); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs index 6890ca49084..6ba5cca01cf 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs @@ -101,7 +101,7 @@ namespace Semmle.Extraction.CSharp.Entities } } - if (Symbol.OverriddenMethod is not null) + if (Symbol.OverriddenMethod is not null && Symbol.OverriddenMethod.ShouldExtractSymbol()) { trapFile.overrides(this, Method.Create(Context, Symbol.OverriddenMethod)); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs index 189a07f6f47..b2106febaff 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs @@ -21,10 +21,9 @@ namespace Semmle.Extraction.CSharp.Entities NamedTypeFactory.Instance.CreateEntityFromSymbol(cx, type); /// - /// Creates a named type entity from a tuple type. Unlike `Create`, this + /// Creates a named type entity from a tuple type. Unlike , this /// will create an entity for the underlying `System.ValueTuple` struct. - /// For example, `(int, string)` will result in an entity for - /// `System.ValueTuple`. + /// For example, `(int, string)` will result in an entity for `System.ValueTuple<int, string>`. /// public static NamedType CreateNamedTypeFromTupleType(Context cx, INamedTypeSymbol type) => UnderlyingTupleTypeFactory.Instance.CreateEntity(cx, (new SymbolEqualityWrapper(type), typeof(TupleType)), type); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs index 9791f386a19..add36226f16 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Nullability.cs @@ -209,8 +209,8 @@ namespace Semmle.Extraction.CSharp.Entities /// This is so that we can avoid populating nullability in most cases. /// For example, /// - /// IEnumerable<string?> // false - /// IEnumerable<string?>? // true + /// IEnumerable<string?> // false + /// IEnumerable<string?>? // true /// string? // true /// string[] // true /// string?[] // false diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs index 56382923a48..efd09409afd 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs @@ -225,7 +225,7 @@ namespace Semmle.Extraction.CSharp.Entities } /// - /// Called to extract all members and nested types. + /// Called to extract members and nested types. /// This is called on each member of a namespace, /// in either source code or an assembly. /// @@ -236,7 +236,7 @@ namespace Semmle.Extraction.CSharp.Entities Context.BindComments(this, l); } - foreach (var member in Symbol.GetMembers()) + foreach (var member in Symbol.GetMembers().ExtractionCandidates()) { switch (member.Kind) { @@ -262,16 +262,16 @@ namespace Semmle.Extraction.CSharp.Entities var members = new List(); - foreach (var member in Symbol.GetMembers()) + foreach (var member in Symbol.GetMembers().ExtractionCandidates()) members.Add(member); - foreach (var member in Symbol.GetTypeMembers()) + foreach (var member in Symbol.GetTypeMembers().ExtractionCandidates()) members.Add(member); // Mono extractor puts all BASE interface members as members of the current interface. if (Symbol.TypeKind == TypeKind.Interface) { - foreach (var baseInterface in Symbol.Interfaces) + foreach (var baseInterface in Symbol.Interfaces.ExtractionCandidates()) { foreach (var member in baseInterface.GetMembers()) members.Add(member); @@ -288,7 +288,7 @@ namespace Semmle.Extraction.CSharp.Entities if (Symbol.BaseType is not null) Create(Context, Symbol.BaseType).PopulateGenerics(); - foreach (var i in Symbol.Interfaces) + foreach (var i in Symbol.Interfaces.ExtractionCandidates()) { Create(Context, i).PopulateGenerics(); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs index f2fc4b85d7f..141bded87ac 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs @@ -86,7 +86,7 @@ namespace Semmle.Extraction.CSharp.Entities /// Logs an error if the name is not found. /// /// Extractor context. - /// The method name. + /// The method symbol. /// The converted name. private static string OperatorSymbol(Context cx, IMethodSymbol method) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Analyser.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Analyser.cs index b839d2c976a..3ea99a0d772 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Analyser.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Analyser.cs @@ -269,7 +269,7 @@ namespace Semmle.Extraction.CSharp AnalyseNamespace(cx, memberNamespace); } - foreach (var memberType in ns.GetTypeMembers()) + foreach (var memberType in ns.GetTypeMembers().ExtractionCandidates()) { Entities.Type.Create(cx, memberType).ExtractRecursive(); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Context.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Context.cs index 8d819d715f9..67bb2808ae6 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Context.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Context.cs @@ -152,7 +152,7 @@ namespace Semmle.Extraction.CSharp /// /// Enqueue the given action to be performed later. /// - /// The action to run. + /// The action to run. public void PopulateLater(Action a, bool preserveDuplicationKey = true) { var key = preserveDuplicationKey ? GetCurrentTagStackKey() : null; @@ -598,7 +598,6 @@ namespace Semmle.Extraction.CSharp /// /// Register a program entity which can be bound to comments. /// - /// Extractor context. /// Program entity. /// Location of the entity. public void BindComments(Entity entity, Microsoft.CodeAnalysis.Location? l) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Extractor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Extractor.cs index 50f673a7158..3c01893dd89 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Extractor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/Extractor.cs @@ -549,7 +549,6 @@ namespace Semmle.Extraction.CSharp compilerArguments.CompilationOptions .WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default) .WithStrongNameProvider(new DesktopStrongNameProvider(compilerArguments.KeyFileSearchPaths)) - .WithMetadataImportOptions(MetadataImportOptions.All) ); }, (compilation, options) => analyser.EndInitialize(compilerArguments, options, compilation, cwd, args), diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/TrapWriter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/TrapWriter.cs index 4830c3209c2..42e933c8eaf 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Extractor/TrapWriter.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor/TrapWriter.cs @@ -171,7 +171,7 @@ namespace Semmle.Extraction.CSharp /// /// Close the trap file, and move it to the right place in the trap directory. /// If the file exists already, rename it to allow the new file (ending .trap.gz) - /// to sit alongside the old file (except if is true, + /// to sit alongside the old file (except if is true, /// in which case only the existing file is kept). /// public void Dispose() diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Trap/EscapingTextWriter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Trap/EscapingTextWriter.cs index 63f5e81c358..28e1d0bf146 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Trap/EscapingTextWriter.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Trap/EscapingTextWriter.cs @@ -8,7 +8,7 @@ namespace Semmle.Extraction.CSharp { /// /// A `TextWriter` object that wraps another `TextWriter` object, and which - /// HTML escapes the characters `&`, `{`, `}`, `"`, `@`, and `#`, before + /// HTML escapes the characters &, {, }, ", @, and #, before /// writing to the underlying object. /// public sealed class EscapingTextWriter : TextWriter diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Trap/TrapExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp/Trap/TrapExtensions.cs index 787ba62e3e8..22e38bac51c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Trap/TrapExtensions.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Trap/TrapExtensions.cs @@ -226,7 +226,7 @@ namespace Semmle.Extraction.CSharp /// /// Builds a trap builder using a separator and an action for each item in the list. /// - /// The type of the items. + /// The type of the items. /// The trap builder to append to. /// The separator string (e.g. ",") /// The list of items. @@ -251,7 +251,7 @@ namespace Semmle.Extraction.CSharp /// /// Builds a trap builder using a separator and an action for each item in the list. /// - /// The type of the items. + /// The type of the items. /// The trap builder to append to. /// The separator string (e.g. ",") /// The list of items. diff --git a/csharp/extractor/Semmle.Util/CanonicalPathCache.cs b/csharp/extractor/Semmle.Util/CanonicalPathCache.cs index a79854333ac..d3cbf41fa10 100644 --- a/csharp/extractor/Semmle.Util/CanonicalPathCache.cs +++ b/csharp/extractor/Semmle.Util/CanonicalPathCache.cs @@ -208,7 +208,7 @@ namespace Semmle.Util /// Create cache with a given capacity. /// /// The algorithm for determining the canonical path. - /// The size of the cache. + /// The size of the cache. public CanonicalPathCache(int maxCapacity, PathStrategy pathStrategy) { if (maxCapacity <= 0) @@ -230,7 +230,6 @@ namespace Semmle.Util /// /// /// Size of the cache. - /// Policy for following symlinks. /// A new CanonicalPathCache. public static CanonicalPathCache Create(ILogger logger, int maxCapacity) { diff --git a/csharp/extractor/Semmle.Util/CommandBuilder.cs b/csharp/extractor/Semmle.Util/CommandBuilder.cs index 3d8f907f866..1b6cd3176c4 100644 --- a/csharp/extractor/Semmle.Util/CommandBuilder.cs +++ b/csharp/extractor/Semmle.Util/CommandBuilder.cs @@ -62,7 +62,6 @@ namespace Semmle.Util /// /// The argument to append. /// Whether to always quote the argument. - /// Whether to escape for cmd.exe /// /// /// This implementation is copied from diff --git a/csharp/paket.dependencies b/csharp/paket.dependencies index f07d495f7db..d3e2988bba6 100644 --- a/csharp/paket.dependencies +++ b/csharp/paket.dependencies @@ -4,6 +4,7 @@ source https://api.nuget.org/v3/index.json # behave like nuget in choosing transitive dependency versions strategy: min +nuget MessagePack >= 2.5.187 nuget Basic.CompilerLog.Util nuget Mono.Posix.NETStandard nuget Newtonsoft.Json diff --git a/csharp/paket.lock b/csharp/paket.lock index d0cd1517b41..1bfc7465d12 100644 --- a/csharp/paket.lock +++ b/csharp/paket.lock @@ -11,11 +11,10 @@ NUGET Microsoft.Extensions.ObjectPool (>= 7.0.13) MSBuild.StructuredLogger (>= 2.2.235) Humanizer.Core (2.14.1) - MessagePack (2.5.129) - MessagePack.Annotations (>= 2.5.129) + MessagePack (2.5.192) + MessagePack.Annotations (>= 2.5.192) Microsoft.NET.StringTools (>= 17.6.3) - System.Runtime.CompilerServices.Unsafe (>= 6.0) - MessagePack.Annotations (2.5.129) + MessagePack.Annotations (2.5.192) Microsoft.Build (17.8.3) Microsoft.Build.Framework (>= 17.8.3) Microsoft.NET.StringTools (>= 17.8.3) @@ -59,18 +58,18 @@ NUGET System.Composition (>= 8.0) System.IO.Pipelines (>= 8.0) System.Threading.Channels (>= 8.0) - Microsoft.CodeCoverage (17.11.1) + Microsoft.CodeCoverage (17.12) Microsoft.Extensions.ObjectPool (7.0.13) Microsoft.NET.StringTools (17.8.3) - Microsoft.NET.Test.Sdk (17.11.1) - Microsoft.CodeCoverage (>= 17.11.1) - Microsoft.TestPlatform.TestHost (>= 17.11.1) + Microsoft.NET.Test.Sdk (17.12) + Microsoft.CodeCoverage (>= 17.12) + Microsoft.TestPlatform.TestHost (>= 17.12) Microsoft.NETCore.Platforms (1.1.1) Microsoft.NETCore.Targets (1.1.3) - Microsoft.TestPlatform.ObjectModel (17.11.1) + Microsoft.TestPlatform.ObjectModel (17.12) System.Reflection.Metadata (>= 1.6) - Microsoft.TestPlatform.TestHost (17.11.1) - Microsoft.TestPlatform.ObjectModel (>= 17.11.1) + Microsoft.TestPlatform.TestHost (17.12) + Microsoft.TestPlatform.ObjectModel (>= 17.12) Newtonsoft.Json (>= 13.0.1) Microsoft.Win32.Primitives (4.3) Microsoft.NETCore.Platforms (>= 1.1) diff --git a/csharp/paket.main.bzl b/csharp/paket.main.bzl index c8e6dbf2c8d..2ec4e25c5f9 100644 --- a/csharp/paket.main.bzl +++ b/csharp/paket.main.bzl @@ -9,8 +9,8 @@ def main(): packages = [ {"name": "Basic.CompilerLog.Util", "id": "Basic.CompilerLog.Util", "version": "0.7.9", "sha512": "sha512-Z50VRWQIXO0E8GM3ZFdL+Mq+YdmPh+OEJ7bDXPIsp1TQJB07i09WdlEb4MucSz9wG4exeLC3HGt23O3NOFL30g==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool"], "net462": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool"], "net47": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool"], "net471": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool"], "net472": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool"], "net48": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool"], "net5.0": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool"], "net6.0": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool"], "net7.0": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool"], "net8.0": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool"], "net9.0": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool"], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool"], "netcoreapp2.1": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool"], "netcoreapp2.2": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool"], "netcoreapp3.0": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool"], "netcoreapp3.1": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool"], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool"], "netstandard2.1": ["MSBuild.StructuredLogger", "MessagePack", "Microsoft.CodeAnalysis", "Microsoft.CodeAnalysis.CSharp", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.Extensions.ObjectPool"]}, "targeting_pack_overrides": [], "framework_list": []}, {"name": "Humanizer.Core", "id": "Humanizer.Core", "version": "2.14.1", "sha512": "sha512-yzqGU/HKNLZ9Uvr6kvSc3wYV/S5O/IvklIUW5WF7MuivGLY8wS5IZnLPkt7D1KW8Et2Enl0I3Lzg2vGWM24Xsw==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": [], "net462": [], "net47": [], "net471": [], "net472": [], "net48": [], "net5.0": [], "net6.0": [], "net7.0": [], "net8.0": [], "net9.0": [], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": [], "netcoreapp2.1": [], "netcoreapp2.2": [], "netcoreapp3.0": [], "netcoreapp3.1": [], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": [], "netstandard2.1": []}, "targeting_pack_overrides": [], "framework_list": []}, - {"name": "MessagePack", "id": "MessagePack", "version": "2.5.129", "sha512": "sha512-wpw2dHkE5AcvMYKE4MrWuoeZ2jeaneDlqAgplxm6yKqPXeUVI2h5DPrKjsljnJSNRZOm3tunasw18Q9xj/3UoA==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Runtime.CompilerServices.Unsafe"], "net462": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Runtime.CompilerServices.Unsafe"], "net47": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Runtime.CompilerServices.Unsafe"], "net471": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Runtime.CompilerServices.Unsafe"], "net472": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Runtime.CompilerServices.Unsafe"], "net48": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Runtime.CompilerServices.Unsafe"], "net5.0": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Runtime.CompilerServices.Unsafe"], "net6.0": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Runtime.CompilerServices.Unsafe"], "net7.0": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Runtime.CompilerServices.Unsafe"], "net8.0": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Runtime.CompilerServices.Unsafe"], "net9.0": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Runtime.CompilerServices.Unsafe"], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Runtime.CompilerServices.Unsafe"], "netcoreapp2.1": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Runtime.CompilerServices.Unsafe"], "netcoreapp2.2": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Runtime.CompilerServices.Unsafe"], "netcoreapp3.0": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Runtime.CompilerServices.Unsafe"], "netcoreapp3.1": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Runtime.CompilerServices.Unsafe"], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Runtime.CompilerServices.Unsafe"], "netstandard2.1": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Runtime.CompilerServices.Unsafe"]}, "targeting_pack_overrides": [], "framework_list": []}, - {"name": "MessagePack.Annotations", "id": "MessagePack.Annotations", "version": "2.5.129", "sha512": "sha512-mr12dLr06Kp7Ra7+GUXHbuxt/gbi6RPGPw1mpSvZsubs7hJxzHDtYTb5KKuseu5cpzOUDfsGcaW+Bo0+lqCFAA==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": [], "net462": [], "net47": [], "net471": [], "net472": [], "net48": [], "net5.0": [], "net6.0": [], "net7.0": [], "net8.0": [], "net9.0": [], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": [], "netcoreapp2.1": [], "netcoreapp2.2": [], "netcoreapp3.0": [], "netcoreapp3.1": [], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": [], "netstandard2.1": []}, "targeting_pack_overrides": [], "framework_list": []}, + {"name": "MessagePack", "id": "MessagePack", "version": "2.5.192", "sha512": "sha512-SnrwSQIKWfxcQvzE1TCUPvJ7A/44KFBDcmCc+YUDIq8QalCf0bGAjiBoAFewhJ81QuS5FsCNCOcKn+IURYlbAQ==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Runtime.CompilerServices.Unsafe"], "net462": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Runtime.CompilerServices.Unsafe"], "net47": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Runtime.CompilerServices.Unsafe"], "net471": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Runtime.CompilerServices.Unsafe"], "net472": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Runtime.CompilerServices.Unsafe"], "net48": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Runtime.CompilerServices.Unsafe"], "net5.0": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Runtime.CompilerServices.Unsafe"], "net6.0": ["MessagePack.Annotations", "Microsoft.NET.StringTools"], "net7.0": ["MessagePack.Annotations", "Microsoft.NET.StringTools"], "net8.0": ["MessagePack.Annotations", "Microsoft.NET.StringTools"], "net9.0": ["MessagePack.Annotations", "Microsoft.NET.StringTools"], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Runtime.CompilerServices.Unsafe"], "netcoreapp2.1": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Runtime.CompilerServices.Unsafe"], "netcoreapp2.2": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Runtime.CompilerServices.Unsafe"], "netcoreapp3.0": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Runtime.CompilerServices.Unsafe"], "netcoreapp3.1": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Runtime.CompilerServices.Unsafe"], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Runtime.CompilerServices.Unsafe"], "netstandard2.1": ["MessagePack.Annotations", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Runtime.CompilerServices.Unsafe"]}, "targeting_pack_overrides": [], "framework_list": []}, + {"name": "MessagePack.Annotations", "id": "MessagePack.Annotations", "version": "2.5.192", "sha512": "sha512-pE/SD2N0+nDAU8BtTHqjyIhLM2L5Mb0NiO4hW0ybiv2I+BbK0JEaGtbKpeEmOvKT+5s2hds0gvk/GrAHhgcpdw==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": [], "net462": [], "net47": [], "net471": [], "net472": [], "net48": [], "net5.0": [], "net6.0": [], "net7.0": [], "net8.0": [], "net9.0": [], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": [], "netcoreapp2.1": [], "netcoreapp2.2": [], "netcoreapp3.0": [], "netcoreapp3.1": [], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": [], "netstandard2.1": []}, "targeting_pack_overrides": [], "framework_list": []}, {"name": "Microsoft.Build", "id": "Microsoft.Build", "version": "17.8.3", "sha512": "sha512-jRz++ltVTU9xGAYSnI7fGwLIsg/AwINaxlXaJrcMszO+fyh1xJ8gKZkDz10foT/5y26jZC6G93wyp85NVHc+lA==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": [], "net462": [], "net47": [], "net471": [], "net472": ["Microsoft.Build.Framework", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Configuration.ConfigurationManager", "System.Reflection.MetadataLoadContext", "System.Security.Principal.Windows", "System.Threading.Tasks.Dataflow", "System.Reflection.Metadata", "System.Runtime.CompilerServices.Unsafe"], "net48": ["Microsoft.Build.Framework", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Configuration.ConfigurationManager", "System.Reflection.MetadataLoadContext", "System.Security.Principal.Windows", "System.Threading.Tasks.Dataflow", "System.Reflection.Metadata", "System.Runtime.CompilerServices.Unsafe"], "net5.0": [], "net6.0": [], "net7.0": [], "net8.0": ["Microsoft.Build.Framework", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Configuration.ConfigurationManager", "System.Reflection.MetadataLoadContext", "System.Security.Principal.Windows", "System.Threading.Tasks.Dataflow", "System.Reflection.Metadata"], "net9.0": ["Microsoft.Build.Framework", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Configuration.ConfigurationManager", "System.Reflection.MetadataLoadContext", "System.Security.Principal.Windows", "System.Threading.Tasks.Dataflow", "System.Reflection.Metadata"], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": [], "netcoreapp2.1": [], "netcoreapp2.2": [], "netcoreapp3.0": [], "netcoreapp3.1": [], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": [], "netstandard2.1": []}, "targeting_pack_overrides": [], "framework_list": []}, {"name": "Microsoft.Build.Framework", "id": "Microsoft.Build.Framework", "version": "17.8.3", "sha512": "sha512-xDOoj8lpNohM0Sieo4sJ47m/3SAquclF8wFZeAYYuDRHc8hII4XWPhSafFmw5A4TMGOyV08Z1TrrqES9HxMB3Q==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": ["System.Runtime.CompilerServices.Unsafe", "System.Security.Principal.Windows"], "net462": ["System.Runtime.CompilerServices.Unsafe", "System.Security.Principal.Windows"], "net47": ["System.Runtime.CompilerServices.Unsafe", "System.Security.Principal.Windows"], "net471": ["System.Runtime.CompilerServices.Unsafe", "System.Security.Principal.Windows"], "net472": ["System.Runtime.CompilerServices.Unsafe"], "net48": ["System.Runtime.CompilerServices.Unsafe"], "net5.0": ["System.Runtime.CompilerServices.Unsafe", "System.Security.Principal.Windows"], "net6.0": ["System.Runtime.CompilerServices.Unsafe", "System.Security.Principal.Windows"], "net7.0": ["System.Runtime.CompilerServices.Unsafe", "System.Security.Principal.Windows"], "net8.0": [], "net9.0": [], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": ["System.Runtime.CompilerServices.Unsafe", "System.Security.Principal.Windows"], "netcoreapp2.1": ["System.Runtime.CompilerServices.Unsafe", "System.Security.Principal.Windows"], "netcoreapp2.2": ["System.Runtime.CompilerServices.Unsafe", "System.Security.Principal.Windows"], "netcoreapp3.0": ["System.Runtime.CompilerServices.Unsafe", "System.Security.Principal.Windows"], "netcoreapp3.1": ["System.Runtime.CompilerServices.Unsafe", "System.Security.Principal.Windows"], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": ["System.Runtime.CompilerServices.Unsafe", "System.Security.Principal.Windows"], "netstandard2.1": ["System.Runtime.CompilerServices.Unsafe", "System.Security.Principal.Windows"]}, "targeting_pack_overrides": [], "framework_list": []}, {"name": "Microsoft.Build.Utilities.Core", "id": "Microsoft.Build.Utilities.Core", "version": "17.5.0", "sha512": "sha512-La1NFQ7SVz1pVGEUnG15BQG26jJkRMCiitySBXLhuTYf9IG6eZ5j5UFjnM4EFKSVKbictRv+D/F0dQtsCiK9ag==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": ["Microsoft.Build.Framework", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Configuration.ConfigurationManager", "System.Security.Permissions"], "net462": ["Microsoft.Build.Framework", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Configuration.ConfigurationManager", "System.Security.Permissions"], "net47": ["Microsoft.Build.Framework", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Configuration.ConfigurationManager", "System.Security.Permissions"], "net471": ["Microsoft.Build.Framework", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Configuration.ConfigurationManager", "System.Security.Permissions"], "net472": ["Microsoft.Build.Framework", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Configuration.ConfigurationManager"], "net48": ["Microsoft.Build.Framework", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Configuration.ConfigurationManager"], "net5.0": ["Microsoft.Build.Framework", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Configuration.ConfigurationManager", "System.Security.Permissions"], "net6.0": ["Microsoft.Build.Framework", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Configuration.ConfigurationManager", "System.Security.Permissions"], "net7.0": ["Microsoft.Build.Framework", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Configuration.ConfigurationManager"], "net8.0": ["Microsoft.Build.Framework", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Configuration.ConfigurationManager"], "net9.0": ["Microsoft.Build.Framework", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Configuration.ConfigurationManager"], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": ["Microsoft.Build.Framework", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Configuration.ConfigurationManager", "System.Security.Permissions"], "netcoreapp2.1": ["Microsoft.Build.Framework", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Configuration.ConfigurationManager", "System.Security.Permissions"], "netcoreapp2.2": ["Microsoft.Build.Framework", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Configuration.ConfigurationManager", "System.Security.Permissions"], "netcoreapp3.0": ["Microsoft.Build.Framework", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Configuration.ConfigurationManager", "System.Security.Permissions"], "netcoreapp3.1": ["Microsoft.Build.Framework", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Configuration.ConfigurationManager", "System.Security.Permissions"], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": ["Microsoft.Build.Framework", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Configuration.ConfigurationManager", "System.Security.Permissions"], "netstandard2.1": ["Microsoft.Build.Framework", "Microsoft.NET.StringTools", "System.Collections.Immutable", "System.Configuration.ConfigurationManager", "System.Security.Permissions"]}, "targeting_pack_overrides": [], "framework_list": []}, @@ -22,14 +22,14 @@ def main(): {"name": "Microsoft.CodeAnalysis.VisualBasic", "id": "Microsoft.CodeAnalysis.VisualBasic", "version": "4.9.2", "sha512": "sha512-Jx3d7jpZ2bdCb/FzVBPD2a4P8jFDhdoEugGoxLxVKtBDzHA5+RdQL0BWvzwrP1Tdw3YPshrUelNlZXmcNXqZyA==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": ["Microsoft.CodeAnalysis.Common"], "net462": ["Microsoft.CodeAnalysis.Common"], "net47": ["Microsoft.CodeAnalysis.Common"], "net471": ["Microsoft.CodeAnalysis.Common"], "net472": ["Microsoft.CodeAnalysis.Common"], "net48": ["Microsoft.CodeAnalysis.Common"], "net5.0": ["Microsoft.CodeAnalysis.Common"], "net6.0": ["Microsoft.CodeAnalysis.Common"], "net7.0": ["Microsoft.CodeAnalysis.Common"], "net8.0": ["Microsoft.CodeAnalysis.Common"], "net9.0": ["Microsoft.CodeAnalysis.Common"], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": ["Microsoft.CodeAnalysis.Common"], "netcoreapp2.1": ["Microsoft.CodeAnalysis.Common"], "netcoreapp2.2": ["Microsoft.CodeAnalysis.Common"], "netcoreapp3.0": ["Microsoft.CodeAnalysis.Common"], "netcoreapp3.1": ["Microsoft.CodeAnalysis.Common"], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": ["Microsoft.CodeAnalysis.Common"], "netstandard2.1": ["Microsoft.CodeAnalysis.Common"]}, "targeting_pack_overrides": [], "framework_list": []}, {"name": "Microsoft.CodeAnalysis.VisualBasic.Workspaces", "id": "Microsoft.CodeAnalysis.VisualBasic.Workspaces", "version": "4.9.2", "sha512": "sha512-v07rvZvckHiPLDzKXFs9AXfEGsDeTvR+N9YHO9wQqboXgms4HCv0fTrZOOgqM/aVS7racJKRo1tf62UfjqMeEw==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": ["Microsoft.CodeAnalysis.Common", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.CodeAnalysis.Workspaces.Common"], "net462": ["Microsoft.CodeAnalysis.Common", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.CodeAnalysis.Workspaces.Common"], "net47": ["Microsoft.CodeAnalysis.Common", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.CodeAnalysis.Workspaces.Common"], "net471": ["Microsoft.CodeAnalysis.Common", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.CodeAnalysis.Workspaces.Common"], "net472": ["Microsoft.CodeAnalysis.Common", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.CodeAnalysis.Workspaces.Common"], "net48": ["Microsoft.CodeAnalysis.Common", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.CodeAnalysis.Workspaces.Common"], "net5.0": ["Microsoft.CodeAnalysis.Common", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.CodeAnalysis.Workspaces.Common"], "net6.0": ["Microsoft.CodeAnalysis.Common", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.CodeAnalysis.Workspaces.Common"], "net7.0": ["Microsoft.CodeAnalysis.Common", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.CodeAnalysis.Workspaces.Common"], "net8.0": ["Microsoft.CodeAnalysis.Common", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.CodeAnalysis.Workspaces.Common"], "net9.0": ["Microsoft.CodeAnalysis.Common", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.CodeAnalysis.Workspaces.Common"], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": ["Microsoft.CodeAnalysis.Common", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.CodeAnalysis.Workspaces.Common"], "netcoreapp2.1": ["Microsoft.CodeAnalysis.Common", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.CodeAnalysis.Workspaces.Common"], "netcoreapp2.2": ["Microsoft.CodeAnalysis.Common", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.CodeAnalysis.Workspaces.Common"], "netcoreapp3.0": ["Microsoft.CodeAnalysis.Common", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.CodeAnalysis.Workspaces.Common"], "netcoreapp3.1": ["Microsoft.CodeAnalysis.Common", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.CodeAnalysis.Workspaces.Common"], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": ["Microsoft.CodeAnalysis.Common", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.CodeAnalysis.Workspaces.Common"], "netstandard2.1": ["Microsoft.CodeAnalysis.Common", "Microsoft.CodeAnalysis.VisualBasic", "Microsoft.CodeAnalysis.Workspaces.Common"]}, "targeting_pack_overrides": [], "framework_list": []}, {"name": "Microsoft.CodeAnalysis.Workspaces.Common", "id": "Microsoft.CodeAnalysis.Workspaces.Common", "version": "4.9.2", "sha512": "sha512-DieswZYcYVGDPeT6m7M4i+0aKkjSgyjmI9z9HJEDSRZdvXfKYLEKwmlFGUTyzFS4brnyMCwLSiw2KWVAydpzVA==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": ["Microsoft.CodeAnalysis.Common", "Humanizer.Core", "System.Composition", "System.IO.Pipelines", "System.Threading.Channels"], "net462": ["Microsoft.CodeAnalysis.Common", "Humanizer.Core", "System.Composition", "System.IO.Pipelines", "System.Threading.Channels"], "net47": ["Microsoft.CodeAnalysis.Common", "Humanizer.Core", "System.Composition", "System.IO.Pipelines", "System.Threading.Channels"], "net471": ["Microsoft.CodeAnalysis.Common", "Humanizer.Core", "System.Composition", "System.IO.Pipelines", "System.Threading.Channels"], "net472": ["Microsoft.CodeAnalysis.Common", "Humanizer.Core", "System.Composition", "System.IO.Pipelines", "System.Threading.Channels"], "net48": ["Microsoft.CodeAnalysis.Common", "Humanizer.Core", "System.Composition", "System.IO.Pipelines", "System.Threading.Channels"], "net5.0": ["Microsoft.CodeAnalysis.Common", "Humanizer.Core", "System.Composition", "System.IO.Pipelines", "System.Threading.Channels"], "net6.0": ["Microsoft.CodeAnalysis.Common", "Humanizer.Core", "System.Composition", "System.IO.Pipelines", "System.Threading.Channels"], "net7.0": ["Microsoft.CodeAnalysis.Common", "Humanizer.Core", "System.Composition", "System.IO.Pipelines", "System.Threading.Channels"], "net8.0": ["Microsoft.CodeAnalysis.Common", "Humanizer.Core", "System.Composition", "System.IO.Pipelines", "System.Threading.Channels"], "net9.0": ["Microsoft.CodeAnalysis.Common", "Humanizer.Core", "System.Composition", "System.IO.Pipelines", "System.Threading.Channels"], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": ["Microsoft.CodeAnalysis.Common", "Humanizer.Core", "System.Composition", "System.IO.Pipelines", "System.Threading.Channels"], "netcoreapp2.1": ["Microsoft.CodeAnalysis.Common", "Humanizer.Core", "System.Composition", "System.IO.Pipelines", "System.Threading.Channels"], "netcoreapp2.2": ["Microsoft.CodeAnalysis.Common", "Humanizer.Core", "System.Composition", "System.IO.Pipelines", "System.Threading.Channels"], "netcoreapp3.0": ["Microsoft.CodeAnalysis.Common", "Humanizer.Core", "System.Composition", "System.IO.Pipelines", "System.Threading.Channels"], "netcoreapp3.1": ["Microsoft.CodeAnalysis.Common", "Humanizer.Core", "System.Composition", "System.IO.Pipelines", "System.Threading.Channels"], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": ["Microsoft.CodeAnalysis.Common", "Humanizer.Core", "System.Composition", "System.IO.Pipelines", "System.Threading.Channels"], "netstandard2.1": ["Microsoft.CodeAnalysis.Common", "Humanizer.Core", "System.Composition", "System.IO.Pipelines", "System.Threading.Channels"]}, "targeting_pack_overrides": [], "framework_list": []}, - {"name": "Microsoft.CodeCoverage", "id": "Microsoft.CodeCoverage", "version": "17.11.1", "sha512": "sha512-ZJ4Ch1u7AemIzNpc0BbLoysJ0dJildIvAybL2vBUfbqho86N2VqzX9PGNc9a9pemZ//1Y6AOJ7SJxi/pCvLhHA==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": [], "net462": [], "net47": [], "net471": [], "net472": [], "net48": [], "net5.0": [], "net6.0": [], "net7.0": [], "net8.0": [], "net9.0": [], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": [], "netcoreapp2.1": [], "netcoreapp2.2": [], "netcoreapp3.0": [], "netcoreapp3.1": [], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": [], "netstandard2.1": []}, "targeting_pack_overrides": [], "framework_list": []}, + {"name": "Microsoft.CodeCoverage", "id": "Microsoft.CodeCoverage", "version": "17.12.0", "sha512": "sha512-POBqg788rrLApvncy8rvtyJ3ynsBdU0/SGUXD+vPqyRDM/aUJbPZWx01qalGJRK1GcArSku8QDd9AVMa0TkCkA==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": [], "net462": [], "net47": [], "net471": [], "net472": [], "net48": [], "net5.0": [], "net6.0": [], "net7.0": [], "net8.0": [], "net9.0": [], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": [], "netcoreapp2.1": [], "netcoreapp2.2": [], "netcoreapp3.0": [], "netcoreapp3.1": [], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": [], "netstandard2.1": []}, "targeting_pack_overrides": [], "framework_list": []}, {"name": "Microsoft.Extensions.ObjectPool", "id": "Microsoft.Extensions.ObjectPool", "version": "7.0.13", "sha512": "sha512-N66kAzKBfcs4zIX/iVMUOhfn8Xv3Ye1QpLGS8IUSpCHa+Vxh2ZsdDiqd0Y2m7ryPU6FU2LOTnZ+0ymmm83vC6w==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": [], "net462": [], "net47": [], "net471": [], "net472": [], "net48": [], "net5.0": [], "net6.0": [], "net7.0": [], "net8.0": [], "net9.0": [], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": [], "netcoreapp2.1": [], "netcoreapp2.2": [], "netcoreapp3.0": [], "netcoreapp3.1": [], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": [], "netstandard2.1": []}, "targeting_pack_overrides": [], "framework_list": []}, {"name": "Microsoft.NET.StringTools", "id": "Microsoft.NET.StringTools", "version": "17.8.3", "sha512": "sha512-3N/Ika66JZeORrIZ68fap6M0LSQ9+SQz277NxjA/dxETnR3dZwJXj67jAAc4FkijG6w//QzrC5NEregtIVjz1w==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": [], "net462": [], "net47": [], "net471": [], "net472": ["System.Runtime.CompilerServices.Unsafe"], "net48": ["System.Runtime.CompilerServices.Unsafe"], "net5.0": ["System.Runtime.CompilerServices.Unsafe"], "net6.0": ["System.Runtime.CompilerServices.Unsafe"], "net7.0": ["System.Runtime.CompilerServices.Unsafe"], "net8.0": [], "net9.0": [], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": ["System.Runtime.CompilerServices.Unsafe"], "netcoreapp2.1": ["System.Runtime.CompilerServices.Unsafe"], "netcoreapp2.2": ["System.Runtime.CompilerServices.Unsafe"], "netcoreapp3.0": ["System.Runtime.CompilerServices.Unsafe"], "netcoreapp3.1": ["System.Runtime.CompilerServices.Unsafe"], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": ["System.Runtime.CompilerServices.Unsafe"], "netstandard2.1": ["System.Runtime.CompilerServices.Unsafe"]}, "targeting_pack_overrides": [], "framework_list": []}, - {"name": "Microsoft.NET.Test.Sdk", "id": "Microsoft.NET.Test.Sdk", "version": "17.11.1", "sha512": "sha512-k3ULrpyrTHKhVeKqdFwiUDOwqKVRtVTcyjmfKqKw/NrIHJ54mkTaGlU5ARUakDC894X1wTyXtdmzzaDZqelliA==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": [], "net462": ["Microsoft.CodeCoverage"], "net47": ["Microsoft.CodeCoverage"], "net471": ["Microsoft.CodeCoverage"], "net472": ["Microsoft.CodeCoverage"], "net48": ["Microsoft.CodeCoverage"], "net5.0": ["Microsoft.TestPlatform.TestHost", "Microsoft.CodeCoverage"], "net6.0": ["Microsoft.TestPlatform.TestHost", "Microsoft.CodeCoverage"], "net7.0": ["Microsoft.TestPlatform.TestHost", "Microsoft.CodeCoverage"], "net8.0": ["Microsoft.TestPlatform.TestHost", "Microsoft.CodeCoverage"], "net9.0": ["Microsoft.TestPlatform.TestHost", "Microsoft.CodeCoverage"], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": [], "netcoreapp2.1": [], "netcoreapp2.2": [], "netcoreapp3.0": [], "netcoreapp3.1": ["Microsoft.TestPlatform.TestHost", "Microsoft.CodeCoverage"], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": [], "netstandard2.1": []}, "targeting_pack_overrides": [], "framework_list": []}, + {"name": "Microsoft.NET.Test.Sdk", "id": "Microsoft.NET.Test.Sdk", "version": "17.12.0", "sha512": "sha512-hGf8I8+yo15etavoMd+7OXcOG6/G7HYPDEJg5aQnhMzsxaUpq+udNZzSxmEN9rGTWMZOAVFcyNXNL7YBsN6chw==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": [], "net462": ["Microsoft.CodeCoverage"], "net47": ["Microsoft.CodeCoverage"], "net471": ["Microsoft.CodeCoverage"], "net472": ["Microsoft.CodeCoverage"], "net48": ["Microsoft.CodeCoverage"], "net5.0": ["Microsoft.TestPlatform.TestHost", "Microsoft.CodeCoverage"], "net6.0": ["Microsoft.TestPlatform.TestHost", "Microsoft.CodeCoverage"], "net7.0": ["Microsoft.TestPlatform.TestHost", "Microsoft.CodeCoverage"], "net8.0": ["Microsoft.TestPlatform.TestHost", "Microsoft.CodeCoverage"], "net9.0": ["Microsoft.TestPlatform.TestHost", "Microsoft.CodeCoverage"], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": [], "netcoreapp2.1": [], "netcoreapp2.2": [], "netcoreapp3.0": [], "netcoreapp3.1": ["Microsoft.TestPlatform.TestHost", "Microsoft.CodeCoverage"], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": [], "netstandard2.1": []}, "targeting_pack_overrides": [], "framework_list": []}, {"name": "Microsoft.NETCore.Platforms", "id": "Microsoft.NETCore.Platforms", "version": "1.1.1", "sha512": "sha512-mDUJD1eLXIzmUnWCzWlmNQZGDp/cVGT8KyhzMcJNk2nlfdFUOoZai9idT8/FacJr8Nv8zhAmdf39FHm5qWUoGQ==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": [], "net462": [], "net47": [], "net471": [], "net472": [], "net48": [], "net5.0": [], "net6.0": [], "net7.0": [], "net8.0": [], "net9.0": [], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": [], "netcoreapp2.1": [], "netcoreapp2.2": [], "netcoreapp3.0": [], "netcoreapp3.1": [], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": [], "netstandard2.1": []}, "targeting_pack_overrides": [], "framework_list": []}, {"name": "Microsoft.NETCore.Targets", "id": "Microsoft.NETCore.Targets", "version": "1.1.3", "sha512": "sha512-pxwq8g2PYRiEF5KXVjmZFMNTqsg2Gr1puv/pR1sqAduAKHAGbaCuJ6+yc3pAJseClQUD29S2Ubrm7n/ZD78dUg==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": [], "net462": [], "net47": [], "net471": [], "net472": [], "net48": [], "net5.0": [], "net6.0": [], "net7.0": [], "net8.0": [], "net9.0": [], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": [], "netcoreapp2.1": [], "netcoreapp2.2": [], "netcoreapp3.0": [], "netcoreapp3.1": [], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": [], "netstandard2.1": []}, "targeting_pack_overrides": [], "framework_list": []}, - {"name": "Microsoft.TestPlatform.ObjectModel", "id": "Microsoft.TestPlatform.ObjectModel", "version": "17.11.1", "sha512": "sha512-9hJ6Gbf3IaPwOP2qgdADYLEk9NXtAsp5y3szBogAe0lj7zaBWU0n8GiCVxpJL8RaoPee46qlJBfZcu1z9DQgAA==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": ["System.Reflection.Metadata"], "net462": ["System.Reflection.Metadata"], "net47": ["System.Reflection.Metadata"], "net471": ["System.Reflection.Metadata"], "net472": ["System.Reflection.Metadata"], "net48": ["System.Reflection.Metadata"], "net5.0": ["System.Reflection.Metadata"], "net6.0": ["System.Reflection.Metadata"], "net7.0": ["System.Reflection.Metadata"], "net8.0": ["System.Reflection.Metadata"], "net9.0": ["System.Reflection.Metadata"], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": ["System.Reflection.Metadata"], "netcoreapp2.1": ["System.Reflection.Metadata"], "netcoreapp2.2": ["System.Reflection.Metadata"], "netcoreapp3.0": ["System.Reflection.Metadata"], "netcoreapp3.1": ["System.Reflection.Metadata"], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": ["System.Reflection.Metadata"], "netstandard2.1": ["System.Reflection.Metadata"]}, "targeting_pack_overrides": [], "framework_list": []}, - {"name": "Microsoft.TestPlatform.TestHost", "id": "Microsoft.TestPlatform.TestHost", "version": "17.11.1", "sha512": "sha512-deRHZRRzHUWbCu31aoFmFt9qelMkDmuBsgJ3jgqQt8KEIj2Tx0R1Qe7nDRZ3YUF84YGICMXMBd+BABtWRw3Wxg==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": [], "net462": [], "net47": [], "net471": [], "net472": [], "net48": [], "net5.0": ["Microsoft.TestPlatform.ObjectModel", "Newtonsoft.Json"], "net6.0": ["Microsoft.TestPlatform.ObjectModel", "Newtonsoft.Json"], "net7.0": ["Microsoft.TestPlatform.ObjectModel", "Newtonsoft.Json"], "net8.0": ["Microsoft.TestPlatform.ObjectModel", "Newtonsoft.Json"], "net9.0": ["Microsoft.TestPlatform.ObjectModel", "Newtonsoft.Json"], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": [], "netcoreapp2.1": [], "netcoreapp2.2": [], "netcoreapp3.0": [], "netcoreapp3.1": ["Microsoft.TestPlatform.ObjectModel", "Newtonsoft.Json"], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": [], "netstandard2.1": []}, "targeting_pack_overrides": [], "framework_list": []}, + {"name": "Microsoft.TestPlatform.ObjectModel", "id": "Microsoft.TestPlatform.ObjectModel", "version": "17.12.0", "sha512": "sha512-klsXMgAPNWYo3ceakLkod4wYrk4lAV2Ehi676zUKgiVpQ5Yj6q3vsMhk/3pm97Ltk/hdcSW0rJKJvcQvTzPgYA==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": ["System.Reflection.Metadata"], "net462": ["System.Reflection.Metadata"], "net47": ["System.Reflection.Metadata"], "net471": ["System.Reflection.Metadata"], "net472": ["System.Reflection.Metadata"], "net48": ["System.Reflection.Metadata"], "net5.0": ["System.Reflection.Metadata"], "net6.0": ["System.Reflection.Metadata"], "net7.0": ["System.Reflection.Metadata"], "net8.0": ["System.Reflection.Metadata"], "net9.0": ["System.Reflection.Metadata"], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": ["System.Reflection.Metadata"], "netcoreapp2.1": ["System.Reflection.Metadata"], "netcoreapp2.2": ["System.Reflection.Metadata"], "netcoreapp3.0": ["System.Reflection.Metadata"], "netcoreapp3.1": ["System.Reflection.Metadata"], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": ["System.Reflection.Metadata"], "netstandard2.1": ["System.Reflection.Metadata"]}, "targeting_pack_overrides": [], "framework_list": []}, + {"name": "Microsoft.TestPlatform.TestHost", "id": "Microsoft.TestPlatform.TestHost", "version": "17.12.0", "sha512": "sha512-gYM2BOGQvFEP2fZt61f3f5Gu+imL1G1bvGUrbJjpYcl66R6uzs5yESg0XMn8IgUgldz8RldOOaYmjk2KcSeG1Q==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": [], "net462": [], "net47": [], "net471": [], "net472": [], "net48": [], "net5.0": ["Microsoft.TestPlatform.ObjectModel", "Newtonsoft.Json"], "net6.0": ["Microsoft.TestPlatform.ObjectModel", "Newtonsoft.Json"], "net7.0": ["Microsoft.TestPlatform.ObjectModel", "Newtonsoft.Json"], "net8.0": ["Microsoft.TestPlatform.ObjectModel", "Newtonsoft.Json"], "net9.0": ["Microsoft.TestPlatform.ObjectModel", "Newtonsoft.Json"], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": [], "netcoreapp2.1": [], "netcoreapp2.2": [], "netcoreapp3.0": [], "netcoreapp3.1": ["Microsoft.TestPlatform.ObjectModel", "Newtonsoft.Json"], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": [], "netstandard2.1": []}, "targeting_pack_overrides": [], "framework_list": []}, {"name": "Microsoft.Win32.Primitives", "id": "Microsoft.Win32.Primitives", "version": "4.3.0", "sha512": "sha512-Nm8Hp51y9tYcK3xD6qk43Wjftrg1mdH24CCJsTb6gr7HS21U1uA+CKPGEtUcVZbjU1y8Kynzm5eoJ7Pnx5gm8A==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": [], "net462": [], "net47": [], "net471": [], "net472": [], "net48": [], "net5.0": ["Microsoft.NETCore.Platforms", "Microsoft.NETCore.Targets", "System.Runtime"], "net6.0": ["Microsoft.NETCore.Platforms", "Microsoft.NETCore.Targets", "System.Runtime"], "net7.0": ["Microsoft.NETCore.Platforms", "Microsoft.NETCore.Targets", "System.Runtime"], "net8.0": ["Microsoft.NETCore.Platforms", "Microsoft.NETCore.Targets", "System.Runtime"], "net9.0": ["Microsoft.NETCore.Platforms", "Microsoft.NETCore.Targets", "System.Runtime"], "netcoreapp1.0": ["Microsoft.NETCore.Platforms", "Microsoft.NETCore.Targets", "System.Runtime"], "netcoreapp1.1": ["Microsoft.NETCore.Platforms", "Microsoft.NETCore.Targets", "System.Runtime"], "netcoreapp2.0": ["Microsoft.NETCore.Platforms", "Microsoft.NETCore.Targets", "System.Runtime"], "netcoreapp2.1": ["Microsoft.NETCore.Platforms", "Microsoft.NETCore.Targets", "System.Runtime"], "netcoreapp2.2": ["Microsoft.NETCore.Platforms", "Microsoft.NETCore.Targets", "System.Runtime"], "netcoreapp3.0": ["Microsoft.NETCore.Platforms", "Microsoft.NETCore.Targets", "System.Runtime"], "netcoreapp3.1": ["Microsoft.NETCore.Platforms", "Microsoft.NETCore.Targets", "System.Runtime"], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": ["Microsoft.NETCore.Platforms", "Microsoft.NETCore.Targets", "System.Runtime"], "netstandard1.4": ["Microsoft.NETCore.Platforms", "Microsoft.NETCore.Targets", "System.Runtime"], "netstandard1.5": ["Microsoft.NETCore.Platforms", "Microsoft.NETCore.Targets", "System.Runtime"], "netstandard1.6": ["Microsoft.NETCore.Platforms", "Microsoft.NETCore.Targets", "System.Runtime"], "netstandard2.0": ["Microsoft.NETCore.Platforms", "Microsoft.NETCore.Targets", "System.Runtime"], "netstandard2.1": ["Microsoft.NETCore.Platforms", "Microsoft.NETCore.Targets", "System.Runtime"]}, "targeting_pack_overrides": [], "framework_list": []}, {"name": "Microsoft.Win32.SystemEvents", "id": "Microsoft.Win32.SystemEvents", "version": "7.0.0", "sha512": "sha512-GO6SWx/wSZIFvxOn67Y6OiIGdz9JGCg5CRDDbSAAvBDQeZFbybu9sEOUb9w/vUlQv+A2XakTFZg9Ug1w+tgbWQ==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": [], "net462": [], "net47": [], "net471": [], "net472": [], "net48": [], "net5.0": [], "net6.0": [], "net7.0": [], "net8.0": [], "net9.0": [], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": [], "netcoreapp2.1": [], "netcoreapp2.2": [], "netcoreapp3.0": [], "netcoreapp3.1": [], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": [], "netstandard2.1": []}, "targeting_pack_overrides": [], "framework_list": []}, {"name": "Mono.Posix.NETStandard", "id": "Mono.Posix.NETStandard", "version": "1.0.0", "sha512": "sha512-RtGiutQZJAmajvQ0QvBvh73VJye85iW9f9tjZlzF88idLxNMo4lAktP/4Y9ilCpais0LDO0tpoICt9Hdv6wooA==", "sources": ["https://api.nuget.org/v3/index.json"], "dependencies": {"net11": [], "net20": [], "net30": [], "net35": [], "net40": [], "net403": [], "net45": [], "net451": [], "net452": [], "net46": [], "net461": [], "net462": [], "net47": [], "net471": [], "net472": [], "net48": [], "net5.0": [], "net6.0": [], "net7.0": [], "net8.0": [], "net9.0": [], "netcoreapp1.0": [], "netcoreapp1.1": [], "netcoreapp2.0": [], "netcoreapp2.1": [], "netcoreapp2.2": [], "netcoreapp3.0": [], "netcoreapp3.1": [], "netstandard": [], "netstandard1.0": [], "netstandard1.1": [], "netstandard1.2": [], "netstandard1.3": [], "netstandard1.4": [], "netstandard1.5": [], "netstandard1.6": [], "netstandard2.0": [], "netstandard2.1": []}, "targeting_pack_overrides": [], "framework_list": []}, diff --git a/csharp/ql/integration-tests/all-platforms/dotnet_build/test.py b/csharp/ql/integration-tests/all-platforms/dotnet_build/test.py index c32d966acb4..75ba09477fa 100644 --- a/csharp/ql/integration-tests/all-platforms/dotnet_build/test.py +++ b/csharp/ql/integration-tests/all-platforms/dotnet_build/test.py @@ -1,7 +1,6 @@ import os def check_build_out(msg, s): - lines = s.splitlines() lines = s.splitlines() assert ( any (("[build-stdout]" in line) and (msg in line) for line in lines) diff --git a/csharp/ql/lib/change-notes/2024-11-26-model-microsoft.jsinterop.ijsruntime.md b/csharp/ql/lib/change-notes/2024-11-26-model-microsoft.jsinterop.ijsruntime.md new file mode 100644 index 00000000000..a99f9c8e0fd --- /dev/null +++ b/csharp/ql/lib/change-notes/2024-11-26-model-microsoft.jsinterop.ijsruntime.md @@ -0,0 +1,5 @@ +--- +category: minorAnalysis +--- +* Added `js-interop` sinks for the `InvokeAsync` and `InvokeVoidAsync` methods of `Microsoft.JSInterop.IJSRuntime`, which can run arbitrary JavaScript. + diff --git a/csharp/ql/lib/change-notes/2024-11-27-navigationmanager.uri-and-uri-parsing-utilities.md b/csharp/ql/lib/change-notes/2024-11-27-navigationmanager.uri-and-uri-parsing-utilities.md new file mode 100644 index 00000000000..2d9866c2e15 --- /dev/null +++ b/csharp/ql/lib/change-notes/2024-11-27-navigationmanager.uri-and-uri-parsing-utilities.md @@ -0,0 +1,8 @@ +--- +category: minorAnalysis +--- +* Added `Microsoft.AspNetCore.Components.NagivationManager::Uri` as a remote flow source, since this value may contain user-specified values. +* Added the following URI-parsing methods as summaries, as they may be tainted with user-specified values: + - `System.Web.HttpUtility::ParseQueryString` + - `Microsoft.AspNetCore.WebUtilities.QueryHelpers::ParseQuery` + - `Microsoft.AspNetCore.WebUtilities.QueryHelpers::ParseNullableQuery` diff --git a/csharp/ql/lib/change-notes/2024-12-03-dynamic-field-flow.md b/csharp/ql/lib/change-notes/2024-12-03-dynamic-field-flow.md new file mode 100644 index 00000000000..4d5f8f9258e --- /dev/null +++ b/csharp/ql/lib/change-notes/2024-12-03-dynamic-field-flow.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added support for data-flow through member accesses of objects with `dynamic` types. diff --git a/csharp/ql/lib/change-notes/2024-12-03-public-protected-reference.md b/csharp/ql/lib/change-notes/2024-12-03-public-protected-reference.md new file mode 100644 index 00000000000..7b284df3652 --- /dev/null +++ b/csharp/ql/lib/change-notes/2024-12-03-public-protected-reference.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Only extract *public* and *protected* members from reference assemblies. This yields an approximate average speed-up of around 10% for extraction and query execution. Custom MaD rows using `Field`-based summaries may need to be changed to `SyntheticField`-based flows if they reference private fields. diff --git a/csharp/ql/lib/change-notes/2024-12-03-remove-dataflow-config-class-api.md b/csharp/ql/lib/change-notes/2024-12-03-remove-dataflow-config-class-api.md new file mode 100644 index 00000000000..d09ec528c99 --- /dev/null +++ b/csharp/ql/lib/change-notes/2024-12-03-remove-dataflow-config-class-api.md @@ -0,0 +1,4 @@ +--- +category: breaking +--- +* Deleted the old deprecated data flow API that was based on extending a configuration class. See https://github.blog/changelog/2023-08-14-new-dataflow-api-for-writing-custom-codeql-queries for instructions on migrating your queries to use the new API. diff --git a/csharp/ql/lib/experimental/code/csharp/Cryptography/NonCryptographicHashes.qll b/csharp/ql/lib/experimental/code/csharp/Cryptography/NonCryptographicHashes.qll index 0f22f772620..49dd011658d 100644 --- a/csharp/ql/lib/experimental/code/csharp/Cryptography/NonCryptographicHashes.qll +++ b/csharp/ql/lib/experimental/code/csharp/Cryptography/NonCryptographicHashes.qll @@ -8,7 +8,6 @@ import csharp private import DataFlow -private import semmle.code.csharp.dataflow.TaintTracking2 predicate maybeANonCryptographicHash( Callable callable, Variable v, Expr xor, Expr mul, LoopStmt loop diff --git a/csharp/ql/lib/ext/Microsoft.AspNetCore.Components.model.yml b/csharp/ql/lib/ext/Microsoft.AspNetCore.Components.model.yml new file mode 100644 index 00000000000..13c7168a1d1 --- /dev/null +++ b/csharp/ql/lib/ext/Microsoft.AspNetCore.Components.model.yml @@ -0,0 +1,12 @@ +extensions: + - addsTo: + pack: codeql/csharp-all + extensible: sourceModel + data: + - ["Microsoft.AspNetCore.Components", "NagivationManager", True, "get_BaseUri", "", "", "ReturnValue", "remote", "manual"] + - ["Microsoft.AspNetCore.Components", "NagivationManager", True, "get_Uri", "", "", "ReturnValue", "remote", "manual"] + - addsTo: + pack: codeql/csharp-all + extensible: summaryModel + data: + - ["Microsoft.AspNetCore.Components", "NagivationManager", True, "ToAbsoluteUri", "(System.String)", "", "Argument[0]", "ReturnValue", "taint", "manual"] diff --git a/csharp/ql/lib/ext/Microsoft.AspNetCore.WebUtilities.model.yml b/csharp/ql/lib/ext/Microsoft.AspNetCore.WebUtilities.model.yml new file mode 100644 index 00000000000..3554f5bb7a6 --- /dev/null +++ b/csharp/ql/lib/ext/Microsoft.AspNetCore.WebUtilities.model.yml @@ -0,0 +1,7 @@ +extensions: + - addsTo: + pack: codeql/csharp-all + extensible: summaryModel + data: + - ["Microsoft.AspNetCore.WebUtilities", "QueryHelpers", False, "ParseQuery", "(System.String)", "", "Argument[0]", "ReturnValue", "taint", "manual"] + - ["Microsoft.AspNetCore.WebUtilities", "QueryHelpers", False, "ParseNullableQuery", "(System.String)", "", "Argument[0]", "ReturnValue", "taint", "manual"] diff --git a/csharp/ql/lib/ext/Microsoft.JSInterop.model.yml b/csharp/ql/lib/ext/Microsoft.JSInterop.model.yml new file mode 100644 index 00000000000..78f5c0964c1 --- /dev/null +++ b/csharp/ql/lib/ext/Microsoft.JSInterop.model.yml @@ -0,0 +1,7 @@ +extensions: + - addsTo: + pack: codeql/csharp-all + extensible: sinkModel + data: + - ["Microsoft.JSInterop", "JSRuntimeExtensions", True, "InvokeAsync", "", "", "Argument[1]", "js-injection", "manual"] + - ["Microsoft.JSInterop", "JSRuntimeExtensions", True, "InvokeVoidAsync", "", "", "Argument[1]", "js-injection", "manual"] diff --git a/csharp/ql/lib/ext/System.Web.model.yml b/csharp/ql/lib/ext/System.Web.model.yml index a2a7470ef8e..ba644e1cc70 100644 --- a/csharp/ql/lib/ext/System.Web.model.yml +++ b/csharp/ql/lib/ext/System.Web.model.yml @@ -22,6 +22,7 @@ extensions: - ["System.Web", "HttpUtility", False, "HtmlEncode", "(System.String,System.IO.TextWriter)", "", "Argument[0]", "ReturnValue", "taint", "manual"] - ["System.Web", "HttpUtility", False, "JavaScriptStringEncode", "(System.String)", "", "Argument[0]", "ReturnValue", "taint", "manual"] - ["System.Web", "HttpUtility", False, "JavaScriptStringEncode", "(System.String,System.Boolean)", "", "Argument[0]", "ReturnValue", "taint", "manual"] + - ["System.Web", "HttpUtility", False, "ParseQueryString", "", "", "Argument[0]", "ReturnValue", "taint", "manual"] - ["System.Web", "HttpUtility", False, "UrlEncode", "(System.Byte[])", "", "Argument[0]", "ReturnValue", "taint", "manual"] - ["System.Web", "HttpUtility", False, "UrlEncode", "(System.Byte[],System.Int32,System.Int32)", "", "Argument[0]", "ReturnValue", "taint", "manual"] - ["System.Web", "HttpUtility", False, "UrlEncode", "(System.String)", "", "Argument[0]", "ReturnValue", "taint", "manual"] diff --git a/csharp/ql/lib/ext/generated/System.Web.model.yml b/csharp/ql/lib/ext/generated/System.Web.model.yml index 19ef940f9ea..af5047a0fc2 100644 --- a/csharp/ql/lib/ext/generated/System.Web.model.yml +++ b/csharp/ql/lib/ext/generated/System.Web.model.yml @@ -25,8 +25,6 @@ extensions: - ["System.Web", "AspNetHostingPermissionAttribute", "AspNetHostingPermissionAttribute", "(System.Security.Permissions.SecurityAction)", "summary", "df-generated"] - ["System.Web", "AspNetHostingPermissionAttribute", "CreatePermission", "()", "summary", "df-generated"] - ["System.Web", "HttpUtility", "HtmlDecode", "(System.String,System.IO.TextWriter)", "summary", "df-generated"] - - ["System.Web", "HttpUtility", "ParseQueryString", "(System.String)", "summary", "df-generated"] - - ["System.Web", "HttpUtility", "ParseQueryString", "(System.String,System.Text.Encoding)", "summary", "df-generated"] - ["System.Web", "HttpUtility", "UrlDecode", "(System.Byte[],System.Int32,System.Int32,System.Text.Encoding)", "summary", "df-generated"] - ["System.Web", "HttpUtility", "UrlDecode", "(System.Byte[],System.Text.Encoding)", "summary", "df-generated"] - ["System.Web", "HttpUtility", "UrlDecode", "(System.String)", "summary", "df-generated"] diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/DataFlow.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/DataFlow.qll index 0fc12debaa8..9c1c8c2fee3 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/DataFlow.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/DataFlow.qll @@ -9,5 +9,5 @@ module DataFlow { private import semmle.code.csharp.dataflow.internal.DataFlowImplSpecific private import codeql.dataflow.DataFlow import DataFlowMake - import semmle.code.csharp.dataflow.internal.DataFlowImpl1 + import Public } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/DataFlow2.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/DataFlow2.qll deleted file mode 100644 index 60525016d31..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/DataFlow2.qll +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) data flow analyses. - */ - -import csharp - -module DataFlow2 { - import semmle.code.csharp.dataflow.internal.DataFlowImpl2 -} diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/DataFlow3.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/DataFlow3.qll deleted file mode 100644 index 7f3b9469449..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/DataFlow3.qll +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) data flow analyses. - */ - -import csharp - -module DataFlow3 { - import semmle.code.csharp.dataflow.internal.DataFlowImpl3 -} diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/DataFlow4.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/DataFlow4.qll deleted file mode 100644 index 29c994a2eec..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/DataFlow4.qll +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) data flow analyses. - */ - -import csharp - -module DataFlow4 { - import semmle.code.csharp.dataflow.internal.DataFlowImpl4 -} diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/DataFlow5.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/DataFlow5.qll deleted file mode 100644 index 48148117166..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/DataFlow5.qll +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) data flow analyses. - */ - -import csharp - -module DataFlow5 { - import semmle.code.csharp.dataflow.internal.DataFlowImpl5 -} diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/TaintTracking.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/TaintTracking.qll index fb39294ed23..781953a8348 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/TaintTracking.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/TaintTracking.qll @@ -6,10 +6,9 @@ import csharp module TaintTracking { - import semmle.code.csharp.dataflow.internal.tainttracking1.TaintTrackingParameter::Public + import semmle.code.csharp.dataflow.internal.TaintTrackingPublic private import semmle.code.csharp.dataflow.internal.DataFlowImplSpecific private import semmle.code.csharp.dataflow.internal.TaintTrackingImplSpecific private import codeql.dataflow.TaintTracking import TaintFlowMake - import semmle.code.csharp.dataflow.internal.tainttracking1.TaintTrackingImpl } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/TaintTracking2.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/TaintTracking2.qll deleted file mode 100644 index 9ee798ed9fd..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/TaintTracking2.qll +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) taint-tracking analyses. - */ - -import csharp - -module TaintTracking2 { - import semmle.code.csharp.dataflow.internal.tainttracking2.TaintTrackingImpl -} diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/TaintTracking3.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/TaintTracking3.qll deleted file mode 100644 index 476d7bf7dd7..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/TaintTracking3.qll +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) taint-tracking analyses. - */ - -import csharp - -module TaintTracking3 { - import semmle.code.csharp.dataflow.internal.tainttracking3.TaintTrackingImpl -} diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/TaintTracking4.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/TaintTracking4.qll deleted file mode 100644 index 45b8f12be5c..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/TaintTracking4.qll +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) taint-tracking analyses. - */ - -import csharp - -module TaintTracking4 { - import semmle.code.csharp.dataflow.internal.tainttracking4.TaintTrackingImpl -} diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/TaintTracking5.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/TaintTracking5.qll deleted file mode 100644 index 7a75ce532bc..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/TaintTracking5.qll +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) taint-tracking analyses. - */ - -import csharp - -module TaintTracking5 { - import semmle.code.csharp.dataflow.internal.tainttracking5.TaintTrackingImpl -} diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl1.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl1.qll deleted file mode 100644 index 17def0c431d..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl1.qll +++ /dev/null @@ -1,361 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * Provides a `Configuration` class backwards-compatible interface to the data - * flow library. - */ - -private import DataFlowImplCommon -private import DataFlowImplSpecific::Private -import DataFlowImplSpecific::Public -private import DataFlowImpl -import DataFlowImplCommonPublic -deprecated import FlowStateString -private import codeql.util.Unit - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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 sink, 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() } - - /** - * 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. - * - * These features are generally not relevant for typical end-to-end data flow - * queries, but should only be used for constructing paths that need to - * somehow be pluggable in another path context. - */ - FlowFeature getAFeature() { none() } - - /** Holds if sources should be grouped in the result of `hasFlowPath`. */ - predicate sourceGrouping(Node source, string sourceGroup) { none() } - - /** Holds if sinks should be grouped in the result of `hasFlowPath`. */ - predicate sinkGrouping(Node sink, string sinkGroup) { none() } - - /** - * Holds if data may flow from `source` to `sink` for this configuration. - */ - predicate hasFlow(Node source, Node sink) { hasFlow(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) { hasFlowPath(source, sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } - - /** - * 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() } -} - -/** - * 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 deprecated 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) - } -} - -deprecated private FlowState relevantState(Configuration config) { - config.isSource(_, result) or - config.isSink(_, result) or - config.isBarrier(_, result) or - config.isAdditionalFlowStep(_, result, _, _) or - config.isAdditionalFlowStep(_, _, _, result) -} - -private newtype TConfigState = - deprecated TMkConfigState(Configuration config, FlowState state) { - state = relevantState(config) or state instanceof FlowStateEmpty - } - -deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) } - -deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) } - -deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) } - -deprecated private module Config implements FullStateConfigSig { - class FlowState = TConfigState; - - predicate isSource(Node source, FlowState state) { - getConfig(state).isSource(source, getState(state)) - or - getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty - } - - predicate isSink(Node sink) { none() } - - predicate isSink(Node sink, FlowState state) { - getConfig(state).isSink(sink, getState(state)) - or - getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty - } - - predicate isBarrier(Node node) { none() } - - predicate isBarrier(Node node, FlowState state) { - getConfig(state).isBarrier(node, getState(state)) or - getConfig(state).isBarrier(node) - } - - predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) } - - predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) } - - predicate isBarrierIn(Node node, FlowState state) { none() } - - predicate isBarrierOut(Node node, FlowState state) { none() } - - predicate isAdditionalFlowStep(Node node1, Node node2, string model) { - singleConfiguration() and - any(Configuration config).isAdditionalFlowStep(node1, node2) and - model = "" - } - - predicate isAdditionalFlowStep( - Node node1, FlowState state1, Node node2, FlowState state2, string model - ) { - getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and - getConfig(state2) = getConfig(state1) and - model = "" - or - not singleConfiguration() and - getConfig(state1).isAdditionalFlowStep(node1, node2) and - state2 = state1 and - model = "" - } - - predicate allowImplicitRead(Node node, ContentSet c) { - any(Configuration config).allowImplicitRead(node, c) - } - - predicate neverSkip(Node node) { none() } - - int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) } - - int accessPathLimit() { result = 5 } - - FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } - - predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } - - predicate observeDiffInformedIncrementalMode() { none() } -} - -deprecated private import Impl as I - -/** - * 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, and which can reach a sink, are generated. - */ -deprecated class PathNode instanceof I::PathNode { - /** Gets a textual representation of this element. */ - final string toString() { result = super.toString() } - - /** - * Gets a textual representation of this element, including a textual - * representation of the call context. - */ - final string toStringWithContext() { result = super.toStringWithContext() } - - /** - * 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/). - */ - final predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - /** Gets the underlying `Node`. */ - final Node getNode() { result = super.getNode() } - - /** Gets the `FlowState` of this node. */ - deprecated final FlowState getState() { result = getState(super.getState()) } - - /** Gets the associated configuration. */ - deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) } - - /** Gets a successor of this node, if any. */ - final PathNode getASuccessor() { result = super.getASuccessor() } - - /** Holds if this node is a source. */ - final predicate isSource() { super.isSource() } - - /** Holds if this node is a grouping of source nodes. */ - final predicate isSourceGroup(string group) { super.isSourceGroup(group) } - - /** Holds if this node is a grouping of sink nodes. */ - final predicate isSinkGroup(string group) { super.isSinkGroup(group) } -} - -deprecated module PathGraph = I::PathGraph; - -deprecated private predicate hasFlow(Node source, Node sink, Configuration config) { - exists(PathNode source0, PathNode sink0 | - hasFlowPath(source0, sink0, config) and - source0.getNode() = source and - sink0.getNode() = sink - ) -} - -deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) { - I::flowPath(source, sink) and source.getConfiguration() = config -} - -deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) } - -deprecated predicate flowsTo = hasFlow/3; diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll deleted file mode 100644 index 17def0c431d..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ /dev/null @@ -1,361 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * Provides a `Configuration` class backwards-compatible interface to the data - * flow library. - */ - -private import DataFlowImplCommon -private import DataFlowImplSpecific::Private -import DataFlowImplSpecific::Public -private import DataFlowImpl -import DataFlowImplCommonPublic -deprecated import FlowStateString -private import codeql.util.Unit - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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 sink, 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() } - - /** - * 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. - * - * These features are generally not relevant for typical end-to-end data flow - * queries, but should only be used for constructing paths that need to - * somehow be pluggable in another path context. - */ - FlowFeature getAFeature() { none() } - - /** Holds if sources should be grouped in the result of `hasFlowPath`. */ - predicate sourceGrouping(Node source, string sourceGroup) { none() } - - /** Holds if sinks should be grouped in the result of `hasFlowPath`. */ - predicate sinkGrouping(Node sink, string sinkGroup) { none() } - - /** - * Holds if data may flow from `source` to `sink` for this configuration. - */ - predicate hasFlow(Node source, Node sink) { hasFlow(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) { hasFlowPath(source, sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } - - /** - * 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() } -} - -/** - * 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 deprecated 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) - } -} - -deprecated private FlowState relevantState(Configuration config) { - config.isSource(_, result) or - config.isSink(_, result) or - config.isBarrier(_, result) or - config.isAdditionalFlowStep(_, result, _, _) or - config.isAdditionalFlowStep(_, _, _, result) -} - -private newtype TConfigState = - deprecated TMkConfigState(Configuration config, FlowState state) { - state = relevantState(config) or state instanceof FlowStateEmpty - } - -deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) } - -deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) } - -deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) } - -deprecated private module Config implements FullStateConfigSig { - class FlowState = TConfigState; - - predicate isSource(Node source, FlowState state) { - getConfig(state).isSource(source, getState(state)) - or - getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty - } - - predicate isSink(Node sink) { none() } - - predicate isSink(Node sink, FlowState state) { - getConfig(state).isSink(sink, getState(state)) - or - getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty - } - - predicate isBarrier(Node node) { none() } - - predicate isBarrier(Node node, FlowState state) { - getConfig(state).isBarrier(node, getState(state)) or - getConfig(state).isBarrier(node) - } - - predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) } - - predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) } - - predicate isBarrierIn(Node node, FlowState state) { none() } - - predicate isBarrierOut(Node node, FlowState state) { none() } - - predicate isAdditionalFlowStep(Node node1, Node node2, string model) { - singleConfiguration() and - any(Configuration config).isAdditionalFlowStep(node1, node2) and - model = "" - } - - predicate isAdditionalFlowStep( - Node node1, FlowState state1, Node node2, FlowState state2, string model - ) { - getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and - getConfig(state2) = getConfig(state1) and - model = "" - or - not singleConfiguration() and - getConfig(state1).isAdditionalFlowStep(node1, node2) and - state2 = state1 and - model = "" - } - - predicate allowImplicitRead(Node node, ContentSet c) { - any(Configuration config).allowImplicitRead(node, c) - } - - predicate neverSkip(Node node) { none() } - - int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) } - - int accessPathLimit() { result = 5 } - - FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } - - predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } - - predicate observeDiffInformedIncrementalMode() { none() } -} - -deprecated private import Impl as I - -/** - * 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, and which can reach a sink, are generated. - */ -deprecated class PathNode instanceof I::PathNode { - /** Gets a textual representation of this element. */ - final string toString() { result = super.toString() } - - /** - * Gets a textual representation of this element, including a textual - * representation of the call context. - */ - final string toStringWithContext() { result = super.toStringWithContext() } - - /** - * 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/). - */ - final predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - /** Gets the underlying `Node`. */ - final Node getNode() { result = super.getNode() } - - /** Gets the `FlowState` of this node. */ - deprecated final FlowState getState() { result = getState(super.getState()) } - - /** Gets the associated configuration. */ - deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) } - - /** Gets a successor of this node, if any. */ - final PathNode getASuccessor() { result = super.getASuccessor() } - - /** Holds if this node is a source. */ - final predicate isSource() { super.isSource() } - - /** Holds if this node is a grouping of source nodes. */ - final predicate isSourceGroup(string group) { super.isSourceGroup(group) } - - /** Holds if this node is a grouping of sink nodes. */ - final predicate isSinkGroup(string group) { super.isSinkGroup(group) } -} - -deprecated module PathGraph = I::PathGraph; - -deprecated private predicate hasFlow(Node source, Node sink, Configuration config) { - exists(PathNode source0, PathNode sink0 | - hasFlowPath(source0, sink0, config) and - source0.getNode() = source and - sink0.getNode() = sink - ) -} - -deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) { - I::flowPath(source, sink) and source.getConfiguration() = config -} - -deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) } - -deprecated predicate flowsTo = hasFlow/3; diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll deleted file mode 100644 index 17def0c431d..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ /dev/null @@ -1,361 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * Provides a `Configuration` class backwards-compatible interface to the data - * flow library. - */ - -private import DataFlowImplCommon -private import DataFlowImplSpecific::Private -import DataFlowImplSpecific::Public -private import DataFlowImpl -import DataFlowImplCommonPublic -deprecated import FlowStateString -private import codeql.util.Unit - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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 sink, 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() } - - /** - * 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. - * - * These features are generally not relevant for typical end-to-end data flow - * queries, but should only be used for constructing paths that need to - * somehow be pluggable in another path context. - */ - FlowFeature getAFeature() { none() } - - /** Holds if sources should be grouped in the result of `hasFlowPath`. */ - predicate sourceGrouping(Node source, string sourceGroup) { none() } - - /** Holds if sinks should be grouped in the result of `hasFlowPath`. */ - predicate sinkGrouping(Node sink, string sinkGroup) { none() } - - /** - * Holds if data may flow from `source` to `sink` for this configuration. - */ - predicate hasFlow(Node source, Node sink) { hasFlow(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) { hasFlowPath(source, sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } - - /** - * 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() } -} - -/** - * 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 deprecated 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) - } -} - -deprecated private FlowState relevantState(Configuration config) { - config.isSource(_, result) or - config.isSink(_, result) or - config.isBarrier(_, result) or - config.isAdditionalFlowStep(_, result, _, _) or - config.isAdditionalFlowStep(_, _, _, result) -} - -private newtype TConfigState = - deprecated TMkConfigState(Configuration config, FlowState state) { - state = relevantState(config) or state instanceof FlowStateEmpty - } - -deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) } - -deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) } - -deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) } - -deprecated private module Config implements FullStateConfigSig { - class FlowState = TConfigState; - - predicate isSource(Node source, FlowState state) { - getConfig(state).isSource(source, getState(state)) - or - getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty - } - - predicate isSink(Node sink) { none() } - - predicate isSink(Node sink, FlowState state) { - getConfig(state).isSink(sink, getState(state)) - or - getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty - } - - predicate isBarrier(Node node) { none() } - - predicate isBarrier(Node node, FlowState state) { - getConfig(state).isBarrier(node, getState(state)) or - getConfig(state).isBarrier(node) - } - - predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) } - - predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) } - - predicate isBarrierIn(Node node, FlowState state) { none() } - - predicate isBarrierOut(Node node, FlowState state) { none() } - - predicate isAdditionalFlowStep(Node node1, Node node2, string model) { - singleConfiguration() and - any(Configuration config).isAdditionalFlowStep(node1, node2) and - model = "" - } - - predicate isAdditionalFlowStep( - Node node1, FlowState state1, Node node2, FlowState state2, string model - ) { - getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and - getConfig(state2) = getConfig(state1) and - model = "" - or - not singleConfiguration() and - getConfig(state1).isAdditionalFlowStep(node1, node2) and - state2 = state1 and - model = "" - } - - predicate allowImplicitRead(Node node, ContentSet c) { - any(Configuration config).allowImplicitRead(node, c) - } - - predicate neverSkip(Node node) { none() } - - int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) } - - int accessPathLimit() { result = 5 } - - FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } - - predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } - - predicate observeDiffInformedIncrementalMode() { none() } -} - -deprecated private import Impl as I - -/** - * 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, and which can reach a sink, are generated. - */ -deprecated class PathNode instanceof I::PathNode { - /** Gets a textual representation of this element. */ - final string toString() { result = super.toString() } - - /** - * Gets a textual representation of this element, including a textual - * representation of the call context. - */ - final string toStringWithContext() { result = super.toStringWithContext() } - - /** - * 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/). - */ - final predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - /** Gets the underlying `Node`. */ - final Node getNode() { result = super.getNode() } - - /** Gets the `FlowState` of this node. */ - deprecated final FlowState getState() { result = getState(super.getState()) } - - /** Gets the associated configuration. */ - deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) } - - /** Gets a successor of this node, if any. */ - final PathNode getASuccessor() { result = super.getASuccessor() } - - /** Holds if this node is a source. */ - final predicate isSource() { super.isSource() } - - /** Holds if this node is a grouping of source nodes. */ - final predicate isSourceGroup(string group) { super.isSourceGroup(group) } - - /** Holds if this node is a grouping of sink nodes. */ - final predicate isSinkGroup(string group) { super.isSinkGroup(group) } -} - -deprecated module PathGraph = I::PathGraph; - -deprecated private predicate hasFlow(Node source, Node sink, Configuration config) { - exists(PathNode source0, PathNode sink0 | - hasFlowPath(source0, sink0, config) and - source0.getNode() = source and - sink0.getNode() = sink - ) -} - -deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) { - I::flowPath(source, sink) and source.getConfiguration() = config -} - -deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) } - -deprecated predicate flowsTo = hasFlow/3; diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll deleted file mode 100644 index 17def0c431d..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ /dev/null @@ -1,361 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * Provides a `Configuration` class backwards-compatible interface to the data - * flow library. - */ - -private import DataFlowImplCommon -private import DataFlowImplSpecific::Private -import DataFlowImplSpecific::Public -private import DataFlowImpl -import DataFlowImplCommonPublic -deprecated import FlowStateString -private import codeql.util.Unit - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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 sink, 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() } - - /** - * 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. - * - * These features are generally not relevant for typical end-to-end data flow - * queries, but should only be used for constructing paths that need to - * somehow be pluggable in another path context. - */ - FlowFeature getAFeature() { none() } - - /** Holds if sources should be grouped in the result of `hasFlowPath`. */ - predicate sourceGrouping(Node source, string sourceGroup) { none() } - - /** Holds if sinks should be grouped in the result of `hasFlowPath`. */ - predicate sinkGrouping(Node sink, string sinkGroup) { none() } - - /** - * Holds if data may flow from `source` to `sink` for this configuration. - */ - predicate hasFlow(Node source, Node sink) { hasFlow(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) { hasFlowPath(source, sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } - - /** - * 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() } -} - -/** - * 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 deprecated 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) - } -} - -deprecated private FlowState relevantState(Configuration config) { - config.isSource(_, result) or - config.isSink(_, result) or - config.isBarrier(_, result) or - config.isAdditionalFlowStep(_, result, _, _) or - config.isAdditionalFlowStep(_, _, _, result) -} - -private newtype TConfigState = - deprecated TMkConfigState(Configuration config, FlowState state) { - state = relevantState(config) or state instanceof FlowStateEmpty - } - -deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) } - -deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) } - -deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) } - -deprecated private module Config implements FullStateConfigSig { - class FlowState = TConfigState; - - predicate isSource(Node source, FlowState state) { - getConfig(state).isSource(source, getState(state)) - or - getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty - } - - predicate isSink(Node sink) { none() } - - predicate isSink(Node sink, FlowState state) { - getConfig(state).isSink(sink, getState(state)) - or - getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty - } - - predicate isBarrier(Node node) { none() } - - predicate isBarrier(Node node, FlowState state) { - getConfig(state).isBarrier(node, getState(state)) or - getConfig(state).isBarrier(node) - } - - predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) } - - predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) } - - predicate isBarrierIn(Node node, FlowState state) { none() } - - predicate isBarrierOut(Node node, FlowState state) { none() } - - predicate isAdditionalFlowStep(Node node1, Node node2, string model) { - singleConfiguration() and - any(Configuration config).isAdditionalFlowStep(node1, node2) and - model = "" - } - - predicate isAdditionalFlowStep( - Node node1, FlowState state1, Node node2, FlowState state2, string model - ) { - getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and - getConfig(state2) = getConfig(state1) and - model = "" - or - not singleConfiguration() and - getConfig(state1).isAdditionalFlowStep(node1, node2) and - state2 = state1 and - model = "" - } - - predicate allowImplicitRead(Node node, ContentSet c) { - any(Configuration config).allowImplicitRead(node, c) - } - - predicate neverSkip(Node node) { none() } - - int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) } - - int accessPathLimit() { result = 5 } - - FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } - - predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } - - predicate observeDiffInformedIncrementalMode() { none() } -} - -deprecated private import Impl as I - -/** - * 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, and which can reach a sink, are generated. - */ -deprecated class PathNode instanceof I::PathNode { - /** Gets a textual representation of this element. */ - final string toString() { result = super.toString() } - - /** - * Gets a textual representation of this element, including a textual - * representation of the call context. - */ - final string toStringWithContext() { result = super.toStringWithContext() } - - /** - * 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/). - */ - final predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - /** Gets the underlying `Node`. */ - final Node getNode() { result = super.getNode() } - - /** Gets the `FlowState` of this node. */ - deprecated final FlowState getState() { result = getState(super.getState()) } - - /** Gets the associated configuration. */ - deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) } - - /** Gets a successor of this node, if any. */ - final PathNode getASuccessor() { result = super.getASuccessor() } - - /** Holds if this node is a source. */ - final predicate isSource() { super.isSource() } - - /** Holds if this node is a grouping of source nodes. */ - final predicate isSourceGroup(string group) { super.isSourceGroup(group) } - - /** Holds if this node is a grouping of sink nodes. */ - final predicate isSinkGroup(string group) { super.isSinkGroup(group) } -} - -deprecated module PathGraph = I::PathGraph; - -deprecated private predicate hasFlow(Node source, Node sink, Configuration config) { - exists(PathNode source0, PathNode sink0 | - hasFlowPath(source0, sink0, config) and - source0.getNode() = source and - sink0.getNode() = sink - ) -} - -deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) { - I::flowPath(source, sink) and source.getConfiguration() = config -} - -deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) } - -deprecated predicate flowsTo = hasFlow/3; diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll deleted file mode 100644 index 17def0c431d..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ /dev/null @@ -1,361 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * Provides a `Configuration` class backwards-compatible interface to the data - * flow library. - */ - -private import DataFlowImplCommon -private import DataFlowImplSpecific::Private -import DataFlowImplSpecific::Public -private import DataFlowImpl -import DataFlowImplCommonPublic -deprecated import FlowStateString -private import codeql.util.Unit - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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 sink, 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() } - - /** - * 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. - * - * These features are generally not relevant for typical end-to-end data flow - * queries, but should only be used for constructing paths that need to - * somehow be pluggable in another path context. - */ - FlowFeature getAFeature() { none() } - - /** Holds if sources should be grouped in the result of `hasFlowPath`. */ - predicate sourceGrouping(Node source, string sourceGroup) { none() } - - /** Holds if sinks should be grouped in the result of `hasFlowPath`. */ - predicate sinkGrouping(Node sink, string sinkGroup) { none() } - - /** - * Holds if data may flow from `source` to `sink` for this configuration. - */ - predicate hasFlow(Node source, Node sink) { hasFlow(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) { hasFlowPath(source, sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } - - /** - * 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() } -} - -/** - * 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 deprecated 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) - } -} - -deprecated private FlowState relevantState(Configuration config) { - config.isSource(_, result) or - config.isSink(_, result) or - config.isBarrier(_, result) or - config.isAdditionalFlowStep(_, result, _, _) or - config.isAdditionalFlowStep(_, _, _, result) -} - -private newtype TConfigState = - deprecated TMkConfigState(Configuration config, FlowState state) { - state = relevantState(config) or state instanceof FlowStateEmpty - } - -deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) } - -deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) } - -deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) } - -deprecated private module Config implements FullStateConfigSig { - class FlowState = TConfigState; - - predicate isSource(Node source, FlowState state) { - getConfig(state).isSource(source, getState(state)) - or - getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty - } - - predicate isSink(Node sink) { none() } - - predicate isSink(Node sink, FlowState state) { - getConfig(state).isSink(sink, getState(state)) - or - getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty - } - - predicate isBarrier(Node node) { none() } - - predicate isBarrier(Node node, FlowState state) { - getConfig(state).isBarrier(node, getState(state)) or - getConfig(state).isBarrier(node) - } - - predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) } - - predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) } - - predicate isBarrierIn(Node node, FlowState state) { none() } - - predicate isBarrierOut(Node node, FlowState state) { none() } - - predicate isAdditionalFlowStep(Node node1, Node node2, string model) { - singleConfiguration() and - any(Configuration config).isAdditionalFlowStep(node1, node2) and - model = "" - } - - predicate isAdditionalFlowStep( - Node node1, FlowState state1, Node node2, FlowState state2, string model - ) { - getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and - getConfig(state2) = getConfig(state1) and - model = "" - or - not singleConfiguration() and - getConfig(state1).isAdditionalFlowStep(node1, node2) and - state2 = state1 and - model = "" - } - - predicate allowImplicitRead(Node node, ContentSet c) { - any(Configuration config).allowImplicitRead(node, c) - } - - predicate neverSkip(Node node) { none() } - - int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) } - - int accessPathLimit() { result = 5 } - - FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } - - predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } - - predicate observeDiffInformedIncrementalMode() { none() } -} - -deprecated private import Impl as I - -/** - * 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, and which can reach a sink, are generated. - */ -deprecated class PathNode instanceof I::PathNode { - /** Gets a textual representation of this element. */ - final string toString() { result = super.toString() } - - /** - * Gets a textual representation of this element, including a textual - * representation of the call context. - */ - final string toStringWithContext() { result = super.toStringWithContext() } - - /** - * 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/). - */ - final predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - /** Gets the underlying `Node`. */ - final Node getNode() { result = super.getNode() } - - /** Gets the `FlowState` of this node. */ - deprecated final FlowState getState() { result = getState(super.getState()) } - - /** Gets the associated configuration. */ - deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) } - - /** Gets a successor of this node, if any. */ - final PathNode getASuccessor() { result = super.getASuccessor() } - - /** Holds if this node is a source. */ - final predicate isSource() { super.isSource() } - - /** Holds if this node is a grouping of source nodes. */ - final predicate isSourceGroup(string group) { super.isSourceGroup(group) } - - /** Holds if this node is a grouping of sink nodes. */ - final predicate isSinkGroup(string group) { super.isSinkGroup(group) } -} - -deprecated module PathGraph = I::PathGraph; - -deprecated private predicate hasFlow(Node source, Node sink, Configuration config) { - exists(PathNode source0, PathNode sink0 | - hasFlowPath(source0, sink0, config) and - source0.getNode() = source and - sink0.getNode() = sink - ) -} - -deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) { - I::flowPath(source, sink) and source.getConfiguration() = config -} - -deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) } - -deprecated predicate flowsTo = hasFlow/3; diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index cab164846e2..5b1342bacd5 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -731,11 +731,9 @@ module LocalFlow { or node2 = node1.(LocalFunctionCreationNode).getAnAccess(true) or - node1 = - unique(FlowSummaryNode n1 | - FlowSummaryImpl::Private::Steps::summaryLocalStep(n1.getSummaryNode(), - node2.(FlowSummaryNode).getSummaryNode(), true, _) - ) + FlowSummaryImpl::Private::Steps::summaryLocalMustFlowStep(node1 + .(FlowSummaryNode) + .getSummaryNode(), node2.(FlowSummaryNode).getSummaryNode()) } } @@ -885,6 +883,17 @@ private predicate fieldOrPropertyStore(Expr e, ContentSet c, Expr src, Expr q, b ) ) ) + or + // A write to a dynamic property + exists(DynamicMemberAccess dma, AssignableDefinition def, DynamicProperty dp | + def.getTargetAccess() = dma and + dp.getAnAccess() = dma and + c.isDynamicProperty(dp) and + src = def.getSource() and + q = dma.getQualifier() and + e = def.getExpr() and + postUpdate = true + ) } /** @@ -896,6 +905,18 @@ private predicate fieldOrPropertyRead(Expr e1, ContentSet c, FieldOrPropertyRead c = e2.getTarget().(FieldOrProperty).getContentSet() } +/** + * Holds if `e2` is an expression that reads the dynamic property `c` from + * expression `e1`. + */ +private predicate dynamicPropertyRead(Expr e1, ContentSet c, DynamicMemberRead e2) { + exists(DynamicPropertyContent dpc | + e1 = e2.getQualifier() and + dpc.getAnAccess() = e2 and + c.isDynamicProperty(dpc.getName()) + ) +} + /** * Holds if `ce` is a collection expression that adds `src` to the collection `ce`. */ @@ -1101,6 +1122,8 @@ private module Cached { | fieldOrPropertyRead(e, _, read) or + dynamicPropertyRead(e, _, read) + or arrayRead(e, read) ) ) @@ -1142,6 +1165,7 @@ private module Cached { newtype TContent = TFieldContent(Field f) { f.isUnboundDeclaration() } or TPropertyContent(Property p) { p.isUnboundDeclaration() } or + TDynamicPropertyContent(DynamicProperty dp) or TElementContent() or TSyntheticFieldContent(SyntheticField f) or TPrimaryConstructorParameterContent(Parameter p) { @@ -1156,12 +1180,16 @@ private module Cached { cached newtype TContentSet = TSingletonContent(Content c) { not c instanceof PropertyContent } or - TPropertyContentSet(Property p) { p.isUnboundDeclaration() } + TPropertyContentSet(Property p) { p.isUnboundDeclaration() } or + TDynamicPropertyContentSet(DynamicProperty dp) cached newtype TContentApprox = TFieldApproxContent(string firstChar) { firstChar = approximateFieldContent(_) } or TPropertyApproxContent(string firstChar) { firstChar = approximatePropertyContent(_) } or + TDynamicPropertyApproxContent(string firstChar) { + firstChar = approximateDynamicPropertyContent(_) + } or TElementApproxContent() or TSyntheticFieldApproxContent() or TPrimaryConstructorParameterApproxContent(string firstChar) { @@ -2086,6 +2114,18 @@ class FieldOrProperty extends Assignable, Modifiable { } } +/** A string that is a reference to a late-bound target of a dynamic member access. */ +class DynamicProperty extends string { + private DynamicMemberAccess dma; + + DynamicProperty() { this = dma.getLateBoundTargetName() } + + ContentSet getContentSet() { result.isDynamicProperty(this) } + + /** Gets an access of this dynamic property. */ + DynamicMemberAccess getAnAccess() { result = dma } +} + private class InstanceFieldOrProperty extends FieldOrProperty { InstanceFieldOrProperty() { not this.isStatic() } } @@ -2344,6 +2384,11 @@ private class ReadStepConfiguration extends ControlFlowReachabilityConfiguration or exactScope = false and isSuccessor = true and + dynamicPropertyRead(e1, _, e2) and + scope = e2 + or + exactScope = false and + isSuccessor = true and arrayRead(e1, e2) and scope = e2 or @@ -2476,6 +2521,8 @@ predicate readStep(Node node1, ContentSet c, Node node2) { exists(ReadStepConfiguration x | hasNodePath(x, node1, node2) | fieldOrPropertyRead(node1.asExpr(), c, node2.asExpr()) or + dynamicPropertyRead(node1.asExpr(), c, node2.asExpr()) + or node2.asExpr().(AwaitExpr).getExpr() = node1.asExpr() and c = getResultContent() ) @@ -3066,6 +3113,11 @@ class ContentApprox extends TContentApprox { this = TPropertyApproxContent(firstChar) and result = "approximated property " + firstChar ) or + exists(string firstChar | + this = TDynamicPropertyApproxContent(firstChar) and + result = "approximated dynamic property " + firstChar + ) + or this = TElementApproxContent() and result = "element" or this = TSyntheticFieldApproxContent() and result = "approximated synthetic field" @@ -3097,6 +3149,11 @@ private string approximatePropertyContent(PropertyContent pc) { result = pc.getProperty().getName().prefix(1) } +/** Gets a string for approximating the name of a dynamic property. */ +private string approximateDynamicPropertyContent(DynamicPropertyContent dpc) { + result = dpc.getName().prefix(1) +} + /** * Gets a string for approximating the name of a synthetic field corresponding * to a primary constructor parameter. @@ -3112,6 +3169,8 @@ ContentApprox getContentApprox(Content c) { or result = TPropertyApproxContent(approximatePropertyContent(c)) or + result = TDynamicPropertyApproxContent(approximateDynamicPropertyContent(c)) + or c instanceof ElementContent and result = TElementApproxContent() or c instanceof SyntheticFieldContent and result = TSyntheticFieldApproxContent() diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll index c5460652746..877630359fd 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll @@ -239,6 +239,23 @@ class PropertyContent extends Content, TPropertyContent { override Location getLocation() { result = p.getLocation() } } +/** A reference to a dynamic property. */ +class DynamicPropertyContent extends Content, TDynamicPropertyContent { + private DynamicProperty name; + + DynamicPropertyContent() { this = TDynamicPropertyContent(name) } + + /** Gets an access of this dynamic property. */ + DynamicMemberAccess getAnAccess() { result = name.getAnAccess() } + + override string toString() { result = "dynamic property " + name } + + override EmptyLocation getLocation() { any() } + + /** Gets the name that is referenced. */ + string getName() { result = name } +} + /** * A reference to the index of an argument of a delegate call. */ @@ -324,6 +341,9 @@ class ContentSet extends TContentSet { */ predicate isProperty(Property p) { this = TPropertyContentSet(p) } + /** Holds if this content set represents the dynamic property `name`. */ + predicate isDynamicProperty(string name) { this = TDynamicPropertyContentSet(name) } + /** * Holds if this content set represents the `i`th argument of a delegate call. */ @@ -348,6 +368,8 @@ class ContentSet extends TContentSet { this.isSingleton(result) or this.isProperty(result.(PropertyContent).getProperty()) + or + this.isDynamicProperty(result.(DynamicPropertyContent).getName()) } /** Gets a content that may be read from when reading from this set. */ @@ -362,6 +384,17 @@ class ContentSet extends TContentSet { or overridesOrImplementsSourceDecl(p1, p2) ) + or + exists(FieldOrProperty p | + this = p.getContentSet() and + result.(DynamicPropertyContent).getName() = p.getName() + ) + or + this.isDynamicProperty([ + result.(DynamicPropertyContent).getName(), + result.(PropertyContent).getProperty().getName(), + result.(FieldContent).getField().getName() + ]) } /** Gets a textual representation of this content set. */ @@ -375,6 +408,11 @@ class ContentSet extends TContentSet { this.isProperty(p) and result = "property " + p.getName() ) + or + exists(string name | + this.isDynamicProperty(name) and + result = "dynamic property " + name + ) } /** Gets the location of this content set. */ @@ -388,5 +426,8 @@ class ContentSet extends TContentSet { this.isProperty(p) and result = p.getLocation() ) + or + this.isDynamicProperty(_) and + result instanceof EmptyLocation } } 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 deleted file mode 100644 index 75e7856fd26..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ /dev/null @@ -1,168 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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) } - - /** - * 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/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingParameter.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingParameter.qll deleted file mode 100644 index 6fa484bea77..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingParameter.qll +++ /dev/null @@ -1,7 +0,0 @@ -import semmle.code.csharp.dataflow.internal.TaintTrackingPublic as Public - -module Private { - import semmle.code.csharp.dataflow.DataFlow::DataFlow as DataFlow - import semmle.code.csharp.dataflow.internal.DataFlowImpl as DataFlowInternal - import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate -} 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 deleted file mode 100644 index 75e7856fd26..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ /dev/null @@ -1,168 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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) } - - /** - * 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/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingParameter.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingParameter.qll deleted file mode 100644 index 6a8fa23ef31..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingParameter.qll +++ /dev/null @@ -1,6 +0,0 @@ -import semmle.code.csharp.dataflow.internal.TaintTrackingPublic as Public - -module Private { - import semmle.code.csharp.dataflow.DataFlow2::DataFlow2 as DataFlow - import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate -} 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 deleted file mode 100644 index 75e7856fd26..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll +++ /dev/null @@ -1,168 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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) } - - /** - * 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/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingParameter.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingParameter.qll deleted file mode 100644 index 6c73b6ceda6..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingParameter.qll +++ /dev/null @@ -1,6 +0,0 @@ -import semmle.code.csharp.dataflow.internal.TaintTrackingPublic as Public - -module Private { - import semmle.code.csharp.dataflow.DataFlow3::DataFlow3 as DataFlow - import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate -} 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 deleted file mode 100644 index 75e7856fd26..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll +++ /dev/null @@ -1,168 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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) } - - /** - * 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/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingParameter.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingParameter.qll deleted file mode 100644 index e394e27a50c..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingParameter.qll +++ /dev/null @@ -1,6 +0,0 @@ -import semmle.code.csharp.dataflow.internal.TaintTrackingPublic as Public - -module Private { - import semmle.code.csharp.dataflow.DataFlow4::DataFlow4 as DataFlow - import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate -} 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 deleted file mode 100644 index 75e7856fd26..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll +++ /dev/null @@ -1,168 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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) } - - /** - * 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/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingParameter.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingParameter.qll deleted file mode 100644 index 2668be3b376..00000000000 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingParameter.qll +++ /dev/null @@ -1,6 +0,0 @@ -import semmle.code.csharp.dataflow.internal.TaintTrackingPublic as Public - -module Private { - import semmle.code.csharp.dataflow.DataFlow5::DataFlow5 as DataFlow - import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate -} diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/Format.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/Format.qll index f0666b921b2..6cef58990b0 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/Format.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/Format.qll @@ -5,7 +5,6 @@ import csharp private import semmle.code.csharp.frameworks.System private import semmle.code.csharp.frameworks.system.Text -private import semmle.code.csharp.dataflow.DataFlow2 /** A method that formats a string, for example `string.Format()`. */ class FormatMethod extends Method { diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/Sql.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/Sql.qll index b3b85299c69..75f72352deb 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/Sql.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/Sql.qll @@ -6,7 +6,6 @@ private import semmle.code.csharp.frameworks.system.data.SqlClient private import semmle.code.csharp.frameworks.EntityFramework private import semmle.code.csharp.frameworks.NHibernate private import semmle.code.csharp.frameworks.Dapper -private import semmle.code.csharp.dataflow.DataFlow4 /** An expression containing a SQL command. */ abstract class SqlExpr extends Expr { diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/system/Xml.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/system/Xml.qll index 0644e75c3df..c0edf9e110e 100644 --- a/csharp/ql/lib/semmle/code/csharp/frameworks/system/Xml.qll +++ b/csharp/ql/lib/semmle/code/csharp/frameworks/system/Xml.qll @@ -2,7 +2,6 @@ import csharp private import semmle.code.csharp.frameworks.System -private import semmle.code.csharp.dataflow.DataFlow3 /** The `System.Xml` namespace. */ class SystemXmlNamespace extends Namespace { diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/ReDoSQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/ReDoSQuery.qll index 5addc03bd88..94dbf1d4cdc 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/ReDoSQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/ReDoSQuery.qll @@ -4,7 +4,6 @@ */ import csharp -private import semmle.code.csharp.dataflow.DataFlow2 private import semmle.code.csharp.security.dataflow.flowsinks.FlowSinks private import semmle.code.csharp.security.dataflow.flowsources.FlowSources private import semmle.code.csharp.frameworks.system.text.RegularExpressions diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/UnsafeDeserializationQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/UnsafeDeserializationQuery.qll index 009e1ab73c1..5d9d18dcbac 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/UnsafeDeserializationQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/UnsafeDeserializationQuery.qll @@ -5,7 +5,6 @@ import csharp private import semmle.code.csharp.serialization.Deserializers -private import semmle.code.csharp.dataflow.TaintTracking2 private import semmle.code.csharp.security.dataflow.flowsinks.FlowSinks private import semmle.code.csharp.security.dataflow.flowsources.FlowSources diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/XSSQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/XSSQuery.qll index 81029cc6572..2d687b51d67 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/XSSQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/XSSQuery.qll @@ -7,8 +7,6 @@ import csharp private import XSSSinks private import semmle.code.csharp.security.Sanitizers private import semmle.code.csharp.security.dataflow.flowsources.FlowSources -private import semmle.code.csharp.dataflow.DataFlow2 -private import semmle.code.csharp.dataflow.TaintTracking2 /** * Holds if there is tainted flow from `source` to `sink` that may lead to a diff --git a/csharp/ql/lib/semmle/code/csharp/security/xml/InsecureXMLQuery.qll b/csharp/ql/lib/semmle/code/csharp/security/xml/InsecureXMLQuery.qll index ba98888fa6f..1abeaf797b0 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/xml/InsecureXMLQuery.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/xml/InsecureXMLQuery.qll @@ -150,8 +150,6 @@ module XmlSettings { /** Provides predicates related to `System.Xml.XmlReader`. */ module XmlReader { - private import semmle.code.csharp.dataflow.DataFlow2 - private class InsecureXmlReaderCreate extends InsecureXmlProcessing, MethodCall { InsecureXmlReaderCreate() { this.getTarget().hasFullyQualifiedName("System.Xml.XmlReader", "Create") diff --git a/csharp/ql/src/Likely Bugs/ThreadUnsafeICryptoTransform.ql b/csharp/ql/src/Likely Bugs/ThreadUnsafeICryptoTransform.ql index e64d714f8bb..f1487d7a2ce 100644 --- a/csharp/ql/src/Likely Bugs/ThreadUnsafeICryptoTransform.ql +++ b/csharp/ql/src/Likely Bugs/ThreadUnsafeICryptoTransform.ql @@ -52,6 +52,7 @@ class ICryptoTransform extends ValueOrRefType { } from UnsafeField field +where field.fromSource() select field, "Static field '" + field.getName() + "' contains a 'System.Security.Cryptography.ICryptoTransform' that could be used in an unsafe way." diff --git a/csharp/ql/src/Telemetry/DatabaseQuality.qll b/csharp/ql/src/Telemetry/DatabaseQuality.qll index 9ef132710ab..eba5ebb5211 100644 --- a/csharp/ql/src/Telemetry/DatabaseQuality.qll +++ b/csharp/ql/src/Telemetry/DatabaseQuality.qll @@ -35,15 +35,73 @@ module ReportStats { module CallTargetStats implements StatsSig { int getNumberOfOk() { result = count(Call c | exists(c.getTarget())) } - int getNumberOfNotOk() { - result = - count(Call c | - not exists(c.getTarget()) and - not c instanceof DelegateCall and - not c instanceof DynamicExpr + private predicate isNoSetterPropertyCallInConstructor(PropertyCall c) { + exists(Property p, Constructor ctor | + p = c.getProperty() and + not exists(Setter a | a = p.getAnAccessor()) and + c.getEnclosingCallable() = ctor and + ( + c.hasThisQualifier() + or + ctor instanceof StaticConstructor and p.getDeclaringType() = ctor.getDeclaringType() ) + ) } + private predicate isNoSetterPropertyInitialization(PropertyCall c) { + exists(Property p, AssignExpr assign | + p = c.getProperty() and + not exists(Setter a | a = p.getAnAccessor()) and + assign = c.getParent() and + assign.getLValue() = c and + assign.getParent() instanceof Property + ) + } + + private predicate isAnonymousObjectMemberDeclaration(PropertyCall c) { + exists(Property p, AssignExpr assign | + p = c.getProperty() and + assign = c.getParent() and + assign.getLValue() = c and + assign.getParent() instanceof ObjectInitializer and + assign.getParent().getParent() instanceof AnonymousObjectCreation + ) + } + + private predicate isInitializedWithObjectOrCollectionInitializer(PropertyCall c) { + exists(Property p, AssignExpr assign | + p = c.getProperty() and + assign = c.getParent() and + assign.getLValue() = c and + assign.getRValue() instanceof ObjectOrCollectionInitializer + ) + } + + private predicate isEventFieldAccess(EventCall c) { + exists(Event e | c.getEvent() = e | + forall(Accessor a | e.getAnAccessor() = a | a.isCompilerGenerated()) + ) + } + + private predicate isTypeParameterInstantiation(ObjectCreation e) { + e.getType() instanceof TypeParameter + } + + additional predicate isNotOkCall(Call c) { + not exists(c.getTarget()) and + not c instanceof DelegateCall and + not c instanceof DynamicExpr and + not isNoSetterPropertyCallInConstructor(c) and + not isNoSetterPropertyInitialization(c) and + not isAnonymousObjectMemberDeclaration(c) and + not isInitializedWithObjectOrCollectionInitializer(c) and + not c.getParent+() instanceof NameOfExpr and + not isEventFieldAccess(c) and + not isTypeParameterInstantiation(c) + } + + int getNumberOfNotOk() { result = count(Call c | isNotOkCall(c)) } + string getOkText() { result = "calls with call target" } string getNotOkText() { result = "calls with missing call target" } diff --git a/csharp/ql/src/change-notes/2024-11-28-db-quality-property-access.md b/csharp/ql/src/change-notes/2024-11-28-db-quality-property-access.md new file mode 100644 index 00000000000..212c01f24bb --- /dev/null +++ b/csharp/ql/src/change-notes/2024-11-28-db-quality-property-access.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* `csharp/diagnostic/database-quality` has been changed to exclude various property access expressions from database quality evaluation. The excluded property access expressions are expected to have no target callables even in manual or autobuilt databases. diff --git a/csharp/ql/src/experimental/dataflow/flowsources/AuthCookie.qll b/csharp/ql/src/experimental/dataflow/flowsources/AuthCookie.qll index 928cf3bdc4f..401944adcc4 100644 --- a/csharp/ql/src/experimental/dataflow/flowsources/AuthCookie.qll +++ b/csharp/ql/src/experimental/dataflow/flowsources/AuthCookie.qll @@ -114,61 +114,6 @@ Expr getAValueForProp(ObjectCreation create, Assignment a, string prop) { */ predicate isPropertySet(ObjectCreation oc, string prop) { exists(getAValueForProp(oc, _, prop)) } -/** - * Tracks if a callback used in `OnAppendCookie` sets a cookie property to `true`. - */ -abstract deprecated private class OnAppendCookieTrackingConfig extends DataFlow::Configuration { - bindingset[this] - OnAppendCookieTrackingConfig() { any() } - - /** - * Specifies the cookie property name to track. - */ - abstract string propertyName(); - - override predicate isSource(DataFlow::Node source) { - exists(PropertyWrite pw, Assignment delegateAssign, Callable c | - pw.getProperty().getName() = "OnAppendCookie" and - pw.getProperty().getDeclaringType() instanceof MicrosoftAspNetCoreBuilderCookiePolicyOptions and - delegateAssign.getLValue() = pw and - ( - exists(LambdaExpr lambda | - delegateAssign.getRValue() = lambda and - lambda = c - ) - or - exists(DelegateCreation delegate | - delegateAssign.getRValue() = delegate and - delegate.getArgument().(CallableAccess).getTarget() = c - ) - ) and - c.getParameter(0) = source.asParameter() - ) - } - - override predicate isSink(DataFlow::Node sink) { - exists(PropertyWrite pw, Assignment a | - pw.getProperty().getDeclaringType() instanceof MicrosoftAspNetCoreHttpCookieOptions and - pw.getProperty().getName() = this.propertyName() and - a.getLValue() = pw and - exists(Expr val | - DataFlow::localExprFlow(val, a.getRValue()) and - val.getValue() = "true" - ) and - sink.asExpr() = pw.getQualifier() - ) - } - - override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { - node2.asExpr() = - any(PropertyRead pr | - pr.getQualifier() = node1.asExpr() and - pr.getProperty().getDeclaringType() instanceof - MicrosoftAspNetCoreCookiePolicyAppendCookieContext - ) - } -} - private signature string propertyName(); /** diff --git a/csharp/ql/test/library-tests/conversion/operator/Operator.expected b/csharp/ql/test/library-tests/conversion/operator/Operator.expected index dd11565ad2a..b0dcfc54260 100644 --- a/csharp/ql/test/library-tests/conversion/operator/Operator.expected +++ b/csharp/ql/test/library-tests/conversion/operator/Operator.expected @@ -21,7 +21,6 @@ | Int32 | Decimal | | Int32 | Index | | Int32 | Int128 | -| Int32 | MetadataToken | | Int32 | NFloat | | Int64 | Decimal | | Int64 | Int128 | @@ -29,7 +28,6 @@ | IntPtr | Int128 | | IntPtr | NFloat | | Memory`1 | ReadOnlyMemory | -| MetadataToken | Int32 | | NFloat | Double | | SByte | Decimal | | SByte | Half | @@ -59,4 +57,3 @@ | UIntPtr | Int128 | | UIntPtr | NFloat | | UIntPtr | UInt128 | -| UnixFileMode | Nullable | diff --git a/csharp/ql/test/library-tests/conversion/reftype/RefType.expected b/csharp/ql/test/library-tests/conversion/reftype/RefType.expected index ab433d45896..ff2c9da9ea3 100644 --- a/csharp/ql/test/library-tests/conversion/reftype/RefType.expected +++ b/csharp/ql/test/library-tests/conversion/reftype/RefType.expected @@ -183,8 +183,6 @@ | IReadOnlyList | dynamic | | Int16[] | Object | | Int16[] | dynamic | -| Int32[,] | Object | -| Int32[,] | dynamic | | Int32[] | Object | | Int32[] | dynamic | | Int64[] | Object | @@ -223,8 +221,6 @@ | T5 | C1 | | T5 | Object | | T5 | dynamic | -| UInt16[][] | Object | -| UInt16[][] | dynamic | | UInt32[] | Object | | UInt32[] | dynamic | | UInt64[] | Object | @@ -283,7 +279,6 @@ | null | IReadOnlyList | | null | IReadOnlyList | | null | Int16[] | -| null | Int32[,] | | null | Int32[] | | null | Int64[] | | null | Object | @@ -294,7 +289,6 @@ | null | T4 | | null | T4[] | | null | T5 | -| null | UInt16[][] | | null | UInt32[] | | null | UInt64[] | | null | dynamic | diff --git a/csharp/ql/test/library-tests/csharp9/FunctionPointer.expected b/csharp/ql/test/library-tests/csharp9/FunctionPointer.expected index d2617be088b..1bf279341ce 100644 --- a/csharp/ql/test/library-tests/csharp9/FunctionPointer.expected +++ b/csharp/ql/test/library-tests/csharp9/FunctionPointer.expected @@ -1,68 +1,33 @@ type | file://:0:0:0:0 | delegate* default | B | DefaultCallingConvention | | file://:0:0:0:0 | delegate* default | A | DefaultCallingConvention | -| file://:0:0:0:0 | delegate* default | Void | DefaultCallingConvention | | file://:0:0:0:0 | delegate* default | ref int | DefaultCallingConvention | | file://:0:0:0:0 | delegate* default | readonly int | DefaultCallingConvention | | file://:0:0:0:0 | delegate* default | Void* | DefaultCallingConvention | | file://:0:0:0:0 | delegate* default | int | DefaultCallingConvention | -| file://:0:0:0:0 | delegate* default | Void | DefaultCallingConvention | -| file://:0:0:0:0 | delegate* default | Void | DefaultCallingConvention | | file://:0:0:0:0 | delegate* default | int | DefaultCallingConvention | | file://:0:0:0:0 | delegate* default | int* | DefaultCallingConvention | -| file://:0:0:0:0 | delegate* default | object | DefaultCallingConvention | | file://:0:0:0:0 | delegate* stdcall | Void | StdCallCallingConvention | -| file://:0:0:0:0 | delegate* unmanaged | Void | UnmanagedCallingConvention | -| file://:0:0:0:0 | delegate* unmanaged | Void | UnmanagedCallingConvention | -| file://:0:0:0:0 | delegate* unmanaged | int | UnmanagedCallingConvention | | file://:0:0:0:0 | delegate* unmanaged | int | UnmanagedCallingConvention | | file://:0:0:0:0 | delegate* unmanaged | Void | UnmanagedCallingConvention | -| file://:0:0:0:0 | delegate* unmanaged | Void | UnmanagedCallingConvention | -| file://:0:0:0:0 | delegate* unmanaged | Void | UnmanagedCallingConvention | -| file://:0:0:0:0 | delegate* unmanaged | Void | UnmanagedCallingConvention | | file://:0:0:0:0 | delegate* unmanaged | Void | UnmanagedCallingConvention | unmanagedCallingConvention parameter | file://:0:0:0:0 | delegate* default | 0 | file://:0:0:0:0 | | A | | file://:0:0:0:0 | delegate* default | 0 | file://:0:0:0:0 | | B | -| file://:0:0:0:0 | delegate* default | 0 | file://:0:0:0:0 | | ref byte! | | file://:0:0:0:0 | delegate* default | 0 | file://:0:0:0:0 | | ref int! | | file://:0:0:0:0 | delegate* default | 1 | file://:0:0:0:0 | `1 | out object? | | file://:0:0:0:0 | delegate* default | 2 | file://:0:0:0:0 | `2 | readonly int! | | file://:0:0:0:0 | delegate* default | 0 | file://:0:0:0:0 | | ref int! | | file://:0:0:0:0 | delegate* default | 1 | file://:0:0:0:0 | `1 | out object? | | file://:0:0:0:0 | delegate* default | 0 | file://:0:0:0:0 | | int*! | -| file://:0:0:0:0 | delegate* default | 0 | file://:0:0:0:0 | | IntPtr! | -| file://:0:0:0:0 | delegate* default | 1 | file://:0:0:0:0 | `1 | ref byte! | -| file://:0:0:0:0 | delegate* default | 2 | file://:0:0:0:0 | `2 | PortableTailCallFrame*! | -| file://:0:0:0:0 | delegate* default | 0 | file://:0:0:0:0 | | object | | file://:0:0:0:0 | delegate* default | 0 | file://:0:0:0:0 | | T | | file://:0:0:0:0 | delegate* default | 0 | file://:0:0:0:0 | | Void*! | -| file://:0:0:0:0 | delegate* default | 0 | file://:0:0:0:0 | | Void*! | | file://:0:0:0:0 | delegate* stdcall | 0 | file://:0:0:0:0 | | ref int! | | file://:0:0:0:0 | delegate* stdcall | 1 | file://:0:0:0:0 | `1 | out object? | | file://:0:0:0:0 | delegate* stdcall | 2 | file://:0:0:0:0 | `2 | T | -| file://:0:0:0:0 | delegate* unmanaged | 0 | file://:0:0:0:0 | | byte*! | -| file://:0:0:0:0 | delegate* unmanaged | 1 | file://:0:0:0:0 | `1 | int! | -| file://:0:0:0:0 | delegate* unmanaged | 2 | file://:0:0:0:0 | `2 | byte! | -| file://:0:0:0:0 | delegate* unmanaged | 3 | file://:0:0:0:0 | `3 | long! | -| file://:0:0:0:0 | delegate* unmanaged | 4 | file://:0:0:0:0 | `4 | long! | -| file://:0:0:0:0 | delegate* unmanaged | 5 | file://:0:0:0:0 | `5 | EVENT_FILTER_DESCRIPTOR*! | -| file://:0:0:0:0 | delegate* unmanaged | 6 | file://:0:0:0:0 | `6 | Void*! | -| file://:0:0:0:0 | delegate* unmanaged | 0 | file://:0:0:0:0 | | char*! | -| file://:0:0:0:0 | delegate* unmanaged | 1 | file://:0:0:0:0 | `1 | IntPtr! | -| file://:0:0:0:0 | delegate* unmanaged | 0 | file://:0:0:0:0 | | int! | -| file://:0:0:0:0 | delegate* unmanaged | 1 | file://:0:0:0:0 | `1 | PosixSignal! | | file://:0:0:0:0 | delegate* unmanaged | 0 | file://:0:0:0:0 | | IntPtr! | | file://:0:0:0:0 | delegate* unmanaged | 0 | file://:0:0:0:0 | | IntPtr! | -| file://:0:0:0:0 | delegate* unmanaged | 0 | file://:0:0:0:0 | | NoGCRegionCallbackFinalizerWorkItem*! | -| file://:0:0:0:0 | delegate* unmanaged | 0 | file://:0:0:0:0 | | Void*! | -| file://:0:0:0:0 | delegate* unmanaged | 1 | file://:0:0:0:0 | `1 | byte*! | -| file://:0:0:0:0 | delegate* unmanaged | 0 | file://:0:0:0:0 | | Void*! | -| file://:0:0:0:0 | delegate* unmanaged | 1 | file://:0:0:0:0 | `1 | Void*! | -| file://:0:0:0:0 | delegate* unmanaged | 2 | file://:0:0:0:0 | `2 | Void*! | -| file://:0:0:0:0 | delegate* unmanaged | 3 | file://:0:0:0:0 | `3 | GCConfigurationType! | -| file://:0:0:0:0 | delegate* unmanaged | 4 | file://:0:0:0:0 | `4 | long! | invocation | FunctionPointer.cs:17:21:17:43 | function pointer call | | FunctionPointer.cs:23:13:23:44 | function pointer call | diff --git a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected index e4cf0bb2673..ef31681f96c 100644 --- a/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected @@ -1162,6 +1162,54 @@ edges | K.cs:8:22:8:22 | access to local variable o : String | K.cs:8:9:8:15 | [post] access to field Strings : String[] [element] : String | provenance | | | K.cs:13:14:13:20 | access to field Strings : String[] [element] : String | K.cs:13:14:13:23 | access to array element | provenance | | | K.cs:13:14:13:20 | access to field Strings : String[] [element] : String | K.cs:13:14:13:23 | access to array element | provenance | | +| L.cs:17:9:17:10 | [post] access to local variable d1 : Object [dynamic property p1] : String | L.cs:18:14:18:15 | access to local variable d1 : Object [dynamic property p1] : String | provenance | | +| L.cs:17:9:17:10 | [post] access to local variable d1 : Object [dynamic property p1] : String | L.cs:18:14:18:15 | access to local variable d1 : Object [dynamic property p1] : String | provenance | | +| L.cs:17:17:17:33 | call to method Source : String | L.cs:17:9:17:10 | [post] access to local variable d1 : Object [dynamic property p1] : String | provenance | | +| L.cs:17:17:17:33 | call to method Source : String | L.cs:17:9:17:10 | [post] access to local variable d1 : Object [dynamic property p1] : String | provenance | | +| L.cs:18:14:18:15 | access to local variable d1 : Object [dynamic property p1] : String | L.cs:18:14:18:18 | dynamic access to member p1 | provenance | | +| L.cs:18:14:18:15 | access to local variable d1 : Object [dynamic property p1] : String | L.cs:18:14:18:18 | dynamic access to member p1 | provenance | | +| L.cs:22:9:22:10 | [post] access to local variable d2 : Object [dynamic property p2] : String | L.cs:23:16:23:17 | (...) ... : L [dynamic property p2] : String | provenance | | +| L.cs:22:9:22:10 | [post] access to local variable d2 : Object [dynamic property p2] : String | L.cs:23:16:23:17 | (...) ... : L [dynamic property p2] : String | provenance | | +| L.cs:22:17:22:33 | call to method Source : String | L.cs:22:9:22:10 | [post] access to local variable d2 : Object [dynamic property p2] : String | provenance | | +| L.cs:22:17:22:33 | call to method Source : String | L.cs:22:9:22:10 | [post] access to local variable d2 : Object [dynamic property p2] : String | provenance | | +| L.cs:23:11:23:12 | access to local variable l2 : L [dynamic property p2] : String | L.cs:24:14:24:15 | access to local variable l2 : L [dynamic property p2] : String | provenance | | +| L.cs:23:11:23:12 | access to local variable l2 : L [dynamic property p2] : String | L.cs:24:14:24:15 | access to local variable l2 : L [dynamic property p2] : String | provenance | | +| L.cs:23:16:23:17 | (...) ... : L [dynamic property p2] : String | L.cs:23:11:23:12 | access to local variable l2 : L [dynamic property p2] : String | provenance | | +| L.cs:23:16:23:17 | (...) ... : L [dynamic property p2] : String | L.cs:23:11:23:12 | access to local variable l2 : L [dynamic property p2] : String | provenance | | +| L.cs:24:14:24:15 | access to local variable l2 : L [dynamic property p2] : String | L.cs:24:14:24:18 | access to property p2 | provenance | | +| L.cs:24:14:24:15 | access to local variable l2 : L [dynamic property p2] : String | L.cs:24:14:24:18 | access to property p2 | provenance | | +| L.cs:27:9:27:12 | [post] this access : L [property p3] : String | L.cs:28:17:28:18 | access to local variable d3 : L [property p3] : String | provenance | | +| L.cs:27:9:27:12 | [post] this access : L [property p3] : String | L.cs:28:17:28:18 | access to local variable d3 : L [property p3] : String | provenance | | +| L.cs:27:19:27:35 | call to method Source : String | L.cs:27:9:27:12 | [post] this access : L [property p3] : String | provenance | | +| L.cs:27:19:27:35 | call to method Source : String | L.cs:27:9:27:12 | [post] this access : L [property p3] : String | provenance | | +| L.cs:28:17:28:18 | access to local variable d3 : L [property p3] : String | L.cs:29:14:29:15 | access to local variable d3 : L [property p3] : String | provenance | | +| L.cs:28:17:28:18 | access to local variable d3 : L [property p3] : String | L.cs:29:14:29:15 | access to local variable d3 : L [property p3] : String | provenance | | +| L.cs:29:14:29:15 | access to local variable d3 : L [property p3] : String | L.cs:29:14:29:18 | dynamic access to member p3 | provenance | | +| L.cs:29:14:29:15 | access to local variable d3 : L [property p3] : String | L.cs:29:14:29:18 | dynamic access to member p3 | provenance | | +| L.cs:33:9:33:10 | [post] access to local variable d4 : Object [dynamic property f1] : String | L.cs:34:14:34:15 | access to local variable d4 : Object [dynamic property f1] : String | provenance | | +| L.cs:33:9:33:10 | [post] access to local variable d4 : Object [dynamic property f1] : String | L.cs:34:14:34:15 | access to local variable d4 : Object [dynamic property f1] : String | provenance | | +| L.cs:33:17:33:33 | call to method Source : String | L.cs:33:9:33:10 | [post] access to local variable d4 : Object [dynamic property f1] : String | provenance | | +| L.cs:33:17:33:33 | call to method Source : String | L.cs:33:9:33:10 | [post] access to local variable d4 : Object [dynamic property f1] : String | provenance | | +| L.cs:34:14:34:15 | access to local variable d4 : Object [dynamic property f1] : String | L.cs:34:14:34:18 | dynamic access to member f1 | provenance | | +| L.cs:34:14:34:15 | access to local variable d4 : Object [dynamic property f1] : String | L.cs:34:14:34:18 | dynamic access to member f1 | provenance | | +| L.cs:38:9:38:10 | [post] access to local variable d5 : Object [dynamic property f2] : String | L.cs:39:16:39:17 | (...) ... : L [dynamic property f2] : String | provenance | | +| L.cs:38:9:38:10 | [post] access to local variable d5 : Object [dynamic property f2] : String | L.cs:39:16:39:17 | (...) ... : L [dynamic property f2] : String | provenance | | +| L.cs:38:17:38:33 | call to method Source : String | L.cs:38:9:38:10 | [post] access to local variable d5 : Object [dynamic property f2] : String | provenance | | +| L.cs:38:17:38:33 | call to method Source : String | L.cs:38:9:38:10 | [post] access to local variable d5 : Object [dynamic property f2] : String | provenance | | +| L.cs:39:11:39:12 | access to local variable l5 : L [dynamic property f2] : String | L.cs:40:14:40:15 | access to local variable l5 : L [dynamic property f2] : String | provenance | | +| L.cs:39:11:39:12 | access to local variable l5 : L [dynamic property f2] : String | L.cs:40:14:40:15 | access to local variable l5 : L [dynamic property f2] : String | provenance | | +| L.cs:39:16:39:17 | (...) ... : L [dynamic property f2] : String | L.cs:39:11:39:12 | access to local variable l5 : L [dynamic property f2] : String | provenance | | +| L.cs:39:16:39:17 | (...) ... : L [dynamic property f2] : String | L.cs:39:11:39:12 | access to local variable l5 : L [dynamic property f2] : String | provenance | | +| L.cs:40:14:40:15 | access to local variable l5 : L [dynamic property f2] : String | L.cs:40:14:40:18 | access to field f2 | provenance | | +| L.cs:40:14:40:15 | access to local variable l5 : L [dynamic property f2] : String | L.cs:40:14:40:18 | access to field f2 | provenance | | +| L.cs:43:9:43:12 | [post] this access : L [field f3] : String | L.cs:44:17:44:18 | access to local variable d6 : L [field f3] : String | provenance | | +| L.cs:43:9:43:12 | [post] this access : L [field f3] : String | L.cs:44:17:44:18 | access to local variable d6 : L [field f3] : String | provenance | | +| L.cs:43:19:43:35 | call to method Source : String | L.cs:43:9:43:12 | [post] this access : L [field f3] : String | provenance | | +| L.cs:43:19:43:35 | call to method Source : String | L.cs:43:9:43:12 | [post] this access : L [field f3] : String | provenance | | +| L.cs:44:17:44:18 | access to local variable d6 : L [field f3] : String | L.cs:45:14:45:15 | access to local variable d6 : L [field f3] : String | provenance | | +| L.cs:44:17:44:18 | access to local variable d6 : L [field f3] : String | L.cs:45:14:45:15 | access to local variable d6 : L [field f3] : String | provenance | | +| L.cs:45:14:45:15 | access to local variable d6 : L [field f3] : String | L.cs:45:14:45:18 | dynamic access to member f3 | provenance | | +| L.cs:45:14:45:15 | access to local variable d6 : L [field f3] : String | L.cs:45:14:45:18 | dynamic access to member f3 | provenance | | nodes | A.cs:5:13:5:13 | access to local variable c : C | semmle.label | access to local variable c : C | | A.cs:5:13:5:13 | access to local variable c : C | semmle.label | access to local variable c : C | @@ -2415,6 +2463,66 @@ nodes | K.cs:13:14:13:20 | access to field Strings : String[] [element] : String | semmle.label | access to field Strings : String[] [element] : String | | K.cs:13:14:13:23 | access to array element | semmle.label | access to array element | | K.cs:13:14:13:23 | access to array element | semmle.label | access to array element | +| L.cs:17:9:17:10 | [post] access to local variable d1 : Object [dynamic property p1] : String | semmle.label | [post] access to local variable d1 : Object [dynamic property p1] : String | +| L.cs:17:9:17:10 | [post] access to local variable d1 : Object [dynamic property p1] : String | semmle.label | [post] access to local variable d1 : Object [dynamic property p1] : String | +| L.cs:17:17:17:33 | call to method Source : String | semmle.label | call to method Source : String | +| L.cs:17:17:17:33 | call to method Source : String | semmle.label | call to method Source : String | +| L.cs:18:14:18:15 | access to local variable d1 : Object [dynamic property p1] : String | semmle.label | access to local variable d1 : Object [dynamic property p1] : String | +| L.cs:18:14:18:15 | access to local variable d1 : Object [dynamic property p1] : String | semmle.label | access to local variable d1 : Object [dynamic property p1] : String | +| L.cs:18:14:18:18 | dynamic access to member p1 | semmle.label | dynamic access to member p1 | +| L.cs:18:14:18:18 | dynamic access to member p1 | semmle.label | dynamic access to member p1 | +| L.cs:22:9:22:10 | [post] access to local variable d2 : Object [dynamic property p2] : String | semmle.label | [post] access to local variable d2 : Object [dynamic property p2] : String | +| L.cs:22:9:22:10 | [post] access to local variable d2 : Object [dynamic property p2] : String | semmle.label | [post] access to local variable d2 : Object [dynamic property p2] : String | +| L.cs:22:17:22:33 | call to method Source : String | semmle.label | call to method Source : String | +| L.cs:22:17:22:33 | call to method Source : String | semmle.label | call to method Source : String | +| L.cs:23:11:23:12 | access to local variable l2 : L [dynamic property p2] : String | semmle.label | access to local variable l2 : L [dynamic property p2] : String | +| L.cs:23:11:23:12 | access to local variable l2 : L [dynamic property p2] : String | semmle.label | access to local variable l2 : L [dynamic property p2] : String | +| L.cs:23:16:23:17 | (...) ... : L [dynamic property p2] : String | semmle.label | (...) ... : L [dynamic property p2] : String | +| L.cs:23:16:23:17 | (...) ... : L [dynamic property p2] : String | semmle.label | (...) ... : L [dynamic property p2] : String | +| L.cs:24:14:24:15 | access to local variable l2 : L [dynamic property p2] : String | semmle.label | access to local variable l2 : L [dynamic property p2] : String | +| L.cs:24:14:24:15 | access to local variable l2 : L [dynamic property p2] : String | semmle.label | access to local variable l2 : L [dynamic property p2] : String | +| L.cs:24:14:24:18 | access to property p2 | semmle.label | access to property p2 | +| L.cs:24:14:24:18 | access to property p2 | semmle.label | access to property p2 | +| L.cs:27:9:27:12 | [post] this access : L [property p3] : String | semmle.label | [post] this access : L [property p3] : String | +| L.cs:27:9:27:12 | [post] this access : L [property p3] : String | semmle.label | [post] this access : L [property p3] : String | +| L.cs:27:19:27:35 | call to method Source : String | semmle.label | call to method Source : String | +| L.cs:27:19:27:35 | call to method Source : String | semmle.label | call to method Source : String | +| L.cs:28:17:28:18 | access to local variable d3 : L [property p3] : String | semmle.label | access to local variable d3 : L [property p3] : String | +| L.cs:28:17:28:18 | access to local variable d3 : L [property p3] : String | semmle.label | access to local variable d3 : L [property p3] : String | +| L.cs:29:14:29:15 | access to local variable d3 : L [property p3] : String | semmle.label | access to local variable d3 : L [property p3] : String | +| L.cs:29:14:29:15 | access to local variable d3 : L [property p3] : String | semmle.label | access to local variable d3 : L [property p3] : String | +| L.cs:29:14:29:18 | dynamic access to member p3 | semmle.label | dynamic access to member p3 | +| L.cs:29:14:29:18 | dynamic access to member p3 | semmle.label | dynamic access to member p3 | +| L.cs:33:9:33:10 | [post] access to local variable d4 : Object [dynamic property f1] : String | semmle.label | [post] access to local variable d4 : Object [dynamic property f1] : String | +| L.cs:33:9:33:10 | [post] access to local variable d4 : Object [dynamic property f1] : String | semmle.label | [post] access to local variable d4 : Object [dynamic property f1] : String | +| L.cs:33:17:33:33 | call to method Source : String | semmle.label | call to method Source : String | +| L.cs:33:17:33:33 | call to method Source : String | semmle.label | call to method Source : String | +| L.cs:34:14:34:15 | access to local variable d4 : Object [dynamic property f1] : String | semmle.label | access to local variable d4 : Object [dynamic property f1] : String | +| L.cs:34:14:34:15 | access to local variable d4 : Object [dynamic property f1] : String | semmle.label | access to local variable d4 : Object [dynamic property f1] : String | +| L.cs:34:14:34:18 | dynamic access to member f1 | semmle.label | dynamic access to member f1 | +| L.cs:34:14:34:18 | dynamic access to member f1 | semmle.label | dynamic access to member f1 | +| L.cs:38:9:38:10 | [post] access to local variable d5 : Object [dynamic property f2] : String | semmle.label | [post] access to local variable d5 : Object [dynamic property f2] : String | +| L.cs:38:9:38:10 | [post] access to local variable d5 : Object [dynamic property f2] : String | semmle.label | [post] access to local variable d5 : Object [dynamic property f2] : String | +| L.cs:38:17:38:33 | call to method Source : String | semmle.label | call to method Source : String | +| L.cs:38:17:38:33 | call to method Source : String | semmle.label | call to method Source : String | +| L.cs:39:11:39:12 | access to local variable l5 : L [dynamic property f2] : String | semmle.label | access to local variable l5 : L [dynamic property f2] : String | +| L.cs:39:11:39:12 | access to local variable l5 : L [dynamic property f2] : String | semmle.label | access to local variable l5 : L [dynamic property f2] : String | +| L.cs:39:16:39:17 | (...) ... : L [dynamic property f2] : String | semmle.label | (...) ... : L [dynamic property f2] : String | +| L.cs:39:16:39:17 | (...) ... : L [dynamic property f2] : String | semmle.label | (...) ... : L [dynamic property f2] : String | +| L.cs:40:14:40:15 | access to local variable l5 : L [dynamic property f2] : String | semmle.label | access to local variable l5 : L [dynamic property f2] : String | +| L.cs:40:14:40:15 | access to local variable l5 : L [dynamic property f2] : String | semmle.label | access to local variable l5 : L [dynamic property f2] : String | +| L.cs:40:14:40:18 | access to field f2 | semmle.label | access to field f2 | +| L.cs:40:14:40:18 | access to field f2 | semmle.label | access to field f2 | +| L.cs:43:9:43:12 | [post] this access : L [field f3] : String | semmle.label | [post] this access : L [field f3] : String | +| L.cs:43:9:43:12 | [post] this access : L [field f3] : String | semmle.label | [post] this access : L [field f3] : String | +| L.cs:43:19:43:35 | call to method Source : String | semmle.label | call to method Source : String | +| L.cs:43:19:43:35 | call to method Source : String | semmle.label | call to method Source : String | +| L.cs:44:17:44:18 | access to local variable d6 : L [field f3] : String | semmle.label | access to local variable d6 : L [field f3] : String | +| L.cs:44:17:44:18 | access to local variable d6 : L [field f3] : String | semmle.label | access to local variable d6 : L [field f3] : String | +| L.cs:45:14:45:15 | access to local variable d6 : L [field f3] : String | semmle.label | access to local variable d6 : L [field f3] : String | +| L.cs:45:14:45:15 | access to local variable d6 : L [field f3] : String | semmle.label | access to local variable d6 : L [field f3] : String | +| L.cs:45:14:45:18 | dynamic access to member f3 | semmle.label | dynamic access to member f3 | +| L.cs:45:14:45:18 | dynamic access to member f3 | semmle.label | dynamic access to member f3 | subpaths | A.cs:6:24:6:24 | access to local variable c : C | A.cs:147:32:147:32 | c : C | A.cs:149:20:149:27 | object creation of type B : B [field c] : C | A.cs:6:17:6:25 | call to method Make : B [field c] : C | | A.cs:6:24:6:24 | access to local variable c : C | A.cs:147:32:147:32 | c : C | A.cs:149:20:149:27 | object creation of type B : B [field c] : C | A.cs:6:17:6:25 | call to method Make : B [field c] : C | @@ -2672,3 +2780,15 @@ testFailures | J.cs:125:14:125:17 | (...) ... | J.cs:119:20:119:34 | call to method Source : Int32 | J.cs:125:14:125:17 | (...) ... | $@ | J.cs:119:20:119:34 | call to method Source : Int32 | call to method Source : Int32 | | K.cs:13:14:13:23 | access to array element | K.cs:7:17:7:33 | call to method Source : String | K.cs:13:14:13:23 | access to array element | $@ | K.cs:7:17:7:33 | call to method Source : String | call to method Source : String | | K.cs:13:14:13:23 | access to array element | K.cs:7:17:7:33 | call to method Source : String | K.cs:13:14:13:23 | access to array element | $@ | K.cs:7:17:7:33 | call to method Source : String | call to method Source : String | +| L.cs:18:14:18:18 | dynamic access to member p1 | L.cs:17:17:17:33 | call to method Source : String | L.cs:18:14:18:18 | dynamic access to member p1 | $@ | L.cs:17:17:17:33 | call to method Source : String | call to method Source : String | +| L.cs:18:14:18:18 | dynamic access to member p1 | L.cs:17:17:17:33 | call to method Source : String | L.cs:18:14:18:18 | dynamic access to member p1 | $@ | L.cs:17:17:17:33 | call to method Source : String | call to method Source : String | +| L.cs:24:14:24:18 | access to property p2 | L.cs:22:17:22:33 | call to method Source : String | L.cs:24:14:24:18 | access to property p2 | $@ | L.cs:22:17:22:33 | call to method Source : String | call to method Source : String | +| L.cs:24:14:24:18 | access to property p2 | L.cs:22:17:22:33 | call to method Source : String | L.cs:24:14:24:18 | access to property p2 | $@ | L.cs:22:17:22:33 | call to method Source : String | call to method Source : String | +| L.cs:29:14:29:18 | dynamic access to member p3 | L.cs:27:19:27:35 | call to method Source : String | L.cs:29:14:29:18 | dynamic access to member p3 | $@ | L.cs:27:19:27:35 | call to method Source : String | call to method Source : String | +| L.cs:29:14:29:18 | dynamic access to member p3 | L.cs:27:19:27:35 | call to method Source : String | L.cs:29:14:29:18 | dynamic access to member p3 | $@ | L.cs:27:19:27:35 | call to method Source : String | call to method Source : String | +| L.cs:34:14:34:18 | dynamic access to member f1 | L.cs:33:17:33:33 | call to method Source : String | L.cs:34:14:34:18 | dynamic access to member f1 | $@ | L.cs:33:17:33:33 | call to method Source : String | call to method Source : String | +| L.cs:34:14:34:18 | dynamic access to member f1 | L.cs:33:17:33:33 | call to method Source : String | L.cs:34:14:34:18 | dynamic access to member f1 | $@ | L.cs:33:17:33:33 | call to method Source : String | call to method Source : String | +| L.cs:40:14:40:18 | access to field f2 | L.cs:38:17:38:33 | call to method Source : String | L.cs:40:14:40:18 | access to field f2 | $@ | L.cs:38:17:38:33 | call to method Source : String | call to method Source : String | +| L.cs:40:14:40:18 | access to field f2 | L.cs:38:17:38:33 | call to method Source : String | L.cs:40:14:40:18 | access to field f2 | $@ | L.cs:38:17:38:33 | call to method Source : String | call to method Source : String | +| L.cs:45:14:45:18 | dynamic access to member f3 | L.cs:43:19:43:35 | call to method Source : String | L.cs:45:14:45:18 | dynamic access to member f3 | $@ | L.cs:43:19:43:35 | call to method Source : String | call to method Source : String | +| L.cs:45:14:45:18 | dynamic access to member f3 | L.cs:43:19:43:35 | call to method Source : String | L.cs:45:14:45:18 | dynamic access to member f3 | $@ | L.cs:43:19:43:35 | call to method Source : String | call to method Source : String | diff --git a/csharp/ql/test/library-tests/dataflow/fields/L.cs b/csharp/ql/test/library-tests/dataflow/fields/L.cs new file mode 100644 index 00000000000..7bc53f45133 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/fields/L.cs @@ -0,0 +1,51 @@ +using System; + +public class L +{ + public string p1 { get; set; } + public string p2 { get; set; } + public string p3 { get; set; } + + private string f1; + private string f2; + private string f3; + + private void M1() + { + // dynamic property write followed by dynamic property read + dynamic d1 = this; + d1.p1 = Source(1); + Sink(d1.p1); // $ hasValueFlow=1 + + // dynamic property write followed by static property read + dynamic d2 = this; + d2.p2 = Source(2); + L l2 = d2; + Sink(l2.p2); // $ hasValueFlow=2 + + // static property write followed by dynamic property read + this.p3 = Source(3); + dynamic d3 = this; + Sink(d3.p3); // $ hasValueFlow=3 + + // dynamic property write followed by dynamic field read + dynamic d4 = this; + d4.f1 = Source(4); + Sink(d4.f1); // $ hasValueFlow=4 + + // dynamic property write followed by static field read + dynamic d5 = this; + d5.f2 = Source(5); + L l5 = d5; + Sink(l5.f2); // $ hasValueFlow=5 + + // static field write followed by dynamic property read + this.f3 = Source(6); + dynamic d6 = this; + Sink(d6.f3); // $ hasValueFlow=6 + } + + public static void Sink(object o) { } + + static T Source(object source) => throw null; +} diff --git a/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.expected b/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.expected index 7b6e623288f..033c83df3bd 100644 --- a/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.expected +++ b/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.expected @@ -256,6 +256,12 @@ sink | Microsoft.EntityFrameworkCore;RelationalDatabaseFacadeExtensions;ExecuteSqlRawAsync;(Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade,System.String,System.Object[]);Argument[1];sql-injection;manual | | Microsoft.EntityFrameworkCore;RelationalDatabaseFacadeExtensions;ExecuteSqlRawAsync;(Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade,System.String,System.Threading.CancellationToken);Argument[1];sql-injection;manual | | Microsoft.EntityFrameworkCore;RelationalQueryableExtensions;FromSqlRaw;(Microsoft.EntityFrameworkCore.DbSet,System.String,System.Object[]);Argument[1];sql-injection;manual | +| Microsoft.JSInterop;JSRuntimeExtensions;InvokeAsync;(Microsoft.JSInterop.IJSRuntime,System.String,System.Object[]);Argument[1];js-injection;manual | +| Microsoft.JSInterop;JSRuntimeExtensions;InvokeAsync;(Microsoft.JSInterop.IJSRuntime,System.String,System.Threading.CancellationToken,System.Object[]);Argument[1];js-injection;manual | +| Microsoft.JSInterop;JSRuntimeExtensions;InvokeAsync;(Microsoft.JSInterop.IJSRuntime,System.String,System.TimeSpan,System.Object[]);Argument[1];js-injection;manual | +| Microsoft.JSInterop;JSRuntimeExtensions;InvokeVoidAsync;(Microsoft.JSInterop.IJSRuntime,System.String,System.Object[]);Argument[1];js-injection;manual | +| Microsoft.JSInterop;JSRuntimeExtensions;InvokeVoidAsync;(Microsoft.JSInterop.IJSRuntime,System.String,System.Threading.CancellationToken,System.Object[]);Argument[1];js-injection;manual | +| Microsoft.JSInterop;JSRuntimeExtensions;InvokeVoidAsync;(Microsoft.JSInterop.IJSRuntime,System.String,System.TimeSpan,System.Object[]);Argument[1];js-injection;manual | | ServiceStack.Messaging;BackgroundMqClient;SendAllOneWay;(System.Collections.Generic.IEnumerable);Argument[1].Element;file-content-store;manual | | ServiceStack.Messaging;BackgroundMqClient;SendOneWay;(System.Object);Argument[0];file-content-store;manual | | ServiceStack.Messaging;BackgroundMqClient;SendOneWay;(System.String,System.Object);Argument[1];file-content-store;manual | @@ -1693,6 +1699,8 @@ summary | Microsoft.AspNetCore.WebUtilities;HttpResponseStreamWriter;WriteLineAsync;(System.String);Argument[0];ReturnValue;taint;df-generated | | Microsoft.AspNetCore.WebUtilities;HttpResponseStreamWriter;WriteLineAsync;(System.String);Argument[this];ReturnValue;taint;df-generated | | Microsoft.AspNetCore.WebUtilities;HttpResponseStreamWriter;get_Encoding;();Argument[this];ReturnValue;taint;df-generated | +| Microsoft.AspNetCore.WebUtilities;QueryHelpers;ParseNullableQuery;(System.String);Argument[0];ReturnValue;taint;manual | +| Microsoft.AspNetCore.WebUtilities;QueryHelpers;ParseQuery;(System.String);Argument[0];ReturnValue;taint;manual | | Microsoft.AspNetCore;WebHost;Start;(Microsoft.AspNetCore.Http.RequestDelegate);Argument[0];Argument[0].Parameter[delegate-self];value;hq-generated | | Microsoft.AspNetCore;WebHost;Start;(System.Action);Argument[0];Argument[0].Parameter[delegate-self];value;hq-generated | | Microsoft.AspNetCore;WebHost;Start;(System.String,Microsoft.AspNetCore.Http.RequestDelegate);Argument[1];Argument[1].Parameter[delegate-self];value;hq-generated | @@ -18315,6 +18323,8 @@ summary | System.Web;HttpUtility;HtmlEncode;(System.String,System.IO.TextWriter);Argument[0];ReturnValue;taint;manual | | System.Web;HttpUtility;JavaScriptStringEncode;(System.String);Argument[0];ReturnValue;taint;manual | | System.Web;HttpUtility;JavaScriptStringEncode;(System.String,System.Boolean);Argument[0];ReturnValue;taint;manual | +| System.Web;HttpUtility;ParseQueryString;(System.String);Argument[0];ReturnValue;taint;manual | +| System.Web;HttpUtility;ParseQueryString;(System.String,System.Text.Encoding);Argument[0];ReturnValue;taint;manual | | System.Web;HttpUtility;UrlEncode;(System.Byte[]);Argument[0];ReturnValue;taint;manual | | System.Web;HttpUtility;UrlEncode;(System.Byte[],System.Int32,System.Int32);Argument[0];ReturnValue;taint;manual | | System.Web;HttpUtility;UrlEncode;(System.String);Argument[0];ReturnValue;taint;manual | @@ -51120,8 +51130,6 @@ neutral | System.Web;AspNetHostingPermissionAttribute;CreatePermission;();summary;df-generated | | System.Web;HtmlString;ToHtmlString;();summary;df-generated | | System.Web;HttpUtility;HtmlDecode;(System.String,System.IO.TextWriter);summary;df-generated | -| System.Web;HttpUtility;ParseQueryString;(System.String);summary;df-generated | -| System.Web;HttpUtility;ParseQueryString;(System.String,System.Text.Encoding);summary;df-generated | | System.Web;HttpUtility;UrlDecode;(System.Byte[],System.Int32,System.Int32,System.Text.Encoding);summary;df-generated | | System.Web;HttpUtility;UrlDecode;(System.Byte[],System.Text.Encoding);summary;df-generated | | System.Web;HttpUtility;UrlDecode;(System.String);summary;df-generated | diff --git a/csharp/ql/test/library-tests/dataflow/library/FlowSummariesFiltered.expected b/csharp/ql/test/library-tests/dataflow/library/FlowSummariesFiltered.expected index 6fb375dae85..199ccee5a50 100644 --- a/csharp/ql/test/library-tests/dataflow/library/FlowSummariesFiltered.expected +++ b/csharp/ql/test/library-tests/dataflow/library/FlowSummariesFiltered.expected @@ -650,6 +650,8 @@ | Microsoft.AspNetCore.WebUtilities;FileBufferingReadStream;FileBufferingReadStream;(System.IO.Stream,System.Int32,System.Nullable,System.Func);Argument[3];Argument[3].Parameter[delegate-self];value;hq-generated | | Microsoft.AspNetCore.WebUtilities;FileBufferingReadStream;FileBufferingReadStream;(System.IO.Stream,System.Int32,System.Nullable,System.Func,System.Buffers.ArrayPool);Argument[3];Argument[3].Parameter[delegate-self];value;hq-generated | | Microsoft.AspNetCore.WebUtilities;FileBufferingWriteStream;FileBufferingWriteStream;(System.Int32,System.Nullable,System.Func);Argument[2];Argument[2].Parameter[delegate-self];value;hq-generated | +| Microsoft.AspNetCore.WebUtilities;QueryHelpers;ParseNullableQuery;(System.String);Argument[0];ReturnValue;taint;manual | +| Microsoft.AspNetCore.WebUtilities;QueryHelpers;ParseQuery;(System.String);Argument[0];ReturnValue;taint;manual | | Microsoft.AspNetCore;WebHost;Start;(Microsoft.AspNetCore.Http.RequestDelegate);Argument[0];Argument[0].Parameter[delegate-self];value;hq-generated | | Microsoft.AspNetCore;WebHost;Start;(System.Action);Argument[0];Argument[0].Parameter[delegate-self];value;hq-generated | | Microsoft.AspNetCore;WebHost;Start;(System.String,Microsoft.AspNetCore.Http.RequestDelegate);Argument[1];Argument[1].Parameter[delegate-self];value;hq-generated | @@ -13988,6 +13990,8 @@ | System.Web;HttpUtility;HtmlEncode;(System.String,System.IO.TextWriter);Argument[0];ReturnValue;taint;manual | | System.Web;HttpUtility;JavaScriptStringEncode;(System.String);Argument[0];ReturnValue;taint;manual | | System.Web;HttpUtility;JavaScriptStringEncode;(System.String,System.Boolean);Argument[0];ReturnValue;taint;manual | +| System.Web;HttpUtility;ParseQueryString;(System.String);Argument[0];ReturnValue;taint;manual | +| System.Web;HttpUtility;ParseQueryString;(System.String,System.Text.Encoding);Argument[0];ReturnValue;taint;manual | | System.Web;HttpUtility;UrlEncode;(System.Byte[]);Argument[0];ReturnValue;taint;manual | | System.Web;HttpUtility;UrlEncode;(System.Byte[],System.Int32,System.Int32);Argument[0];ReturnValue;taint;manual | | System.Web;HttpUtility;UrlEncode;(System.String);Argument[0];ReturnValue;taint;manual | diff --git a/csharp/ql/test/library-tests/tuples/tuples.expected b/csharp/ql/test/library-tests/tuples/tuples.expected index c2042bfb14a..cb39eb0ca3b 100644 --- a/csharp/ql/test/library-tests/tuples/tuples.expected +++ b/csharp/ql/test/library-tests/tuples/tuples.expected @@ -8,13 +8,11 @@ members2 | tuple.cs:7:17:7:22 | (Int32,Int32) | ValueTuple | Equals(object, IEqualityComparer) | | tuple.cs:7:17:7:22 | (Int32,Int32) | ValueTuple | GetHashCode() | | tuple.cs:7:17:7:22 | (Int32,Int32) | ValueTuple | GetHashCode(IEqualityComparer) | -| tuple.cs:7:17:7:22 | (Int32,Int32) | ValueTuple | GetHashCodeCore(IEqualityComparer) | | tuple.cs:7:17:7:22 | (Int32,Int32) | ValueTuple | Item1 | | tuple.cs:7:17:7:22 | (Int32,Int32) | ValueTuple | Item2 | | tuple.cs:7:17:7:22 | (Int32,Int32) | ValueTuple | Item[int] | | tuple.cs:7:17:7:22 | (Int32,Int32) | ValueTuple | Length | | tuple.cs:7:17:7:22 | (Int32,Int32) | ValueTuple | ToString() | -| tuple.cs:7:17:7:22 | (Int32,Int32) | ValueTuple | ToStringEnd() | | tuple.cs:7:17:7:22 | (Int32,Int32) | ValueTuple | ValueTuple() | | tuple.cs:7:17:7:22 | (Int32,Int32) | ValueTuple | ValueTuple(int, int) | | tuple.cs:12:17:12:37 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | CompareTo((int, int, int, int, int, int, int)) | @@ -25,7 +23,6 @@ members2 | tuple.cs:12:17:12:37 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Equals(object, IEqualityComparer) | | tuple.cs:12:17:12:37 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | GetHashCode() | | tuple.cs:12:17:12:37 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | GetHashCode(IEqualityComparer) | -| tuple.cs:12:17:12:37 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | GetHashCodeCore(IEqualityComparer) | | tuple.cs:12:17:12:37 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Item1 | | tuple.cs:12:17:12:37 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Item2 | | tuple.cs:12:17:12:37 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Item3 | @@ -36,7 +33,6 @@ members2 | tuple.cs:12:17:12:37 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Item[int] | | tuple.cs:12:17:12:37 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Length | | tuple.cs:12:17:12:37 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | ToString() | -| tuple.cs:12:17:12:37 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | ToStringEnd() | | tuple.cs:12:17:12:37 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | ValueTuple() | | tuple.cs:12:17:12:37 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | ValueTuple(int, int, int, int, int, int, int) | | tuple.cs:15:17:15:40 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | CompareTo((int, int, int, int, int, int, int, int)) | @@ -47,7 +43,6 @@ members2 | tuple.cs:15:17:15:40 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Equals(object, IEqualityComparer) | | tuple.cs:15:17:15:40 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | GetHashCode() | | tuple.cs:15:17:15:40 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | GetHashCode(IEqualityComparer) | -| tuple.cs:15:17:15:40 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | GetHashCodeCore(IEqualityComparer) | | tuple.cs:15:17:15:40 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Item1 | | tuple.cs:15:17:15:40 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Item2 | | tuple.cs:15:17:15:40 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Item3 | @@ -60,7 +55,6 @@ members2 | tuple.cs:15:17:15:40 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Length | | tuple.cs:15:17:15:40 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Rest | | tuple.cs:15:17:15:40 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | ToString() | -| tuple.cs:15:17:15:40 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | ToStringEnd() | | tuple.cs:15:17:15:40 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | ValueTuple() | | tuple.cs:15:17:15:40 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | ValueTuple(int, int, int, int, int, int, int, (int)) | | tuple.cs:18:17:18:47 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | CompareTo((int, int, int, int, int, int, int, int, int, int)) | @@ -71,7 +65,6 @@ members2 | tuple.cs:18:17:18:47 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Equals(object, IEqualityComparer) | | tuple.cs:18:17:18:47 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | GetHashCode() | | tuple.cs:18:17:18:47 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | GetHashCode(IEqualityComparer) | -| tuple.cs:18:17:18:47 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | GetHashCodeCore(IEqualityComparer) | | tuple.cs:18:17:18:47 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Item1 | | tuple.cs:18:17:18:47 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Item2 | | tuple.cs:18:17:18:47 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Item3 | @@ -86,6 +79,5 @@ members2 | tuple.cs:18:17:18:47 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Length | | tuple.cs:18:17:18:47 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | Rest | | tuple.cs:18:17:18:47 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | ToString() | -| tuple.cs:18:17:18:47 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | ToStringEnd() | | tuple.cs:18:17:18:47 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | ValueTuple() | | tuple.cs:18:17:18:47 | (Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32,Int32) | ValueTuple | ValueTuple(int, int, int, int, int, int, int, (int, int, int)) | diff --git a/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/IsNotOkayCall.expected b/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/IsNotOkayCall.expected new file mode 100644 index 00000000000..205022b7180 --- /dev/null +++ b/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/IsNotOkayCall.expected @@ -0,0 +1,4 @@ +| Quality.cs:26:19:26:26 | access to indexer | Call without target $@. | Quality.cs:26:19:26:26 | access to indexer | access to indexer | +| Quality.cs:29:21:29:27 | access to indexer | Call without target $@. | Quality.cs:29:21:29:27 | access to indexer | access to indexer | +| Quality.cs:32:9:32:21 | access to indexer | Call without target $@. | Quality.cs:32:9:32:21 | access to indexer | access to indexer | +| Quality.cs:34:21:34:25 | object creation of type null | Call without target $@. | Quality.cs:34:21:34:25 | object creation of type null | object creation of type null | diff --git a/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/IsNotOkayCall.ql b/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/IsNotOkayCall.ql new file mode 100644 index 00000000000..cbe7c82a4a1 --- /dev/null +++ b/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/IsNotOkayCall.ql @@ -0,0 +1,12 @@ +/** + * @id test/missing-call-target + * @kind problem + * @problem.severity warning + */ + +import csharp +import Telemetry.DatabaseQuality + +from Call call +where CallTargetStats::isNotOkCall(call) +select call, "Call without target $@.", call, call.toString() diff --git a/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/NoTarget.expected b/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/NoTarget.expected new file mode 100644 index 00000000000..84b6994e033 --- /dev/null +++ b/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/NoTarget.expected @@ -0,0 +1,15 @@ +| Quality.cs:8:9:8:19 | access to property MyProperty5 | Call without target $@. | Quality.cs:8:9:8:19 | access to property MyProperty5 | access to property MyProperty5 | +| Quality.cs:13:9:13:19 | access to property MyProperty1 | Call without target $@. | Quality.cs:13:9:13:19 | access to property MyProperty1 | access to property MyProperty1 | +| Quality.cs:14:24:14:34 | access to property MyProperty3 | Call without target $@. | Quality.cs:14:24:14:34 | access to property MyProperty3 | access to property MyProperty3 | +| Quality.cs:15:24:15:34 | access to property MyProperty3 | Call without target $@. | Quality.cs:15:24:15:34 | access to property MyProperty3 | access to property MyProperty3 | +| Quality.cs:15:24:15:46 | access to property MyProperty2 | Call without target $@. | Quality.cs:15:24:15:46 | access to property MyProperty2 | access to property MyProperty2 | +| Quality.cs:19:13:19:23 | access to property MyProperty4 | Call without target $@. | Quality.cs:19:13:19:23 | access to property MyProperty4 | access to property MyProperty4 | +| Quality.cs:20:13:20:23 | access to property MyProperty6 | Call without target $@. | Quality.cs:20:13:20:23 | access to property MyProperty6 | access to property MyProperty6 | +| Quality.cs:23:9:23:14 | access to event Event1 | Call without target $@. | Quality.cs:23:9:23:14 | access to event Event1 | access to event Event1 | +| Quality.cs:23:9:23:30 | delegate call | Call without target $@. | Quality.cs:23:9:23:30 | delegate call | delegate call | +| Quality.cs:26:19:26:26 | access to indexer | Call without target $@. | Quality.cs:26:19:26:26 | access to indexer | access to indexer | +| Quality.cs:29:21:29:27 | access to indexer | Call without target $@. | Quality.cs:29:21:29:27 | access to indexer | access to indexer | +| Quality.cs:32:9:32:21 | access to indexer | Call without target $@. | Quality.cs:32:9:32:21 | access to indexer | access to indexer | +| Quality.cs:34:21:34:25 | object creation of type null | Call without target $@. | Quality.cs:34:21:34:25 | object creation of type null | object creation of type null | +| Quality.cs:38:16:38:26 | access to property MyProperty2 | Call without target $@. | Quality.cs:38:16:38:26 | access to property MyProperty2 | access to property MyProperty2 | +| Quality.cs:50:20:50:26 | object creation of type T | Call without target $@. | Quality.cs:50:20:50:26 | object creation of type T | object creation of type T | diff --git a/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/NoTarget.ql b/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/NoTarget.ql new file mode 100644 index 00000000000..6aa56662a87 --- /dev/null +++ b/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/NoTarget.ql @@ -0,0 +1,12 @@ +/** + * @id test/missing-call-target + * @kind problem + * @problem.severity warning + */ + +import csharp +import Telemetry.DatabaseQuality + +from Call call +where not exists(call.getTarget()) +select call, "Call without target $@.", call, call.toString() diff --git a/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/Quality.cs b/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/Quality.cs new file mode 100644 index 00000000000..c3ec759d687 --- /dev/null +++ b/csharp/ql/test/query-tests/Telemetry/DatabaseQuality/Quality.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; + +public class Test +{ + static Test() + { + MyProperty5 = 42; + } + + public Test() + { + MyProperty1 = 42; + var x = nameof(MyProperty3); + var y = nameof(MyProperty3.MyProperty2); + + new Test() + { + MyProperty4 = { 1, 2, 3 }, + MyProperty6 = { [1] = "" } + }; + + Event1.Invoke(this, 5); + + var str = "abcd"; + var sub = str[..3]; // TODO: this is not an indexer call, but rather a `str.Substring(0, 3)` call. + + Span sp = null; + var slice = sp[..3]; // TODO: this is not an indexer call, but rather a `sp.Slice(0, 3)` call. + + Span guidBytes = stackalloc byte[16]; + guidBytes[08] = 1; // TODO: this indexer call has no target, because the target is a `ref` returning getter. + + new MyList([new(), new Test()]); // TODO: the `new()` call has no target, which is unexpected, as we know at compile time, that this is a `new Test()` call. + } + + public int MyProperty1 { get; } + public int MyProperty2 { get; } = 42; + public Test MyProperty3 { get; set; } + public List MyProperty4 { get; } + static int MyProperty5 { get; } + public Dictionary MyProperty6 { get; } + + public event EventHandler Event1; + + class Gen where T : new() + { + public static T Factory() + { + return new T(); + } + } + + class MyList + { + public MyList(IEnumerable init) { } + } +} diff --git a/csharp/ql/test/resources/stubs/System.Web.cs b/csharp/ql/test/resources/stubs/System.Web.cs index d876a83e318..d1942c07dc1 100644 --- a/csharp/ql/test/resources/stubs/System.Web.cs +++ b/csharp/ql/test/resources/stubs/System.Web.cs @@ -390,6 +390,8 @@ namespace System.Web.Script.Serialization public JavaScriptSerializer() => throw null; public JavaScriptSerializer(System.Web.Script.Serialization.JavaScriptTypeResolver resolver) => throw null; public object DeserializeObject(string input) => throw null; + public T Deserialize (string input) => throw null; + public object Deserialize(string input, Type targetType) => throw null; } // Generated from `System.Web.Script.Serialization.JavaScriptTypeResolver` in `System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35` diff --git a/docs/codeql/codeql-language-guides/codeql-for-go.rst b/docs/codeql/codeql-language-guides/codeql-for-go.rst index 360ff6bb82f..30799c146a8 100644 --- a/docs/codeql/codeql-language-guides/codeql-for-go.rst +++ b/docs/codeql/codeql-language-guides/codeql-for-go.rst @@ -12,6 +12,7 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat codeql-library-for-go abstract-syntax-tree-classes-for-working-with-go-programs modeling-data-flow-in-go-libraries + customizing-library-models-for-go - :doc:`Basic query for Go code `: Learn to write and run a simple CodeQL query. @@ -23,3 +24,5 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat - :doc:`Modeling data flow in Go libraries `: When analyzing a Go program, CodeQL does not examine the source code for external packages. To track the flow of untrusted data through a library, you can create a model of the library. + +- :doc:`Customizing library models for Go `: You can model frameworks and libraries that your codebase depends on using data extensions and publish them as CodeQL model packs. diff --git a/docs/codeql/codeql-language-guides/customizing-library-models-for-go.rst b/docs/codeql/codeql-language-guides/customizing-library-models-for-go.rst new file mode 100644 index 00000000000..c5b74ccd73a --- /dev/null +++ b/docs/codeql/codeql-language-guides/customizing-library-models-for-go.rst @@ -0,0 +1,427 @@ +.. _customizing-library-models-for-go: + +Customizing library models for Go +================================= + +You can model the methods and functions that control data flow in any framework or library. This is especially useful for custom frameworks or niche libraries, that are not supported by the standard CodeQL libraries. + +.. include:: ../reusables/beta-note-customizing-library-models.rst + +About this article +------------------ + +This article contains reference material about how to define custom models for sources, sinks, and flow summaries for Go dependencies in data extension files. + +About data extensions +--------------------- + +You can customize analysis by defining models (summaries, sinks, and sources) of your code's Go dependencies in data extension files. Each model defines the behavior of one or more elements of your library or framework, such as functions, methods, and fields. When you run dataflow analysis, these models expand the potential sources and sinks tracked by dataflow analysis and improve the precision of results. + +Most of the security queries search for paths from a source of untrusted input to a sink that represents a vulnerability. This is known as taint tracking. Each source is a starting point for dataflow analysis to track tainted data and each sink is an end point. + +Taint tracking queries also need to know how data can flow through elements that are not included in the source code. These are modeled as summaries. A summary model enables queries to synthesize the flow behavior through elements in dependency code that is not stored in your repository. + +Syntax used to define an element in an extension file +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Each model of an element is defined using a data extension where each tuple constitutes a model. +A data extension file to extend the standard Go queries included with CodeQL is a YAML file with the form: + +.. code-block:: yaml + + extensions: + - addsTo: + pack: codeql/go-all + extensible: + data: + - + - + - ... + +Each YAML file may contain one or more top-level extensions. + +- ``addsTo`` defines the CodeQL pack name and extensible predicate that the extension is injected into. +- ``data`` defines one or more rows of tuples that are injected as values into the extensible predicate. The number of columns and their types must match the definition of the extensible predicate. + +Data extensions use union semantics, which means that the tuples of all extensions for a single extensible predicate are combined, duplicates are removed, and all of the remaining tuples are queryable by referencing the extensible predicate. + +Publish data extension files in a CodeQL model pack to share +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can group one or more data extension files into a CodeQL model pack and publish it to the GitHub Container Registry. This makes it easy for anyone to download the model pack and use it to extend their analysis. For more information, see `Creating a CodeQL model pack `__ and `Publishing and using CodeQL packs `__ in the CodeQL CLI documentation. + +Extensible predicates used to create custom models in Go +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The CodeQL library for Go analysis exposes the following extensible predicates: + +- ``sourceModel(package, type, subtypes, name, signature, ext, output, kind, provenance)``. This is used to model sources of potentially tainted data. The ``kind`` of the sources defined using this predicate determine which threat model they are associated with. Different threat models can be used to customize the sources used in an analysis. For more information, see ":ref:`Threat models `." +- ``sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance)``. This is used to model sinks where tainted data may be used in a way that makes the code vulnerable. +- ``summaryModel(package, type, subtypes, name, signature, ext, input, output, kind, provenance)``. This is used to model flow through elements. +- ``neutralModel(package, type, name, signature, kind, provenance)``. This is similar to a summary model but used to model the flow of values that have only a minor impact on the dataflow analysis. Manual neutral models (those with a provenance such as ``manual`` or ``ai-manual``) can be used to override generated summary models (those with a provenance such as ``df-generated``), so that the summary model will be ignored. Other than that, neutral models have no effect. + +The extensible predicates are populated using the models defined in data extension files. + +Examples of custom model definitions +------------------------------------ + +The examples in this section are taken from the standard CodeQL Go query pack published by GitHub. They demonstrate how to add tuples to extend extensible predicates that are used by the standard queries. + +Example: Taint sink in the ``database/sql`` package +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This example shows how the Go query pack models the argument of the ``Prepare`` method as a SQL injection sink. +This is the ``Prepare`` method of the ``DB`` type in the ``database/sql`` package which creates a prepared statement. + +.. code-block:: go + + func Tainted(db *sql.DB, name string) { + stmt, err := db.Prepare("SELECT * FROM users WHERE name = " + name) // The argument to this method is a SQL injection sink. + ... + } + +We need to add a tuple to the ``sinkModel``\(package, type, subtypes, name, signature, ext, input, kind, provenance) extensible predicate by updating a data extension file. + +.. code-block:: yaml + + extensions: + - addsTo: + pack: codeql/go-all + extensible: sinkModel + data: + - ["database/sql", "DB", True, "Prepare", "", "", "Argument[0]", "sql-injection", "manual"] + +Since we want to add a new sink, we need to add a tuple to the ``sinkModel`` extensible predicate. +The first five values identify the function (in this case a method) to be modeled as a sink. + +- The first value ``database/sql`` is the package name. +- The second value ``DB`` is the name of the type that the method is associated with. +- The third value ``True`` is a flag that indicates whether or not the sink also applies to subtypes. This includes when the subtype embeds the given type, so that the method or field is promoted to be a method or field of the subtype. For interface methods it also includes types which implement the interface type. +- The fourth value ``Prepare`` is the method name. +- The fifth value ``""`` is the input type signature. For Go it should always be an empty string. It is needed for other languages where multiple functions may have the same name and they need to be distinguished by the number and types of the arguments. + +The sixth value should be left empty and is out of scope for this documentation. +The remaining values are used to define the ``access path``, the ``kind``, and the ``provenance`` (origin) of the sink. + +- The seventh value ``Argument[0]`` is the ``access path`` to the first argument passed to the method, which means that this is the location of the sink. +- The eighth value ``sql-injection`` is the kind of the sink. The sink kind is used to define the queries where the sink is in scope. In this case - the SQL injection queries. +- The ninth value ``manual`` is the provenance of the sink, which is used to identify the origin of the sink. + +Example: Taint source from the ``net/http`` package +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This example shows how the Go query pack models the return value from the ``FormValue`` method as a ``remote`` source. +This is the ``FormValue`` method of the ``Request`` type which is located in the ``net/http`` package. + +.. code-block:: go + + func Tainted(r *http.Request) { + name := r.FormValue("name") // The return value of this method is a source of tainted data. + ... + } + + +We need to add a tuple to the ``sourceModel``\(package, type, subtypes, name, signature, ext, output, kind, provenance) extensible predicate by updating a data extension file. + +.. code-block:: yaml + + extensions: + - addsTo: + pack: codeql/go-all + extensible: sourceModel + data: + - ["net/http", "Request", True, "FormValue", "", "", "ReturnValue", "remote", "manual"] + + +Since we are adding a new source, we need to add a tuple to the ``sourceModel`` extensible predicate. +The first five values identify the function to be modeled as a source. + +- The first value ``net/http`` is the package name. +- The second value ``Request`` is the type name, since the function is a method of the ``Request`` type. +- The third value ``True`` is a flag that indicates whether or not the sink also applies to subtypes. This includes when the subtype embeds the given type, so that the method or field is promoted to be a method or field of the subtype. For interface methods it also includes types which implement the interface type. +- The fourth value ``FormValue`` is the function name. +- The fifth value ``""`` is the input type signature. For Go it should always be an empty string. It is needed for other languages where multiple functions may have the same name and they need to be distinguished by the number and types of the arguments. + +The sixth value should be left empty and is out of scope for this documentation. +The remaining values are used to define the ``access path``, the ``kind``, and the ``provenance`` (origin) of the source. + +- The seventh value ``ReturnValue`` is the access path to the return of the method, which means that it is the return value that should be considered a source of tainted input. +- The eighth value ``remote`` is the kind of the source. The source kind is used to define the threat model where the source is in scope. ``remote`` applies to many of the security related queries as it means a remote source of untrusted data. As an example the SQL injection query uses ``remote`` sources. For more information, see ":ref:`Threat models `." +- The ninth value ``manual`` is the provenance of the source, which is used to identify the origin of the source. + +Example: Add flow through the ``Max`` function +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This example shows how the Go query pack models flow through a function for a simple case. +This pattern covers many of the cases where we need to summarize flow through a function that is stored in a library or framework outside the repository. + +.. code-block:: go + + func ValueFlow { + a := []int{1, 2, 3} + max := slices.Max(a) // There is value flow from the elements of `a` to `max`. + ... + } + +We need to add a tuple to the ``summaryModel``\(package, type, subtypes, name, signature, ext, input, output, kind, provenance) extensible predicate by updating a data extension file: + +.. code-block:: yaml + + extensions: + - addsTo: + pack: codeql/go-all + extensible: summaryModel + data: + - ["slices", "", False, "Max", "", "", "Argument[0].ArrayElement", "ReturnValue", "value", "manual"] + +Since we are adding flow through a method, we need to add tuples to the ``summaryModel`` extensible predicate. +The first row defines flow from the first argument (``a`` in the example) to the return value (``max`` in the example). + +The first five values identify the function to be modeled as a summary. + +- The first value ``slices`` is the package name. +- The second value ``""`` is left blank, since the function is not a method of a type. +- The third value ``False`` is a flag that indicates whether or not the sink also applies to subtypes. This has no effect for non-method functions. +- The fourth value ``Max`` is the function name. +- The fifth value ``""`` is the input type signature. For Go it should always be an empty string. It is needed for other languages where multiple functions may have the same name and they need to be distinguished by the number and types of the arguments. + +The sixth value should be left empty and is out of scope for this documentation. +The remaining values are used to define the ``access path``, the ``kind``, and the ``provenance`` (origin) of the summary. + +- The seventh value is the access path to the input (where data flows from). ``Argument[0].ArrayElement`` is the access path to the array elements of the first argument (the elements of the slice in the example). +- The eighth value ``ReturnValue`` is the access path to the output (where data flows to), in this case ``ReturnValue``, which means that the input flows to the return value. +- The ninth value ``value`` is the kind of the flow. ``value`` flow indicates an entire value is moved, ``taint`` means that taint is propagated through the call. +- The tenth value ``manual`` is the provenance of the summary, which is used to identify the origin of the summary. + +Example: Add flow through the ``Concat`` function +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This example shows how the Go query pack models flow through a function for a simple case. +This pattern covers many of the cases where we need to summarize flow through a function that is stored in a library or framework outside the repository. + +.. code-block:: go + + func ValueFlow { + a := []int{1, 2, 3} + b := []int{4, 5, 6} + c := slices.Concat(a, b) // There is taint flow from `a` and `b` to `c`. + ... + } + +We need to add a tuple to the ``summaryModel``\(package, type, subtypes, name, signature, ext, input, output, kind, provenance) extensible predicate by updating a data extension file: + +.. code-block:: yaml + + extensions: + - addsTo: + pack: codeql/go-all + extensible: summaryModel + data: + - ["slices", "", False, "Concat", "", "", "Argument[0].ArrayElement.ArrayElement", "ReturnValue.ArrayElement", "value", "manual"] + +Since we are adding flow through a method, we need to add tuples to the ``summaryModel`` extensible predicate. +The first row defines flow from the arguments (``a`` and ``b`` in the example) to the return value (``c`` in the example). + +The first five values identify the function to be modeled as a summary. + +- The first value ``slices`` is the package name. +- The second value ``""`` is left blank, since the function is not a method of a type. +- The third value ``False`` is a flag that indicates whether or not the sink also applies to subtypes. This has no effect for non-method functions. +- The fourth value ``Max`` is the function name. +- The fifth value ``""`` is the input type signature. For Go it should always be an empty string. It is needed for other languages where multiple functions may have the same name and they need to be distinguished by the number and types of the arguments. + +The sixth value should be left empty and is out of scope for this documentation. +The remaining values are used to define the ``access path``, the ``kind``, and the ``provenance`` (origin) of the summary. + +- The seventh value is the access path to the input (where data flows from). ``Argument[0].ArrayElement.ArrayElement`` is the access path to the array elements of the array elements of the first argument. Note that a variadic parameter of type `...T` is treated as if it has type `[]T` and arguments corresponding to the variadic parameter are accessed as elements of this slice. +- The eighth value ``ReturnValue.ArrayElement`` is the access path to the output (where data flows to), in this case ``ReturnValue.ArrayElement``, which means that the input flows to the array elements of the return value. +- The ninth value ``value`` is the kind of the flow. ``value`` flow indicates an entire value is moved, ``taint`` means that taint is propagated through the call. +- The tenth value ``manual`` is the provenance of the summary, which is used to identify the origin of the summary. + +Example: Add flow through the ``Join`` function +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This example shows how the Go query pack models flow through a method for a simple case. +This pattern covers many of the cases where we need to summarize flow through a function that is stored in a library or framework outside the repository. + +.. code-block:: go + + func TaintFlow() { + elems := []string{"Hello", "World"} + sep := " " + t := strings.Join(elems, sep) // There is taint flow from elems and sep to t. + ... + } + +We need to add tuples to the ``summaryModel``\(package, type, subtypes, name, signature, ext, input, output, kind, provenance) extensible predicate by updating a data extension file: + +.. code-block:: yaml + + extensions: + - addsTo: + pack: codeql/go-all + extensible: summaryModel + data: + - ["strings", "", False, "Join", "", "", "Argument[0]", "ReturnValue", "taint", "manual"] + - ["strings", "", False, "Join", "", "", "Argument[1]", "ReturnValue", "taint", "manual"] + +Since we are adding flow through a method, we need to add tuples to the ``summaryModel`` extensible predicate. +Each tuple defines flow from one argument to the return value. +The first row defines flow from the first argument (``elems`` in the example) to the return value (``t`` in the example) and the second row defines flow from the second argument (``sep`` in the example) to the return value (``t`` in the example). + +The first five values identify the function to be modeled as a summary. +These are the same for both of the rows above as we are adding two summaries for the same method. + +- The first value ``strings`` is the package name. +- The second value ``""`` is left blank, since the function is not a method of a type. +- The third value ``False`` is a flag that indicates whether or not the sink also applies to subtypes. This has no effect for non-method functions. +- The fourth value ``Join`` is the function name. +- The fifth value ``""`` is the input type signature. For Go it should always be an empty string. It is needed for other languages where multiple functions may have the same name and they need to be distinguished by the number and types of the arguments. + +The sixth value should be left empty and is out of scope for this documentation. +The remaining values are used to define the ``access path``, the ``kind``, and the ``provenance`` (origin) of the summary. + +- The seventh value is the access path to the input (where data flows from). ``Argument[0]`` is the access path to the first argument (``elems`` in the example) and ``Argument[1]`` is the access path to the second argument (``sep`` in the example). +- The eighth value ``ReturnValue`` is the access path to the output (where data flows to), in this case ``ReturnValue``, which means that the input flows to the return value. +- The ninth value ``taint`` is the kind of the flow. ``taint`` means that taint is propagated through the call. +- The tenth value ``manual`` is the provenance of the summary, which is used to identify the origin of the summary. + +It would also be possible to merge the two rows into one by using ".." to indicate a range in the seventh value. This would be useful if the method has many arguments and the flow is the same for all of them. + +.. code-block:: yaml + + extensions: + - addsTo: + pack: codeql/go-all + extensible: summaryModel + data: + - ["strings", "", False, "Join", "", "", "Argument[0..1]", "ReturnValue", "taint", "manual"] + +This row defines flow from both the first and the second argument to the return value. The seventh value ``Argument[0..1]`` is shorthand for specifying an access path to both ``Argument[0]`` and ``Argument[1]``. + +Example: Add flow through the ``Hostname`` method +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This example shows how the Go query pack models flow through a method for a simple case. + +.. code-block:: go + + func TaintFlow(u *url.URL) { + host := u.Hostname() // There is taint flow from u to host. + ... + } + +We need to add a tuple to the ``summaryModel``\(package, type, subtypes, name, signature, ext, input, output, kind, provenance) extensible predicate by updating a data extension file: + +.. code-block:: yaml + + extensions: + - addsTo: + pack: codeql/go-all + extensible: summaryModel + data: + - ["net/url", "URL", True, "Hostname", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] + +Since we are adding flow through a method, we need to add tuples to the ``summaryModel`` extensible predicate. +Each tuple defines flow from one argument to the return value. +The first row defines flow from the qualifier of the method call (``u`` in the example) to the return value (``host`` in the example). + +The first five values identify the function (in this case a method) to be modeled as a summary. + +- The first value ``net/url`` is the package name. +- The second value ``URL`` is the receiver type. +- The third value ``True`` is a flag that indicates whether or not the sink also applies to subtypes. This includes when the subtype embeds the given type, so that the method or field is promoted to be a method or field of the subtype. For interface methods it also includes types which implement the interface type. +- The fourth value ``Hostname`` is the method name. +- The fifth value ``""`` is the input type signature. For Go it should always be an empty string. It is needed for other languages where multiple functions may have the same name and they need to be distinguished by the number and types of the arguments. + +The sixth value should be left empty and is out of scope for this documentation. +The remaining values are used to define the ``access path``, the ``kind``, and the ``provenance`` (origin) of the summary. + +- The seventh value is the access path to the input (where data flows from). ``Argument[receiver]`` is the access path to the receiver (``u`` in the example). +- The eighth value ``ReturnValue`` is the access path to the output (where data flows to), in this case ``ReturnValue``, which means that the input flows to the return value. When there are multiple return values, use ``ReturnValue[i]`` to refer to the ``i`` th return value (starting from 0). +- The ninth value ``taint`` is the kind of the flow. ``taint`` means that taint is propagated through the call. +- The tenth value ``manual`` is the provenance of the summary, which is used to identify the origin of the summary. + +Example: Accessing the ``Body`` field of an HTTP request +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This example shows how we can model a field read as a source of tainted data. + +.. code-block:: go + + func TaintFlow(w http.ResponseWriter, r *http.Request) { + body := r.Body // The Body field of an HTTP request is a source of tainted data. + ... + } + +We need to add a tuple to the ``sourceModel``\(package, type, subtypes, name, signature, ext, output, kind, provenance) extensible predicate by updating a data extension file. + +.. code-block:: yaml + + extensions: + - addsTo: + pack: codeql/go-all + extensible: sourceModel + data: + - ["net/http", "Request", True, "Body", "", "", "", "remote", "manual"] + +Since we are adding a new source, we need to add a tuple to the ``sourceModel`` extensible predicate. +The first five values identify the field to be modeled as a source. + +- The first value ``net/http`` is the package name. +- The second value ``Request`` is the name of the type that the field is associated with. +- The third value ``True`` is a flag that indicates whether or not the sink also applies to subtypes. For fields this means when the field is accessed as a promoted field in another type. +- The fourth value ``Body`` is the field name. +- The fifth value ``""`` is the input type signature. For Go it should always be an empty string. It is needed for other languages where multiple functions may have the same name and they need to be distinguished by the number and types of the arguments. + +The sixth value should be left empty and is out of scope for this documentation. +The remaining values are used to define the ``access path``, the ``kind``, and the ``provenance`` (origin) of the source. + +- The seventh value ``""`` is left blank. Leaving the access path of a source model blank indicates that it is a field access. +- The eighth value ``remote`` is the source kind. This indicates that the source is a remote source of untrusted data. +- The ninth value ``manual`` is the provenance of the source, which is used to identify the origin of the source. + +Package versions +~~~~~~~~~~~~~~~~ + +When the major version number is greater than 1 it is included in the package import path. It usually looks like ``/v2`` after the module import path. This is called the major version suffix. We normally want our models to apply to all versions of a package. Rather than having to repeat models with the package column changed to include all available versions, we can just use the package name without the major version suffix and this will be matched to any version. So models with ``github.com/couchbase/gocb`` in the package column will match packages imported from ``github.com/couchbase/gocb`` and ``github.com/couchbase/gocb/v2`` (or any other version). + +Note that packages hosted at ``gopkg.in`` use a slightly different syntax: the major version suffix looks like ``.v2``, and it is present even for version 1. This is also supported. So models with ``gopkg.in/yaml`` in the package column will match packages imported from ``gopkg.in/yaml.v1``, ``gopkg.in/yaml.v2`` and ``gopkg.in/yaml.v3``. + +To write models that only apply to ``github.com/couchbase/gocb/v2``, it is sufficient to include the major version suffix (``/v2``) in the package column. To write models that only apply to ``github.com/couchbase/gocb``, you may prefix the package column with ``fixed-version:``. For example, here are two models for a method that has changed name from v1 to v2. + +.. code-block:: yaml + + extensions: + - addsTo: + pack: codeql/go-all + extensible: sinkModel + data: + - ["fixed-version:github.com/couchbase/gocb", "Cluster", True, "ExecuteAnalyticsQuery", "", "", "Argument[0]", "nosql-injection", "manual"] + - ["github.com/couchbase/gocb/v2", "Cluster", True, "AnalyticsQuery", "", "", "Argument[0]", "nosql-injection", "manual"] + +Package grouping +~~~~~~~~~~~~~~~~ + +Since Go uses URLs for package identifiers, it is possible for packages to be imported with different paths. For example, the ``glog`` package can be imported using both the ``github.com/golang/glog`` and ``gopkg.in/glog`` paths. + +To handle this, the CodeQL Go library uses a mapping from the package path to a group name for the package. This mapping can be specified using the ``packageGrouping`` extensible predicate, and then the models for the APIs in the package +will use the the prefix ``group:`` followed by the group name in place of the package path. + +.. code-block:: yaml + + extensions: + - addsTo: + pack: codeql/go + extensible: packageGrouping + data: + - ["glog", "github.com/golang/glog"] + - ["glog", "gopkg.in/glog"] + - addsTo: + pack: codeql/go + extensible: sinkModel + data: + - ["group:glog", "", False, "Info", "", "", "Argument[0]", "log-injection", "manual"] + +.. _threat-models-go: + +Threat models +------------- + +.. include:: ../reusables/threat-model-description.rst diff --git a/docs/codeql/ql-language-reference/modules.rst b/docs/codeql/ql-language-reference/modules.rst index 75b61667246..d0cbdd39e36 100644 --- a/docs/codeql/ql-language-reference/modules.rst +++ b/docs/codeql/ql-language-reference/modules.rst @@ -431,10 +431,7 @@ The above query therefore evalutes to: BigInt ====== -The built-in ``QlBuiltins`` module provides an **experimental** type ``BigInt`` of arbitrary-precision integers. - -This type is not available in the CodeQL CLI by default, but you can enable it by passing the ``--allow-experimental=bigint`` -option to the CodeQL CLI. Consequently, BigInts are currently disallowed in query results and dbscheme columns. +The built-in ``QlBuiltins`` module provides a type ``BigInt`` of arbitrary-range integers. Unlike ``int`` and ``float``, there is no automatic conversion between ``BigInt`` and other numeric types. Instead, big integers can be constructed using the ``.toBigInt()`` methods of ``int`` and ``string``. @@ -451,3 +448,5 @@ The other built-in operations are: ``rank``, ``unique``, ``any``. * other: ``.pow(int)``, ``.abs()``, ``.gcd(BigInt)``, ``.minimum(BigInt)``, ``.maximum(BigInt)``. + +Note: big integers are currently disallowed in query results and dbscheme columns. diff --git a/docs/codeql/ql-language-reference/ql-language-specification.rst b/docs/codeql/ql-language-reference/ql-language-specification.rst index 60e5ece7330..4c8fd30076a 100644 --- a/docs/codeql/ql-language-reference/ql-language-specification.rst +++ b/docs/codeql/ql-language-reference/ql-language-specification.rst @@ -445,7 +445,7 @@ An integer value is of type ``int``. Each value is a 32-bit two's complement int A string is a finite sequence of 16-bit characters. The characters are interpreted as Unicode code points. -A :ref:`big integer ` value is of type ``QlBuiltins::BigInt``. Each value is a signed arbitrary-precision integer. +A :ref:`big integer ` value is of type ``QlBuiltins::BigInt``. Each value is a signed arbitrary-range integer. The database includes a number of opaque entity values. Each such value has a type that is one of the database types, and an identifying integer. An entity value is written as the name of its database type followed by its identifying integer in parentheses. For example, ``@tree(12)``, ``@person(16)``, and ``@location(38132)`` are entity values. The identifying integers are left opaque to programmers in this specification, so an implementation of QL is free to use some other set of countable labels to identify its entities. diff --git a/docs/codeql/ql-language-reference/types.rst b/docs/codeql/ql-language-reference/types.rst index e14f542dcf8..d2d79fe8409 100644 --- a/docs/codeql/ql-language-reference/types.rst +++ b/docs/codeql/ql-language-reference/types.rst @@ -52,7 +52,7 @@ independent of the database that you are querying. QL has a range of built-in operations defined on primitive types. These are available by using dispatch on expressions of the appropriate type. For example, ``1.toString()`` is the string representation of the integer constant ``1``. For a full list of built-in operations available in QL, see the section on `built-ins `__ in the QL language specification. -Additionally, there is an experimental arbitrary-precision integer primitive type at :ref:`QlBuiltins::BigInt `. This type is not available in the CodeQL CLI by default, but you can enable it by passing the ``--allow-experimental=bigint`` option to the CodeQL CLI. +Additionally, there is an arbitrary-range integer primitive type at :ref:`QlBuiltins::BigInt `. .. index:: class .. _classes: diff --git a/go/documentation/library-coverage/coverage.csv b/go/documentation/library-coverage/coverage.csv index 364e17aa94b..cf5a8b715b0 100644 --- a/go/documentation/library-coverage/coverage.csv +++ b/go/documentation/library-coverage/coverage.csv @@ -1,121 +1,142 @@ -package,sink,source,summary,sink:command-injection,sink:credentials-key,sink:jwt,sink:path-injection,sink:regex-use[0],sink:regex-use[1],sink:regex-use[c],sink:request-forgery,sink:request-forgery[TCP Addr + Port],sink:url-redirection,sink:url-redirection[0],sink:url-redirection[receiver],sink:xpath-injection,source:environment,source:file,source:remote,summary:taint,summary:value -,,,8,,,,,,,,,,,,,,,,,3,5 -archive/tar,,,5,,,,,,,,,,,,,,,,,5, -archive/zip,,,6,,,,,,,,,,,,,,,,,6, -bufio,,,17,,,,,,,,,,,,,,,,,17, -bytes,,,43,,,,,,,,,,,,,,,,,43, -clevergo.tech/clevergo,1,,,,,,,,,,,,,,1,,,,,, -compress/bzip2,,,1,,,,,,,,,,,,,,,,,1, -compress/flate,,,4,,,,,,,,,,,,,,,,,4, -compress/gzip,,,3,,,,,,,,,,,,,,,,,3, -compress/lzw,,,1,,,,,,,,,,,,,,,,,1, -compress/zlib,,,4,,,,,,,,,,,,,,,,,4, -container/heap,,,5,,,,,,,,,,,,,,,,,5, -container/list,,,20,,,,,,,,,,,,,,,,,20, -container/ring,,,5,,,,,,,,,,,,,,,,,5, -context,,,5,,,,,,,,,,,,,,,,,5, -crypto,,,10,,,,,,,,,,,,,,,,,10, -database/sql,,,11,,,,,,,,,,,,,,,,,11, -encoding,,,77,,,,,,,,,,,,,,,,,77, -errors,,,3,,,,,,,,,,,,,,,,,3, -expvar,,,6,,,,,,,,,,,,,,,,,6, -fmt,,,16,,,,,,,,,,,,,,,,,16, -github.com/ChrisTrenkamp/goxpath,3,,,,,,,,,,,,,,,3,,,,, -github.com/antchfx/htmlquery,4,,,,,,,,,,,,,,,4,,,,, -github.com/antchfx/jsonquery,4,,,,,,,,,,,,,,,4,,,,, -github.com/antchfx/xmlquery,8,,,,,,,,,,,,,,,8,,,,, -github.com/antchfx/xpath,4,,,,,,,,,,,,,,,4,,,,, -github.com/appleboy/gin-jwt,1,,,,1,,,,,,,,,,,,,,,, -github.com/astaxie/beego,7,21,21,,,,5,,,,,,2,,,,,,21,21, -github.com/beego/beego,14,42,42,,,,10,,,,,,4,,,,,,42,42, -github.com/caarlos0/env,,5,2,,,,,,,,,,,,,,5,,,1,1 -github.com/clevergo/clevergo,1,,,,,,,,,,,,,,1,,,,,, -github.com/codeskyblue/go-sh,4,,,4,,,,,,,,,,,,,,,,, -github.com/couchbase/gocb,,,18,,,,,,,,,,,,,,,,,18, -github.com/couchbaselabs/gocb,,,18,,,,,,,,,,,,,,,,,18, -github.com/crankycoder/xmlpath,2,,,,,,,,,,,,,,,2,,,,, -github.com/cristalhq/jwt,1,,,,1,,,,,,,,,,,,,,,, -github.com/dgrijalva/jwt-go,3,,9,,2,1,,,,,,,,,,,,,,9, -github.com/elazarl/goproxy,,2,2,,,,,,,,,,,,,,,,2,2, -github.com/emicklei/go-restful,,7,,,,,,,,,,,,,,,,,7,, -github.com/evanphx/json-patch,,,12,,,,,,,,,,,,,,,,,12, -github.com/form3tech-oss/jwt-go,2,,,,2,,,,,,,,,,,,,,,, -github.com/gin-gonic/gin,3,46,2,,,,3,,,,,,,,,,,,46,2, -github.com/go-chi/chi,,3,,,,,,,,,,,,,,,,,3,, -github.com/go-chi/jwtauth,1,,,,1,,,,,,,,,,,,,,,, -github.com/go-jose/go-jose,3,,4,,2,1,,,,,,,,,,,,,,4, -github.com/go-kit/kit/auth/jwt,1,,,,1,,,,,,,,,,,,,,,, -github.com/go-pg/pg/orm,,,6,,,,,,,,,,,,,,,,,6, -github.com/go-xmlpath/xmlpath,2,,,,,,,,,,,,,,,2,,,,, -github.com/gobuffalo/envy,,7,,,,,,,,,,,,,,,7,,,, -github.com/gobwas/ws,,2,,,,,,,,,,,,,,,,,2,, -github.com/gofiber/fiber,5,,,,,,4,,,,,,,,1,,,,,, -github.com/gogf/gf-jwt,1,,,,1,,,,,,,,,,,,,,,, -github.com/going/toolkit/xmlpath,2,,,,,,,,,,,,,,,2,,,,, -github.com/golang-jwt/jwt,3,,11,,2,1,,,,,,,,,,,,,,11, -github.com/golang/protobuf/proto,,,4,,,,,,,,,,,,,,,,,4, -github.com/gorilla/mux,,1,,,,,,,,,,,,,,,,,1,, -github.com/gorilla/websocket,,3,,,,,,,,,,,,,,,,,3,, -github.com/hashicorp/go-envparse,,1,,,,,,,,,,,,,,,1,,,, -github.com/jbowtie/gokogiri/xml,4,,,,,,,,,,,,,,,4,,,,, -github.com/jbowtie/gokogiri/xpath,1,,,,,,,,,,,,,,,1,,,,, -github.com/joho/godotenv,,4,,,,,,,,,,,,,,,4,,,, -github.com/json-iterator/go,,,4,,,,,,,,,,,,,,,,,4, -github.com/kataras/iris/context,6,,,,,,6,,,,,,,,,,,,,, -github.com/kataras/iris/middleware/jwt,2,,,,2,,,,,,,,,,,,,,,, -github.com/kataras/iris/server/web/context,6,,,,,,6,,,,,,,,,,,,,, -github.com/kataras/jwt,5,,,,5,,,,,,,,,,,,,,,, -github.com/kelseyhightower/envconfig,,6,,,,,,,,,,,,,,,6,,,, -github.com/labstack/echo,3,12,2,,,,2,,,,,,1,,,,,,12,2, -github.com/lestrrat-go/jwx,2,,,,2,,,,,,,,,,,,,,,, -github.com/lestrrat-go/libxml2/parser,3,,,,,,,,,,,,,,,3,,,,, -github.com/lestrrat/go-jwx/jwk,1,,,,1,,,,,,,,,,,,,,,, -github.com/masterzen/xmlpath,2,,,,,,,,,,,,,,,2,,,,, -github.com/moovweb/gokogiri/xml,4,,,,,,,,,,,,,,,4,,,,, -github.com/moovweb/gokogiri/xpath,1,,,,,,,,,,,,,,,1,,,,, -github.com/ory/fosite/token/jwt,2,,,,2,,,,,,,,,,,,,,,, -github.com/revel/revel,2,23,10,,,,1,,,,,,1,,,,,,23,10, -github.com/robfig/revel,2,23,10,,,,1,,,,,,1,,,,,,23,10, -github.com/santhosh-tekuri/xpathparser,2,,,,,,,,,,,,,,,2,,,,, -github.com/sendgrid/sendgrid-go/helpers/mail,,,1,,,,,,,,,,,,,,,,,1, -github.com/spf13/afero,34,,,,,,34,,,,,,,,,,,,,, -github.com/square/go-jose,3,,4,,2,1,,,,,,,,,,,,,,4, -github.com/valyala/fasthttp,35,50,5,,,,8,,,,17,8,2,,,,,,50,5, -go.uber.org/zap,,,11,,,,,,,,,,,,,,,,,11, -golang.org/x/crypto/ssh,4,,,4,,,,,,,,,,,,,,,,, -golang.org/x/net/context,,,5,,,,,,,,,,,,,,,,,5, -golang.org/x/net/html,,,16,,,,,,,,,,,,,,,,,16, -golang.org/x/net/websocket,,2,,,,,,,,,,,,,,,,,2,, -google.golang.org/protobuf/internal/encoding/text,,,1,,,,,,,,,,,,,,,,,1, -google.golang.org/protobuf/internal/impl,,,2,,,,,,,,,,,,,,,,,2, -google.golang.org/protobuf/proto,,,8,,,,,,,,,,,,,,,,,8, -google.golang.org/protobuf/reflect/protoreflect,,,1,,,,,,,,,,,,,,,,,1, -gopkg.in/couchbase/gocb,,,18,,,,,,,,,,,,,,,,,18, -gopkg.in/go-jose/go-jose,3,,4,,2,1,,,,,,,,,,,,,,4, -gopkg.in/go-xmlpath/xmlpath,2,,,,,,,,,,,,,,,2,,,,, -gopkg.in/macaron,1,12,1,,,,,,,,,,,,1,,,,12,1, -gopkg.in/square/go-jose,3,,4,,2,1,,,,,,,,,,,,,,4, -gopkg.in/xmlpath,2,,,,,,,,,,,,,,,2,,,,, -gopkg.in/yaml,,,9,,,,,,,,,,,,,,,,,9, -html,,,8,,,,,,,,,,,,,,,,,8, -io,5,4,34,,,,5,,,,,,,,,,,4,,34, -k8s.io/api/core,,,10,,,,,,,,,,,,,,,,,10, -k8s.io/apimachinery/pkg/runtime,,,47,,,,,,,,,,,,,,,,,47, -launchpad.net/xmlpath,2,,,,,,,,,,,,,,,2,,,,, -log,,,3,,,,,,,,,,,,,,,,,3, -math/big,,,1,,,,,,,,,,,,,,,,,1, -mime,,,14,,,,,,,,,,,,,,,,,14, -net,2,16,100,,,,1,,,,,,,1,,,,,16,100, -nhooyr.io/websocket,,2,,,,,,,,,,,,,,,,,2,, -os,29,10,6,3,,,26,,,,,,,,,,7,3,,6, -path,,,18,,,,,,,,,,,,,,,,,18, -reflect,,,37,,,,,,,,,,,,,,,,,37, -regexp,10,,20,,,,,3,3,4,,,,,,,,,,20, -sort,,,1,,,,,,,,,,,,,,,,,1, -strconv,,,9,,,,,,,,,,,,,,,,,9, -strings,,,34,,,,,,,,,,,,,,,,,34, -sync,,,34,,,,,,,,,,,,,,,,,34, -syscall,5,2,8,5,,,,,,,,,,,,,2,,,8, -text/scanner,,,3,,,,,,,,,,,,,,,,,3, -text/tabwriter,,,1,,,,,,,,,,,,,,,,,1, -text/template,,,6,,,,,,,,,,,,,,,,,6, +package,sink,source,summary,sink:command-injection,sink:credentials-key,sink:jwt,sink:log-injection,sink:nosql-injection,sink:path-injection,sink:regex-use[0],sink:regex-use[1],sink:regex-use[c],sink:request-forgery,sink:request-forgery[TCP Addr + Port],sink:sql-injection,sink:url-redirection,sink:url-redirection[0],sink:url-redirection[receiver],sink:xpath-injection,source:environment,source:file,source:remote,source:stdin,summary:taint,summary:value +,,,8,,,,,,,,,,,,,,,,,,,,,3,5 +archive/tar,,,5,,,,,,,,,,,,,,,,,,,,,5, +archive/zip,,,6,,,,,,,,,,,,,,,,,,,,,6, +bufio,,,17,,,,,,,,,,,,,,,,,,,,,17, +bytes,,,43,,,,,,,,,,,,,,,,,,,,,43, +clevergo.tech/clevergo,1,,,,,,,,,,,,,,,,,1,,,,,,, +compress/bzip2,,,1,,,,,,,,,,,,,,,,,,,,,1, +compress/flate,,,4,,,,,,,,,,,,,,,,,,,,,4, +compress/gzip,,,3,,,,,,,,,,,,,,,,,,,,,3, +compress/lzw,,,1,,,,,,,,,,,,,,,,,,,,,1, +compress/zlib,,,4,,,,,,,,,,,,,,,,,,,,,4, +container/heap,,,5,,,,,,,,,,,,,,,,,,,,,5, +container/list,,,20,,,,,,,,,,,,,,,,,,,,,20, +container/ring,,,5,,,,,,,,,,,,,,,,,,,,,5, +context,,,5,,,,,,,,,,,,,,,,,,,,,5, +crypto,,,10,,,,,,,,,,,,,,,,,,,,,10, +database/sql,30,,11,,,,,,,,,,,,30,,,,,,,,,11, +encoding,,,77,,,,,,,,,,,,,,,,,,,,,77, +errors,,,3,,,,,,,,,,,,,,,,,,,,,3, +expvar,,,6,,,,,,,,,,,,,,,,,,,,,6, +fmt,3,,16,,,,3,,,,,,,,,,,,,,,,,16, +github.com/ChrisTrenkamp/goxpath,3,,,,,,,,,,,,,,,,,,3,,,,,, +github.com/Masterminds/squirrel,32,,,,,,,,,,,,,,32,,,,,,,,,, +github.com/Sirupsen/logrus,145,,,,,,145,,,,,,,,,,,,,,,,,, +github.com/antchfx/htmlquery,4,,,,,,,,,,,,,,,,,,4,,,,,, +github.com/antchfx/jsonquery,4,,,,,,,,,,,,,,,,,,4,,,,,, +github.com/antchfx/xmlquery,8,,,,,,,,,,,,,,,,,,8,,,,,, +github.com/antchfx/xpath,4,,,,,,,,,,,,,,,,,,4,,,,,, +github.com/appleboy/gin-jwt,1,,,,1,,,,,,,,,,,,,,,,,,,, +github.com/astaxie/beego,71,21,21,,,,34,,5,,,,,,30,2,,,,,,21,,21, +github.com/beego/beego,142,42,42,,,,68,,10,,,,,,60,4,,,,,,42,,42, +github.com/caarlos0/env,,5,2,,,,,,,,,,,,,,,,,5,,,,1,1 +github.com/clevergo/clevergo,1,,,,,,,,,,,,,,,,,1,,,,,,, +github.com/codeskyblue/go-sh,4,,,4,,,,,,,,,,,,,,,,,,,,, +github.com/couchbase/gocb,8,,18,,,,,8,,,,,,,,,,,,,,,,18, +github.com/couchbaselabs/gocb,8,,18,,,,,8,,,,,,,,,,,,,,,,18, +github.com/crankycoder/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,, +github.com/cristalhq/jwt,1,,,,1,,,,,,,,,,,,,,,,,,,, +github.com/davecgh/go-spew/spew,9,,,,,,9,,,,,,,,,,,,,,,,,, +github.com/dgrijalva/jwt-go,3,,9,,2,1,,,,,,,,,,,,,,,,,,9, +github.com/elazarl/goproxy,2,2,2,,,,2,,,,,,,,,,,,,,,2,,2, +github.com/emicklei/go-restful,,7,,,,,,,,,,,,,,,,,,,,7,,, +github.com/evanphx/json-patch,,,12,,,,,,,,,,,,,,,,,,,,,12, +github.com/form3tech-oss/jwt-go,2,,,,2,,,,,,,,,,,,,,,,,,,, +github.com/gin-gonic/gin,3,46,2,,,,,,3,,,,,,,,,,,,,46,,2, +github.com/go-chi/chi,,3,,,,,,,,,,,,,,,,,,,,3,,, +github.com/go-chi/jwtauth,1,,,,1,,,,,,,,,,,,,,,,,,,, +github.com/go-gorm/gorm,13,,,,,,,,,,,,,,13,,,,,,,,,, +github.com/go-jose/go-jose,3,,4,,2,1,,,,,,,,,,,,,,,,,,4, +github.com/go-kit/kit/auth/jwt,1,,,,1,,,,,,,,,,,,,,,,,,,, +github.com/go-pg/pg/orm,,,6,,,,,,,,,,,,,,,,,,,,,6, +github.com/go-xmlpath/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,, +github.com/go-xorm/xorm,34,,,,,,,,,,,,,,34,,,,,,,,,, +github.com/gobuffalo/envy,,7,,,,,,,,,,,,,,,,,,7,,,,, +github.com/gobwas/ws,,2,,,,,,,,,,,,,,,,,,,,2,,, +github.com/gofiber/fiber,5,,,,,,,,4,,,,,,,,,1,,,,,,, +github.com/gogf/gf-jwt,1,,,,1,,,,,,,,,,,,,,,,,,,, +github.com/gogf/gf/database/gdb,51,,,,,,,,,,,,,,51,,,,,,,,,, +github.com/going/toolkit/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,, +github.com/golang-jwt/jwt,3,,11,,2,1,,,,,,,,,,,,,,,,,,11, +github.com/golang/glog,90,,,,,,90,,,,,,,,,,,,,,,,,, +github.com/golang/protobuf/proto,,,4,,,,,,,,,,,,,,,,,,,,,4, +github.com/gorilla/mux,,1,,,,,,,,,,,,,,,,,,,,1,,, +github.com/gorilla/websocket,,3,,,,,,,,,,,,,,,,,,,,3,,, +github.com/hashicorp/go-envparse,,1,,,,,,,,,,,,,,,,,,1,,,,, +github.com/jbowtie/gokogiri/xml,4,,,,,,,,,,,,,,,,,,4,,,,,, +github.com/jbowtie/gokogiri/xpath,1,,,,,,,,,,,,,,,,,,1,,,,,, +github.com/jinzhu/gorm,13,,,,,,,,,,,,,,13,,,,,,,,,, +github.com/jmoiron/sqlx,12,,,,,,,,,,,,,,12,,,,,,,,,, +github.com/joho/godotenv,,4,,,,,,,,,,,,,,,,,,4,,,,, +github.com/json-iterator/go,,,4,,,,,,,,,,,,,,,,,,,,,4, +github.com/kataras/iris/context,6,,,,,,,,6,,,,,,,,,,,,,,,, +github.com/kataras/iris/middleware/jwt,2,,,,2,,,,,,,,,,,,,,,,,,,, +github.com/kataras/iris/server/web/context,6,,,,,,,,6,,,,,,,,,,,,,,,, +github.com/kataras/jwt,5,,,,5,,,,,,,,,,,,,,,,,,,, +github.com/kelseyhightower/envconfig,,6,,,,,,,,,,,,,,,,,,6,,,,, +github.com/labstack/echo,3,12,2,,,,,,2,,,,,,,1,,,,,,12,,2, +github.com/lann/squirrel,32,,,,,,,,,,,,,,32,,,,,,,,,, +github.com/lestrrat-go/jwx,2,,,,2,,,,,,,,,,,,,,,,,,,, +github.com/lestrrat-go/libxml2/parser,3,,,,,,,,,,,,,,,,,,3,,,,,, +github.com/lestrrat/go-jwx/jwk,1,,,,1,,,,,,,,,,,,,,,,,,,, +github.com/masterzen/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,, +github.com/moovweb/gokogiri/xml,4,,,,,,,,,,,,,,,,,,4,,,,,, +github.com/moovweb/gokogiri/xpath,1,,,,,,,,,,,,,,,,,,1,,,,,, +github.com/ory/fosite/token/jwt,2,,,,2,,,,,,,,,,,,,,,,,,,, +github.com/raindog308/gorqlite,24,,,,,,,,,,,,,,24,,,,,,,,,, +github.com/revel/revel,2,23,10,,,,,,1,,,,,,,1,,,,,,23,,10, +github.com/robfig/revel,2,23,10,,,,,,1,,,,,,,1,,,,,,23,,10, +github.com/rqlite/gorqlite,24,,,,,,,,,,,,,,24,,,,,,,,,, +github.com/santhosh-tekuri/xpathparser,2,,,,,,,,,,,,,,,,,,2,,,,,, +github.com/sendgrid/sendgrid-go/helpers/mail,,,1,,,,,,,,,,,,,,,,,,,,,1, +github.com/sirupsen/logrus,145,,,,,,145,,,,,,,,,,,,,,,,,, +github.com/spf13/afero,34,,,,,,,,34,,,,,,,,,,,,,,,, +github.com/square/go-jose,3,,4,,2,1,,,,,,,,,,,,,,,,,,4, +github.com/uptrace/bun,63,,,,,,,,,,,,,,63,,,,,,,,,, +github.com/valyala/fasthttp,35,50,5,,,,,,8,,,,17,8,,2,,,,,,50,,5, +go.mongodb.org/mongo-driver/mongo,14,,,,,,,14,,,,,,,,,,,,,,,,, +go.uber.org/zap,33,,11,,,,33,,,,,,,,,,,,,,,,,11, +golang.org/x/crypto/ssh,4,,,4,,,,,,,,,,,,,,,,,,,,, +golang.org/x/net/context,,,5,,,,,,,,,,,,,,,,,,,,,5, +golang.org/x/net/html,,,16,,,,,,,,,,,,,,,,,,,,,16, +golang.org/x/net/websocket,,2,,,,,,,,,,,,,,,,,,,,2,,, +google.golang.org/protobuf/internal/encoding/text,,,1,,,,,,,,,,,,,,,,,,,,,1, +google.golang.org/protobuf/internal/impl,,,2,,,,,,,,,,,,,,,,,,,,,2, +google.golang.org/protobuf/proto,,,8,,,,,,,,,,,,,,,,,,,,,8, +google.golang.org/protobuf/reflect/protoreflect,,,1,,,,,,,,,,,,,,,,,,,,,1, +gopkg.in/Masterminds/squirrel,32,,,,,,,,,,,,,,32,,,,,,,,,, +gopkg.in/couchbase/gocb,8,,18,,,,,8,,,,,,,,,,,,,,,,18, +gopkg.in/glog,90,,,,,,90,,,,,,,,,,,,,,,,,, +gopkg.in/go-jose/go-jose,3,,4,,2,1,,,,,,,,,,,,,,,,,,4, +gopkg.in/go-xmlpath/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,, +gopkg.in/macaron,1,12,1,,,,,,,,,,,,,,,1,,,,12,,1, +gopkg.in/square/go-jose,3,,4,,2,1,,,,,,,,,,,,,,,,,,4, +gopkg.in/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,, +gopkg.in/yaml,,,9,,,,,,,,,,,,,,,,,,,,,9, +gorm.io/gorm,13,,,,,,,,,,,,,,13,,,,,,,,,, +html,,,8,,,,,,,,,,,,,,,,,,,,,8, +io,5,4,34,,,,,,5,,,,,,,,,,,,4,,,34, +k8s.io/api/core,,,10,,,,,,,,,,,,,,,,,,,,,10, +k8s.io/apimachinery/pkg/runtime,,,47,,,,,,,,,,,,,,,,,,,,,47, +k8s.io/klog,90,,,,,,90,,,,,,,,,,,,,,,,,, +launchpad.net/xmlpath,2,,,,,,,,,,,,,,,,,,2,,,,,, +log,20,,3,,,,20,,,,,,,,,,,,,,,,,3, +math/big,,,1,,,,,,,,,,,,,,,,,,,,,1, +mime,,,14,,,,,,,,,,,,,,,,,,,,,14, +net,2,16,100,,,,,,1,,,,,,,,1,,,,,16,,100, +nhooyr.io/websocket,,2,,,,,,,,,,,,,,,,,,,,2,,, +os,29,11,6,3,,,,,26,,,,,,,,,,,7,3,,1,6, +path,,,18,,,,,,,,,,,,,,,,,,,,,18, +reflect,,,37,,,,,,,,,,,,,,,,,,,,,37, +regexp,10,,20,,,,,,,3,3,4,,,,,,,,,,,,20, +slices,,,17,,,,,,,,,,,,,,,,,,,,,,17 +sort,,,1,,,,,,,,,,,,,,,,,,,,,1, +strconv,,,9,,,,,,,,,,,,,,,,,,,,,9, +strings,,,34,,,,,,,,,,,,,,,,,,,,,34, +sync,,,34,,,,,,,,,,,,,,,,,,,,,34, +syscall,5,2,8,5,,,,,,,,,,,,,,,,2,,,,8, +text/scanner,,,3,,,,,,,,,,,,,,,,,,,,,3, +text/tabwriter,,,1,,,,,,,,,,,,,,,,,,,,,1, +text/template,,,6,,,,,,,,,,,,,,,,,,,,,6, +xorm.io/xorm,34,,,,,,,,,,,,,,34,,,,,,,,,, diff --git a/go/documentation/library-coverage/coverage.rst b/go/documentation/library-coverage/coverage.rst index 848d989d2d5..48f24355a33 100644 --- a/go/documentation/library-coverage/coverage.rst +++ b/go/documentation/library-coverage/coverage.rst @@ -9,27 +9,27 @@ Go framework & library support Framework / library,Package,Flow sources,Taint & value steps,Sinks (total) `Afero `_,``github.com/spf13/afero*``,,,34 `CleverGo `_,"``clevergo.tech/clevergo*``, ``github.com/clevergo/clevergo*``",,,2 - `Couchbase official client(gocb) `_,"``github.com/couchbase/gocb*``, ``gopkg.in/couchbase/gocb*``",,36, - `Couchbase unofficial client `_,``github.com/couchbaselabs/gocb*``,,18, + `Couchbase official client(gocb) `_,"``github.com/couchbase/gocb*``, ``gopkg.in/couchbase/gocb*``",,36,16 + `Couchbase unofficial client `_,``github.com/couchbaselabs/gocb*``,,18,8 `Echo `_,``github.com/labstack/echo*``,12,2,3 `Fiber `_,``github.com/gofiber/fiber*``,,,5 `Fosite `_,``github.com/ory/fosite*``,,,2 `Gin `_,``github.com/gin-gonic/gin*``,46,2,3 - `Glog `_,"``github.com/golang/glog*``, ``gopkg.in/glog*``, ``k8s.io/klog*``",,, + `Glog `_,"``github.com/golang/glog*``, ``gopkg.in/glog*``, ``k8s.io/klog*``",,,270 `Go JOSE `_,"``github.com/go-jose/go-jose*``, ``github.com/square/go-jose*``, ``gopkg.in/square/go-jose*``, ``gopkg.in/go-jose/go-jose*``",,16,12 `Go kit `_,``github.com/go-kit/kit*``,,,1 - `Go-spew `_,``github.com/davecgh/go-spew/spew*``,,, + `Go-spew `_,``github.com/davecgh/go-spew/spew*``,,,9 `Gokogiri `_,"``github.com/jbowtie/gokogiri*``, ``github.com/moovweb/gokogiri*``",,,10 `Iris `_,``github.com/kataras/iris*``,,,14 `Kubernetes `_,"``k8s.io/api*``, ``k8s.io/apimachinery*``",,57, - `Logrus `_,"``github.com/Sirupsen/logrus*``, ``github.com/sirupsen/logrus*``",,, + `Logrus `_,"``github.com/Sirupsen/logrus*``, ``github.com/sirupsen/logrus*``",,,290 `Macaron `_,``gopkg.in/macaron*``,12,1,1 `Revel `_,"``github.com/revel/revel*``, ``github.com/robfig/revel*``",46,20,4 `SendGrid `_,``github.com/sendgrid/sendgrid-go*``,,1, - `Standard library `_,"````, ``archive/*``, ``bufio``, ``bytes``, ``cmp``, ``compress/*``, ``container/*``, ``context``, ``crypto``, ``crypto/*``, ``database/*``, ``debug/*``, ``embed``, ``encoding``, ``encoding/*``, ``errors``, ``expvar``, ``flag``, ``fmt``, ``go/*``, ``hash``, ``hash/*``, ``html``, ``html/*``, ``image``, ``image/*``, ``index/*``, ``io``, ``io/*``, ``log``, ``log/*``, ``maps``, ``math``, ``math/*``, ``mime``, ``mime/*``, ``net``, ``net/*``, ``os``, ``os/*``, ``path``, ``path/*``, ``plugin``, ``reflect``, ``reflect/*``, ``regexp``, ``regexp/*``, ``slices``, ``sort``, ``strconv``, ``strings``, ``sync``, ``sync/*``, ``syscall``, ``syscall/*``, ``testing``, ``testing/*``, ``text/*``, ``time``, ``time/*``, ``unicode``, ``unicode/*``, ``unsafe``",32,587,51 + `Standard library `_,"````, ``archive/*``, ``bufio``, ``bytes``, ``cmp``, ``compress/*``, ``container/*``, ``context``, ``crypto``, ``crypto/*``, ``database/*``, ``debug/*``, ``embed``, ``encoding``, ``encoding/*``, ``errors``, ``expvar``, ``flag``, ``fmt``, ``go/*``, ``hash``, ``hash/*``, ``html``, ``html/*``, ``image``, ``image/*``, ``index/*``, ``io``, ``io/*``, ``log``, ``log/*``, ``maps``, ``math``, ``math/*``, ``mime``, ``mime/*``, ``net``, ``net/*``, ``os``, ``os/*``, ``path``, ``path/*``, ``plugin``, ``reflect``, ``reflect/*``, ``regexp``, ``regexp/*``, ``slices``, ``sort``, ``strconv``, ``strings``, ``sync``, ``sync/*``, ``syscall``, ``syscall/*``, ``testing``, ``testing/*``, ``text/*``, ``time``, ``time/*``, ``unicode``, ``unicode/*``, ``unsafe``",33,604,104 `XPath `_,``github.com/antchfx/xpath*``,,,4 `appleboy/gin-jwt `_,``github.com/appleboy/gin-jwt*``,,,1 - `beego `_,"``github.com/astaxie/beego*``, ``github.com/beego/beego*``",63,63,21 + `beego `_,"``github.com/astaxie/beego*``, ``github.com/beego/beego*``",63,63,213 `chi `_,``github.com/go-chi/chi*``,3,, `cristalhq/jwt `_,``github.com/cristalhq/jwt*``,,,1 `fasthttp `_,``github.com/valyala/fasthttp*``,50,5,35 @@ -39,7 +39,7 @@ Go framework & library support `go-sh `_,``github.com/codeskyblue/go-sh*``,,,4 `golang.org/x/crypto/ssh `_,``golang.org/x/crypto/ssh*``,,,4 `golang.org/x/net `_,``golang.org/x/net*``,2,21, - `goproxy `_,``github.com/elazarl/goproxy*``,2,2, + `goproxy `_,``github.com/elazarl/goproxy*``,2,2,2 `gorilla/mux `_,``github.com/gorilla/mux*``,1,, `gorilla/websocket `_,``github.com/gorilla/websocket*``,3,, `goxpath `_,``github.com/ChrisTrenkamp/goxpath*``,,,3 @@ -59,7 +59,7 @@ Go framework & library support `xmlquery `_,``github.com/antchfx/xmlquery*``,,,8 `xpathparser `_,``github.com/santhosh-tekuri/xpathparser*``,,,2 `yaml `_,``gopkg.in/yaml*``,,9, - `zap `_,``go.uber.org/zap*``,,11, - Others,"``github.com/caarlos0/env``, ``github.com/gobuffalo/envy``, ``github.com/hashicorp/go-envparse``, ``github.com/joho/godotenv``, ``github.com/kelseyhightower/envconfig``",23,2, - Totals,,306,911,268 + `zap `_,``go.uber.org/zap*``,,11,33 + Others,"``github.com/Masterminds/squirrel``, ``github.com/caarlos0/env``, ``github.com/go-gorm/gorm``, ``github.com/go-xorm/xorm``, ``github.com/gobuffalo/envy``, ``github.com/gogf/gf/database/gdb``, ``github.com/hashicorp/go-envparse``, ``github.com/jinzhu/gorm``, ``github.com/jmoiron/sqlx``, ``github.com/joho/godotenv``, ``github.com/kelseyhightower/envconfig``, ``github.com/lann/squirrel``, ``github.com/raindog308/gorqlite``, ``github.com/rqlite/gorqlite``, ``github.com/uptrace/bun``, ``go.mongodb.org/mongo-driver/mongo``, ``gopkg.in/Masterminds/squirrel``, ``gorm.io/gorm``, ``xorm.io/xorm``",23,2,391 + Totals,,307,928,1532 diff --git a/go/ql/lib/change-notes/2024-11-17-fix-missing-promoted-fields-and-methods-name-clash.md b/go/ql/lib/change-notes/2024-11-17-fix-missing-promoted-fields-and-methods-name-clash.md new file mode 100644 index 00000000000..8b1ee9b60b2 --- /dev/null +++ b/go/ql/lib/change-notes/2024-11-17-fix-missing-promoted-fields-and-methods-name-clash.md @@ -0,0 +1,4 @@ +--- +category: fix +--- +* Fixed a bug which meant that promoted fields and methods were missing when the embedded parent was not promoted due to a name clash. diff --git a/go/ql/lib/change-notes/2024-11-20-heuristic-logging-sinks.md b/go/ql/lib/change-notes/2024-11-20-heuristic-logging-sinks.md new file mode 100644 index 00000000000..46f5988b379 --- /dev/null +++ b/go/ql/lib/change-notes/2024-11-20-heuristic-logging-sinks.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* A call to a method whose name starts with "Debug", "Error", "Fatal", "Info", "Log", "Output", "Panic", "Print", "Trace", "Warn" or "With" defined on an interface whose name ends in "logger" or "Logger" is now considered a LoggerCall. In particular, it is a sink for `go/clear-text-logging` and `go/log-injection`. This may lead to some more alerts in those queries. diff --git a/go/ql/lib/change-notes/2024-12-03-remove-dataflow-config-class-api.md b/go/ql/lib/change-notes/2024-12-03-remove-dataflow-config-class-api.md new file mode 100644 index 00000000000..d09ec528c99 --- /dev/null +++ b/go/ql/lib/change-notes/2024-12-03-remove-dataflow-config-class-api.md @@ -0,0 +1,4 @@ +--- +category: breaking +--- +* Deleted the old deprecated data flow API that was based on extending a configuration class. See https://github.blog/changelog/2023-08-14-new-dataflow-api-for-writing-custom-codeql-queries for instructions on migrating your queries to use the new API. diff --git a/go/ql/lib/ext/database.sql.driver.model.yml b/go/ql/lib/ext/database.sql.driver.model.yml index c2d780bb7c8..10cfba9388a 100644 --- a/go/ql/lib/ext/database.sql.driver.model.yml +++ b/go/ql/lib/ext/database.sql.driver.model.yml @@ -1,4 +1,14 @@ extensions: + - addsTo: + pack: codeql/go-all + extensible: sinkModel + data: + - ["database/sql/driver", "Execer", True, "Exec", "", "", "Argument[0]", "sql-injection", "manual"] + - ["database/sql/driver", "ExecerContext", True, "ExecContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["database/sql/driver", "Conn", True, "Prepare", "", "", "Argument[0]", "sql-injection", "manual"] + - ["database/sql/driver", "ConnPrepareContext", True, "PrepareContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["database/sql/driver", "Queryer", True, "Query", "", "", "Argument[0]", "sql-injection", "manual"] + - ["database/sql/driver", "QueryerContext", True, "QueryContext", "", "", "Argument[1]", "sql-injection", "manual"] - addsTo: pack: codeql/go-all extensible: summaryModel diff --git a/go/ql/lib/ext/database.sql.model.yml b/go/ql/lib/ext/database.sql.model.yml index e1083f6e49a..5854ced527d 100644 --- a/go/ql/lib/ext/database.sql.model.yml +++ b/go/ql/lib/ext/database.sql.model.yml @@ -1,4 +1,32 @@ extensions: + - addsTo: + pack: codeql/go-all + extensible: sinkModel + data: + - ["database/sql", "Conn", True, "Exec", "", "", "Argument[0]", "sql-injection", "manual"] + - ["database/sql", "Conn", True, "ExecContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["database/sql", "Conn", True, "Prepare", "", "", "Argument[0]", "sql-injection", "manual"] + - ["database/sql", "Conn", True, "PrepareContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["database/sql", "Conn", True, "Query", "", "", "Argument[0]", "sql-injection", "manual"] + - ["database/sql", "Conn", True, "QueryContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["database/sql", "Conn", True, "QueryRow", "", "", "Argument[0]", "sql-injection", "manual"] + - ["database/sql", "Conn", True, "QueryRowContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["database/sql", "DB", True, "Exec", "", "", "Argument[0]", "sql-injection", "manual"] + - ["database/sql", "DB", True, "ExecContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["database/sql", "DB", True, "Prepare", "", "", "Argument[0]", "sql-injection", "manual"] + - ["database/sql", "DB", True, "PrepareContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["database/sql", "DB", True, "Query", "", "", "Argument[0]", "sql-injection", "manual"] + - ["database/sql", "DB", True, "QueryContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["database/sql", "DB", True, "QueryRow", "", "", "Argument[0]", "sql-injection", "manual"] + - ["database/sql", "DB", True, "QueryRowContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["database/sql", "Tx", True, "Exec", "", "", "Argument[0]", "sql-injection", "manual"] + - ["database/sql", "Tx", True, "ExecContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["database/sql", "Tx", True, "Prepare", "", "", "Argument[0]", "sql-injection", "manual"] + - ["database/sql", "Tx", True, "PrepareContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["database/sql", "Tx", True, "Query", "", "", "Argument[0]", "sql-injection", "manual"] + - ["database/sql", "Tx", True, "QueryContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["database/sql", "Tx", True, "QueryRow", "", "", "Argument[0]", "sql-injection", "manual"] + - ["database/sql", "Tx", True, "QueryRowContext", "", "", "Argument[1]", "sql-injection", "manual"] - addsTo: pack: codeql/go-all extensible: summaryModel diff --git a/go/ql/lib/ext/fmt.model.yml b/go/ql/lib/ext/fmt.model.yml index cad64ce0fdf..2baac68da3a 100644 --- a/go/ql/lib/ext/fmt.model.yml +++ b/go/ql/lib/ext/fmt.model.yml @@ -1,4 +1,11 @@ extensions: + - addsTo: + pack: codeql/go-all + extensible: sinkModel + data: + - ["fmt", "", False, "Print", "", "", "Argument[0]", "log-injection", "manual"] + - ["fmt", "", False, "Printf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["fmt", "", False, "Println", "", "", "Argument[0]", "log-injection", "manual"] - addsTo: pack: codeql/go-all extensible: summaryModel diff --git a/go/ql/lib/ext/github.com.beego.beego.client.orm.model.yml b/go/ql/lib/ext/github.com.beego.beego.client.orm.model.yml new file mode 100644 index 00000000000..08c0572b894 --- /dev/null +++ b/go/ql/lib/ext/github.com.beego.beego.client.orm.model.yml @@ -0,0 +1,42 @@ +extensions: + - addsTo: + pack: codeql/go-all + extensible: packageGrouping + data: + - ["beego-orm", "github.com/beego/beego/client/orm"] + - ["beego-orm", "github.com/astaxie/beego/orm"] + - ["beego-orm", "github.com/beego/beego/orm"] + - addsTo: + pack: codeql/go-all + extensible: sinkModel + data: + - ["group:beego-orm", "Condition", True, "Raw", "", "", "Argument[1]", "sql-injection", "manual"] + - ["group:beego-orm", "DB", True, "Exec", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:beego-orm", "DB", True, "ExecContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["group:beego-orm", "DB", True, "Prepare", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:beego-orm", "DB", True, "PrepareContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["group:beego-orm", "DB", True, "Query", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:beego-orm", "DB", True, "QueryContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["group:beego-orm", "DB", True, "QueryRow", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:beego-orm", "DB", True, "QueryRowContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["group:beego-orm", "Ormer", True, "Raw", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:beego-orm", "QueryBuilder", True, "And", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:beego-orm", "QueryBuilder", True, "Delete", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:beego-orm", "QueryBuilder", True, "From", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:beego-orm", "QueryBuilder", True, "GroupBy", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:beego-orm", "QueryBuilder", True, "Having", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:beego-orm", "QueryBuilder", True, "In", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:beego-orm", "QueryBuilder", True, "InnerJoin", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:beego-orm", "QueryBuilder", True, "InsertInto", "", "", "Argument[0..1]", "sql-injection", "manual"] + - ["group:beego-orm", "QueryBuilder", True, "LeftJoin", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:beego-orm", "QueryBuilder", True, "On", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:beego-orm", "QueryBuilder", True, "Or", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:beego-orm", "QueryBuilder", True, "OrderBy", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:beego-orm", "QueryBuilder", True, "RightJoin", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:beego-orm", "QueryBuilder", True, "Select", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:beego-orm", "QueryBuilder", True, "Set", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:beego-orm", "QueryBuilder", True, "Subquery", "", "", "Argument[0..1]", "sql-injection", "manual"] + - ["group:beego-orm", "QueryBuilder", True, "Update", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:beego-orm", "QueryBuilder", True, "Values", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:beego-orm", "QueryBuilder", True, "Where", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:beego-orm", "QuerySeter", True, "FilterRaw", "", "", "Argument[1]", "sql-injection", "manual"] diff --git a/go/ql/lib/ext/github.com.beego.beego.core.logs.model.yml b/go/ql/lib/ext/github.com.beego.beego.core.logs.model.yml new file mode 100644 index 00000000000..b55c3be507d --- /dev/null +++ b/go/ql/lib/ext/github.com.beego.beego.core.logs.model.yml @@ -0,0 +1,34 @@ +extensions: + - addsTo: + pack: codeql/go-all + extensible: packageGrouping + data: + - ["beego-logs", "github.com/astaxie/beego/logs"] + - ["beego-logs", "github.com/beego/beego/logs"] + - ["beego-logs", "github.com/beego/beego/core/logs"] + - addsTo: + pack: codeql/go-all + extensible: sinkModel + data: + - ["group:beego-logs", "", False, "Alert", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego-logs", "", False, "Critical", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego-logs", "", False, "Debug", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego-logs", "", False, "Emergency", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego-logs", "", False, "Error", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego-logs", "", False, "Info", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego-logs", "", False, "Informational", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego-logs", "", False, "Notice", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego-logs", "", False, "Trace", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego-logs", "", False, "Warn", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego-logs", "", False, "Warning", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego-logs", "BeeLogger", True, "Alert", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego-logs", "BeeLogger", True, "Critical", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego-logs", "BeeLogger", True, "Debug", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego-logs", "BeeLogger", True, "Emergency", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego-logs", "BeeLogger", True, "Error", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego-logs", "BeeLogger", True, "Info", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego-logs", "BeeLogger", True, "Informational", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego-logs", "BeeLogger", True, "Notice", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego-logs", "BeeLogger", True, "Trace", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego-logs", "BeeLogger", True, "Warn", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego-logs", "BeeLogger", True, "Warning", "", "", "Argument[0..1]", "log-injection", "manual"] diff --git a/go/ql/lib/ext/github.com.beego.beego.core.utils.model.yml b/go/ql/lib/ext/github.com.beego.beego.core.utils.model.yml index 4eb0688e37e..63c05b92040 100644 --- a/go/ql/lib/ext/github.com.beego.beego.core.utils.model.yml +++ b/go/ql/lib/ext/github.com.beego.beego.core.utils.model.yml @@ -6,6 +6,11 @@ extensions: - ["beego-utils", "github.com/astaxie/beego/utils"] - ["beego-utils", "github.com/beego/beego/utils"] - ["beego-utils", "github.com/beego/beego/core/utils"] + - addsTo: + pack: codeql/go-all + extensible: sinkModel + data: + - ["group:beego-utils", "", False, "Display", "", "", "Argument[0]", "log-injection", "manual"] - addsTo: pack: codeql/go-all extensible: summaryModel diff --git a/go/ql/lib/ext/github.com.beego.beego.server.web.model.yml b/go/ql/lib/ext/github.com.beego.beego.server.web.model.yml index 963000fffcc..0c539522c5a 100644 --- a/go/ql/lib/ext/github.com.beego.beego.server.web.model.yml +++ b/go/ql/lib/ext/github.com.beego.beego.server.web.model.yml @@ -10,6 +10,18 @@ extensions: pack: codeql/go-all extensible: sinkModel data: + # log-injection + - ["group:beego", "", False, "Alert", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego", "", False, "Critical", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego", "", False, "Debug", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego", "", False, "Emergency", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego", "", False, "Error", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego", "", False, "Info", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego", "", False, "Informational", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego", "", False, "Notice", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego", "", False, "Trace", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego", "", False, "Warn", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:beego", "", False, "Warning", "", "", "Argument[0..1]", "log-injection", "manual"] # path-injection - ["group:beego", "", False, "Walk", "", "", "Argument[1]", "path-injection", "manual"] - ["group:beego", "Controller", True, "SaveToFile", "", "", "Argument[1]", "path-injection", "manual"] diff --git a/go/ql/lib/ext/github.com.couchbase.gocb.model.yml b/go/ql/lib/ext/github.com.couchbase.gocb.model.yml index ff0a4c22c8d..d17b53dd6da 100644 --- a/go/ql/lib/ext/github.com.couchbase.gocb.model.yml +++ b/go/ql/lib/ext/github.com.couchbase.gocb.model.yml @@ -3,28 +3,43 @@ extensions: pack: codeql/go-all extensible: packageGrouping data: - - ["gocb", "github.com/couchbase/gocb"] - - ["gocb", "gopkg.in/couchbase/gocb"] - - ["gocb", "github.com/couchbaselabs/gocb"] + - ["gocb1", "fixed-version:github.com/couchbase/gocb"] + - ["gocb1", "fixed-version:gopkg.in/couchbase/gocb.v1"] + - ["gocb1", "fixed-version:github.com/couchbaselabs/gocb"] + - ["gocb2", "github.com/couchbase/gocb/v2"] + - ["gocb2", "gopkg.in/couchbase/gocb.v2"] + - ["gocb2", "github.com/couchbaselabs/gocb/v2"] + - addsTo: + pack: codeql/go-all + extensible: sinkModel + data: + - ["group:gocb1", "Bucket", True, "ExecuteN1qlQuery", "", "", "Argument[0]", "nosql-injection", "manual"] + - ["group:gocb1", "Bucket", True, "ExecuteAnalyticsQuery", "", "", "Argument[0]", "nosql-injection", "manual"] + - ["group:gocb1", "Cluster", True, "ExecuteN1qlQuery", "", "", "Argument[0]", "nosql-injection", "manual"] + - ["group:gocb1", "Cluster", True, "ExecuteAnalyticsQuery", "", "", "Argument[0]", "nosql-injection", "manual"] + - ["group:gocb2", "Cluster", True, "AnalyticsQuery", "", "", "Argument[0]", "nosql-injection", "manual"] + - ["group:gocb2", "Cluster", True, "Query", "", "", "Argument[0]", "nosql-injection", "manual"] + - ["group:gocb2", "Scope", True, "AnalyticsQuery", "", "", "Argument[0]", "nosql-injection", "manual"] + - ["group:gocb2", "Scope", True, "Query", "", "", "Argument[0]", "nosql-injection", "manual"] - addsTo: pack: codeql/go-all extensible: summaryModel data: - - ["group:gocb", "", False, "NewAnalyticsQuery", "", "", "Argument[0]", "ReturnValue", "taint", "manual"] - - ["group:gocb", "", False, "NewN1qlQuery", "", "", "Argument[0]", "ReturnValue", "taint", "manual"] - - ["group:gocb", "AnalyticsQuery", True, "ContextId", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] - - ["group:gocb", "AnalyticsQuery", True, "Deferred", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] - - ["group:gocb", "AnalyticsQuery", True, "Pretty", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] - - ["group:gocb", "AnalyticsQuery", True, "Priority", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] - - ["group:gocb", "AnalyticsQuery", True, "RawParam", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] - - ["group:gocb", "AnalyticsQuery", True, "ServerSideTimeout", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] - - ["group:gocb", "N1qlQuery", True, "AdHoc", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] - - ["group:gocb", "N1qlQuery", True, "Consistency", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] - - ["group:gocb", "N1qlQuery", True, "ConsistentWith", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] - - ["group:gocb", "N1qlQuery", True, "Custom", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] - - ["group:gocb", "N1qlQuery", True, "PipelineBatch", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] - - ["group:gocb", "N1qlQuery", True, "PipelineCap", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] - - ["group:gocb", "N1qlQuery", True, "Profile", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] - - ["group:gocb", "N1qlQuery", True, "ReadOnly", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] - - ["group:gocb", "N1qlQuery", True, "ScanCap", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] - - ["group:gocb", "N1qlQuery", True, "Timeout", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] + - ["group:gocb1", "", False, "NewAnalyticsQuery", "", "", "Argument[0]", "ReturnValue", "taint", "manual"] + - ["group:gocb1", "", False, "NewN1qlQuery", "", "", "Argument[0]", "ReturnValue", "taint", "manual"] + - ["group:gocb1", "AnalyticsQuery", True, "ContextId", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] + - ["group:gocb1", "AnalyticsQuery", True, "Deferred", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] + - ["group:gocb1", "AnalyticsQuery", True, "Pretty", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] + - ["group:gocb1", "AnalyticsQuery", True, "Priority", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] + - ["group:gocb1", "AnalyticsQuery", True, "RawParam", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] + - ["group:gocb1", "AnalyticsQuery", True, "ServerSideTimeout", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] + - ["group:gocb1", "N1qlQuery", True, "AdHoc", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] + - ["group:gocb1", "N1qlQuery", True, "Consistency", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] + - ["group:gocb1", "N1qlQuery", True, "ConsistentWith", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] + - ["group:gocb1", "N1qlQuery", True, "Custom", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] + - ["group:gocb1", "N1qlQuery", True, "PipelineBatch", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] + - ["group:gocb1", "N1qlQuery", True, "PipelineCap", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] + - ["group:gocb1", "N1qlQuery", True, "Profile", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] + - ["group:gocb1", "N1qlQuery", True, "ReadOnly", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] + - ["group:gocb1", "N1qlQuery", True, "ScanCap", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] + - ["group:gocb1", "N1qlQuery", True, "Timeout", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"] diff --git a/go/ql/lib/ext/github.com.davecgh.go-spew.spew.model.yml b/go/ql/lib/ext/github.com.davecgh.go-spew.spew.model.yml new file mode 100644 index 00000000000..4b4996926e3 --- /dev/null +++ b/go/ql/lib/ext/github.com.davecgh.go-spew.spew.model.yml @@ -0,0 +1,14 @@ +extensions: + - addsTo: + pack: codeql/go-all + extensible: sinkModel + data: + - ["github.com/davecgh/go-spew/spew", "", False, "Dump", "", "", "Argument[0]", "log-injection", "manual"] + - ["github.com/davecgh/go-spew/spew", "", False, "Errorf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["github.com/davecgh/go-spew/spew", "", False, "Fdump", "", "", "Argument[1]", "log-injection", "manual"] + - ["github.com/davecgh/go-spew/spew", "", False, "Fprint", "", "", "Argument[1]", "log-injection", "manual"] + - ["github.com/davecgh/go-spew/spew", "", False, "Fprintf", "", "", "Argument[1..2]", "log-injection", "manual"] + - ["github.com/davecgh/go-spew/spew", "", False, "Fprintln", "", "", "Argument[1]", "log-injection", "manual"] + - ["github.com/davecgh/go-spew/spew", "", False, "Print", "", "", "Argument[0]", "log-injection", "manual"] + - ["github.com/davecgh/go-spew/spew", "", False, "Printf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["github.com/davecgh/go-spew/spew", "", False, "Println", "", "", "Argument[0]", "log-injection", "manual"] diff --git a/go/ql/lib/ext/github.com.elazarl.goproxy.model.yml b/go/ql/lib/ext/github.com.elazarl.goproxy.model.yml index 20e4a26f1cd..9dc8284ea58 100644 --- a/go/ql/lib/ext/github.com.elazarl.goproxy.model.yml +++ b/go/ql/lib/ext/github.com.elazarl.goproxy.model.yml @@ -1,4 +1,10 @@ extensions: + - addsTo: + pack: codeql/go-all + extensible: sinkModel + data: + - ["github.com/elazarl/goproxy", "ProxyCtx", True, "Logf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["github.com/elazarl/goproxy", "ProxyCtx", True, "Warnf", "", "", "Argument[0..1]", "log-injection", "manual"] - addsTo: pack: codeql/go-all extensible: summaryModel diff --git a/go/ql/lib/ext/github.com.gogf.gf.database.gdb.model.yml b/go/ql/lib/ext/github.com.gogf.gf.database.gdb.model.yml new file mode 100644 index 00000000000..030656c6eb8 --- /dev/null +++ b/go/ql/lib/ext/github.com.gogf.gf.database.gdb.model.yml @@ -0,0 +1,57 @@ +extensions: + - addsTo: + pack: codeql/go-all + extensible: sinkModel + data: + # These models are for v1. Some of them hold for v2, but we should model v2 properly. + - ["github.com/gogf/gf/database/gdb", "Core", True, "DoCommit", "", "", "Argument[2]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Core", True, "DoExec", "", "", "Argument[2]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Core", True, "DoGetAll", "", "", "Argument[2]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Core", True, "DoQuery", "", "", "Argument[2]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Core", True, "DoPrepare", "", "", "Argument[2]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Core", True, "Exec", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Core", True, "GetAll", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Core", True, "GetArray", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Core", True, "GetCount", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Core", True, "GetOne", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Core", True, "GetScan", "", "", "Argument[1]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Core", True, "GetStruct", "", "", "Argument[1]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Core", True, "GetStructs", "", "", "Argument[1]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Core", True, "GetValue", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Core", True, "Prepare", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Core", True, "Query", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Core", True, "Raw", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "DB", True, "DoCommit", "", "", "Argument[2]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "DB", True, "DoExec", "", "", "Argument[2]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "DB", True, "DoGetAll", "", "", "Argument[2]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "DB", True, "DoQuery", "", "", "Argument[2]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "DB", True, "DoPrepare", "", "", "Argument[2]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "DB", True, "Exec", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "DB", True, "GetAll", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "DB", True, "GetArray", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "DB", True, "GetCount", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "DB", True, "GetOne", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "DB", True, "GetScan", "", "", "Argument[1]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "DB", True, "GetStruct", "", "", "Argument[1]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "DB", True, "GetStructs", "", "", "Argument[1]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "DB", True, "GetValue", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "DB", True, "Prepare", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "DB", True, "Query", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "DB", True, "Raw", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Tx", True, "DoCommit", "", "", "Argument[2]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Tx", True, "DoExec", "", "", "Argument[2]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Tx", True, "DoGetAll", "", "", "Argument[2]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Tx", True, "DoQuery", "", "", "Argument[2]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Tx", True, "DoPrepare", "", "", "Argument[2]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Tx", True, "Exec", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Tx", True, "GetAll", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Tx", True, "GetArray", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Tx", True, "GetCount", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Tx", True, "GetOne", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Tx", True, "GetScan", "", "", "Argument[1]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Tx", True, "GetStruct", "", "", "Argument[1]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Tx", True, "GetStructs", "", "", "Argument[1]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Tx", True, "GetValue", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Tx", True, "Prepare", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Tx", True, "Query", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/gogf/gf/database/gdb", "Tx", True, "Raw", "", "", "Argument[0]", "sql-injection", "manual"] diff --git a/go/ql/lib/ext/github.com.golang.glog.model.yml b/go/ql/lib/ext/github.com.golang.glog.model.yml new file mode 100644 index 00000000000..275450f2c44 --- /dev/null +++ b/go/ql/lib/ext/github.com.golang.glog.model.yml @@ -0,0 +1,102 @@ +extensions: + - addsTo: + pack: codeql/go-all + extensible: packageGrouping + data: + - ["glog", "github.com/golang/glog"] + - ["glog", "gopkg.in/glog"] + - ["glog", "k8s.io/klog"] + - addsTo: + pack: codeql/go-all + extensible: sinkModel + data: + - ["group:glog", "", False, "Error", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:glog", "", False, "ErrorContext", "", "", "Argument[1]", "log-injection", "manual"] + - ["group:glog", "", False, "ErrorContextDepth", "", "", "Argument[2]", "log-injection", "manual"] + - ["group:glog", "", False, "ErrorContextDepthf", "", "", "Argument[2..3]", "log-injection", "manual"] + - ["group:glog", "", False, "ErrorContextf", "", "", "Argument[1..2]", "log-injection", "manual"] + - ["group:glog", "", False, "ErrorDepth", "", "", "Argument[1]", "log-injection", "manual"] + - ["group:glog", "", False, "ErrorDepthf", "", "", "Argument[1..2]", "log-injection", "manual"] + - ["group:glog", "", False, "Errorf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:glog", "", False, "Errorln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:glog", "", False, "Exit", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:glog", "", False, "ExitContext", "", "", "Argument[1]", "log-injection", "manual"] + - ["group:glog", "", False, "ExitContextDepth", "", "", "Argument[2]", "log-injection", "manual"] + - ["group:glog", "", False, "ExitContextDepthf", "", "", "Argument[2..3]", "log-injection", "manual"] + - ["group:glog", "", False, "ExitContextf", "", "", "Argument[1..2]", "log-injection", "manual"] + - ["group:glog", "", False, "ExitDepth", "", "", "Argument[1]", "log-injection", "manual"] + - ["group:glog", "", False, "ExitDepthf", "", "", "Argument[1..2]", "log-injection", "manual"] + - ["group:glog", "", False, "Exitf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:glog", "", False, "Exitln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:glog", "", False, "Fatal", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:glog", "", False, "FatalContext", "", "", "Argument[1]", "log-injection", "manual"] + - ["group:glog", "", False, "FatalContextDepth", "", "", "Argument[2]", "log-injection", "manual"] + - ["group:glog", "", False, "FatalContextDepthf", "", "", "Argument[2..3]", "log-injection", "manual"] + - ["group:glog", "", False, "FatalContextf", "", "", "Argument[1..2]", "log-injection", "manual"] + - ["group:glog", "", False, "FatalDepth", "", "", "Argument[1]", "log-injection", "manual"] + - ["group:glog", "", False, "FatalDepthf", "", "", "Argument[1..2]", "log-injection", "manual"] + - ["group:glog", "", False, "Fatalf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:glog", "", False, "Fatalln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:glog", "", False, "Info", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:glog", "", False, "InfoContext", "", "", "Argument[1]", "log-injection", "manual"] + - ["group:glog", "", False, "InfoContextDepth", "", "", "Argument[2]", "log-injection", "manual"] + - ["group:glog", "", False, "InfoContextDepthf", "", "", "Argument[2..3]", "log-injection", "manual"] + - ["group:glog", "", False, "InfoContextf", "", "", "Argument[1..2]", "log-injection", "manual"] + - ["group:glog", "", False, "InfoDepth", "", "", "Argument[1]", "log-injection", "manual"] + - ["group:glog", "", False, "InfoDepthf", "", "", "Argument[1..2]", "log-injection", "manual"] + - ["group:glog", "", False, "Infof", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:glog", "", False, "Infoln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:glog", "", False, "Warning", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:glog", "", False, "WarningContext", "", "", "Argument[1]", "log-injection", "manual"] + - ["group:glog", "", False, "WarningContextDepth", "", "", "Argument[2]", "log-injection", "manual"] + - ["group:glog", "", False, "WarningContextDepthf", "", "", "Argument[2..3]", "log-injection", "manual"] + - ["group:glog", "", False, "WarningContextf", "", "", "Argument[1..2]", "log-injection", "manual"] + - ["group:glog", "", False, "WarningDepth", "", "", "Argument[1]", "log-injection", "manual"] + - ["group:glog", "", False, "WarningDepthf", "", "", "Argument[1..2]", "log-injection", "manual"] + - ["group:glog", "", False, "Warningf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:glog", "", False, "Warningln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "Error", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "ErrorContext", "", "", "Argument[1]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "ErrorContextDepth", "", "", "Argument[2]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "ErrorContextDepthf", "", "", "Argument[2..3]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "ErrorContextf", "", "", "Argument[1..2]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "ErrorDepth", "", "", "Argument[1]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "ErrorDepthf", "", "", "Argument[1..2]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "Errorf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "Errorln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "Exit", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "ExitContext", "", "", "Argument[1]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "ExitContextDepth", "", "", "Argument[2]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "ExitContextDepthf", "", "", "Argument[2..3]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "ExitContextf", "", "", "Argument[1..2]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "ExitDepth", "", "", "Argument[1]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "ExitDepthf", "", "", "Argument[1..2]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "Exitf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "Exitln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "Fatal", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "FatalContext", "", "", "Argument[1]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "FatalContextDepth", "", "", "Argument[2]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "FatalContextDepthf", "", "", "Argument[2..3]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "FatalContextf", "", "", "Argument[1..2]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "FatalDepth", "", "", "Argument[1]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "FatalDepthf", "", "", "Argument[1..2]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "Fatalf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "Fatalln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "Info", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "InfoContext", "", "", "Argument[1]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "InfoContextDepth", "", "", "Argument[2]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "InfoContextDepthf", "", "", "Argument[2..3]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "InfoContextf", "", "", "Argument[1..2]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "InfoDepth", "", "", "Argument[1]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "InfoDepthf", "", "", "Argument[1..2]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "Infof", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "Infoln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "Warning", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "WarningContext", "", "", "Argument[1]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "WarningContextDepth", "", "", "Argument[2]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "WarningContextDepthf", "", "", "Argument[2..3]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "WarningContextf", "", "", "Argument[1..2]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "WarningDepth", "", "", "Argument[1]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "WarningDepthf", "", "", "Argument[1..2]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "Warningf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:glog", "Verbose", True, "Warningln", "", "", "Argument[0]", "log-injection", "manual"] diff --git a/go/ql/lib/ext/github.com.jmoiron.sqlx.model.yml b/go/ql/lib/ext/github.com.jmoiron.sqlx.model.yml new file mode 100644 index 00000000000..8c9d19b4b85 --- /dev/null +++ b/go/ql/lib/ext/github.com.jmoiron.sqlx.model.yml @@ -0,0 +1,17 @@ +extensions: + - addsTo: + pack: codeql/go-all + extensible: sinkModel + data: + - ["github.com/jmoiron/sqlx", "DB", True, "Get", "", "", "Argument[1]", "sql-injection", "manual"] + - ["github.com/jmoiron/sqlx", "DB", True, "MustExec", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/jmoiron/sqlx", "DB", True, "NamedExec", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/jmoiron/sqlx", "DB", True, "NamedQuery", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/jmoiron/sqlx", "DB", True, "Queryx", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/jmoiron/sqlx", "DB", True, "Select", "", "", "Argument[1]", "sql-injection", "manual"] + - ["github.com/jmoiron/sqlx", "Tx", True, "Get", "", "", "Argument[1]", "sql-injection", "manual"] + - ["github.com/jmoiron/sqlx", "Tx", True, "MustExec", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/jmoiron/sqlx", "Tx", True, "NamedExec", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/jmoiron/sqlx", "Tx", True, "NamedQuery", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/jmoiron/sqlx", "Tx", True, "Queryx", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/jmoiron/sqlx", "Tx", True, "Select", "", "", "Argument[1]", "sql-injection", "manual"] diff --git a/go/ql/lib/ext/github.com.mastermind.squirrel.model.yml b/go/ql/lib/ext/github.com.mastermind.squirrel.model.yml new file mode 100644 index 00000000000..6f3c5830e45 --- /dev/null +++ b/go/ql/lib/ext/github.com.mastermind.squirrel.model.yml @@ -0,0 +1,51 @@ +extensions: + - addsTo: + pack: codeql/go-all + extensible: packageGrouping + data: + - ["squirrel", "github.com/Masterminds/squirrel"] + - ["squirrel", "gopkg.in/Masterminds/squirrel"] + - ["squirrel", "github.com/lann/squirrel"] + - addsTo: + pack: codeql/go-all + extensible: sinkModel + data: + - ["group:squirrel", "", False, "Delete", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:squirrel", "", False, "Expr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:squirrel", "", False, "Insert", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:squirrel", "", False, "Select", "", "", "Argument[0]", "sql-injection", "manual"] # TODO: when sources can have access paths, use .ArrayElement + - ["group:squirrel", "", False, "Update", "", "", "Argument[0]", "sql-injection", "manual"] # TODO: when sources can have access paths, use .ArrayElement + + - ["group:squirrel", "DeleteBuilder", True, "From", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:squirrel", "DeleteBuilder", True, "OrderBy", "", "", "Argument[0]", "sql-injection", "manual"] # TODO: when sources can have access paths, use .ArrayElement + - ["group:squirrel", "DeleteBuilder", True, "Prefix", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:squirrel", "DeleteBuilder", True, "Suffix", "", "", "Argument[0]", "sql-injection", "manual"] + # DeleteBuilder.Where has to be modeled in QL to avoid FPs when a non-string argument is used + + - ["group:squirrel", "InsertBuilder", True, "Columns", "", "", "Argument[0]", "sql-injection", "manual"] # TODO: when sources can have access paths, use .ArrayElement + - ["group:squirrel", "InsertBuilder", True, "Into", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:squirrel", "InsertBuilder", True, "Options", "", "", "Argument[0]", "sql-injection", "manual"] # TODO: when sources can have access paths, use .ArrayElement + - ["group:squirrel", "InsertBuilder", True, "Prefix", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:squirrel", "InsertBuilder", True, "Suffix", "", "", "Argument[0]", "sql-injection", "manual"] + + - ["group:squirrel", "SelectBuilder", True, "CrossJoin", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:squirrel", "SelectBuilder", True, "Column", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:squirrel", "SelectBuilder", True, "Columns", "", "", "Argument[0]", "sql-injection", "manual"] # TODO: when sources can have access paths, use .ArrayElement + - ["group:squirrel", "SelectBuilder", True, "From", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:squirrel", "SelectBuilder", True, "GroupBy", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:squirrel", "SelectBuilder", True, "InnerJoin", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:squirrel", "SelectBuilder", True, "LeftJoin", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:squirrel", "SelectBuilder", True, "Options", "", "", "Argument[0]", "sql-injection", "manual"] # TODO: when sources can have access paths, use .ArrayElement + - ["group:squirrel", "SelectBuilder", True, "OrderBy", "", "", "Argument[0]", "sql-injection", "manual"] # TODO: when sources can have access paths, use .ArrayElement + - ["group:squirrel", "SelectBuilder", True, "Prefix", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:squirrel", "SelectBuilder", True, "RightJoin", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:squirrel", "SelectBuilder", True, "Suffix", "", "", "Argument[0]", "sql-injection", "manual"] + # SelectBuilder.Where has to be modeled in QL to avoid FPs when a non-string argument is used + + - ["group:squirrel", "UpdateBuilder", True, "From", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:squirrel", "UpdateBuilder", True, "OrderBy", "", "", "Argument[0]", "sql-injection", "manual"] # TODO: when sources can have access paths, use .ArrayElement + - ["group:squirrel", "UpdateBuilder", True, "Prefix", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:squirrel", "UpdateBuilder", True, "Set", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:squirrel", "UpdateBuilder", True, "Suffix", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:squirrel", "UpdateBuilder", True, "Table", "", "", "Argument[0]", "sql-injection", "manual"] + # UpdateBuilder.Where has to be modeled in QL to avoid FPs when a non-string argument is used diff --git a/go/ql/lib/ext/github.com.rqlite.gorqlite.model.yml b/go/ql/lib/ext/github.com.rqlite.gorqlite.model.yml new file mode 100644 index 00000000000..62e24f2c920 --- /dev/null +++ b/go/ql/lib/ext/github.com.rqlite.gorqlite.model.yml @@ -0,0 +1,35 @@ +extensions: + - addsTo: + pack: codeql/go-all + extensible: packageGrouping + data: + - ["gorqlite", "github.com/rqlite/gorqlite"] + - ["gorqlite", "github.com/raindog308/gorqlite"] + - addsTo: + pack: codeql/go-all + extensible: sinkModel + data: + - ["group:gorqlite", "Connection", True, "Query", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:gorqlite", "Connection", True, "QueryContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["group:gorqlite", "Connection", True, "QueryOne", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:gorqlite", "Connection", True, "QueryOneContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["group:gorqlite", "Connection", True, "QueryOneParameterized", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:gorqlite", "Connection", True, "QueryOneParameterizedContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["group:gorqlite", "Connection", True, "QueryParameterized", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:gorqlite", "Connection", True, "QueryParameterizedContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["group:gorqlite", "Connection", True, "Queue", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:gorqlite", "Connection", True, "QueueContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["group:gorqlite", "Connection", True, "QueueOne", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:gorqlite", "Connection", True, "QueueOneContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["group:gorqlite", "Connection", True, "QueueOneParameterized", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:gorqlite", "Connection", True, "QueueOneParameterizedContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["group:gorqlite", "Connection", True, "QueueParameterized", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:gorqlite", "Connection", True, "QueueParameterizedContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["group:gorqlite", "Connection", True, "Write", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:gorqlite", "Connection", True, "WriteContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["group:gorqlite", "Connection", True, "WriteOne", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:gorqlite", "Connection", True, "WriteOneContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["group:gorqlite", "Connection", True, "WriteOneParameterized", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:gorqlite", "Connection", True, "WriteOneParameterizedContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["group:gorqlite", "Connection", True, "WriteParameterized", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:gorqlite", "Connection", True, "WriteParameterizedContext", "", "", "Argument[1]", "sql-injection", "manual"] diff --git a/go/ql/lib/ext/github.com.sirupsen.logrus.model.yml b/go/ql/lib/ext/github.com.sirupsen.logrus.model.yml new file mode 100644 index 00000000000..06f9a54622b --- /dev/null +++ b/go/ql/lib/ext/github.com.sirupsen.logrus.model.yml @@ -0,0 +1,159 @@ +extensions: + - addsTo: + pack: codeql/go-all + extensible: packageGrouping + data: + - ["logrus", "github.com/sirupsen/logrus"] + - ["logrus", "github.com/Sirupsen/logrus"] + - addsTo: + pack: codeql/go-all + extensible: sinkModel + data: + - ["group:logrus", "", False, "Debug", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "DebugFn", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "Debugf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "", False, "Debugln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "Error", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "ErrorFn", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "Errorf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "", False, "Errorln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "Fatal", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "FatalFn", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "Fatalf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "", False, "Fatalln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "Info", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "InfoFn", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "Infof", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "", False, "Infoln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "Panic", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "PanicFn", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "Panicf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "", False, "Panicln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "Print", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "PrintFn", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "Printf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "", False, "Println", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "Trace", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "TraceFn", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "Tracef", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "", False, "Traceln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "Warn", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "WarnFn", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "Warnf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "", False, "Warnln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "Warning", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "WarningFn", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "Warningf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "", False, "Warningln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "WithError", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "WithField", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "", False, "WithFields", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "", False, "WithTime", "", "", "Argument[0]", "log-injection", "manual"] + + - ["group:logrus", "Entry", True, "Debug", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Debugf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Debugln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Error", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Errorf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Errorln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Fatal", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Fatalf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Fatalln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Info", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Infof", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Infoln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Log", "", "", "Argument[1]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Logf", "", "", "Argument[1..2]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Logln", "", "", "Argument[1]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Panic", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Panicf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Panicln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Print", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Printf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Println", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Trace", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Tracef", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Traceln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Warn", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Warnf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Warnln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Warning", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Warningf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "Warningln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "WithError", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "WithField", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "WithFields", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Entry", True, "WithTime", "", "", "Argument[0]", "log-injection", "manual"] + + - ["group:logrus", "FieldLogger", True, "Debug", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "FieldLogger", True, "Debugf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "FieldLogger", True, "Debugln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "FieldLogger", True, "Error", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "FieldLogger", True, "Errorf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "FieldLogger", True, "Errorln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "FieldLogger", True, "Fatal", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "FieldLogger", True, "Fatalf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "FieldLogger", True, "Fatalln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "FieldLogger", True, "Info", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "FieldLogger", True, "Infof", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "FieldLogger", True, "Infoln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "FieldLogger", True, "Panic", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "FieldLogger", True, "Panicf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "FieldLogger", True, "Panicln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "FieldLogger", True, "Print", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "FieldLogger", True, "Printf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "FieldLogger", True, "Println", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "FieldLogger", True, "Warn", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "FieldLogger", True, "Warnf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "FieldLogger", True, "Warnln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "FieldLogger", True, "Warning", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "FieldLogger", True, "Warningf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "FieldLogger", True, "Warningln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "FieldLogger", True, "WithError", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "FieldLogger", True, "WithField", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "FieldLogger", True, "WithFields", "", "", "Argument[0]", "log-injection", "manual"] + + - ["group:logrus", "Logger", True, "Debug", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "DebugFn", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Debugf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Debugln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Error", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "ErrorFn", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Errorf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Errorln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Fatal", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "FatalFn", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Fatalf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Fatalln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Info", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "InfoFn", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Infof", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Infoln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Log", "", "", "Argument[1]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "LogFn", "", "", "Argument[1]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Logf", "", "", "Argument[1..2]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Logln", "", "", "Argument[1]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Panic", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "PanicFn", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Panicf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Panicln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Print", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "PrintFn", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Printf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Println", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Trace", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "TraceFn", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Tracef", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Traceln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Warn", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "WarnFn", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Warnf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Warnln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Warning", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "WarningFn", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Warningf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "Warningln", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "WithError", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "WithField", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "WithFields", "", "", "Argument[0]", "log-injection", "manual"] + - ["group:logrus", "Logger", True, "WithTime", "", "", "Argument[0]", "log-injection", "manual"] diff --git a/go/ql/lib/ext/github.com.uptrace.bun.model.yml b/go/ql/lib/ext/github.com.uptrace.bun.model.yml new file mode 100644 index 00000000000..a08adb07973 --- /dev/null +++ b/go/ql/lib/ext/github.com.uptrace.bun.model.yml @@ -0,0 +1,68 @@ +extensions: + - addsTo: + pack: codeql/go-all + extensible: sinkModel + data: + - ["github.com/uptrace/bun", "", False, "NewRawQuery", "", "", "Argument[1]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "AddColumnQuery", True, "ColumnExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "AddColumnQuery", True, "ModelTableExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "AddColumnQuery", True, "TableExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "Conn", True, "Exec", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "Conn", True, "ExecContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "Conn", True, "NewRaw", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "Conn", True, "Prepare", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "Conn", True, "Query", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "Conn", True, "QueryRow", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "Conn", True, "PrepareContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "Conn", True, "QueryContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "Conn", True, "QueryRowContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "Conn", True, "Raw", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "CreateIndexQuery", True, "ColumnExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "CreateIndexQuery", True, "ModelTableExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "CreateIndexQuery", True, "TableExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "CreateIndexQuery", True, "Where", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "CreateIndexQuery", True, "WhereOr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "CreateTableQuery", True, "ColumnExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "CreateTableQuery", True, "ModelTableExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "CreateTableQuery", True, "TableExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "DB", True, "Exec", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "DB", True, "ExecContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "DB", True, "NewRaw", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "DB", True, "Prepare", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "DB", True, "Query", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "DB", True, "QueryRow", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "DB", True, "PrepareContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "DB", True, "QueryContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "DB", True, "QueryRowContext", "", "", "Argument[1]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "DB", True, "Raw", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "DeleteQuery", True, "TableExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "DeleteQuery", True, "Where", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "DeleteQuery", True, "WhereOr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "DropColumnQuery", True, "ColumnExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "DropColumnQuery", True, "ModelTableExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "DropColumnQuery", True, "TableExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "DropTableQuery", True, "ModelTableExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "DropTableQuery", True, "TableExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "InsertQuery", True, "ColumnExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "InsertQuery", True, "ModelTableExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "InsertQuery", True, "TableExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "InsertQuery", True, "Where", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "InsertQuery", True, "WhereOr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "MergeQuery", True, "ModelTableExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "MergeQuery", True, "TableExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "RawQuery", True, "NewRaw", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "SelectQuery", True, "ColumnExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "SelectQuery", True, "DistinctOn", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "SelectQuery", True, "For", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "SelectQuery", True, "GroupExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "SelectQuery", True, "Having", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "SelectQuery", True, "ModelTableExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "SelectQuery", True, "OrderExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "SelectQuery", True, "TableExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "SelectQuery", True, "Where", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "SelectQuery", True, "WhereOr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "TruncateTableQuery", True, "TableExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "UpdateQuery", True, "ModelTableExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "UpdateQuery", True, "TableExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "UpdateQuery", True, "Where", "", "", "Argument[0]", "sql-injection", "manual"] + - ["github.com/uptrace/bun", "UpdateQuery", True, "WhereOr", "", "", "Argument[0]", "sql-injection", "manual"] diff --git a/go/ql/lib/ext/go.mongodb.org.mongo-driver.mongo.model.yml b/go/ql/lib/ext/go.mongodb.org.mongo-driver.mongo.model.yml new file mode 100644 index 00000000000..6c2d4afdeae --- /dev/null +++ b/go/ql/lib/ext/go.mongodb.org.mongo-driver.mongo.model.yml @@ -0,0 +1,19 @@ +extensions: + - addsTo: + pack: codeql/go-all + extensible: sinkModel + data: + - ["go.mongodb.org/mongo-driver/mongo", "Collection", True, "Aggregate", "", "", "Argument[1]", "nosql-injection", "manual"] + - ["go.mongodb.org/mongo-driver/mongo", "Collection", True, "CountDocuments", "", "", "Argument[1]", "nosql-injection", "manual"] + - ["go.mongodb.org/mongo-driver/mongo", "Collection", True, "DeleteMany", "", "", "Argument[1]", "nosql-injection", "manual"] + - ["go.mongodb.org/mongo-driver/mongo", "Collection", True, "DeleteOne", "", "", "Argument[1]", "nosql-injection", "manual"] + - ["go.mongodb.org/mongo-driver/mongo", "Collection", True, "Distinct", "", "", "Argument[2]", "nosql-injection", "manual"] + - ["go.mongodb.org/mongo-driver/mongo", "Collection", True, "Find", "", "", "Argument[1]", "nosql-injection", "manual"] + - ["go.mongodb.org/mongo-driver/mongo", "Collection", True, "FindOne", "", "", "Argument[1]", "nosql-injection", "manual"] + - ["go.mongodb.org/mongo-driver/mongo", "Collection", True, "FindOneAndDelete", "", "", "Argument[1]", "nosql-injection", "manual"] + - ["go.mongodb.org/mongo-driver/mongo", "Collection", True, "FindOneAndReplace", "", "", "Argument[1]", "nosql-injection", "manual"] + - ["go.mongodb.org/mongo-driver/mongo", "Collection", True, "FindOneAndUpdate", "", "", "Argument[1]", "nosql-injection", "manual"] + - ["go.mongodb.org/mongo-driver/mongo", "Collection", True, "ReplaceOne", "", "", "Argument[1]", "nosql-injection", "manual"] + - ["go.mongodb.org/mongo-driver/mongo", "Collection", True, "UpdateMany", "", "", "Argument[1]", "nosql-injection", "manual"] + - ["go.mongodb.org/mongo-driver/mongo", "Collection", True, "UpdateOne", "", "", "Argument[1]", "nosql-injection", "manual"] + - ["go.mongodb.org/mongo-driver/mongo", "Collection", True, "Watch", "", "", "Argument[1]", "nosql-injection", "manual"] diff --git a/go/ql/lib/ext/go.uber.org.zap.model.yml b/go/ql/lib/ext/go.uber.org.zap.model.yml index 2ca7f7e8a80..e9fc971e5fa 100644 --- a/go/ql/lib/ext/go.uber.org.zap.model.yml +++ b/go/ql/lib/ext/go.uber.org.zap.model.yml @@ -1,4 +1,41 @@ extensions: + - addsTo: + pack: codeql/go-all + extensible: sinkModel + data: + - ["go.uber.org/zap", "Logger", True, "DPanic", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["go.uber.org/zap", "Logger", True, "Debug", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["go.uber.org/zap", "Logger", True, "Error", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["go.uber.org/zap", "Logger", True, "Fatal", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["go.uber.org/zap", "Logger", True, "Info", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["go.uber.org/zap", "Logger", True, "Named", "", "", "Argument[0]", "log-injection", "manual"] + - ["go.uber.org/zap", "Logger", True, "Panic", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["go.uber.org/zap", "Logger", True, "Warn", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["go.uber.org/zap", "Logger", True, "With", "", "", "Argument[0]", "log-injection", "manual"] + - ["go.uber.org/zap", "Logger", True, "WithOptions", "", "", "Argument[0]", "log-injection", "manual"] + - ["go.uber.org/zap", "SugaredLogger", True, "DPanic", "", "", "Argument[0]", "log-injection", "manual"] + - ["go.uber.org/zap", "SugaredLogger", True, "DPanicf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["go.uber.org/zap", "SugaredLogger", True, "DPanicw", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["go.uber.org/zap", "SugaredLogger", True, "Debug", "", "", "Argument[0]", "log-injection", "manual"] + - ["go.uber.org/zap", "SugaredLogger", True, "Debugf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["go.uber.org/zap", "SugaredLogger", True, "Debugw", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["go.uber.org/zap", "SugaredLogger", True, "Error", "", "", "Argument[0]", "log-injection", "manual"] + - ["go.uber.org/zap", "SugaredLogger", True, "Errorf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["go.uber.org/zap", "SugaredLogger", True, "Errorw", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["go.uber.org/zap", "SugaredLogger", True, "Fatal", "", "", "Argument[0]", "log-injection", "manual"] + - ["go.uber.org/zap", "SugaredLogger", True, "Fatalf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["go.uber.org/zap", "SugaredLogger", True, "Fatalw", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["go.uber.org/zap", "SugaredLogger", True, "Info", "", "", "Argument[0]", "log-injection", "manual"] + - ["go.uber.org/zap", "SugaredLogger", True, "Infof", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["go.uber.org/zap", "SugaredLogger", True, "Infow", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["go.uber.org/zap", "SugaredLogger", True, "Named", "", "", "Argument[0]", "log-injection", "manual"] + - ["go.uber.org/zap", "SugaredLogger", True, "Panic", "", "", "Argument[0]", "log-injection", "manual"] + - ["go.uber.org/zap", "SugaredLogger", True, "Panicf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["go.uber.org/zap", "SugaredLogger", True, "Panicw", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["go.uber.org/zap", "SugaredLogger", True, "Warn", "", "", "Argument[0]", "log-injection", "manual"] + - ["go.uber.org/zap", "SugaredLogger", True, "Warnf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["go.uber.org/zap", "SugaredLogger", True, "Warnw", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["go.uber.org/zap", "SugaredLogger", True, "With", "", "", "Argument[0]", "log-injection", "manual"] - addsTo: pack: codeql/go-all extensible: summaryModel diff --git a/go/ql/lib/ext/gorm.io.gorm.model.yml b/go/ql/lib/ext/gorm.io.gorm.model.yml new file mode 100644 index 00000000000..bfcf1fa66a7 --- /dev/null +++ b/go/ql/lib/ext/gorm.io.gorm.model.yml @@ -0,0 +1,25 @@ +extensions: + - addsTo: + pack: codeql/go-all + extensible: packageGrouping + data: + - ["gorm", "gorm.io/gorm"] + - ["gorm", "github.com/jinzhu/gorm"] + - ["gorm", "github.com/go-gorm/gorm"] + - addsTo: + pack: codeql/go-all + extensible: sinkModel + data: + - ["group:gorm", "DB", True, "Where", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:gorm", "DB", True, "Raw", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:gorm", "DB", True, "Order", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:gorm", "DB", True, "Not", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:gorm", "DB", True, "Or", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:gorm", "DB", True, "Select", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:gorm", "DB", True, "Table", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:gorm", "DB", True, "Group", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:gorm", "DB", True, "Having", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:gorm", "DB", True, "Joins", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:gorm", "DB", True, "Exec", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:gorm", "DB", True, "Distinct", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:gorm", "DB", True, "Pluck", "", "", "Argument[0]", "sql-injection", "manual"] diff --git a/go/ql/lib/ext/log.model.yml b/go/ql/lib/ext/log.model.yml index 7f52a173307..4d1df7cf082 100644 --- a/go/ql/lib/ext/log.model.yml +++ b/go/ql/lib/ext/log.model.yml @@ -1,4 +1,28 @@ extensions: + - addsTo: + pack: codeql/go-all + extensible: sinkModel + data: + - ["log", "", False, "Fatal", "", "", "Argument[0]", "log-injection", "manual"] + - ["log", "", False, "Fatalf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["log", "", False, "Fatalln", "", "", "Argument[0]", "log-injection", "manual"] + - ["log", "", False, "Output", "", "", "Argument[1]", "log-injection", "manual"] + - ["log", "", False, "Panic", "", "", "Argument[0]", "log-injection", "manual"] + - ["log", "", False, "Panicf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["log", "", False, "Panicln", "", "", "Argument[0]", "log-injection", "manual"] + - ["log", "", False, "Print", "", "", "Argument[0]", "log-injection", "manual"] + - ["log", "", False, "Printf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["log", "", False, "Println", "", "", "Argument[0]", "log-injection", "manual"] + - ["log", "Logger", True, "Fatal", "", "", "Argument[0]", "log-injection", "manual"] + - ["log", "Logger", True, "Fatalf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["log", "Logger", True, "Fatalln", "", "", "Argument[0]", "log-injection", "manual"] + - ["log", "Logger", True, "Output", "", "", "Argument[1]", "log-injection", "manual"] + - ["log", "Logger", True, "Panic", "", "", "Argument[0]", "log-injection", "manual"] + - ["log", "Logger", True, "Panicf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["log", "Logger", True, "Panicln", "", "", "Argument[0]", "log-injection", "manual"] + - ["log", "Logger", True, "Print", "", "", "Argument[0]", "log-injection", "manual"] + - ["log", "Logger", True, "Printf", "", "", "Argument[0..1]", "log-injection", "manual"] + - ["log", "Logger", True, "Println", "", "", "Argument[0]", "log-injection", "manual"] - addsTo: pack: codeql/go-all extensible: summaryModel diff --git a/go/ql/lib/ext/os.model.yml b/go/ql/lib/ext/os.model.yml index 3d87eefe43f..2c1c64db93a 100644 --- a/go/ql/lib/ext/os.model.yml +++ b/go/ql/lib/ext/os.model.yml @@ -53,6 +53,7 @@ extensions: - ["os", "", False, "Open", "", "", "ReturnValue[0]", "file", "manual"] - ["os", "", False, "OpenFile", "", "", "ReturnValue[0]", "file", "manual"] - ["os", "", False, "ReadFile", "", "", "ReturnValue[0]", "file", "manual"] + - ["os", "", False, "Stdin", "", "", "", "stdin", "manual"] - ["os", "", False, "UserCacheDir", "", "", "ReturnValue[0]", "environment", "manual"] - ["os", "", False, "UserConfigDir", "", "", "ReturnValue[0]", "environment", "manual"] - ["os", "", False, "UserHomeDir", "", "", "ReturnValue[0]", "environment", "manual"] diff --git a/go/ql/lib/ext/slices.model.yml b/go/ql/lib/ext/slices.model.yml new file mode 100644 index 00000000000..2023aeb3db2 --- /dev/null +++ b/go/ql/lib/ext/slices.model.yml @@ -0,0 +1,31 @@ +extensions: + - addsTo: + pack: codeql/go-all + extensible: summaryModel + data: + # All should be modeled when we have a way to model iterators + # AppendSec should be modeled when we have a way to model iterators + # Backward should be modeled when we have a way to model iterators + # Chunk should be modeled when we have a way to model iterators + - ["slices", "", False, "Clip", "", "", "Argument[0].ArrayElement", "ReturnValue.ArrayElement", "value", "manual"] + - ["slices", "", False, "Clone", "", "", "Argument[0].ArrayElement", "ReturnValue.ArrayElement", "value", "manual"] + # Collect should be modeled when we have a way to model iterators + - ["slices", "", False, "Compact", "", "", "Argument[0].ArrayElement", "ReturnValue.ArrayElement", "value", "manual"] + - ["slices", "", False, "CompactFunc", "", "", "Argument[0].ArrayElement", "ReturnValue.ArrayElement", "value", "manual"] + - ["slices", "", False, "Concat", "", "", "Argument[0].ArrayElement.ArrayElement", "ReturnValue.ArrayElement", "value", "manual"] + - ["slices", "", False, "Delete", "", "", "Argument[0].ArrayElement", "ReturnValue.ArrayElement", "value", "manual"] + - ["slices", "", False, "DeleteFunc", "", "", "Argument[0].ArrayElement", "ReturnValue.ArrayElement", "value", "manual"] + - ["slices", "", False, "Grow", "", "", "Argument[0].ArrayElement", "ReturnValue.ArrayElement", "value", "manual"] + - ["slices", "", False, "Insert", "", "", "Argument[0].ArrayElement", "ReturnValue.ArrayElement", "value", "manual"] + - ["slices", "", False, "Insert", "", "", "Argument[2].ArrayElement", "ReturnValue.ArrayElement", "value", "manual"] + - ["slices", "", False, "Max", "", "", "Argument[0].ArrayElement", "ReturnValue", "value", "manual"] + - ["slices", "", False, "MaxFunc", "", "", "Argument[0].ArrayElement", "ReturnValue", "value", "manual"] + - ["slices", "", False, "Min", "", "", "Argument[0].ArrayElement", "ReturnValue", "value", "manual"] + - ["slices", "", False, "MinFunc", "", "", "Argument[0].ArrayElement", "ReturnValue", "value", "manual"] + - ["slices", "", False, "Repeat", "", "", "Argument[0].ArrayElement", "ReturnValue.ArrayElement", "value", "manual"] + - ["slices", "", False, "Replace", "", "", "Argument[0].ArrayElement", "ReturnValue.ArrayElement", "value", "manual"] + - ["slices", "", False, "Replace", "", "", "Argument[3].ArrayElement", "ReturnValue.ArrayElement", "value", "manual"] + # Sorted should be modeled when we have a way to model iterators + # SortedFunc should be modeled when we have a way to model iterators + # SortedStableFunc should be modeled when we have a way to model iterators + # Values should be modeled when we have a way to model iterators diff --git a/go/ql/lib/ext/xorm.io.xorm.model.yml b/go/ql/lib/ext/xorm.io.xorm.model.yml new file mode 100644 index 00000000000..5cf1ac4f5d7 --- /dev/null +++ b/go/ql/lib/ext/xorm.io.xorm.model.yml @@ -0,0 +1,49 @@ +extensions: + - addsTo: + pack: codeql/go-all + extensible: packageGrouping + data: + - ["xorm", "xorm.io/xorm"] + - ["xorm", "github.com/go-xorm/xorm"] + - addsTo: + pack: codeql/go-all + extensible: sinkModel + data: + - ["group:xorm", "Engine", True, "Alias", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:xorm", "Engine", True, "And", "", "", "Argument[0]", "sql-injection", "manual"] + # Engine.Exec has to be modeled in QL to select only the first syntactic argument + - ["group:xorm", "Engine", True, "GroupBy", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:xorm", "Engine", True, "Having", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:xorm", "Engine", True, "In", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:xorm", "Engine", True, "Join", "", "", "Argument[0..2]", "sql-injection", "manual"] + - ["group:xorm", "Engine", True, "NotIn", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:xorm", "Engine", True, "Or", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:xorm", "Engine", True, "OrderBy", "", "", "Argument[0]", "sql-injection", "manual"] + # Engine.Query, Engine.QueryInterface and Engine.QueryString have to be modeled in QL to select only the first syntactic argument + - ["group:xorm", "Engine", True, "Select", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:xorm", "Engine", True, "SetExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:xorm", "Engine", True, "SQL", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:xorm", "Engine", True, "Sum", "", "", "Argument[1]", "sql-injection", "manual"] + - ["group:xorm", "Engine", True, "Sums", "", "", "Argument[1]", "sql-injection", "manual"] + - ["group:xorm", "Engine", True, "SumInt", "", "", "Argument[1]", "sql-injection", "manual"] + - ["group:xorm", "Engine", True, "SumsInt", "", "", "Argument[1]", "sql-injection", "manual"] + - ["group:xorm", "Engine", True, "Where", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:xorm", "Session", True, "Alias", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:xorm", "Session", True, "And", "", "", "Argument[0]", "sql-injection", "manual"] + # Session.Exec has to be modeled in QL to select only the first syntactic argument + - ["group:xorm", "Session", True, "GroupBy", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:xorm", "Session", True, "Having", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:xorm", "Session", True, "In", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:xorm", "Session", True, "Join", "", "", "Argument[0..2]", "sql-injection", "manual"] + - ["group:xorm", "Session", True, "NotIn", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:xorm", "Session", True, "Or", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:xorm", "Session", True, "OrderBy", "", "", "Argument[0]", "sql-injection", "manual"] + # Session.Query, Session.QueryInterface and Session.QueryString have to be modeled in QL to select only the first syntactic argument + - ["group:xorm", "Session", True, "Select", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:xorm", "Session", True, "SetExpr", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:xorm", "Session", True, "SQL", "", "", "Argument[0]", "sql-injection", "manual"] + - ["group:xorm", "Session", True, "Sum", "", "", "Argument[1]", "sql-injection", "manual"] + - ["group:xorm", "Session", True, "Sums", "", "", "Argument[1]", "sql-injection", "manual"] + - ["group:xorm", "Session", True, "SumInt", "", "", "Argument[1]", "sql-injection", "manual"] + - ["group:xorm", "Session", True, "SumsInt", "", "", "Argument[1]", "sql-injection", "manual"] + - ["group:xorm", "Session", True, "Where", "", "", "Argument[0]", "sql-injection", "manual"] diff --git a/go/ql/lib/go.qll b/go/ql/lib/go.qll index fb59790dcc5..8d3955e4dad 100644 --- a/go/ql/lib/go.qll +++ b/go/ql/lib/go.qll @@ -25,11 +25,9 @@ import semmle.go.controlflow.BasicBlocks import semmle.go.controlflow.ControlFlowGraph import semmle.go.controlflow.IR import semmle.go.dataflow.DataFlow -import semmle.go.dataflow.DataFlow2 import semmle.go.dataflow.GlobalValueNumbering import semmle.go.dataflow.SSA import semmle.go.dataflow.TaintTracking -import semmle.go.dataflow.TaintTracking2 import semmle.go.frameworks.Afero import semmle.go.frameworks.AwsLambda import semmle.go.frameworks.Beego diff --git a/go/ql/lib/semmle/go/Concepts.qll b/go/ql/lib/semmle/go/Concepts.qll index c15d3683b40..3f0cd0f8885 100644 --- a/go/ql/lib/semmle/go/Concepts.qll +++ b/go/ql/lib/semmle/go/Concepts.qll @@ -373,6 +373,48 @@ module LoggerCall { } } +private class DefaultLoggerCall extends LoggerCall::Range, DataFlow::CallNode { + DataFlow::ArgumentNode messageComponent; + + DefaultLoggerCall() { + sinkNode(messageComponent, "log-injection") and + this = messageComponent.getCall() + } + + override DataFlow::Node getAMessageComponent() { + not messageComponent instanceof DataFlow::ImplicitVarargsSlice and + result = messageComponent + or + messageComponent instanceof DataFlow::ImplicitVarargsSlice and + result = this.getAnImplicitVarargsArgument() + } +} + +/** + * A call to an interface that looks like a logger. It is common to use a + * locally-defined interface for logging to make it easy to changing logging + * library. + */ +private class HeuristicLoggerCall extends LoggerCall::Range, DataFlow::CallNode { + HeuristicLoggerCall() { + exists(Method m, string tp, string logFunctionPrefix, string name | + m = this.getTarget() and + m.hasQualifiedName(_, tp, name) and + m.getReceiverBaseType().getUnderlyingType() instanceof InterfaceType + | + tp.regexpMatch(".*[lL]ogger") and + logFunctionPrefix = + [ + "Debug", "Error", "Fatal", "Info", "Log", "Output", "Panic", "Print", "Trace", "Warn", + "With" + ] and + name.matches(logFunctionPrefix + "%") + ) + } + + override DataFlow::Node getAMessageComponent() { result = this.getASyntacticArgument() } +} + /** * A function that encodes data into a binary or textual format. * diff --git a/go/ql/lib/semmle/go/Scopes.qll b/go/ql/lib/semmle/go/Scopes.qll index f9b9e3a26b9..c3671c74b5c 100644 --- a/go/ql/lib/semmle/go/Scopes.qll +++ b/go/ql/lib/semmle/go/Scopes.qll @@ -472,7 +472,7 @@ class Function extends ValueEntity, @functionobject { /** Gets a parameter of this function. */ Parameter getAParameter() { result = this.getParameter(_) } - /** Gets the `i`th reslt variable of this function. */ + /** Gets the `i`th result variable of this function. */ ResultVariable getResult(int i) { result.isResultOf(this.getFuncDecl(), i) } /** Gets a result variable of this function. */ diff --git a/go/ql/lib/semmle/go/Types.qll b/go/ql/lib/semmle/go/Types.qll index 1b09ea466cc..1f1234aa1de 100644 --- a/go/ql/lib/semmle/go/Types.qll +++ b/go/ql/lib/semmle/go/Types.qll @@ -496,14 +496,15 @@ class StructType extends @structtype, CompositeType { Field getFieldOfEmbedded(Field embeddedParent, string name, int depth, boolean isEmbedded) { // embeddedParent is a field of 'this' at depth 'depth - 1' this.hasFieldCand(_, embeddedParent, depth - 1, true) and - // embeddedParent's type has the result field - exists(StructType embeddedType, Type fieldType | - fieldType = embeddedParent.getType().getUnderlyingType() and - pragma[only_bind_into](embeddedType) = - [fieldType, fieldType.(PointerType).getBaseType().getUnderlyingType()] - | - result = embeddedType.getOwnField(name, isEmbedded) - ) + // embeddedParent's type has the result field. Note that it is invalid Go + // to have an embedded field with a named type whose underlying type is a + // pointer, so we don't have to have + // `lookThroughPointerType(embeddedParent.getType().getUnderlyingType())`. + result = + lookThroughPointerType(embeddedParent.getType()) + .getUnderlyingType() + .(StructType) + .getOwnField(name, isEmbedded) } /** @@ -523,8 +524,12 @@ class StructType extends @structtype, CompositeType { private predicate hasFieldCand(string name, Field f, int depth, boolean isEmbedded) { f = this.getOwnField(name, isEmbedded) and depth = 0 or - not this.hasOwnField(_, name, _, _) and - f = this.getFieldOfEmbedded(_, name, depth, isEmbedded) + f = this.getFieldOfEmbedded(_, name, depth, isEmbedded) and + // If this is a cyclic field and this is not the first time we see this embedded field + // then don't include it as a field candidate to avoid non-termination. + not exists(Type t | lookThroughPointerType(t) = lookThroughPointerType(f.getType()) | + this.hasOwnField(_, name, t, _) + ) } private predicate hasMethodCand(string name, Method m, int depth) { @@ -541,15 +546,7 @@ class StructType extends @structtype, CompositeType { predicate hasField(string name, Type tp) { exists(int mindepth | mindepth = min(int depth | this.hasFieldCand(name, _, depth, _)) and - tp = unique(Field f | f = this.getFieldCand(name, mindepth, _)).getType() - ) - } - - private Field getFieldCand(string name, int depth, boolean isEmbedded) { - result = this.getOwnField(name, isEmbedded) and depth = 0 - or - exists(Type embedded | this.hasEmbeddedField(embedded, depth - 1) | - result = embedded.getUnderlyingType().(StructType).getOwnField(name, isEmbedded) + tp = unique(Field f | this.hasFieldCand(name, f, mindepth, _)).getType() ) } @@ -564,9 +561,9 @@ class StructType extends @structtype, CompositeType { * The depth of a field `f` declared in this type is zero. */ Field getFieldAtDepth(string name, int depth) { - depth = min(int depthCand | exists(this.getFieldCand(name, depthCand, _))) and - result = this.getFieldCand(name, depth, _) and - strictcount(this.getFieldCand(name, depth, _)) = 1 + depth = min(int depthCand | this.hasFieldCand(name, _, depthCand, _)) and + this.hasFieldCand(name, result, depth, _) and + strictcount(Field f | this.hasFieldCand(name, f, depth, _)) = 1 } Method getMethodAtDepth(string name, int depth) { diff --git a/go/ql/lib/semmle/go/dataflow/DataFlow.qll b/go/ql/lib/semmle/go/dataflow/DataFlow.qll index 9363bc93abd..c26adbfd2c2 100644 --- a/go/ql/lib/semmle/go/dataflow/DataFlow.qll +++ b/go/ql/lib/semmle/go/dataflow/DataFlow.qll @@ -25,7 +25,7 @@ module DataFlow { private import semmle.go.dataflow.internal.DataFlowImplSpecific private import codeql.dataflow.DataFlow import DataFlowMake - import semmle.go.dataflow.internal.DataFlowImpl1 + import Public import Properties } diff --git a/go/ql/lib/semmle/go/dataflow/DataFlow2.qll b/go/ql/lib/semmle/go/dataflow/DataFlow2.qll deleted file mode 100644 index a2bae8bd939..00000000000 --- a/go/ql/lib/semmle/go/dataflow/DataFlow2.qll +++ /dev/null @@ -1,27 +0,0 @@ -/** - * 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_. - * - * 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 track these types of flow, where the - * exact value may not be preserved, import - * `semmle.code.go.dataflow.TaintTracking`. - * - * To use global (interprocedural) data flow, extend the class - * `DataFlow::Configuration` as documented on that class. To use local - * (intraprocedural) data flow, invoke `DataFlow::localFlow` or - * `DataFlow::LocalFlowStep` with arguments of type `DataFlow::Node`. - */ - -import go - -/** - * Provides a library for local (intra-procedural) and global (inter-procedural) - * data flow analysis. - */ -module DataFlow2 { - import semmle.go.dataflow.internal.DataFlowImpl2 - import Properties -} diff --git a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll index a59c7294e80..5ae7b6a7f0d 100644 --- a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll +++ b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll @@ -38,7 +38,8 @@ * first 6 columns, and the `output` column specifies how data leaves the * element selected by the first 6 columns. An `input` can be either "", * "Argument[n]", or "Argument[n1..n2]": - * - "": Selects a write to the selected element in case this is a field. + * - "": Selects a write to the selected element in case this is a field or + * package-level variable. * - "Argument[n]": Selects an argument in a call to the selected element. * The arguments are zero-indexed, and `receiver` specifies the receiver. * - "Argument[n1..n2]": Similar to "Argument[n]" but selects any argument @@ -47,7 +48,7 @@ * An `output` can be either "", "Argument[n]", "Argument[n1..n2]", "Parameter", * "Parameter[n]", "Parameter[n1..n2]", , "ReturnValue", "ReturnValue[n]", or * "ReturnValue[n1..n2]": - * - "": Selects a read of a selected field. + * - "": Selects a read of a selected field or package-level variable. * - "Argument[n]": Selects the post-update value of an argument in a call to the * selected element. That is, the value of the argument after the call returns. * The arguments are zero-indexed, and `receiver` specifies the receiver. diff --git a/go/ql/lib/semmle/go/dataflow/TaintTracking.qll b/go/ql/lib/semmle/go/dataflow/TaintTracking.qll index d762e925ab5..c469574b3b9 100644 --- a/go/ql/lib/semmle/go/dataflow/TaintTracking.qll +++ b/go/ql/lib/semmle/go/dataflow/TaintTracking.qll @@ -10,11 +10,10 @@ import semmle.go.dataflow.DataFlow * global (inter-procedural) taint-tracking analyses. */ module TaintTracking { - import semmle.go.dataflow.internal.tainttracking1.TaintTrackingParameter::Public + import semmle.go.dataflow.internal.TaintTrackingUtil private import semmle.go.dataflow.internal.DataFlowImplSpecific private import semmle.go.dataflow.internal.TaintTrackingImplSpecific private import semmle.go.Locations private import codeql.dataflow.TaintTracking import TaintFlowMake - import semmle.go.dataflow.internal.tainttracking1.TaintTrackingImpl } diff --git a/go/ql/lib/semmle/go/dataflow/TaintTracking2.qll b/go/ql/lib/semmle/go/dataflow/TaintTracking2.qll deleted file mode 100644 index 6b1b2487e5b..00000000000 --- a/go/ql/lib/semmle/go/dataflow/TaintTracking2.qll +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) taint-tracking analyses. - */ - -/** - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) taint-tracking analyses. - */ -module TaintTracking2 { - import semmle.go.dataflow.internal.tainttracking2.TaintTrackingImpl -} diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl1.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl1.qll deleted file mode 100644 index 17def0c431d..00000000000 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl1.qll +++ /dev/null @@ -1,361 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * Provides a `Configuration` class backwards-compatible interface to the data - * flow library. - */ - -private import DataFlowImplCommon -private import DataFlowImplSpecific::Private -import DataFlowImplSpecific::Public -private import DataFlowImpl -import DataFlowImplCommonPublic -deprecated import FlowStateString -private import codeql.util.Unit - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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 sink, 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() } - - /** - * 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. - * - * These features are generally not relevant for typical end-to-end data flow - * queries, but should only be used for constructing paths that need to - * somehow be pluggable in another path context. - */ - FlowFeature getAFeature() { none() } - - /** Holds if sources should be grouped in the result of `hasFlowPath`. */ - predicate sourceGrouping(Node source, string sourceGroup) { none() } - - /** Holds if sinks should be grouped in the result of `hasFlowPath`. */ - predicate sinkGrouping(Node sink, string sinkGroup) { none() } - - /** - * Holds if data may flow from `source` to `sink` for this configuration. - */ - predicate hasFlow(Node source, Node sink) { hasFlow(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) { hasFlowPath(source, sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } - - /** - * 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() } -} - -/** - * 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 deprecated 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) - } -} - -deprecated private FlowState relevantState(Configuration config) { - config.isSource(_, result) or - config.isSink(_, result) or - config.isBarrier(_, result) or - config.isAdditionalFlowStep(_, result, _, _) or - config.isAdditionalFlowStep(_, _, _, result) -} - -private newtype TConfigState = - deprecated TMkConfigState(Configuration config, FlowState state) { - state = relevantState(config) or state instanceof FlowStateEmpty - } - -deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) } - -deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) } - -deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) } - -deprecated private module Config implements FullStateConfigSig { - class FlowState = TConfigState; - - predicate isSource(Node source, FlowState state) { - getConfig(state).isSource(source, getState(state)) - or - getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty - } - - predicate isSink(Node sink) { none() } - - predicate isSink(Node sink, FlowState state) { - getConfig(state).isSink(sink, getState(state)) - or - getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty - } - - predicate isBarrier(Node node) { none() } - - predicate isBarrier(Node node, FlowState state) { - getConfig(state).isBarrier(node, getState(state)) or - getConfig(state).isBarrier(node) - } - - predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) } - - predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) } - - predicate isBarrierIn(Node node, FlowState state) { none() } - - predicate isBarrierOut(Node node, FlowState state) { none() } - - predicate isAdditionalFlowStep(Node node1, Node node2, string model) { - singleConfiguration() and - any(Configuration config).isAdditionalFlowStep(node1, node2) and - model = "" - } - - predicate isAdditionalFlowStep( - Node node1, FlowState state1, Node node2, FlowState state2, string model - ) { - getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and - getConfig(state2) = getConfig(state1) and - model = "" - or - not singleConfiguration() and - getConfig(state1).isAdditionalFlowStep(node1, node2) and - state2 = state1 and - model = "" - } - - predicate allowImplicitRead(Node node, ContentSet c) { - any(Configuration config).allowImplicitRead(node, c) - } - - predicate neverSkip(Node node) { none() } - - int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) } - - int accessPathLimit() { result = 5 } - - FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } - - predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } - - predicate observeDiffInformedIncrementalMode() { none() } -} - -deprecated private import Impl as I - -/** - * 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, and which can reach a sink, are generated. - */ -deprecated class PathNode instanceof I::PathNode { - /** Gets a textual representation of this element. */ - final string toString() { result = super.toString() } - - /** - * Gets a textual representation of this element, including a textual - * representation of the call context. - */ - final string toStringWithContext() { result = super.toStringWithContext() } - - /** - * 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/). - */ - final predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - /** Gets the underlying `Node`. */ - final Node getNode() { result = super.getNode() } - - /** Gets the `FlowState` of this node. */ - deprecated final FlowState getState() { result = getState(super.getState()) } - - /** Gets the associated configuration. */ - deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) } - - /** Gets a successor of this node, if any. */ - final PathNode getASuccessor() { result = super.getASuccessor() } - - /** Holds if this node is a source. */ - final predicate isSource() { super.isSource() } - - /** Holds if this node is a grouping of source nodes. */ - final predicate isSourceGroup(string group) { super.isSourceGroup(group) } - - /** Holds if this node is a grouping of sink nodes. */ - final predicate isSinkGroup(string group) { super.isSinkGroup(group) } -} - -deprecated module PathGraph = I::PathGraph; - -deprecated private predicate hasFlow(Node source, Node sink, Configuration config) { - exists(PathNode source0, PathNode sink0 | - hasFlowPath(source0, sink0, config) and - source0.getNode() = source and - sink0.getNode() = sink - ) -} - -deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) { - I::flowPath(source, sink) and source.getConfiguration() = config -} - -deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) } - -deprecated predicate flowsTo = hasFlow/3; diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl2.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl2.qll deleted file mode 100644 index 17def0c431d..00000000000 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl2.qll +++ /dev/null @@ -1,361 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * Provides a `Configuration` class backwards-compatible interface to the data - * flow library. - */ - -private import DataFlowImplCommon -private import DataFlowImplSpecific::Private -import DataFlowImplSpecific::Public -private import DataFlowImpl -import DataFlowImplCommonPublic -deprecated import FlowStateString -private import codeql.util.Unit - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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 sink, 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() } - - /** - * 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. - * - * These features are generally not relevant for typical end-to-end data flow - * queries, but should only be used for constructing paths that need to - * somehow be pluggable in another path context. - */ - FlowFeature getAFeature() { none() } - - /** Holds if sources should be grouped in the result of `hasFlowPath`. */ - predicate sourceGrouping(Node source, string sourceGroup) { none() } - - /** Holds if sinks should be grouped in the result of `hasFlowPath`. */ - predicate sinkGrouping(Node sink, string sinkGroup) { none() } - - /** - * Holds if data may flow from `source` to `sink` for this configuration. - */ - predicate hasFlow(Node source, Node sink) { hasFlow(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) { hasFlowPath(source, sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } - - /** - * 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() } -} - -/** - * 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 deprecated 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) - } -} - -deprecated private FlowState relevantState(Configuration config) { - config.isSource(_, result) or - config.isSink(_, result) or - config.isBarrier(_, result) or - config.isAdditionalFlowStep(_, result, _, _) or - config.isAdditionalFlowStep(_, _, _, result) -} - -private newtype TConfigState = - deprecated TMkConfigState(Configuration config, FlowState state) { - state = relevantState(config) or state instanceof FlowStateEmpty - } - -deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) } - -deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) } - -deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) } - -deprecated private module Config implements FullStateConfigSig { - class FlowState = TConfigState; - - predicate isSource(Node source, FlowState state) { - getConfig(state).isSource(source, getState(state)) - or - getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty - } - - predicate isSink(Node sink) { none() } - - predicate isSink(Node sink, FlowState state) { - getConfig(state).isSink(sink, getState(state)) - or - getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty - } - - predicate isBarrier(Node node) { none() } - - predicate isBarrier(Node node, FlowState state) { - getConfig(state).isBarrier(node, getState(state)) or - getConfig(state).isBarrier(node) - } - - predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) } - - predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) } - - predicate isBarrierIn(Node node, FlowState state) { none() } - - predicate isBarrierOut(Node node, FlowState state) { none() } - - predicate isAdditionalFlowStep(Node node1, Node node2, string model) { - singleConfiguration() and - any(Configuration config).isAdditionalFlowStep(node1, node2) and - model = "" - } - - predicate isAdditionalFlowStep( - Node node1, FlowState state1, Node node2, FlowState state2, string model - ) { - getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and - getConfig(state2) = getConfig(state1) and - model = "" - or - not singleConfiguration() and - getConfig(state1).isAdditionalFlowStep(node1, node2) and - state2 = state1 and - model = "" - } - - predicate allowImplicitRead(Node node, ContentSet c) { - any(Configuration config).allowImplicitRead(node, c) - } - - predicate neverSkip(Node node) { none() } - - int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) } - - int accessPathLimit() { result = 5 } - - FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } - - predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } - - predicate observeDiffInformedIncrementalMode() { none() } -} - -deprecated private import Impl as I - -/** - * 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, and which can reach a sink, are generated. - */ -deprecated class PathNode instanceof I::PathNode { - /** Gets a textual representation of this element. */ - final string toString() { result = super.toString() } - - /** - * Gets a textual representation of this element, including a textual - * representation of the call context. - */ - final string toStringWithContext() { result = super.toStringWithContext() } - - /** - * 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/). - */ - final predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - /** Gets the underlying `Node`. */ - final Node getNode() { result = super.getNode() } - - /** Gets the `FlowState` of this node. */ - deprecated final FlowState getState() { result = getState(super.getState()) } - - /** Gets the associated configuration. */ - deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) } - - /** Gets a successor of this node, if any. */ - final PathNode getASuccessor() { result = super.getASuccessor() } - - /** Holds if this node is a source. */ - final predicate isSource() { super.isSource() } - - /** Holds if this node is a grouping of source nodes. */ - final predicate isSourceGroup(string group) { super.isSourceGroup(group) } - - /** Holds if this node is a grouping of sink nodes. */ - final predicate isSinkGroup(string group) { super.isSinkGroup(group) } -} - -deprecated module PathGraph = I::PathGraph; - -deprecated private predicate hasFlow(Node source, Node sink, Configuration config) { - exists(PathNode source0, PathNode sink0 | - hasFlowPath(source0, sink0, config) and - source0.getNode() = source and - sink0.getNode() = sink - ) -} - -deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) { - I::flowPath(source, sink) and source.getConfiguration() = config -} - -deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) } - -deprecated predicate flowsTo = hasFlow/3; diff --git a/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll b/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll index b82039a32fe..40c68ceb900 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll @@ -399,6 +399,13 @@ module SourceSinkInterpretationInput implements c = "" and pragma[only_bind_into](e) = getElementWithQualifier(frn.getField(), frn.getBase()) ) + or + // A package-scope (or universe-scope) variable + exists(Variable v | not v instanceof Field | + c = "" and + n.(DataFlow::ReadNode).reads(v) and + pragma[only_bind_into](e).asEntity() = v + ) ) } @@ -420,6 +427,17 @@ module SourceSinkInterpretationInput implements fw.writesField(base, f, node.asNode()) and pragma[only_bind_into](e) = getElementWithQualifier(f, base) ) + or + // A package-scope (or universe-scope) variable + exists(Node n, SourceOrSinkElement e, DataFlow::Write w, Variable v | + n = node.asNode() and + e = mid.asElement() and + not v instanceof Field + | + c = "" and + w.writes(v, n) and + pragma[only_bind_into](e).asEntity() = v + ) } } diff --git a/go/ql/lib/semmle/go/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/go/ql/lib/semmle/go/dataflow/internal/tainttracking1/TaintTrackingImpl.qll deleted file mode 100644 index 75e7856fd26..00000000000 --- a/go/ql/lib/semmle/go/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ /dev/null @@ -1,168 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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) } - - /** - * 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/go/ql/lib/semmle/go/dataflow/internal/tainttracking1/TaintTrackingParameter.qll b/go/ql/lib/semmle/go/dataflow/internal/tainttracking1/TaintTrackingParameter.qll deleted file mode 100644 index a5a45514a06..00000000000 --- a/go/ql/lib/semmle/go/dataflow/internal/tainttracking1/TaintTrackingParameter.qll +++ /dev/null @@ -1,6 +0,0 @@ -import semmle.go.dataflow.internal.TaintTrackingUtil as Public - -module Private { - import semmle.go.dataflow.DataFlow::DataFlow as DataFlow - import semmle.go.dataflow.internal.DataFlowImpl as DataFlowInternal -} diff --git a/go/ql/lib/semmle/go/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/go/ql/lib/semmle/go/dataflow/internal/tainttracking2/TaintTrackingImpl.qll deleted file mode 100644 index 75e7856fd26..00000000000 --- a/go/ql/lib/semmle/go/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ /dev/null @@ -1,168 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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) } - - /** - * 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/go/ql/lib/semmle/go/dataflow/internal/tainttracking2/TaintTrackingParameter.qll b/go/ql/lib/semmle/go/dataflow/internal/tainttracking2/TaintTrackingParameter.qll deleted file mode 100644 index 1130c2e42e1..00000000000 --- a/go/ql/lib/semmle/go/dataflow/internal/tainttracking2/TaintTrackingParameter.qll +++ /dev/null @@ -1,5 +0,0 @@ -import semmle.go.dataflow.internal.TaintTrackingUtil as Public - -module Private { - import semmle.go.dataflow.DataFlow2::DataFlow2 as DataFlow -} diff --git a/go/ql/lib/semmle/go/frameworks/Beego.qll b/go/ql/lib/semmle/go/frameworks/Beego.qll index 9f6ee598003..a9e296a1f97 100644 --- a/go/ql/lib/semmle/go/frameworks/Beego.qll +++ b/go/ql/lib/semmle/go/frameworks/Beego.qll @@ -33,13 +33,6 @@ module Beego { result = package(v2modulePath(), "server/web/context") } - /** Gets the path for the logs package of beego. */ - string logsPackagePath() { - result = package(v1modulePath(), "logs") - or - result = package(v2modulePath(), "core/logs") - } - /** Gets the path for the utils package of beego. */ string utilsPackagePath() { result = package(v1modulePath(), "utils") @@ -172,36 +165,6 @@ module Beego { override string getAContentType() { none() } } - private string getALogFunctionName() { - result = - [ - "Alert", "Critical", "Debug", "Emergency", "Error", "Info", "Informational", "Notice", - "Trace", "Warn", "Warning" - ] - } - - private class ToplevelBeegoLoggers extends LoggerCall::Range, DataFlow::CallNode { - ToplevelBeegoLoggers() { - this.getTarget().hasQualifiedName([packagePath(), logsPackagePath()], getALogFunctionName()) - } - - override DataFlow::Node getAMessageComponent() { result = this.getASyntacticArgument() } - } - - private class BeegoLoggerMethods extends LoggerCall::Range, DataFlow::MethodCallNode { - BeegoLoggerMethods() { - this.getTarget().hasQualifiedName(logsPackagePath(), "BeeLogger", getALogFunctionName()) - } - - override DataFlow::Node getAMessageComponent() { result = this.getASyntacticArgument() } - } - - private class UtilLoggers extends LoggerCall::Range, DataFlow::CallNode { - UtilLoggers() { this.getTarget().hasQualifiedName(utilsPackagePath(), "Display") } - - override DataFlow::Node getAMessageComponent() { result = this.getASyntacticArgument() } - } - private class HtmlQuoteSanitizer extends SharedXss::Sanitizer { HtmlQuoteSanitizer() { exists(DataFlow::CallNode c | c.getTarget().hasQualifiedName(packagePath(), "Htmlquote") | diff --git a/go/ql/lib/semmle/go/frameworks/BeegoOrm.qll b/go/ql/lib/semmle/go/frameworks/BeegoOrm.qll index c1de0cf4244..925b0f19fa3 100644 --- a/go/ql/lib/semmle/go/frameworks/BeegoOrm.qll +++ b/go/ql/lib/semmle/go/frameworks/BeegoOrm.qll @@ -14,57 +14,6 @@ module BeegoOrm { /** Gets the package name `github.com/astaxie/beego/orm`. */ string packagePath() { result = package("github.com/astaxie/beego", "orm") } - private class DbSink extends SQL::QueryString::Range { - DbSink() { - exists(Method m, string methodName, int argNum | - m.hasQualifiedName(packagePath(), "DB", methodName) and - ( - methodName = ["Exec", "Prepare", "Query", "QueryRow"] and - argNum = 0 - or - methodName = ["ExecContext", "PrepareContext", "QueryContext", "QueryRowContext"] and - argNum = 1 - ) - | - this = m.getACall().getArgument(argNum) - ) - } - } - - private class QueryBuilderSink extends SQL::QueryString::Range { - // Note this class doesn't do any escaping, unlike the true ORM part of the package - QueryBuilderSink() { - exists(Method impl | impl.implements(packagePath(), "QueryBuilder", _) | - this = impl.getACall().getASyntacticArgument() - ) and - this.getType().getUnderlyingType() instanceof StringType - } - } - - private class OrmerRawSink extends SQL::QueryString::Range { - OrmerRawSink() { - exists(Method impl | impl.implements(packagePath(), "Ormer", "Raw") | - this = impl.getACall().getArgument(0) - ) - } - } - - private class QuerySeterFilterRawSink extends SQL::QueryString::Range { - QuerySeterFilterRawSink() { - exists(Method impl | impl.implements(packagePath(), "QuerySeter", "FilterRaw") | - this = impl.getACall().getArgument(1) - ) - } - } - - private class ConditionRawSink extends SQL::QueryString::Range { - ConditionRawSink() { - exists(Method impl | impl.implements(packagePath(), "Condition", "Raw") | - this = impl.getACall().getArgument(1) - ) - } - } - private class OrmerSource extends StoredXss::Source { OrmerSource() { exists(Method impl | diff --git a/go/ql/lib/semmle/go/frameworks/Couchbase.qll b/go/ql/lib/semmle/go/frameworks/Couchbase.qll index 5eaa4d20c3a..b5bfbcb22a2 100644 --- a/go/ql/lib/semmle/go/frameworks/Couchbase.qll +++ b/go/ql/lib/semmle/go/frameworks/Couchbase.qll @@ -5,57 +5,23 @@ import go /** + * DEPRECATED + * * Provides models of commonly used functions in the official Couchbase Go SDK library. */ -module Couchbase { +deprecated module Couchbase { /** + * DEPRECATED + * * Gets a package path for the official Couchbase Go SDK library. * * Note that v1 and v2 have different APIs, but the names are disjoint so there is no need to * distinguish between them. */ - string packagePath() { + deprecated string packagePath() { result = package([ "gopkg.in/couchbase/gocb", "github.com/couchbase/gocb", "github.com/couchbaselabs/gocb" ], "") } - - /** - * A query used in an API function acting on a `Bucket` or `Cluster` struct of v1 of - * the official Couchbase Go library, gocb. - */ - private class CouchbaseV1Query extends NoSql::Query::Range { - CouchbaseV1Query() { - // func (b *Bucket) ExecuteAnalyticsQuery(q *AnalyticsQuery, params interface{}) (AnalyticsResults, error) - // func (b *Bucket) ExecuteN1qlQuery(q *N1qlQuery, params interface{}) (QueryResults, error) - // func (c *Cluster) ExecuteAnalyticsQuery(q *AnalyticsQuery, params interface{}) (AnalyticsResults, error) - // func (c *Cluster) ExecuteN1qlQuery(q *N1qlQuery, params interface{}) (QueryResults, error) - exists(Method meth, string structName, string methodName | - structName in ["Bucket", "Cluster"] and - methodName in ["ExecuteN1qlQuery", "ExecuteAnalyticsQuery"] and - meth.hasQualifiedName(packagePath(), structName, methodName) and - this = meth.getACall().getArgument(0) - ) - } - } - - /** - * A query used in an API function acting on a `Bucket` or `Cluster` struct of v1 of - * the official Couchbase Go library, gocb. - */ - private class CouchbaseV2Query extends NoSql::Query::Range { - CouchbaseV2Query() { - // func (c *Cluster) AnalyticsQuery(statement string, opts *AnalyticsOptions) (*AnalyticsResult, error) - // func (c *Cluster) Query(statement string, opts *QueryOptions) (*QueryResult, error) - // func (s *Scope) AnalyticsQuery(statement string, opts *AnalyticsOptions) (*AnalyticsResult, error) - // func (s *Scope) Query(statement string, opts *QueryOptions) (*QueryResult, error) - exists(Method meth, string structName, string methodName | - structName in ["Cluster", "Scope"] and - methodName in ["AnalyticsQuery", "Query"] and - meth.hasQualifiedName(packagePath(), structName, methodName) and - this = meth.getACall().getArgument(0) - ) - } - } } diff --git a/go/ql/lib/semmle/go/frameworks/ElazarlGoproxy.qll b/go/ql/lib/semmle/go/frameworks/ElazarlGoproxy.qll index 4d10c8af312..b1bf4571216 100644 --- a/go/ql/lib/semmle/go/frameworks/ElazarlGoproxy.qll +++ b/go/ql/lib/semmle/go/frameworks/ElazarlGoproxy.qll @@ -100,10 +100,4 @@ module ElazarlGoproxy { override int getFormatStringIndex() { result = 0 } } - - private class ProxyLog extends LoggerCall::Range, DataFlow::MethodCallNode { - ProxyLog() { this.getTarget() instanceof ProxyLogFunction } - - override DataFlow::Node getAMessageComponent() { result = this.getASyntacticArgument() } - } } diff --git a/go/ql/lib/semmle/go/frameworks/Glog.qll b/go/ql/lib/semmle/go/frameworks/Glog.qll index f9f5c9e3f11..146b8a4f814 100644 --- a/go/ql/lib/semmle/go/frameworks/Glog.qll +++ b/go/ql/lib/semmle/go/frameworks/Glog.qll @@ -40,14 +40,4 @@ module Glog { override int getFormatStringIndex() { result = super.getFirstPrintedArg() } } - - private class GlogCall extends LoggerCall::Range, DataFlow::CallNode { - GlogFunction callee; - - GlogCall() { this = callee.getACall() } - - override DataFlow::Node getAMessageComponent() { - result = this.getSyntacticArgument(any(int i | i >= callee.getFirstPrintedArg())) - } - } } diff --git a/go/ql/lib/semmle/go/frameworks/Logrus.qll b/go/ql/lib/semmle/go/frameworks/Logrus.qll index f7de9a75dae..83278a4cd9e 100644 --- a/go/ql/lib/semmle/go/frameworks/Logrus.qll +++ b/go/ql/lib/semmle/go/frameworks/Logrus.qll @@ -28,12 +28,6 @@ module Logrus { } } - private class LogCall extends LoggerCall::Range, DataFlow::CallNode { - LogCall() { this = any(LogFunction f).getACall() } - - override DataFlow::Node getAMessageComponent() { result = this.getASyntacticArgument() } - } - private class StringFormatters extends StringOps::Formatting::Range instanceof LogFunction { int argOffset; diff --git a/go/ql/lib/semmle/go/frameworks/NoSQL.qll b/go/ql/lib/semmle/go/frameworks/NoSQL.qll index c2469fc02ac..36932149628 100644 --- a/go/ql/lib/semmle/go/frameworks/NoSQL.qll +++ b/go/ql/lib/semmle/go/frameworks/NoSQL.qll @@ -31,84 +31,6 @@ module NoSql { ) } } - - /** - * Holds if method `name` of struct `Collection` from package - * [go.mongodb.org/mongo-driver/mongo](https://pkg.go.dev/go.mongodb.org/mongo-driver/mongo) - * interprets parameter `n` as a query. - */ - private predicate mongoDbCollectionMethod(string name, int n) { - // func (coll *Collection) CountDocuments(ctx context.Context, filter interface{}, - // opts ...*options.CountOptions) (int64, error) - name = "CountDocuments" and n = 1 - or - // func (coll *Collection) DeleteMany(ctx context.Context, filter interface{}, - // opts ...*options.DeleteOptions) (*DeleteResult, error) - name = "DeleteMany" and n = 1 - or - // func (coll *Collection) DeleteOne(ctx context.Context, filter interface{}, - // opts ...*options.DeleteOptions) (*DeleteResult, error) - name = "DeleteOne" and n = 1 - or - // func (coll *Collection) Distinct(ctx context.Context, fieldName string, filter interface{}, - // ...) ([]interface{}, error) - name = "Distinct" and n = 2 - or - // func (coll *Collection) Find(ctx context.Context, filter interface{}, - // opts ...*options.FindOptions) (*Cursor, error) - name = "Find" and n = 1 - or - // func (coll *Collection) FindOne(ctx context.Context, filter interface{}, - // opts ...*options.FindOneOptions) *SingleResult - name = "FindOne" and n = 1 - or - // func (coll *Collection) FindOneAndDelete(ctx context.Context, filter interface{}, ...) - // *SingleResult - name = "FindOneAndDelete" and n = 1 - or - // func (coll *Collection) FindOneAndReplace(ctx context.Context, filter interface{}, - // replacement interface{}, ...) *SingleResult - name = "FindOneAndReplace" and n = 1 - or - // func (coll *Collection) FindOneAndUpdate(ctx context.Context, filter interface{}, - // update interface{}, ...) *SingleResult - name = "FindOneAndUpdate" and n = 1 - or - // func (coll *Collection) ReplaceOne(ctx context.Context, filter interface{}, - // replacement interface{}, ...) (*UpdateResult, error) - name = "ReplaceOne" and n = 1 - or - // func (coll *Collection) UpdateMany(ctx context.Context, filter interface{}, - // update interface{}, ...) (*UpdateResult, error) - name = "UpdateMany" and n = 1 - or - // func (coll *Collection) UpdateOne(ctx context.Context, filter interface{}, - // update interface{}, ...) (*UpdateResult, error) - name = "UpdateOne" and n = 1 - or - // func (coll *Collection) Watch(ctx context.Context, pipeline interface{}, ...) - // (*ChangeStream, error) - name = "Watch" and n = 1 - or - // func (coll *Collection) Aggregate(ctx context.Context, pipeline interface{}, - // opts ...*options.AggregateOptions) (*Cursor, error) - name = "Aggregate" and n = 1 - } - - /** - * A query used in an API function acting on a `Collection` struct of package - * [go.mongodb.org/mongo-driver/mongo](https://pkg.go.dev/go.mongodb.org/mongo-driver/mongo). - */ - private class MongoDbCollectionQuery extends Range { - MongoDbCollectionQuery() { - exists(Method meth, string methodName, int n | - mongoDbCollectionMethod(methodName, n) and - meth.hasQualifiedName(package("go.mongodb.org/mongo-driver", "mongo"), "Collection", - methodName) and - this = meth.getACall().getArgument(n) - ) - } - } } /** diff --git a/go/ql/lib/semmle/go/frameworks/SQL.qll b/go/ql/lib/semmle/go/frameworks/SQL.qll index 1a6e2280781..a0e80fde1c9 100644 --- a/go/ql/lib/semmle/go/frameworks/SQL.qll +++ b/go/ql/lib/semmle/go/frameworks/SQL.qll @@ -67,41 +67,34 @@ module SQL { */ abstract class Range extends DataFlow::Node { } + private class DefaultQueryString extends Range { + DefaultQueryString() { + exists(DataFlow::ArgumentNode arg | sinkNode(arg, "sql-injection") | + not arg instanceof DataFlow::ImplicitVarargsSlice and + this = arg + or + arg instanceof DataFlow::ImplicitVarargsSlice and + this = arg.getCall().getAnImplicitVarargsArgument() + ) + } + } + /** * An argument to an API of the squirrel library that is directly interpreted as SQL without * taking syntactic structure into account. */ private class SquirrelQueryString extends Range { SquirrelQueryString() { - exists(Function fn | - exists(string sq | - sq = - package([ - "github.com/Masterminds/squirrel", "gopkg.in/Masterminds/squirrel", - "github.com/lann/squirrel" - ], "") - | - fn.hasQualifiedName(sq, ["Delete", "Expr", "Insert", "Select", "Update"]) - or - exists(Method m, string builder | m = fn | - builder = ["DeleteBuilder", "InsertBuilder", "SelectBuilder", "UpdateBuilder"] and - m.hasQualifiedName(sq, builder, - ["Columns", "From", "Options", "OrderBy", "Prefix", "Suffix", "Where"]) - or - builder = "InsertBuilder" and - m.hasQualifiedName(sq, builder, ["Replace", "Into"]) - or - builder = "SelectBuilder" and - m.hasQualifiedName(sq, builder, - ["CrossJoin", "GroupBy", "InnerJoin", "LeftJoin", "RightJoin"]) - or - builder = "UpdateBuilder" and - m.hasQualifiedName(sq, builder, ["Set", "Table"]) - ) - ) and - this = fn.getACall().getArgument(0) + exists(string sq, Method m, string builder | + FlowExtensions::packageGrouping("squirrel", sq) and + builder = ["DeleteBuilder", "SelectBuilder", "UpdateBuilder"] | - this.getType().getUnderlyingType() instanceof StringType or + m.hasQualifiedName(sq, builder, "Where") and + this = m.getACall().getArgument(0) + ) and + ( + this.getType().getUnderlyingType() instanceof StringType + or this.getType().getUnderlyingType().(SliceType).getElementType() instanceof StringType ) } @@ -113,14 +106,6 @@ module SQL { /** A string that might identify package `go-pg/pg/orm` or a specific version of it. */ private string gopgorm() { result = package("github.com/go-pg/pg", "orm") } - /** A string that might identify package `github.com/rqlite/gorqlite` or `github.com/raindog308/gorqlite` or a specific version of it. */ - private string gorqlite() { - result = package(["github.com/rqlite/gorqlite", "github.com/raindog308/gorqlite"], "") - } - - /** A string that might identify package `github.com/gogf/gf/database/gdb` or a specific version of it. */ - private string gogf() { result = package("github.com/gogf/gf", "database/gdb") } - /** * A string argument to an API of `go-pg/pg` that is directly interpreted as SQL without * taking syntactic structure into account. @@ -185,94 +170,6 @@ module SQL { ) } } - - /** - * A string argument to an API of `github.com/rqlite/gorqlite`, or a specific version of it, that is directly interpreted as SQL without - * taking syntactic structure into account. - */ - private class GorqliteQueryString extends Range { - GorqliteQueryString() { - // func (conn *Connection) Query(sqlStatements []string) (results []QueryResult, err error) - // func (conn *Connection) QueryOne(sqlStatement string) (qr QueryResult, err error) - // func (conn *Connection) Queue(sqlStatements []string) (seq int64, err error) - // func (conn *Connection) QueueOne(sqlStatement string) (seq int64, err error) - // func (conn *Connection) Write(sqlStatements []string) (results []WriteResult, err error) - // func (conn *Connection) WriteOne(sqlStatement string) (wr WriteResult, err error) - exists(Method m, string name | m.hasQualifiedName(gorqlite(), "Connection", name) | - name = ["Query", "QueryOne", "Queue", "QueueOne", "Write", "WriteOne"] and - this = m.getACall().getArgument(0) - ) - } - } - - /** - * A string argument to an API of `github.com/gogf/gf/database/gdb`, or a specific version of it, that is directly interpreted as SQL without - * taking syntactic structure into account. - */ - private class GogfQueryString extends Range { - GogfQueryString() { - exists(Method m, string name | m.implements(gogf(), ["DB", "Core", "TX"], name) | - // func (c *Core) Exec(sql string, args ...interface{}) (result sql.Result, err error) - // func (c *Core) GetAll(sql string, args ...interface{}) (Result, error) - // func (c *Core) GetArray(sql string, args ...interface{}) ([]Value, error) - // func (c *Core) GetCount(sql string, args ...interface{}) (int, error) - // func (c *Core) GetOne(sql string, args ...interface{}) (Record, error) - // func (c *Core) GetValue(sql string, args ...interface{}) (Value, error) - // func (c *Core) Prepare(sql string, execOnMaster ...bool) (*Stmt, error) - // func (c *Core) Query(sql string, args ...interface{}) (rows *sql.Rows, err error) - // func (c *Core) Raw(rawSql string, args ...interface{}) *Model - name = - [ - "Query", "Exec", "Prepare", "GetAll", "GetOne", "GetValue", "GetArray", "GetCount", - "Raw" - ] and - this = m.getACall().getArgument(0) - or - // func (c *Core) GetScan(pointer interface{}, sql string, args ...interface{}) error - // func (c *Core) GetStruct(pointer interface{}, sql string, args ...interface{}) error - // func (c *Core) GetStructs(pointer interface{}, sql string, args ...interface{}) error - name = ["GetScan", "GetStruct", "GetStructs"] and - this = m.getACall().getArgument(1) - or - // func (c *Core) DoCommit(ctx context.Context, link Link, sql string, args []interface{}) (newSql string, newArgs []interface{}, err error) - // func (c *Core) DoExec(ctx context.Context, link Link, sql string, args ...interface{}) (result sql.Result, err error) - // func (c *Core) DoGetAll(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error) - // func (c *Core) DoPrepare(ctx context.Context, link Link, sql string) (*Stmt, error) - // func (c *Core) DoQuery(ctx context.Context, link Link, sql string, args ...interface{}) (rows *sql.Rows, err error) - name = ["DoGetAll", "DoQuery", "DoExec", "DoCommit", "DoPrepare"] and - this = m.getACall().getArgument(2) - ) - } - } - } - - /** A model for sinks of GORM. */ - private class GormSink extends SQL::QueryString::Range { - GormSink() { - exists(Method meth, string package, string name | - meth.hasQualifiedName(package, "DB", name) and - this = meth.getACall().getSyntacticArgument(0) and - package = Gorm::packagePath() and - name in [ - "Where", "Raw", "Order", "Not", "Or", "Select", "Table", "Group", "Having", "Joins", - "Exec", "Distinct", "Pluck" - ] - ) - } - } - - /** A model for sinks of github.com/jmoiron/sqlx. */ - private class SqlxSink extends SQL::QueryString::Range { - SqlxSink() { - exists(Method meth, string name, int n | - meth.hasQualifiedName(package("github.com/jmoiron/sqlx", ""), ["DB", "Tx"], name) and - this = meth.getACall().getArgument(n) - | - name = ["Select", "Get"] and n = 1 - or - name = ["MustExec", "Queryx", "NamedExec", "NamedQuery"] and n = 0 - ) - } } } @@ -291,71 +188,25 @@ module Gorm { */ module Xorm { /** Gets the package name for Xorm. */ - string packagePath() { result = package(["xorm.io/xorm", "github.com/go-xorm/xorm"], "") } + string packagePath() { FlowExtensions::packageGrouping("xorm", result) } /** A model for sinks of XORM. */ private class XormSink extends SQL::QueryString::Range { XormSink() { - exists(Method meth, string type, string name, int n | + exists(Method meth, string type, string name | meth.hasQualifiedName(Xorm::packagePath(), type, name) and - this = meth.getACall().getSyntacticArgument(n) and - type = ["Engine", "Session"] + type = ["Engine", "Session"] and + name = ["Exec", "Query", "QueryInterface", "QueryString"] | - name = - [ - "Query", "Exec", "QueryString", "QueryInterface", "SQL", "Where", "And", "Or", "Alias", - "NotIn", "In", "Select", "SetExpr", "OrderBy", "Having", "GroupBy" - ] and - n = 0 - or - name = ["SumInt", "Sum", "Sums", "SumsInt"] and n = 1 - or - name = "Join" and n = [0, 1, 2] + this = meth.getACall().getSyntacticArgument(0) ) } } } /** + * DEPRECATED + * * Provides classes for working with the [Bun](https://bun.uptrace.dev/) package. */ -module Bun { - /** Gets the package name for Bun package. */ - private string packagePath() { result = package("github.com/uptrace/bun", "") } - - /** A model for sinks of Bun. */ - private class BunSink extends SQL::QueryString::Range { - BunSink() { - exists(Function f, string m, int arg | this = f.getACall().getArgument(arg) | - f.hasQualifiedName(packagePath(), m) and - m = "NewRawQuery" and - arg = 1 - ) - or - exists(Method f, string tp, string m, int arg | this = f.getACall().getArgument(arg) | - f.hasQualifiedName(packagePath(), tp, m) and - ( - tp = ["DB", "Conn"] and - m = ["ExecContext", "PrepareContext", "QueryContext", "QueryRowContext"] and - arg = 1 - or - tp = ["DB", "Conn"] and - m = ["Exec", "NewRaw", "Prepare", "Query", "QueryRow", "Raw"] and - arg = 0 - or - tp.matches("%Query") and - m = - [ - "ColumnExpr", "DistinctOn", "For", "GroupExpr", "Having", "ModelTableExpr", - "OrderExpr", "TableExpr", "Where", "WhereOr" - ] and - arg = 0 - or - tp = "RawQuery" and - m = "NewRaw" and - arg = 0 - ) - ) - } - } -} +deprecated module Bun { } diff --git a/go/ql/lib/semmle/go/frameworks/Spew.qll b/go/ql/lib/semmle/go/frameworks/Spew.qll index b12bd0fed81..f49a4aa4d89 100644 --- a/go/ql/lib/semmle/go/frameworks/Spew.qll +++ b/go/ql/lib/semmle/go/frameworks/Spew.qll @@ -33,16 +33,6 @@ module Spew { override int getFormatStringIndex() { result = super.getFirstPrintedArg() } } - private class SpewCall extends LoggerCall::Range, DataFlow::CallNode { - SpewFunction target; - - SpewCall() { this = target.getACall() } - - override DataFlow::Node getAMessageComponent() { - result = this.getSyntacticArgument(any(int i | i >= target.getFirstPrintedArg())) - } - } - // These are expressed using TaintTracking::FunctionModel because varargs functions don't work with Models-as-Data sumamries yet. /** The `Sprint` function or one of its variants. */ class Sprinter extends TaintTracking::FunctionModel { diff --git a/go/ql/lib/semmle/go/frameworks/Zap.qll b/go/ql/lib/semmle/go/frameworks/Zap.qll index 359f9aba410..0928d2b0595 100644 --- a/go/ql/lib/semmle/go/frameworks/Zap.qll +++ b/go/ql/lib/semmle/go/frameworks/Zap.qll @@ -34,18 +34,6 @@ module Zap { override int getFormatStringIndex() { result = 0 } } - /** - * A call to a logger function in Zap. - * - * Functions which add data to be included the next time a direct logging - * function is called are included. - */ - private class ZapCall extends LoggerCall::Range, DataFlow::MethodCallNode { - ZapCall() { this = any(ZapFunction f).getACall() } - - override DataFlow::Node getAMessageComponent() { result = this.getASyntacticArgument() } - } - // These are expressed using TaintTracking::FunctionModel because varargs functions don't work with Models-as-Data sumamries yet. /** The function `Fields` that creates an `Option` that can be added to the logger out of `Field`s. */ class FieldsFunction extends TaintTracking::FunctionModel { diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/DatabaseSql.qll b/go/ql/lib/semmle/go/frameworks/stdlib/DatabaseSql.qll index 845225af5bd..f4132688796 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/DatabaseSql.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/DatabaseSql.qll @@ -26,7 +26,7 @@ module DatabaseSql { override DataFlow::Node getAResult() { result = this.getResult(0) } override SQL::QueryString getAQueryString() { - result = this.getAnArgument() + result = this.getASyntacticArgument() or // attempt to resolve a `QueryString` for `Stmt`s using local data flow. t = "Stmt" and @@ -34,24 +34,6 @@ module DatabaseSql { } } - /** A query string used in an API function of the `database/sql` package. */ - private class QueryString extends SQL::QueryString::Range { - QueryString() { - exists(Method meth, string base, string t, string m, int n | - t = ["DB", "Tx", "Conn"] and - meth.hasQualifiedName("database/sql", t, m) and - this = meth.getACall().getArgument(n) - | - base = ["Exec", "Prepare", "Query", "QueryRow"] and - ( - m = base and n = 0 - or - m = base + "Context" and n = 1 - ) - ) - } - } - /** A query in the standard `database/sql/driver` package. */ private class DriverQuery extends SQL::Query::Range, DataFlow::MethodCallNode { DriverQuery() { @@ -78,36 +60,13 @@ module DatabaseSql { override DataFlow::Node getAResult() { result = this.getResult(0) } override SQL::QueryString getAQueryString() { - result = this.getAnArgument() + result = this.getASyntacticArgument() or this.getTarget().hasQualifiedName("database/sql/driver", "Stmt") and result = this.getReceiver().getAPredecessor*().(DataFlow::MethodCallNode).getAnArgument() } } - /** A query string used in an API function of the standard `database/sql/driver` package. */ - private class DriverQueryString extends SQL::QueryString::Range { - DriverQueryString() { - exists(Method meth, int n | - ( - meth.hasQualifiedName("database/sql/driver", "Execer", "Exec") and n = 0 - or - meth.hasQualifiedName("database/sql/driver", "ExecerContext", "ExecContext") and n = 1 - or - meth.hasQualifiedName("database/sql/driver", "Conn", "Prepare") and n = 0 - or - meth.hasQualifiedName("database/sql/driver", "ConnPrepareContext", "PrepareContext") and - n = 1 - or - meth.hasQualifiedName("database/sql/driver", "Queryer", "Query") and n = 0 - or - meth.hasQualifiedName("database/sql/driver", "QueryerContext", "QueryContext") and n = 1 - ) and - this = meth.getACall().getArgument(n) - ) - } - } - // These are expressed using TaintTracking::FunctionModel because varargs functions don't work with Models-as-Data sumamries yet. private class SqlMethodModels extends TaintTracking::FunctionModel, Method { FunctionInput inp; diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Fmt.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Fmt.qll index 54794ea21c9..6adbd542e9b 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Fmt.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Fmt.qll @@ -41,13 +41,6 @@ module Fmt { Printer() { this.hasQualifiedName("fmt", ["Print", "Printf", "Println"]) } } - /** A call to `Print` or similar. */ - private class PrintCall extends LoggerCall::Range, DataFlow::CallNode { - PrintCall() { this.getTarget() instanceof Printer } - - override DataFlow::Node getAMessageComponent() { result = this.getASyntacticArgument() } - } - /** The `Fprint` function or one of its variants. */ private class Fprinter extends TaintTracking::FunctionModel { Fprinter() { diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Log.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Log.qll index 5b402fca1b7..ca74160bf0d 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Log.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Log.qll @@ -32,16 +32,6 @@ module Log { override int getFormatStringIndex() { result = 0 } } - private class LogCall extends LoggerCall::Range, DataFlow::CallNode { - LogFunction target; - - LogCall() { this = target.getACall() } - - override DataFlow::Node getAMessageComponent() { - result = this.getSyntacticArgument(any(int i | i >= target.getFirstPrintedArg())) - } - } - /** A fatal log function, which calls `os.Exit`. */ private class FatalLogFunction extends Function { FatalLogFunction() { this.hasQualifiedName("log", ["Fatal", "Fatalf", "Fatalln"]) } diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/Os.qll b/go/ql/lib/semmle/go/frameworks/stdlib/Os.qll index fb153451c59..72ea4cc6c57 100644 --- a/go/ql/lib/semmle/go/frameworks/stdlib/Os.qll +++ b/go/ql/lib/semmle/go/frameworks/stdlib/Os.qll @@ -43,12 +43,4 @@ module Os { input = inp and output = outp } } - - private class Stdin extends SourceNode { - Stdin() { - exists(Variable osStdin | osStdin.hasQualifiedName("os", "Stdin") | this = osStdin.getARead()) - } - - override string getThreatModel() { result = "stdin" } - } } diff --git a/go/ql/lib/semmle/go/security/CleartextLogging.qll b/go/ql/lib/semmle/go/security/CleartextLogging.qll index 7c29f0ba130..2e0c9665c4b 100644 --- a/go/ql/lib/semmle/go/security/CleartextLogging.qll +++ b/go/ql/lib/semmle/go/security/CleartextLogging.qll @@ -16,49 +16,6 @@ import go module CleartextLogging { import CleartextLoggingCustomizations::CleartextLogging - /** - * DEPRECATED: Use `Flow` instead. - * - * A data-flow tracking configuration for clear-text logging of sensitive information. - * - * This configuration identifies flows from `Source`s, which are sources of - * sensitive data, to `Sink`s, which is an abstract class representing all - * the places sensitive data may be stored in cleartext. Additional sources or sinks can be - * added either by extending the relevant class, or by subclassing this configuration itself, - * and amending the sources and sinks. - */ - deprecated class Configuration extends DataFlow::Configuration { - Configuration() { this = "CleartextLogging" } - - override predicate isSource(DataFlow::Node source) { source instanceof Source } - - override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } - - override predicate isBarrier(DataFlow::Node node) { - node instanceof Barrier - or - exists(DataFlow::CallNode call | node = call.getResult() | - call.getTarget() = Builtin::error().getType().getMethod("Error") - or - call.getTarget().(Method).hasQualifiedName("fmt", "Stringer", "String") - ) - } - - override predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node trg) { - // A taint propagating data-flow edge through structs: a tainted write taints the entire struct. - exists(Write write | - write.writesField(trg.(DataFlow::PostUpdateNode).getPreUpdateNode(), _, src) - ) - or - // taint steps that do not include flow through fields. Field reads would produce FPs due to - // the additional taint step above that taints whole structs from individual field writes. - TaintTracking::localTaintStep(src, trg) and - not TaintTracking::fieldReadStep(src, trg) and - // Also exclude protobuf field fetches, since they amount to single field reads. - not any(Protobuf::GetMethod gm).taintStep(src, trg) - } - } - private module Config implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof Source } diff --git a/go/ql/lib/semmle/go/security/IncorrectIntegerConversionLib.qll b/go/ql/lib/semmle/go/security/IncorrectIntegerConversionLib.qll index 68d874768ce..3c6cddc427f 100644 --- a/go/ql/lib/semmle/go/security/IncorrectIntegerConversionLib.qll +++ b/go/ql/lib/semmle/go/security/IncorrectIntegerConversionLib.qll @@ -53,132 +53,6 @@ int getIntTypeBitSize(File file, int architectureSpecificBitSize) { result = architectureSpecificBitSize } -/** - * Holds if converting from an integer types with size `sourceBitSize` to - * one with size `sinkBitSize` can produce unexpected values, where 0 means - * architecture-dependent. - * - * Architecture-dependent bit sizes can be 32 or 64. To catch flows that - * only manifest on 64-bit architectures we consider an - * architecture-dependent source bit size to be 64. To catch flows that - * only happen on 32-bit architectures we consider an - * architecture-dependent sink bit size to be 32. We exclude the case where - * both source and sink have architecture-dependent bit sizes. - */ -private predicate isIncorrectIntegerConversion(int sourceBitSize, int sinkBitSize) { - sourceBitSize in [16, 32, 64] and - sinkBitSize in [8, 16, 32] and - sourceBitSize > sinkBitSize - or - // Treat `sourceBitSize = 0` like `sourceBitSize = 64`, and exclude `sinkBitSize = 0` - sourceBitSize = 0 and - sinkBitSize in [8, 16, 32] - or - // Treat `sinkBitSize = 0` like `sinkBitSize = 32`, and exclude `sourceBitSize = 0` - sourceBitSize = 64 and - sinkBitSize = 0 -} - -/** - * DEPRECATED: use `Flow` instead. - * - * A taint-tracking configuration for reasoning about when an integer - * obtained from parsing a string flows to a type conversion to a smaller - * integer types, which could cause unexpected values. - */ -deprecated class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration { - boolean sinkIsSigned; - int sourceBitSize; - int sinkBitSize; - - ConversionWithoutBoundsCheckConfig() { - sinkIsSigned in [true, false] and - isIncorrectIntegerConversion(sourceBitSize, sinkBitSize) and - this = "ConversionWithoutBoundsCheckConfig" + sourceBitSize + sinkIsSigned + sinkBitSize - } - - /** Gets the bit size of the source. */ - int getSourceBitSize() { result = sourceBitSize } - - override predicate isSource(DataFlow::Node source) { - exists( - DataFlow::CallNode c, IntegerParser::Range ip, int apparentBitSize, int effectiveBitSize - | - c.getTarget() = ip and source = c.getResult(0) - | - ( - apparentBitSize = ip.getTargetBitSize() - or - // If we are reading a variable, check if it is - // `strconv.IntSize`, and use 0 if it is. - exists(DataFlow::Node rawBitSize | rawBitSize = ip.getTargetBitSizeInput().getNode(c) | - if rawBitSize = any(Strconv::IntSize intSize).getARead() - then apparentBitSize = 0 - else apparentBitSize = rawBitSize.getIntValue() - ) - ) and - ( - if apparentBitSize = 0 - then effectiveBitSize = getIntTypeBitSize(source.getFile(), 0) - else effectiveBitSize = apparentBitSize - ) and - // `effectiveBitSize` could be any value between 0 and 64, but we - // can round it up to the nearest size of an integer type without - // changing behavior. - sourceBitSize = min(int b | b in [0, 8, 16, 32, 64] and b >= effectiveBitSize) - ) - } - - /** - * Holds if `sink` is a typecast to an integer type with size `bitSize` (where - * 0 represents architecture-dependent) and the expression being typecast is - * not also in a right-shift expression. We allow this case because it is - * a common pattern to serialise `byte(v)`, `byte(v >> 8)`, and so on. - */ - predicate isSinkWithBitSize(DataFlow::TypeCastNode sink, int bitSize) { - sink.asExpr() instanceof ConversionExpr and - exists(IntegerType integerType | sink.getResultType().getUnderlyingType() = integerType | - ( - bitSize = integerType.getSize() - or - not exists(integerType.getSize()) and - bitSize = getIntTypeBitSize(sink.getFile(), 0) - ) and - if integerType instanceof SignedIntegerType then sinkIsSigned = true else sinkIsSigned = false - ) and - not exists(ShrExpr shrExpr | - shrExpr.getLeftOperand().getGlobalValueNumber() = - sink.getOperand().asExpr().getGlobalValueNumber() or - shrExpr.getLeftOperand().(AndExpr).getAnOperand().getGlobalValueNumber() = - sink.getOperand().asExpr().getGlobalValueNumber() - ) - } - - override predicate isSink(DataFlow::Node sink) { - // We use the argument of the type conversion as the configuration sink so that we - // can sanitize the result of the conversion to prevent flow on to further sinks - // without needing to use `isSanitizerOut`, which doesn't work with flow states - // (and therefore the legacy `TaintTracking::Configuration` class). - this.isSinkWithBitSize(sink.getASuccessor(), sinkBitSize) - } - - override predicate isSanitizer(DataFlow::Node node) { - // To catch flows that only happen on 32-bit architectures we - // consider an architecture-dependent sink bit size to be 32. - exists(UpperBoundCheckGuard g, int bitSize | - if sinkBitSize != 0 then bitSize = sinkBitSize else bitSize = 32 - | - node = DataFlow::BarrierGuard::getABarrierNodeForGuard(g) and - if sinkIsSigned = true then g.isBoundFor(bitSize, 32) else g.isBoundFor(bitSize - 1, 32) - ) - or - exists(int bitSize | - isIncorrectIntegerConversion(sourceBitSize, bitSize) and - this.isSinkWithBitSize(node, bitSize) - ) - } -} - private int validBitSize() { result = [7, 8, 15, 16, 31, 32, 63, 64] } private newtype TArchitectureBitSize = diff --git a/go/ql/lib/semmle/go/security/InsecureRandomness.qll b/go/ql/lib/semmle/go/security/InsecureRandomness.qll index 675f0b4b9a2..83746f7b96e 100644 --- a/go/ql/lib/semmle/go/security/InsecureRandomness.qll +++ b/go/ql/lib/semmle/go/security/InsecureRandomness.qll @@ -16,25 +16,6 @@ import go module InsecureRandomness { import InsecureRandomnessCustomizations::InsecureRandomness - /** - * DEPRECATED: Use `Flow` instead. - * - * A taint-tracking configuration for reasoning about random values that are - * not cryptographically secure. - */ - deprecated class Configuration extends TaintTracking::Configuration { - Configuration() { this = "InsecureRandomness" } - - override predicate isSource(DataFlow::Node source) { source instanceof Source } - - override predicate isSink(DataFlow::Node sink) { this.isSinkWithKind(sink, _) } - - /** Holds if `sink` is a sink for this configuration with kind `kind`. */ - predicate isSinkWithKind(Sink sink, string kind) { kind = sink.getKind() } - - override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer } - } - /** Holds if `sink` is a sink for this configuration with kind `kind`. */ predicate isSinkWithKind(Sink sink, string kind) { kind = sink.getKind() } diff --git a/go/ql/lib/semmle/go/security/OpenUrlRedirect.qll b/go/ql/lib/semmle/go/security/OpenUrlRedirect.qll index d3576f005b9..bfe47f260cd 100644 --- a/go/ql/lib/semmle/go/security/OpenUrlRedirect.qll +++ b/go/ql/lib/semmle/go/security/OpenUrlRedirect.qll @@ -17,51 +17,6 @@ import UrlConcatenation module OpenUrlRedirect { import OpenUrlRedirectCustomizations::OpenUrlRedirect - /** - * DEPRECATED: Use `Flow` instead. - * - * A data-flow configuration for reasoning about unvalidated URL redirections. - */ - deprecated class Configuration extends DataFlow::Configuration { - Configuration() { this = "OpenUrlRedirect" } - - override predicate isSource(DataFlow::Node source) { source instanceof Source } - - override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } - - override predicate isBarrier(DataFlow::Node node) { node instanceof Barrier } - - override predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) { - // taint steps that do not include flow through fields - TaintTracking::localTaintStep(pred, succ) and not TaintTracking::fieldReadStep(pred, succ) - or - // explicit extra taint steps for this query - any(AdditionalStep s).hasTaintStep(pred, succ) - or - // propagate to a URL when its host is assigned to - exists(Write w, Field f, SsaWithFields v | f.hasQualifiedName("net/url", "URL", "Host") | - w.writesField(v.getAUse(), f, pred) and succ = v.getAUse() - ) - or - // propagate out of most URL fields, but not `ForceQuery` and `Scheme` - exists(Field f, string fn | - f.hasQualifiedName("net/url", "URL", fn) and - not fn in ["ForceQuery", "Scheme"] - | - succ.(Read).readsField(pred, f) - ) - } - - override predicate isBarrierOut(DataFlow::Node node) { - // block propagation of this unsafe value when its host is overwritten - exists(Write w, Field f | f.hasQualifiedName("net/url", "URL", "Host") | - w.writesField(node.getASuccessor(), f, _) - ) - or - hostnameSanitizingPrefixEdge(node, _) - } - } - private module Config implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof Source } diff --git a/go/ql/lib/semmle/go/security/ReflectedXss.qll b/go/ql/lib/semmle/go/security/ReflectedXss.qll index a605d78633d..1068c6fae3d 100644 --- a/go/ql/lib/semmle/go/security/ReflectedXss.qll +++ b/go/ql/lib/semmle/go/security/ReflectedXss.qll @@ -16,24 +16,6 @@ import go module ReflectedXss { import ReflectedXssCustomizations::ReflectedXss - /** - * DEPRECATED: Use `Flow` instead. - * - * A taint-tracking configuration for reasoning about XSS. - */ - deprecated class Configuration extends TaintTracking::Configuration { - Configuration() { this = "ReflectedXss" } - - override predicate isSource(DataFlow::Node source) { source instanceof Source } - - override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } - - override predicate isSanitizer(DataFlow::Node node) { - super.isSanitizer(node) or - node instanceof Sanitizer - } - } - private module Config implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof Source } diff --git a/go/ql/lib/semmle/go/security/RequestForgery.qll b/go/ql/lib/semmle/go/security/RequestForgery.qll index 5f7139a1b44..bdf26a1f18f 100644 --- a/go/ql/lib/semmle/go/security/RequestForgery.qll +++ b/go/ql/lib/semmle/go/security/RequestForgery.qll @@ -16,36 +16,6 @@ import go module RequestForgery { import RequestForgeryCustomizations::RequestForgery - /** - * DEPRECATED: Use `Flow` instead. - * - * A taint-tracking configuration for reasoning about request forgery. - */ - deprecated class Configuration extends TaintTracking::Configuration { - Configuration() { this = "RequestForgery" } - - override predicate isSource(DataFlow::Node source) { source instanceof Source } - - override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } - - override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { - // propagate to a URL when its host is assigned to - exists(Write w, Field f, SsaWithFields v | f.hasQualifiedName("net/url", "URL", "Host") | - w.writesField(v.getAUse(), f, pred) and succ = v.getAUse() - ) - } - - override predicate isSanitizer(DataFlow::Node node) { - super.isSanitizer(node) or - node instanceof Sanitizer - } - - override predicate isSanitizerOut(DataFlow::Node node) { - super.isSanitizerOut(node) or - node instanceof SanitizerEdge - } - } - private module Config implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof Source } diff --git a/go/ql/lib/semmle/go/security/SafeUrlFlow.qll b/go/ql/lib/semmle/go/security/SafeUrlFlow.qll index f4d1a535bad..d74e2156a60 100644 --- a/go/ql/lib/semmle/go/security/SafeUrlFlow.qll +++ b/go/ql/lib/semmle/go/security/SafeUrlFlow.qll @@ -16,35 +16,6 @@ import go module SafeUrlFlow { import SafeUrlFlowCustomizations::SafeUrlFlow - /** - * DEPRECATED: Use `Flow` instead. - * - * A taint-tracking configuration for reasoning about safe URLs. - */ - deprecated class Configuration extends TaintTracking::Configuration { - Configuration() { this = "SafeUrlFlow" } - - override predicate isSource(DataFlow::Node source) { source instanceof Source } - - override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } - - override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { - // propagate to a URL when its host is assigned to - exists(Write w, Field f, SsaWithFields v | f.hasQualifiedName("net/url", "URL", "Host") | - w.writesField(v.getAUse(), f, pred) and succ = v.getAUse() - ) - } - - override predicate isSanitizerOut(DataFlow::Node node) { - // block propagation of this safe value when its host is overwritten - exists(Write w, Field f | f.hasQualifiedName("net/url", "URL", "Host") | - w.writesField(node.getASuccessor(), f, _) - ) - or - node instanceof SanitizerEdge - } - } - private module Config implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof Source } diff --git a/go/ql/lib/semmle/go/security/SqlInjection.qll b/go/ql/lib/semmle/go/security/SqlInjection.qll index 366a05cf3df..e24b30f40d3 100644 --- a/go/ql/lib/semmle/go/security/SqlInjection.qll +++ b/go/ql/lib/semmle/go/security/SqlInjection.qll @@ -13,28 +13,6 @@ import go module SqlInjection { import SqlInjectionCustomizations::SqlInjection - /** - * DEPRECATED: Use `Flow` instead. - * - * A taint-tracking configuration for reasoning about SQL-injection vulnerabilities. - */ - deprecated class Configuration extends TaintTracking::Configuration { - Configuration() { this = "SqlInjection" } - - override predicate isSource(DataFlow::Node source) { source instanceof Source } - - override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } - - override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { - NoSql::isAdditionalMongoTaintStep(pred, succ) - } - - override predicate isSanitizer(DataFlow::Node node) { - super.isSanitizer(node) or - node instanceof Sanitizer - } - } - private module Config implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof Source } diff --git a/go/ql/lib/semmle/go/security/StoredCommand.qll b/go/ql/lib/semmle/go/security/StoredCommand.qll index 4c21a292371..38555370cfc 100644 --- a/go/ql/lib/semmle/go/security/StoredCommand.qll +++ b/go/ql/lib/semmle/go/security/StoredCommand.qll @@ -16,28 +16,6 @@ import CommandInjectionCustomizations * injection vulnerabilities. */ module StoredCommand { - /** - * DEPRECATED: Use `Flow` instead. - * - * A taint-tracking configuration for reasoning about command-injection vulnerabilities. - */ - deprecated class Configuration extends TaintTracking::Configuration { - Configuration() { this = "StoredCommand" } - - override predicate isSource(DataFlow::Node source) { - source instanceof StoredXss::Source and - // exclude file names, since those are not generally an issue - not source instanceof StoredXss::FileNameSource - } - - override predicate isSink(DataFlow::Node sink) { sink instanceof CommandInjection::Sink } - - override predicate isSanitizer(DataFlow::Node node) { - super.isSanitizer(node) or - node instanceof CommandInjection::Sanitizer - } - } - private module Config implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof StoredXss::Source and diff --git a/go/ql/lib/semmle/go/security/StoredXss.qll b/go/ql/lib/semmle/go/security/StoredXss.qll index 37e4b048910..2bf6bf24804 100644 --- a/go/ql/lib/semmle/go/security/StoredXss.qll +++ b/go/ql/lib/semmle/go/security/StoredXss.qll @@ -16,24 +16,6 @@ import go module StoredXss { import StoredXssCustomizations::StoredXss - /** - * DEPRECATED: Use `Flow` instead. - * - * A taint-tracking configuration for reasoning about XSS. - */ - deprecated class Configuration extends TaintTracking::Configuration { - Configuration() { this = "StoredXss" } - - override predicate isSource(DataFlow::Node source) { source instanceof Source } - - override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } - - override predicate isSanitizer(DataFlow::Node node) { - super.isSanitizer(node) or - node instanceof Sanitizer - } - } - private module Config implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof Source } diff --git a/go/ql/lib/semmle/go/security/StringBreak.qll b/go/ql/lib/semmle/go/security/StringBreak.qll index fed3b9b1443..02b4c5b3313 100644 --- a/go/ql/lib/semmle/go/security/StringBreak.qll +++ b/go/ql/lib/semmle/go/security/StringBreak.qll @@ -13,27 +13,6 @@ import go module StringBreak { import StringBreakCustomizations::StringBreak - /** - * DEPRECATED: Use `Flow` instead. - * - * A taint-tracking configuration for reasoning about unsafe-quoting vulnerabilities, - * parameterized with the type of quote being tracked. - */ - deprecated class Configuration extends TaintTracking::Configuration { - Quote quote; - - Configuration() { this = "StringBreak" + quote } - - /** Gets the type of quote being tracked by this configuration. */ - Quote getQuote() { result = quote } - - override predicate isSource(DataFlow::Node nd) { nd instanceof Source } - - override predicate isSink(DataFlow::Node nd) { quote = nd.(Sink).getQuote() } - - override predicate isSanitizer(DataFlow::Node nd) { quote = nd.(Sanitizer).getQuote() } - } - private module Config implements DataFlow::StateConfigSig { /** The flow state that we track is the type of quote used. */ class FlowState = Quote; diff --git a/go/ql/lib/semmle/go/security/TaintedPath.qll b/go/ql/lib/semmle/go/security/TaintedPath.qll index 26009554c24..674cda1157c 100644 --- a/go/ql/lib/semmle/go/security/TaintedPath.qll +++ b/go/ql/lib/semmle/go/security/TaintedPath.qll @@ -11,24 +11,6 @@ import go module TaintedPath { import TaintedPathCustomizations::TaintedPath - /** - * DEPRECATED: Use `Flow` instead. - * - * A taint-tracking configuration for reasoning about path-traversal vulnerabilities. - */ - deprecated class Configuration extends TaintTracking::Configuration { - Configuration() { this = "TaintedPath" } - - override predicate isSource(DataFlow::Node source) { source instanceof Source } - - override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } - - override predicate isSanitizer(DataFlow::Node node) { - super.isSanitizer(node) or - node instanceof Sanitizer - } - } - private module Config implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof Source } diff --git a/go/ql/lib/semmle/go/security/UnsafeUnzipSymlink.qll b/go/ql/lib/semmle/go/security/UnsafeUnzipSymlink.qll index 2b969ffc4d9..1d18ac5f639 100644 --- a/go/ql/lib/semmle/go/security/UnsafeUnzipSymlink.qll +++ b/go/ql/lib/semmle/go/security/UnsafeUnzipSymlink.qll @@ -13,24 +13,6 @@ import go module UnsafeUnzipSymlink { import UnsafeUnzipSymlinkCustomizations::UnsafeUnzipSymlink - /** - * DEPRECATED: Use copies of `EvalSymlinksConfig` and `EvalSymlinksFlow` instead. - * - * A taint-flow configuration tracking archive header fields flowing to a `path/filepath.EvalSymlinks` call. - */ - deprecated class EvalSymlinksConfiguration extends TaintTracking2::Configuration { - EvalSymlinksConfiguration() { this = "Archive header field symlinks resolved" } - - override predicate isSource(DataFlow::Node source) { source instanceof FilenameWithSymlinks } - - override predicate isSink(DataFlow::Node sink) { sink instanceof EvalSymlinksSink } - - override predicate isSanitizer(DataFlow::Node node) { - super.isSanitizer(node) or - node instanceof EvalSymlinksInvalidator - } - } - // Archive header field symlinks resolved private module EvalSymlinksConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof FilenameWithSymlinks } @@ -53,28 +35,6 @@ module UnsafeUnzipSymlink { EvalSymlinksFlow::flow(getASimilarReadNode(node), _) } - /** - * DEPRECATED: Use `Flow` instead. - * - * A taint-flow configuration tracking archive header fields flowing to an `os.Symlink` call, - * which never flow to a `path/filepath.EvalSymlinks` call. - */ - deprecated class SymlinkConfiguration extends TaintTracking::Configuration { - SymlinkConfiguration() { this = "Unsafe unzipping of symlinks" } - - override predicate isSource(DataFlow::Node source) { - source instanceof FilenameWithSymlinks and - not symlinksEvald(source) - } - - override predicate isSink(DataFlow::Node sink) { sink instanceof SymlinkSink } - - override predicate isSanitizer(DataFlow::Node node) { - super.isSanitizer(node) or - node instanceof SymlinkSanitizer - } - } - private module Config implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof FilenameWithSymlinks and diff --git a/go/ql/lib/semmle/go/security/XPathInjection.qll b/go/ql/lib/semmle/go/security/XPathInjection.qll index 2e374dfbf24..61bd00977da 100644 --- a/go/ql/lib/semmle/go/security/XPathInjection.qll +++ b/go/ql/lib/semmle/go/security/XPathInjection.qll @@ -13,24 +13,6 @@ import go module XPathInjection { import XPathInjectionCustomizations::XPathInjection - /** - * DEPRECATED: Use `Flow` instead. - * - * A taint-tracking configuration for reasoning about untrusted user input used in an XPath expression. - */ - deprecated class Configuration extends TaintTracking::Configuration { - Configuration() { this = "XPathInjection" } - - override predicate isSource(DataFlow::Node source) { source instanceof Source } - - override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } - - override predicate isSanitizer(DataFlow::Node node) { - super.isSanitizer(node) or - node instanceof Sanitizer - } - } - private module Config implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof Source } diff --git a/go/ql/lib/semmle/go/security/ZipSlip.qll b/go/ql/lib/semmle/go/security/ZipSlip.qll index 4a7ba231f0f..f16daf84c3d 100644 --- a/go/ql/lib/semmle/go/security/ZipSlip.qll +++ b/go/ql/lib/semmle/go/security/ZipSlip.qll @@ -11,24 +11,6 @@ import go module ZipSlip { import ZipSlipCustomizations::ZipSlip - /** - * DEPRECATED: Use `Flow` instead. - * - * A taint-tracking configuration for reasoning about zip-slip vulnerabilities. - */ - deprecated class Configuration extends TaintTracking::Configuration { - Configuration() { this = "ZipSlip" } - - override predicate isSource(DataFlow::Node source) { source instanceof Source } - - override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } - - override predicate isSanitizer(DataFlow::Node node) { - super.isSanitizer(node) or - node instanceof Sanitizer - } - } - private module Config implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof Source } diff --git a/go/ql/src/Security/CWE-640/EmailInjection.qll b/go/ql/src/Security/CWE-640/EmailInjection.qll index 479fe6dc055..35b7795ad55 100644 --- a/go/ql/src/Security/CWE-640/EmailInjection.qll +++ b/go/ql/src/Security/CWE-640/EmailInjection.qll @@ -16,19 +16,6 @@ import go module EmailInjection { import EmailInjectionCustomizations::EmailInjection - /** - * DEPRECATED: Use `Flow` instead. - * - * A taint-tracking configuration for reasoning about email-injection vulnerabilities. - */ - deprecated class Configuration extends TaintTracking::Configuration { - Configuration() { this = "Email Injection" } - - override predicate isSource(DataFlow::Node source) { source instanceof Source } - - override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } - } - private module Config implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof Source } diff --git a/go/ql/src/change-notes/2024-11-26-model-slices-package.md b/go/ql/src/change-notes/2024-11-26-model-slices-package.md new file mode 100644 index 00000000000..5a3141c8075 --- /dev/null +++ b/go/ql/src/change-notes/2024-11-26-model-slices-package.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added value flow models for functions in the `slices` package which do not involve the `iter` package. diff --git a/go/ql/src/experimental/CWE-090/LDAPInjection.qll b/go/ql/src/experimental/CWE-090/LDAPInjection.qll index 4e0a6e290da..fd138fa0645 100644 --- a/go/ql/src/experimental/CWE-090/LDAPInjection.qll +++ b/go/ql/src/experimental/CWE-090/LDAPInjection.qll @@ -95,22 +95,6 @@ private class LdapClientDNSink extends LdapSink { } } -/** - * DEPRECATED: Use `LdapInjectionFlow` instead. - * - * A taint-tracking configuration for reasoning about when a `ActiveThreatModelSource` - * flows into an argument or field that is vulnerable to LDAP injection. - */ -deprecated class LdapInjectionConfiguration extends TaintTracking::Configuration { - LdapInjectionConfiguration() { this = "Ldap injection" } - - override predicate isSource(DataFlow::Node source) { source instanceof ActiveThreatModelSource } - - override predicate isSink(DataFlow::Node sink) { sink instanceof LdapSink } - - override predicate isSanitizer(DataFlow::Node sanitizer) { sanitizer instanceof LdapSanitizer } -} - private module LdapInjectionConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof ActiveThreatModelSource } diff --git a/go/ql/src/experimental/CWE-1004/AuthCookie.qll b/go/ql/src/experimental/CWE-1004/AuthCookie.qll index c995a8b2f68..411da5a79fa 100644 --- a/go/ql/src/experimental/CWE-1004/AuthCookie.qll +++ b/go/ql/src/experimental/CWE-1004/AuthCookie.qll @@ -64,28 +64,6 @@ private class SetCookieSink extends DataFlow::Node { } } -/** - * DEPRECATED: Use `NameToNetHttpCookieTrackingFlow` instead. - * - * A taint-tracking configuration for tracking flow from sensitive names to - * `net/http.SetCookie`. - */ -deprecated class NameToNetHttpCookieTrackingConfiguration extends TaintTracking::Configuration { - NameToNetHttpCookieTrackingConfiguration() { this = "NameToNetHttpCookieTrackingConfiguration" } - - override predicate isSource(DataFlow::Node source) { isAuthVariable(source.asExpr()) } - - override predicate isSink(DataFlow::Node sink) { sink instanceof SetCookieSink } - - override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { - exists(StructLit sl | - sl.getType() instanceof NetHttpCookieType and - getValueForFieldWrite(sl, "Name") = pred and - sl = succ.asExpr() - ) - } -} - private module NameToNetHttpCookieTrackingConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { isAuthVariable(source.asExpr()) } @@ -103,30 +81,6 @@ private module NameToNetHttpCookieTrackingConfig implements DataFlow::ConfigSig /** Tracks taint flow from sensitive names to `net/http.SetCookie`. */ module NameToNetHttpCookieTrackingFlow = TaintTracking::Global; -/** - * DEPRECATED: Use `BoolToNetHttpCookieTrackingFlow` instead. - * - * A taint-tracking configuration for tracking flow from `bool` assigned to - * `HttpOnly` that flows into `net/http.SetCookie`. - */ -deprecated class BoolToNetHttpCookieTrackingConfiguration extends TaintTracking::Configuration { - BoolToNetHttpCookieTrackingConfiguration() { this = "BoolToNetHttpCookieTrackingConfiguration" } - - override predicate isSource(DataFlow::Node source) { - source.getType().getUnderlyingType() instanceof BoolType - } - - override predicate isSink(DataFlow::Node sink) { sink instanceof SetCookieSink } - - override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { - exists(StructLit sl | - sl.getType() instanceof NetHttpCookieType and - getValueForFieldWrite(sl, "HttpOnly") = pred and - sl = succ.asExpr() - ) - } -} - private module BoolToNetHttpCookieTrackingConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source.getType().getUnderlyingType() instanceof BoolType @@ -149,29 +103,6 @@ private module BoolToNetHttpCookieTrackingConfig implements DataFlow::ConfigSig */ module BoolToNetHttpCookieTrackingFlow = TaintTracking::Global; -/** - * DEPRECATED: Use `BoolToGinSetCookieTrackingFlow` instead. - * - * A taint-tracking configuration for tracking flow from `HttpOnly` set to - * `false` to `gin-gonic/gin.Context.SetCookie`. - */ -deprecated class BoolToGinSetCookieTrackingConfiguration extends DataFlow::Configuration { - BoolToGinSetCookieTrackingConfiguration() { this = "BoolToGinSetCookieTrackingConfiguration" } - - override predicate isSource(DataFlow::Node source) { source.getBoolValue() = false } - - override predicate isSink(DataFlow::Node sink) { - exists(DataFlow::MethodCallNode mcn | - mcn.getTarget() instanceof GinContextSetCookieMethod and - mcn.getArgument(6) = sink and - exists(NameToGinSetCookieTrackingConfiguration cfg, DataFlow::Node nameArg | - cfg.hasFlowTo(nameArg) and - mcn.getArgument(0) = nameArg - ) - ) - } -} - private module BoolToGinSetCookieTrackingConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source.getBoolValue() = false } @@ -193,25 +124,6 @@ private module BoolToGinSetCookieTrackingConfig implements DataFlow::ConfigSig { */ module BoolToGinSetCookieTrackingFlow = DataFlow::Global; -/** - * DEPRECATED: Use `NameToGinSetCookieTrackingFlow` instead. - * - * A taint-tracking configuration for tracking flow from sensitive names to - * `gin-gonic/gin.Context.SetCookie`. - */ -deprecated private class NameToGinSetCookieTrackingConfiguration extends DataFlow2::Configuration { - NameToGinSetCookieTrackingConfiguration() { this = "NameToGinSetCookieTrackingConfiguration" } - - override predicate isSource(DataFlow::Node source) { isAuthVariable(source.asExpr()) } - - override predicate isSink(DataFlow::Node sink) { - exists(DataFlow::MethodCallNode mcn | - mcn.getTarget() instanceof GinContextSetCookieMethod and - mcn.getArgument(0) = sink - ) - } -} - private module NameToGinSetCookieTrackingConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { isAuthVariable(source.asExpr()) } @@ -251,39 +163,6 @@ private class GorillaStoreSaveSink extends DataFlow::Node { } } -/** - * DEPRECATED: Use `GorillaCookieStoreSaveTrackingFlow` instead. - * - * A taint-tracking configuration for tracking flow from gorilla cookie store - * creation to `gorilla/sessions.Session.Save`. - */ -deprecated class GorillaCookieStoreSaveTrackingConfiguration extends DataFlow::Configuration { - GorillaCookieStoreSaveTrackingConfiguration() { - this = "GorillaCookieStoreSaveTrackingConfiguration" - } - - override predicate isSource(DataFlow::Node source) { - source - .(DataFlow::CallNode) - .getTarget() - .hasQualifiedName(package("github.com/gorilla/sessions", ""), "NewCookieStore") - } - - override predicate isSink(DataFlow::Node sink) { - sink instanceof GorillaSessionSaveSink or - sink instanceof GorillaStoreSaveSink - } - - override predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) { - exists(DataFlow::MethodCallNode cn | - cn.getTarget() - .hasQualifiedName(package("github.com/gorilla/sessions", ""), "CookieStore", "Get") and - pred = cn.getReceiver() and - succ = cn.getResult(0) - ) - } -} - private module GorillaCookieStoreSaveTrackingConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source @@ -313,34 +192,6 @@ private module GorillaCookieStoreSaveTrackingConfig implements DataFlow::ConfigS */ module GorillaCookieStoreSaveTrackingFlow = DataFlow::Global; -/** - * DEPRECATED: Use `GorillaSessionOptionsTrackingFlow` instead. - * - * A taint-tracking configuration for tracking flow from session options to - * `gorilla/sessions.Session.Save`. - */ -deprecated class GorillaSessionOptionsTrackingConfiguration extends TaintTracking::Configuration { - GorillaSessionOptionsTrackingConfiguration() { - this = "GorillaSessionOptionsTrackingConfiguration" - } - - override predicate isSource(DataFlow::Node source) { - exists(StructLit sl | - sl.getType().hasQualifiedName(package("github.com/gorilla/sessions", ""), "Options") and - source.asExpr() = sl - ) - } - - override predicate isSink(DataFlow::Node sink) { sink instanceof GorillaSessionSaveSink } - - override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { - exists(GorillaSessionOptionsField f, DataFlow::Write w, DataFlow::Node base | - w.writesField(base, f, pred) and - succ = base - ) - } -} - private module GorillaSessionOptionsTrackingConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { exists(StructLit sl | @@ -366,37 +217,6 @@ private module GorillaSessionOptionsTrackingConfig implements DataFlow::ConfigSi module GorillaSessionOptionsTrackingFlow = TaintTracking::Global; -/** - * DEPRECATED: Use `BoolToGorillaSessionOptionsTrackingFlow` instead. - * - * A taint-tracking configuration for tracking flow from a `bool` assigned to - * `HttpOnly` to `gorilla/sessions.Session.Save`. - */ -deprecated class BoolToGorillaSessionOptionsTrackingConfiguration extends TaintTracking::Configuration -{ - BoolToGorillaSessionOptionsTrackingConfiguration() { - this = "BoolToGorillaSessionOptionsTrackingConfiguration" - } - - override predicate isSource(DataFlow::Node source) { - source.getType().getUnderlyingType() instanceof BoolType - } - - override predicate isSink(DataFlow::Node sink) { sink instanceof GorillaSessionSaveSink } - - override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { - exists(StructLit sl | - getValueForFieldWrite(sl, "HttpOnly") = pred and - sl = succ.asExpr() - ) - or - exists(GorillaSessionOptionsField f, DataFlow::Write w, DataFlow::Node base | - w.writesField(base, f, pred) and - succ = base - ) - } -} - private module BoolToGorillaSessionOptionsTrackingConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source.getType().getUnderlyingType() instanceof BoolType diff --git a/go/ql/src/experimental/CWE-327/WeakCryptoAlgorithmCustomizations.qll b/go/ql/src/experimental/CWE-327/WeakCryptoAlgorithmCustomizations.qll index 61a55bdd32b..1d64d731f50 100644 --- a/go/ql/src/experimental/CWE-327/WeakCryptoAlgorithmCustomizations.qll +++ b/go/ql/src/experimental/CWE-327/WeakCryptoAlgorithmCustomizations.qll @@ -48,24 +48,6 @@ module WeakCryptoAlgorithm { } } - /** - * DEPRECATED: Use `Flow` instead. - * - * A configuration depicting taint flow from sensitive information to weak cryptographic algorithms. - */ - deprecated class Configuration extends TaintTracking::Configuration { - Configuration() { this = "WeakCryptoAlgorithm" } - - override predicate isSource(DataFlow::Node source) { source instanceof Source } - - override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } - - override predicate isSanitizer(DataFlow::Node node) { - super.isSanitizer(node) or - node instanceof Sanitizer - } - } - private module Config implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof Source } diff --git a/go/ql/src/experimental/CWE-74/DsnInjectionCustomizations.qll b/go/ql/src/experimental/CWE-74/DsnInjectionCustomizations.qll index 5417ddf4f3e..2c320855072 100644 --- a/go/ql/src/experimental/CWE-74/DsnInjectionCustomizations.qll +++ b/go/ql/src/experimental/CWE-74/DsnInjectionCustomizations.qll @@ -6,28 +6,6 @@ import semmle.go.dataflow.barrierguardutil.RegexpCheck /** A source for `DsnInjection` taint-flow configuration. */ abstract class Source extends DataFlow::Node { } -/** - * DEPRECATED: Use `DsnInjectionFlow` instead. - * - * A taint-tracking configuration to reason about Data Source Name injection vulnerabilities. - */ -deprecated class DsnInjection extends TaintTracking::Configuration { - DsnInjection() { this = "DsnInjection" } - - override predicate isSource(DataFlow::Node node) { node instanceof Source } - - override predicate isSink(DataFlow::Node node) { - exists(DataFlow::CallNode c | - c.getTarget().hasQualifiedName("database/sql", "Open") and - c.getArgument(0).getStringValue() = "mysql" - | - node = c.getArgument(1) - ) - } - - override predicate isSanitizer(DataFlow::Node node) { node instanceof RegexpCheckBarrier } -} - private module DsnInjectionConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof Source } diff --git a/go/ql/src/experimental/CWE-807/SensitiveConditionBypass.qll b/go/ql/src/experimental/CWE-807/SensitiveConditionBypass.qll index 0d4bdfb1dd0..2f2ca94fa87 100644 --- a/go/ql/src/experimental/CWE-807/SensitiveConditionBypass.qll +++ b/go/ql/src/experimental/CWE-807/SensitiveConditionBypass.qll @@ -42,33 +42,6 @@ private class ConstComparisonExpr extends ComparisonExpr { } } -/** - * DEPRECATED: Use `Flow` instead. - * - * A data-flow configuration for reasoning about - * user-controlled bypassing of sensitive actions. - */ -deprecated class Configuration extends TaintTracking::Configuration { - Configuration() { this = "Condtional Expression Check Bypass" } - - override predicate isSource(DataFlow::Node source) { - source instanceof ActiveThreatModelSource - or - exists(DataFlow::FieldReadNode f | - f.getField().hasQualifiedName("net/http", "Request", "Host") - | - source = f - ) - } - - override predicate isSink(DataFlow::Node sink) { - exists(ConstComparisonExpr c | - c.getAnOperand() = sink.asExpr() and - not c.isPotentialFalsePositive() - ) - } -} - private module Config implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof ActiveThreatModelSource diff --git a/go/ql/src/experimental/CWE-918/SSRF.qll b/go/ql/src/experimental/CWE-918/SSRF.qll index 42b017ac487..b1374da8a5f 100644 --- a/go/ql/src/experimental/CWE-918/SSRF.qll +++ b/go/ql/src/experimental/CWE-918/SSRF.qll @@ -15,36 +15,6 @@ module ServerSideRequestForgery { private import semmle.go.dataflow.barrierguardutil.RegexpCheck private import semmle.go.dataflow.Properties - /** - * DEPRECATED: Use `Flow` instead. - * - * A taint-tracking configuration for reasoning about request forgery. - */ - deprecated class Configuration extends TaintTracking::Configuration { - Configuration() { this = "SSRF" } - - override predicate isSource(DataFlow::Node source) { source instanceof Source } - - override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } - - override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { - // propagate to a URL when its host is assigned to - exists(Write w, Field f, SsaWithFields v | f.hasQualifiedName("net/url", "URL", "Host") | - w.writesField(v.getAUse(), f, pred) and succ = v.getAUse() - ) - } - - override predicate isSanitizer(DataFlow::Node node) { - super.isSanitizer(node) or - node instanceof Sanitizer - } - - override predicate isSanitizerOut(DataFlow::Node node) { - super.isSanitizerOut(node) or - node instanceof SanitizerEdge - } - } - private module Config implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof Source } diff --git a/go/ql/test/experimental/CWE-522-DecompressionBombs/DecompressionBombTest.expected b/go/ql/test/experimental/CWE-522-DecompressionBombs/DecompressionBombTest.expected index 105b7026d0c..42831abaf15 100644 --- a/go/ql/test/experimental/CWE-522-DecompressionBombs/DecompressionBombTest.expected +++ b/go/ql/test/experimental/CWE-522-DecompressionBombs/DecompressionBombTest.expected @@ -1,3 +1,2 @@ -failures invalidModelRow testFailures diff --git a/go/ql/test/experimental/frameworks/CleverGo/HeaderWrite.expected b/go/ql/test/experimental/frameworks/CleverGo/HeaderWrite.expected index 48de9172b36..e69de29bb2d 100644 --- a/go/ql/test/experimental/frameworks/CleverGo/HeaderWrite.expected +++ b/go/ql/test/experimental/frameworks/CleverGo/HeaderWrite.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/go/ql/test/experimental/frameworks/CleverGo/HttpRedirect.expected b/go/ql/test/experimental/frameworks/CleverGo/HttpRedirect.expected index 48de9172b36..e69de29bb2d 100644 --- a/go/ql/test/experimental/frameworks/CleverGo/HttpRedirect.expected +++ b/go/ql/test/experimental/frameworks/CleverGo/HttpRedirect.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/go/ql/test/experimental/frameworks/CleverGo/HttpResponseBody.expected b/go/ql/test/experimental/frameworks/CleverGo/HttpResponseBody.expected index 48de9172b36..e69de29bb2d 100644 --- a/go/ql/test/experimental/frameworks/CleverGo/HttpResponseBody.expected +++ b/go/ql/test/experimental/frameworks/CleverGo/HttpResponseBody.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/go/ql/test/experimental/frameworks/CleverGo/RemoteSources.expected b/go/ql/test/experimental/frameworks/CleverGo/RemoteSources.expected index 48de9172b36..e69de29bb2d 100644 --- a/go/ql/test/experimental/frameworks/CleverGo/RemoteSources.expected +++ b/go/ql/test/experimental/frameworks/CleverGo/RemoteSources.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/go/ql/test/experimental/frameworks/Fiber/HeaderWrite.expected b/go/ql/test/experimental/frameworks/Fiber/HeaderWrite.expected index 48de9172b36..e69de29bb2d 100644 --- a/go/ql/test/experimental/frameworks/Fiber/HeaderWrite.expected +++ b/go/ql/test/experimental/frameworks/Fiber/HeaderWrite.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/go/ql/test/experimental/frameworks/Fiber/Redirect.expected b/go/ql/test/experimental/frameworks/Fiber/Redirect.expected index 48de9172b36..e69de29bb2d 100644 --- a/go/ql/test/experimental/frameworks/Fiber/Redirect.expected +++ b/go/ql/test/experimental/frameworks/Fiber/Redirect.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/go/ql/test/experimental/frameworks/Fiber/RemoteFlowSources.expected b/go/ql/test/experimental/frameworks/Fiber/RemoteFlowSources.expected index 48de9172b36..e69de29bb2d 100644 --- a/go/ql/test/experimental/frameworks/Fiber/RemoteFlowSources.expected +++ b/go/ql/test/experimental/frameworks/Fiber/RemoteFlowSources.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/go/ql/test/experimental/frameworks/Fiber/ResponseBody.expected b/go/ql/test/experimental/frameworks/Fiber/ResponseBody.expected index 48de9172b36..e69de29bb2d 100644 --- a/go/ql/test/experimental/frameworks/Fiber/ResponseBody.expected +++ b/go/ql/test/experimental/frameworks/Fiber/ResponseBody.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/go/ql/test/library-tests/semmle/go/Function/isVariadic.expected b/go/ql/test/library-tests/semmle/go/Function/isVariadic.expected index 48de9172b36..e69de29bb2d 100644 --- a/go/ql/test/library-tests/semmle/go/Function/isVariadic.expected +++ b/go/ql/test/library-tests/semmle/go/Function/isVariadic.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/go/ql/test/library-tests/semmle/go/Types/Field_getPackage.expected b/go/ql/test/library-tests/semmle/go/Types/Field_getPackage.expected index 485a42b185e..8a527e3d4f7 100644 --- a/go/ql/test/library-tests/semmle/go/Types/Field_getPackage.expected +++ b/go/ql/test/library-tests/semmle/go/Types/Field_getPackage.expected @@ -13,8 +13,8 @@ | depth.go:19:2:19:2 | f | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | | embedded.go:4:2:4:2 | A | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | | embedded.go:8:3:8:5 | Baz | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | -| embedded.go:13:2:13:4 | Qux | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | -| embedded.go:14:2:14:4 | Baz | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | +| embedded.go:12:2:12:4 | Qux | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | +| embedded.go:13:2:13:4 | Baz | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | | generic.go:4:2:4:11 | valueField | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | | generic.go:5:2:5:13 | pointerField | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | | generic.go:6:2:6:11 | arrayField | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | @@ -26,6 +26,7 @@ | generic.go:21:2:21:9 | mapField | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | | generic.go:25:2:25:12 | structField | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | | generic.go:29:2:29:13 | pointerField | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | +| main.go:18:7:18:15 | NameClash | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | | pkg1/embedding.go:19:23:19:26 | base | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | | pkg1/embedding.go:22:27:22:30 | base | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | | pkg1/embedding.go:25:24:25:31 | embedder | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | @@ -36,20 +37,22 @@ | pkg1/promotedStructs.go:14:2:14:7 | PField | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | | pkg1/promotedStructs.go:22:22:22:22 | S | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | | pkg1/promotedStructs.go:25:22:25:22 | P | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | -| pkg1/tst.go:4:2:4:2 | f | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | -| pkg1/tst.go:5:2:5:4 | Foo | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | -| pkg1/tst.go:6:2:6:4 | Bar | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | -| pkg1/tst.go:10:2:10:4 | Foo | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | -| pkg1/tst.go:11:2:11:4 | Bar | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | -| pkg1/tst.go:15:3:15:5 | Foo | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | -| pkg1/tst.go:16:3:16:5 | Bar | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | -| pkg1/tst.go:20:3:20:5 | Foo | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | -| pkg1/tst.go:21:2:21:4 | Bar | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | -| pkg1/tst.go:25:2:25:4 | val | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | -| pkg1/tst.go:26:2:26:5 | flag | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | -| pkg1/tst.go:30:2:30:5 | flag | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | +| pkg1/tst.go:6:2:6:2 | f | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | +| pkg1/tst.go:7:2:7:4 | Foo | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | +| pkg1/tst.go:8:2:8:4 | Bar | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | +| pkg1/tst.go:12:2:12:4 | Foo | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | +| pkg1/tst.go:13:2:13:4 | Bar | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | +| pkg1/tst.go:17:3:17:5 | Foo | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | +| pkg1/tst.go:18:3:18:5 | Bar | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | +| pkg1/tst.go:22:3:22:5 | Foo | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | +| pkg1/tst.go:23:2:23:4 | Bar | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | +| pkg1/tst.go:27:2:27:4 | val | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | +| pkg1/tst.go:28:2:28:5 | flag | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | +| pkg1/tst.go:32:2:32:5 | flag | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | +| pkg1/tst.go:62:7:62:15 | NameClash | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | | pkg2/tst.go:4:2:4:2 | g | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg2 | | pkg2/tst.go:8:2:8:2 | g | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg2 | +| pkg2/tst.go:17:2:17:8 | NCField | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg2 | | struct_tags.go:4:2:4:7 | field1 | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | | struct_tags.go:5:2:5:7 | field2 | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | | struct_tags.go:9:2:9:7 | field1 | package github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | diff --git a/go/ql/test/library-tests/semmle/go/Types/Field_hasQualifiedName2.expected b/go/ql/test/library-tests/semmle/go/Types/Field_hasQualifiedName2.expected index c8575332f6f..e7ffe6bc1ba 100644 --- a/go/ql/test/library-tests/semmle/go/Types/Field_hasQualifiedName2.expected +++ b/go/ql/test/library-tests/semmle/go/Types/Field_hasQualifiedName2.expected @@ -18,10 +18,11 @@ | depth.go:19:2:19:2 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.c | f | | depth.go:19:2:19:2 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.d | f | | embedded.go:4:2:4:2 | A | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.Baz | A | +| embedded.go:4:2:4:2 | A | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.EmbedsBaz | A | | embedded.go:4:2:4:2 | A | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.Qux | A | | embedded.go:8:3:8:5 | Baz | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.Qux | Baz | -| embedded.go:13:2:13:4 | Qux | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.EmbedsBaz | Qux | -| embedded.go:14:2:14:4 | Baz | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.EmbedsBaz | Baz | +| embedded.go:12:2:12:4 | Qux | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.EmbedsBaz | Qux | +| embedded.go:13:2:13:4 | Baz | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.EmbedsBaz | Baz | | generic.go:4:2:4:11 | valueField | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.GenericStruct1 | valueField | | generic.go:5:2:5:13 | pointerField | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.GenericStruct1 | pointerField | | generic.go:6:2:6:11 | arrayField | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.GenericStruct1 | arrayField | @@ -33,6 +34,7 @@ | generic.go:21:2:21:9 | mapField | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.GenericStruct2 | mapField | | generic.go:25:2:25:12 | structField | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.GenericStruct2b | structField | | generic.go:29:2:29:13 | pointerField | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.CircularGenericStruct2 | pointerField | +| main.go:18:7:18:15 | NameClash | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.EmbedsNameClash | NameClash | | pkg1/embedding.go:19:23:19:26 | base | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.embedder | base | | pkg1/embedding.go:19:23:19:26 | base | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.embedder2 | base | | pkg1/embedding.go:19:23:19:26 | base | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.embedder3 | base | @@ -49,27 +51,31 @@ | pkg1/promotedStructs.go:14:2:14:7 | PField | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.SEmbedP | PField | | pkg1/promotedStructs.go:22:22:22:22 | S | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.SEmbedS | S | | pkg1/promotedStructs.go:25:22:25:22 | P | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.SEmbedP | P | -| pkg1/tst.go:4:2:4:2 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T | f | -| pkg1/tst.go:5:2:5:4 | Foo | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T | Foo | -| pkg1/tst.go:6:2:6:4 | Bar | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T | Bar | -| pkg1/tst.go:10:2:10:4 | Foo | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T2 | Foo | -| pkg1/tst.go:11:2:11:4 | Bar | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T2 | Bar | -| pkg1/tst.go:15:3:15:5 | Foo | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T3 | Foo | -| pkg1/tst.go:16:3:16:5 | Bar | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T3 | Bar | -| pkg1/tst.go:20:3:20:5 | Foo | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T4 | Foo | -| pkg1/tst.go:21:2:21:4 | Bar | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T4 | Bar | -| pkg1/tst.go:25:2:25:4 | val | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.Foo | val | -| pkg1/tst.go:25:2:25:4 | val | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T | val | -| pkg1/tst.go:25:2:25:4 | val | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T3 | val | -| pkg1/tst.go:25:2:25:4 | val | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T4 | val | -| pkg1/tst.go:26:2:26:5 | flag | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.Foo | flag | -| pkg1/tst.go:26:2:26:5 | flag | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T4 | flag | -| pkg1/tst.go:30:2:30:5 | flag | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.Bar | flag | -| pkg1/tst.go:30:2:30:5 | flag | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T2 | flag | +| pkg1/tst.go:6:2:6:2 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T | f | +| pkg1/tst.go:7:2:7:4 | Foo | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T | Foo | +| pkg1/tst.go:8:2:8:4 | Bar | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T | Bar | +| pkg1/tst.go:12:2:12:4 | Foo | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T2 | Foo | +| pkg1/tst.go:13:2:13:4 | Bar | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T2 | Bar | +| pkg1/tst.go:17:3:17:5 | Foo | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T3 | Foo | +| pkg1/tst.go:18:3:18:5 | Bar | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T3 | Bar | +| pkg1/tst.go:22:3:22:5 | Foo | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T4 | Foo | +| pkg1/tst.go:23:2:23:4 | Bar | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T4 | Bar | +| pkg1/tst.go:27:2:27:4 | val | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.Foo | val | +| pkg1/tst.go:27:2:27:4 | val | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T | val | +| pkg1/tst.go:27:2:27:4 | val | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T3 | val | +| pkg1/tst.go:27:2:27:4 | val | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T4 | val | +| pkg1/tst.go:28:2:28:5 | flag | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.Foo | flag | +| pkg1/tst.go:28:2:28:5 | flag | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T4 | flag | +| pkg1/tst.go:32:2:32:5 | flag | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.Bar | flag | +| pkg1/tst.go:32:2:32:5 | flag | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T2 | flag | +| pkg1/tst.go:62:7:62:15 | NameClash | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.NameClash | NameClash | | pkg2/tst.go:4:2:4:2 | g | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg2.G | g | | pkg2/tst.go:4:2:4:2 | g | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg2.T | g | | pkg2/tst.go:8:2:8:2 | g | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg2.G | g | | pkg2/tst.go:8:2:8:2 | g | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg2.T | g | +| pkg2/tst.go:17:2:17:8 | NCField | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.EmbedsNameClash | NCField | +| pkg2/tst.go:17:2:17:8 | NCField | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.NameClash | NCField | +| pkg2/tst.go:17:2:17:8 | NCField | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg2.NameClash | NCField | | struct_tags.go:4:2:4:7 | field1 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.S1 | field1 | | struct_tags.go:5:2:5:7 | field2 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.S1 | field2 | | struct_tags.go:9:2:9:7 | field1 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.S2 | field1 | diff --git a/go/ql/test/library-tests/semmle/go/Types/Field_hasQualifiedName3.expected b/go/ql/test/library-tests/semmle/go/Types/Field_hasQualifiedName3.expected index 56176082d9a..03b93b37c74 100644 --- a/go/ql/test/library-tests/semmle/go/Types/Field_hasQualifiedName3.expected +++ b/go/ql/test/library-tests/semmle/go/Types/Field_hasQualifiedName3.expected @@ -18,10 +18,11 @@ | depth.go:19:2:19:2 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | c | f | | depth.go:19:2:19:2 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | d | f | | embedded.go:4:2:4:2 | A | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | Baz | A | +| embedded.go:4:2:4:2 | A | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | EmbedsBaz | A | | embedded.go:4:2:4:2 | A | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | Qux | A | | embedded.go:8:3:8:5 | Baz | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | Qux | Baz | -| embedded.go:13:2:13:4 | Qux | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | EmbedsBaz | Qux | -| embedded.go:14:2:14:4 | Baz | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | EmbedsBaz | Baz | +| embedded.go:12:2:12:4 | Qux | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | EmbedsBaz | Qux | +| embedded.go:13:2:13:4 | Baz | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | EmbedsBaz | Baz | | generic.go:4:2:4:11 | valueField | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | GenericStruct1 | valueField | | generic.go:5:2:5:13 | pointerField | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | GenericStruct1 | pointerField | | generic.go:6:2:6:11 | arrayField | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | GenericStruct1 | arrayField | @@ -33,6 +34,7 @@ | generic.go:21:2:21:9 | mapField | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | GenericStruct2 | mapField | | generic.go:25:2:25:12 | structField | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | GenericStruct2b | structField | | generic.go:29:2:29:13 | pointerField | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | CircularGenericStruct2 | pointerField | +| main.go:18:7:18:15 | NameClash | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | EmbedsNameClash | NameClash | | pkg1/embedding.go:19:23:19:26 | base | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder | base | | pkg1/embedding.go:19:23:19:26 | base | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder2 | base | | pkg1/embedding.go:19:23:19:26 | base | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | embedder3 | base | @@ -49,27 +51,31 @@ | pkg1/promotedStructs.go:14:2:14:7 | PField | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | SEmbedP | PField | | pkg1/promotedStructs.go:22:22:22:22 | S | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | SEmbedS | S | | pkg1/promotedStructs.go:25:22:25:22 | P | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | SEmbedP | P | -| pkg1/tst.go:4:2:4:2 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T | f | -| pkg1/tst.go:5:2:5:4 | Foo | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T | Foo | -| pkg1/tst.go:6:2:6:4 | Bar | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T | Bar | -| pkg1/tst.go:10:2:10:4 | Foo | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T2 | Foo | -| pkg1/tst.go:11:2:11:4 | Bar | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T2 | Bar | -| pkg1/tst.go:15:3:15:5 | Foo | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T3 | Foo | -| pkg1/tst.go:16:3:16:5 | Bar | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T3 | Bar | -| pkg1/tst.go:20:3:20:5 | Foo | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T4 | Foo | -| pkg1/tst.go:21:2:21:4 | Bar | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T4 | Bar | -| pkg1/tst.go:25:2:25:4 | val | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | Foo | val | -| pkg1/tst.go:25:2:25:4 | val | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T | val | -| pkg1/tst.go:25:2:25:4 | val | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T3 | val | -| pkg1/tst.go:25:2:25:4 | val | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T4 | val | -| pkg1/tst.go:26:2:26:5 | flag | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | Foo | flag | -| pkg1/tst.go:26:2:26:5 | flag | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T4 | flag | -| pkg1/tst.go:30:2:30:5 | flag | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | Bar | flag | -| pkg1/tst.go:30:2:30:5 | flag | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T2 | flag | +| pkg1/tst.go:6:2:6:2 | f | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T | f | +| pkg1/tst.go:7:2:7:4 | Foo | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T | Foo | +| pkg1/tst.go:8:2:8:4 | Bar | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T | Bar | +| pkg1/tst.go:12:2:12:4 | Foo | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T2 | Foo | +| pkg1/tst.go:13:2:13:4 | Bar | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T2 | Bar | +| pkg1/tst.go:17:3:17:5 | Foo | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T3 | Foo | +| pkg1/tst.go:18:3:18:5 | Bar | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T3 | Bar | +| pkg1/tst.go:22:3:22:5 | Foo | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T4 | Foo | +| pkg1/tst.go:23:2:23:4 | Bar | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T4 | Bar | +| pkg1/tst.go:27:2:27:4 | val | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | Foo | val | +| pkg1/tst.go:27:2:27:4 | val | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T | val | +| pkg1/tst.go:27:2:27:4 | val | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T3 | val | +| pkg1/tst.go:27:2:27:4 | val | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T4 | val | +| pkg1/tst.go:28:2:28:5 | flag | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | Foo | flag | +| pkg1/tst.go:28:2:28:5 | flag | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T4 | flag | +| pkg1/tst.go:32:2:32:5 | flag | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | Bar | flag | +| pkg1/tst.go:32:2:32:5 | flag | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T2 | flag | +| pkg1/tst.go:62:7:62:15 | NameClash | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | NameClash | NameClash | | pkg2/tst.go:4:2:4:2 | g | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg2 | G | g | | pkg2/tst.go:4:2:4:2 | g | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg2 | T | g | | pkg2/tst.go:8:2:8:2 | g | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg2 | G | g | | pkg2/tst.go:8:2:8:2 | g | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg2 | T | g | +| pkg2/tst.go:17:2:17:8 | NCField | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | EmbedsNameClash | NCField | +| pkg2/tst.go:17:2:17:8 | NCField | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | NameClash | NCField | +| pkg2/tst.go:17:2:17:8 | NCField | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg2 | NameClash | NCField | | struct_tags.go:4:2:4:7 | field1 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | S1 | field1 | | struct_tags.go:5:2:5:7 | field2 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | S1 | field2 | | struct_tags.go:9:2:9:7 | field1 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | S2 | field1 | diff --git a/go/ql/test/library-tests/semmle/go/Types/ImplementsComparable.expected b/go/ql/test/library-tests/semmle/go/Types/ImplementsComparable.expected index 48de9172b36..e69de29bb2d 100644 --- a/go/ql/test/library-tests/semmle/go/Types/ImplementsComparable.expected +++ b/go/ql/test/library-tests/semmle/go/Types/ImplementsComparable.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/go/ql/test/library-tests/semmle/go/Types/MethodCount.expected b/go/ql/test/library-tests/semmle/go/Types/MethodCount.expected index 9d576b0f4f6..351b29c6222 100644 --- a/go/ql/test/library-tests/semmle/go/Types/MethodCount.expected +++ b/go/ql/test/library-tests/semmle/go/Types/MethodCount.expected @@ -1,4 +1,6 @@ +| * EmbedsNameClash | 1 | | * Foo | 1 | +| * NameClash | 1 | | * P | 1 | | * S | 1 | | * SEmbedP | 1 | @@ -19,10 +21,12 @@ | AExtended | 2 | | B | 2 | | C | 2 | +| EmbedsNameClash | 1 | | Foo | 1 | | GenericInterface | 1 | | MixedExportedAndNot | 2 | | MyInterface | 17 | +| NameClash | 1 | | S | 1 | | SEmbedS | 1 | | T | 1 | diff --git a/go/ql/test/library-tests/semmle/go/Types/MethodTypes.expected b/go/ql/test/library-tests/semmle/go/Types/MethodTypes.expected index 326debd2f80..d143fb3121e 100644 --- a/go/ql/test/library-tests/semmle/go/Types/MethodTypes.expected +++ b/go/ql/test/library-tests/semmle/go/Types/MethodTypes.expected @@ -30,6 +30,7 @@ | interface.go:95:6:95:8 | i18 | StringA | func() string | | interface.go:101:6:101:8 | i19 | StringB | func() string | | interface.go:105:6:105:8 | i20 | StringB | func() string | +| main.go:17:6:17:20 | EmbedsNameClash | NCMethod | func() | | pkg1/embedding.go:19:6:19:13 | embedder | f | func() int | | pkg1/embedding.go:22:6:22:16 | ptrembedder | f | func() int | | pkg1/embedding.go:22:6:22:16 | ptrembedder | g | func() int | @@ -51,8 +52,9 @@ | pkg1/interfaces.go:35:6:35:24 | MixedExportedAndNot | Exported | func() | | pkg1/interfaces.go:35:6:35:24 | MixedExportedAndNot | notExported | func() | | pkg1/promotedStructs.go:22:6:22:12 | SEmbedS | SMethod | func() interface { } | -| pkg1/tst.go:3:6:3:6 | T | half | func() Foo | -| pkg1/tst.go:14:6:14:7 | T3 | half | func() Foo | -| pkg1/tst.go:19:6:19:7 | T4 | half | func() Foo | +| pkg1/tst.go:5:6:5:6 | T | half | func() Foo | +| pkg1/tst.go:16:6:16:7 | T3 | half | func() Foo | +| pkg1/tst.go:21:6:21:7 | T4 | half | func() Foo | +| pkg1/tst.go:61:6:61:14 | NameClash | NCMethod | func() | | pkg2/tst.go:11:6:11:24 | MixedExportedAndNot | Exported | func() | | pkg2/tst.go:11:6:11:24 | MixedExportedAndNot | notExported | func() | diff --git a/go/ql/test/library-tests/semmle/go/Types/Method_hasQualifiedName2.expected b/go/ql/test/library-tests/semmle/go/Types/Method_hasQualifiedName2.expected index 1f893728e30..3929e1d98d5 100644 --- a/go/ql/test/library-tests/semmle/go/Types/Method_hasQualifiedName2.expected +++ b/go/ql/test/library-tests/semmle/go/Types/Method_hasQualifiedName2.expected @@ -59,9 +59,12 @@ | pkg1/promotedStructs.go:8:12:8:18 | SMethod | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.SEmbedS | SMethod | | pkg1/promotedStructs.go:17:13:17:19 | PMethod | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.P | PMethod | | pkg1/promotedStructs.go:17:13:17:19 | PMethod | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.SEmbedP | PMethod | -| pkg1/tst.go:33:16:33:19 | half | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.Foo | half | -| pkg1/tst.go:33:16:33:19 | half | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T | half | -| pkg1/tst.go:33:16:33:19 | half | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T3 | half | -| pkg1/tst.go:33:16:33:19 | half | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T4 | half | +| pkg1/tst.go:35:16:35:19 | half | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.Foo | half | +| pkg1/tst.go:35:16:35:19 | half | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T | half | +| pkg1/tst.go:35:16:35:19 | half | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T3 | half | +| pkg1/tst.go:35:16:35:19 | half | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T4 | half | | pkg2/tst.go:12:2:12:9 | Exported | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg2.MixedExportedAndNot | Exported | | pkg2/tst.go:13:2:13:12 | notExported | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg2.MixedExportedAndNot | notExported | +| pkg2/tst.go:20:20:20:27 | NCMethod | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.EmbedsNameClash | NCMethod | +| pkg2/tst.go:20:20:20:27 | NCMethod | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.NameClash | NCMethod | +| pkg2/tst.go:20:20:20:27 | NCMethod | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg2.NameClash | NCMethod | diff --git a/go/ql/test/library-tests/semmle/go/Types/Method_hasQualifiedName3.expected b/go/ql/test/library-tests/semmle/go/Types/Method_hasQualifiedName3.expected index 59a298e4b5f..9699ba3f382 100644 --- a/go/ql/test/library-tests/semmle/go/Types/Method_hasQualifiedName3.expected +++ b/go/ql/test/library-tests/semmle/go/Types/Method_hasQualifiedName3.expected @@ -59,9 +59,12 @@ | pkg1/promotedStructs.go:8:12:8:18 | SMethod | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | SEmbedS | SMethod | | pkg1/promotedStructs.go:17:13:17:19 | PMethod | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | P | PMethod | | pkg1/promotedStructs.go:17:13:17:19 | PMethod | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | SEmbedP | PMethod | -| pkg1/tst.go:33:16:33:19 | half | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | Foo | half | -| pkg1/tst.go:33:16:33:19 | half | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T | half | -| pkg1/tst.go:33:16:33:19 | half | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T3 | half | -| pkg1/tst.go:33:16:33:19 | half | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T4 | half | +| pkg1/tst.go:35:16:35:19 | half | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | Foo | half | +| pkg1/tst.go:35:16:35:19 | half | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T | half | +| pkg1/tst.go:35:16:35:19 | half | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T3 | half | +| pkg1/tst.go:35:16:35:19 | half | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | T4 | half | | pkg2/tst.go:12:2:12:9 | Exported | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg2 | MixedExportedAndNot | Exported | | pkg2/tst.go:13:2:13:12 | notExported | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg2 | MixedExportedAndNot | notExported | +| pkg2/tst.go:20:20:20:27 | NCMethod | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types | EmbedsNameClash | NCMethod | +| pkg2/tst.go:20:20:20:27 | NCMethod | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1 | NameClash | NCMethod | +| pkg2/tst.go:20:20:20:27 | NCMethod | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg2 | NameClash | NCMethod | diff --git a/go/ql/test/library-tests/semmle/go/Types/Methods.expected b/go/ql/test/library-tests/semmle/go/Types/Methods.expected index 2c17013c186..c75b336543a 100644 --- a/go/ql/test/library-tests/semmle/go/Types/Methods.expected +++ b/go/ql/test/library-tests/semmle/go/Types/Methods.expected @@ -1,11 +1,13 @@ -| * Foo | half | pkg1/tst.go:33:16:33:19 | half | +| * EmbedsNameClash | NCMethod | pkg2/tst.go:20:20:20:27 | NCMethod | +| * Foo | half | pkg1/tst.go:35:16:35:19 | half | +| * NameClash | NCMethod | pkg2/tst.go:20:20:20:27 | NCMethod | | * P | PMethod | pkg1/promotedStructs.go:17:13:17:19 | PMethod | | * S | SMethod | pkg1/promotedStructs.go:8:12:8:18 | SMethod | | * SEmbedP | PMethod | pkg1/promotedStructs.go:17:13:17:19 | PMethod | | * SEmbedS | SMethod | pkg1/promotedStructs.go:8:12:8:18 | SMethod | -| * T | half | pkg1/tst.go:33:16:33:19 | half | -| * T3 | half | pkg1/tst.go:33:16:33:19 | half | -| * T4 | half | pkg1/tst.go:33:16:33:19 | half | +| * T | half | pkg1/tst.go:35:16:35:19 | half | +| * T3 | half | pkg1/tst.go:35:16:35:19 | half | +| * T4 | half | pkg1/tst.go:35:16:35:19 | half | | * base | f | pkg1/embedding.go:10:13:10:13 | f | | * base | g | pkg1/embedding.go:14:14:14:14 | g | | * embedder | f | pkg1/embedding.go:10:13:10:13 | f | @@ -29,7 +31,8 @@ | B | n | pkg1/interfaces.go:9:2:9:2 | n | | C | n | pkg1/interfaces.go:13:2:13:2 | n | | C | o | pkg1/interfaces.go:14:2:14:2 | o | -| Foo | half | pkg1/tst.go:33:16:33:19 | half | +| EmbedsNameClash | NCMethod | pkg2/tst.go:20:20:20:27 | NCMethod | +| Foo | half | pkg1/tst.go:35:16:35:19 | half | | GenericInterface | GetT | generic.go:33:2:33:5 | GetT | | MixedExportedAndNot | Exported | pkg1/interfaces.go:36:2:36:9 | Exported | | MixedExportedAndNot | Exported | pkg2/tst.go:12:2:12:9 | Exported | @@ -52,11 +55,12 @@ | MyInterface | dummy18 | generic.go:62:2:62:8 | dummy18 | | MyInterface | dummy19 | generic.go:63:2:63:8 | dummy19 | | MyInterface | dummy20 | generic.go:64:2:64:8 | dummy20 | +| NameClash | NCMethod | pkg2/tst.go:20:20:20:27 | NCMethod | | S | SMethod | pkg1/promotedStructs.go:8:12:8:18 | SMethod | | SEmbedS | SMethod | pkg1/promotedStructs.go:8:12:8:18 | SMethod | -| T | half | pkg1/tst.go:33:16:33:19 | half | -| T3 | half | pkg1/tst.go:33:16:33:19 | half | -| T4 | half | pkg1/tst.go:33:16:33:19 | half | +| T | half | pkg1/tst.go:35:16:35:19 | half | +| T3 | half | pkg1/tst.go:35:16:35:19 | half | +| T4 | half | pkg1/tst.go:35:16:35:19 | half | | base | f | pkg1/embedding.go:10:13:10:13 | f | | embedder | f | pkg1/embedding.go:10:13:10:13 | f | | embedder2 | f | pkg1/embedding.go:10:13:10:13 | f | diff --git a/go/ql/test/library-tests/semmle/go/Types/QualifiedNames.expected b/go/ql/test/library-tests/semmle/go/Types/QualifiedNames.expected index 660209effbb..dd6e9021a4f 100644 --- a/go/ql/test/library-tests/semmle/go/Types/QualifiedNames.expected +++ b/go/ql/test/library-tests/semmle/go/Types/QualifiedNames.expected @@ -9,7 +9,7 @@ | depth.go:18:6:18:6 | d | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.d | | embedded.go:3:6:3:8 | Baz | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.Baz | | embedded.go:7:6:7:8 | Qux | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.Qux | -| embedded.go:12:6:12:14 | EmbedsBaz | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.EmbedsBaz | +| embedded.go:11:6:11:14 | EmbedsBaz | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.EmbedsBaz | | generic.go:3:6:3:19 | GenericStruct1 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.GenericStruct1 | | generic.go:11:6:11:27 | CircularGenericStruct1 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.CircularGenericStruct1 | | generic.go:15:6:15:31 | UsesCircularGenericStruct1 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.UsesCircularGenericStruct1 | @@ -77,6 +77,7 @@ | interface.go:136:6:136:21 | testComparable21 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable21 | | interface.go:137:6:137:21 | testComparable22 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable22 | | interface.go:138:6:138:21 | testComparable23 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.testComparable23 | +| main.go:17:6:17:20 | EmbedsNameClash | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.EmbedsNameClash | | pkg1/embedding.go:8:6:8:9 | base | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.base | | pkg1/embedding.go:19:6:19:13 | embedder | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.embedder | | pkg1/embedding.go:22:6:22:16 | ptrembedder | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.ptrembedder | @@ -95,14 +96,16 @@ | pkg1/promotedStructs.go:13:6:13:6 | P | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.P | | pkg1/promotedStructs.go:22:6:22:12 | SEmbedS | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.SEmbedS | | pkg1/promotedStructs.go:25:6:25:12 | SEmbedP | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.SEmbedP | -| pkg1/tst.go:3:6:3:6 | T | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T | -| pkg1/tst.go:9:6:9:7 | T2 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T2 | -| pkg1/tst.go:14:6:14:7 | T3 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T3 | -| pkg1/tst.go:19:6:19:7 | T4 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T4 | -| pkg1/tst.go:24:6:24:8 | Foo | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.Foo | -| pkg1/tst.go:29:6:29:8 | Bar | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.Bar | +| pkg1/tst.go:5:6:5:6 | T | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T | +| pkg1/tst.go:11:6:11:7 | T2 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T2 | +| pkg1/tst.go:16:6:16:7 | T3 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T3 | +| pkg1/tst.go:21:6:21:7 | T4 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.T4 | +| pkg1/tst.go:26:6:26:8 | Foo | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.Foo | +| pkg1/tst.go:31:6:31:8 | Bar | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.Bar | +| pkg1/tst.go:61:6:61:14 | NameClash | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1.NameClash | | pkg2/tst.go:3:6:3:6 | T | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg2.T | | pkg2/tst.go:7:6:7:6 | G | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg2.G | | pkg2/tst.go:11:6:11:24 | MixedExportedAndNot | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg2.MixedExportedAndNot | +| pkg2/tst.go:16:6:16:14 | NameClash | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg2.NameClash | | struct_tags.go:3:6:3:7 | S1 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.S1 | | struct_tags.go:8:6:8:7 | S2 | github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types.S2 | diff --git a/go/ql/test/library-tests/semmle/go/Types/SignatureType_getNumParameter.expected b/go/ql/test/library-tests/semmle/go/Types/SignatureType_getNumParameter.expected index faedd5aa0de..5831152884b 100644 --- a/go/ql/test/library-tests/semmle/go/Types/SignatureType_getNumParameter.expected +++ b/go/ql/test/library-tests/semmle/go/Types/SignatureType_getNumParameter.expected @@ -4,18 +4,19 @@ | depth.go:22:1:25:1 | function declaration | 0 | | generic.go:70:1:72:1 | function declaration | 1 | | generic.go:74:1:80:1 | function declaration | 1 | -| main.go:5:1:5:30 | function declaration | 1 | -| main.go:7:1:9:1 | function declaration | 2 | -| main.go:11:1:11:14 | function declaration | 0 | +| main.go:9:1:9:30 | function declaration | 1 | +| main.go:11:1:13:1 | function declaration | 2 | +| main.go:15:1:15:14 | function declaration | 0 | | pkg1/embedding.go:10:1:12:1 | function declaration | 0 | | pkg1/embedding.go:14:1:16:1 | function declaration | 0 | | pkg1/embedding.go:30:1:32:1 | function declaration | 0 | | pkg1/embedding.go:40:1:61:1 | function declaration | 0 | | pkg1/promotedStructs.go:8:1:10:1 | function declaration | 0 | | pkg1/promotedStructs.go:17:1:19:1 | function declaration | 0 | -| pkg1/tst.go:33:1:35:1 | function declaration | 0 | -| pkg1/tst.go:37:1:37:26 | function declaration | 1 | -| pkg1/tst.go:39:1:57:1 | function declaration | 2 | +| pkg1/tst.go:35:1:37:1 | function declaration | 0 | +| pkg1/tst.go:39:1:39:26 | function declaration | 1 | +| pkg1/tst.go:41:1:59:1 | function declaration | 2 | +| pkg2/tst.go:20:1:20:32 | function declaration | 0 | | promoted.go:7:1:10:1 | function declaration | 1 | | promoted.go:12:1:15:1 | function declaration | 1 | | promoted.go:17:1:20:1 | function declaration | 1 | diff --git a/go/ql/test/library-tests/semmle/go/Types/SignatureType_getNumResult.expected b/go/ql/test/library-tests/semmle/go/Types/SignatureType_getNumResult.expected index 513ad56bd3c..960a272f73c 100644 --- a/go/ql/test/library-tests/semmle/go/Types/SignatureType_getNumResult.expected +++ b/go/ql/test/library-tests/semmle/go/Types/SignatureType_getNumResult.expected @@ -4,18 +4,19 @@ | depth.go:22:1:25:1 | function declaration | 0 | | generic.go:70:1:72:1 | function declaration | 1 | | generic.go:74:1:80:1 | function declaration | 0 | -| main.go:5:1:5:30 | function declaration | 0 | -| main.go:7:1:9:1 | function declaration | 2 | -| main.go:11:1:11:14 | function declaration | 0 | +| main.go:9:1:9:30 | function declaration | 0 | +| main.go:11:1:13:1 | function declaration | 2 | +| main.go:15:1:15:14 | function declaration | 0 | | pkg1/embedding.go:10:1:12:1 | function declaration | 1 | | pkg1/embedding.go:14:1:16:1 | function declaration | 1 | | pkg1/embedding.go:30:1:32:1 | function declaration | 1 | | pkg1/embedding.go:40:1:61:1 | function declaration | 0 | | pkg1/promotedStructs.go:8:1:10:1 | function declaration | 1 | | pkg1/promotedStructs.go:17:1:19:1 | function declaration | 1 | -| pkg1/tst.go:33:1:35:1 | function declaration | 1 | -| pkg1/tst.go:37:1:37:26 | function declaration | 0 | -| pkg1/tst.go:39:1:57:1 | function declaration | 0 | +| pkg1/tst.go:35:1:37:1 | function declaration | 1 | +| pkg1/tst.go:39:1:39:26 | function declaration | 0 | +| pkg1/tst.go:41:1:59:1 | function declaration | 0 | +| pkg2/tst.go:20:1:20:32 | function declaration | 0 | | promoted.go:7:1:10:1 | function declaration | 0 | | promoted.go:12:1:15:1 | function declaration | 0 | | promoted.go:17:1:20:1 | function declaration | 0 | diff --git a/go/ql/test/library-tests/semmle/go/Types/SignatureType_isVariadic.expected b/go/ql/test/library-tests/semmle/go/Types/SignatureType_isVariadic.expected index 48de9172b36..e69de29bb2d 100644 --- a/go/ql/test/library-tests/semmle/go/Types/SignatureType_isVariadic.expected +++ b/go/ql/test/library-tests/semmle/go/Types/SignatureType_isVariadic.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/go/ql/test/library-tests/semmle/go/Types/StructFields.expected b/go/ql/test/library-tests/semmle/go/Types/StructFields.expected index 502b4fa07ad..1757e0cdaf9 100644 --- a/go/ql/test/library-tests/semmle/go/Types/StructFields.expected +++ b/go/ql/test/library-tests/semmle/go/Types/StructFields.expected @@ -20,8 +20,9 @@ | embedded.go:3:6:3:8 | Baz | embedded.go:3:10:5:1 | struct type | A | string | | embedded.go:7:6:7:8 | Qux | embedded.go:7:10:9:1 | struct type | A | string | | embedded.go:7:6:7:8 | Qux | embedded.go:7:10:9:1 | struct type | Baz | * Baz | -| embedded.go:12:6:12:14 | EmbedsBaz | embedded.go:12:16:15:1 | struct type | Baz | string | -| embedded.go:12:6:12:14 | EmbedsBaz | embedded.go:12:16:15:1 | struct type | Qux | Qux | +| embedded.go:11:6:11:14 | EmbedsBaz | embedded.go:11:16:14:1 | struct type | A | string | +| embedded.go:11:6:11:14 | EmbedsBaz | embedded.go:11:16:14:1 | struct type | Baz | string | +| embedded.go:11:6:11:14 | EmbedsBaz | embedded.go:11:16:14:1 | struct type | Qux | Qux | | generic.go:3:6:3:19 | GenericStruct1 | generic.go:3:28:9:1 | struct type | arrayField | [10]T | | generic.go:3:6:3:19 | GenericStruct1 | generic.go:3:28:9:1 | struct type | mapField | [string]T | | generic.go:3:6:3:19 | GenericStruct1 | generic.go:3:28:9:1 | struct type | pointerField | * T | @@ -33,6 +34,8 @@ | generic.go:19:6:19:19 | GenericStruct2 | generic.go:19:42:22:1 | struct type | structField | GenericStruct1 | | generic.go:24:6:24:20 | GenericStruct2b | generic.go:24:39:26:1 | struct type | structField | GenericStruct2 | | generic.go:28:6:28:27 | CircularGenericStruct2 | generic.go:28:39:30:1 | struct type | pointerField | * CircularGenericStruct2 | +| main.go:17:6:17:20 | EmbedsNameClash | main.go:17:22:19:1 | struct type | NCField | string | +| main.go:17:6:17:20 | EmbedsNameClash | main.go:17:22:19:1 | struct type | NameClash | NameClash | | pkg1/embedding.go:19:6:19:13 | embedder | pkg1/embedding.go:19:15:19:28 | struct type | base | base | | pkg1/embedding.go:22:6:22:16 | ptrembedder | pkg1/embedding.go:22:18:22:32 | struct type | base | * base | | pkg1/embedding.go:25:6:25:14 | embedder2 | pkg1/embedding.go:25:16:25:33 | struct type | base | base | @@ -51,27 +54,30 @@ | pkg1/promotedStructs.go:22:6:22:12 | SEmbedS | pkg1/promotedStructs.go:22:14:22:24 | struct type | SField | string | | pkg1/promotedStructs.go:25:6:25:12 | SEmbedP | pkg1/promotedStructs.go:25:14:25:24 | struct type | P | P | | pkg1/promotedStructs.go:25:6:25:12 | SEmbedP | pkg1/promotedStructs.go:25:14:25:24 | struct type | PField | string | -| pkg1/tst.go:3:6:3:6 | T | pkg1/tst.go:3:8:7:1 | struct type | Bar | Bar | -| pkg1/tst.go:3:6:3:6 | T | pkg1/tst.go:3:8:7:1 | struct type | Foo | Foo | -| pkg1/tst.go:3:6:3:6 | T | pkg1/tst.go:3:8:7:1 | struct type | f | int | -| pkg1/tst.go:3:6:3:6 | T | pkg1/tst.go:3:8:7:1 | struct type | val | int | -| pkg1/tst.go:9:6:9:7 | T2 | pkg1/tst.go:9:9:12:1 | struct type | Bar | Bar | -| pkg1/tst.go:9:6:9:7 | T2 | pkg1/tst.go:9:9:12:1 | struct type | Foo | Foo | -| pkg1/tst.go:9:6:9:7 | T2 | pkg1/tst.go:9:9:12:1 | struct type | flag | bool | -| pkg1/tst.go:14:6:14:7 | T3 | pkg1/tst.go:14:9:17:1 | struct type | Bar | * Bar | -| pkg1/tst.go:14:6:14:7 | T3 | pkg1/tst.go:14:9:17:1 | struct type | Foo | * Foo | -| pkg1/tst.go:14:6:14:7 | T3 | pkg1/tst.go:14:9:17:1 | struct type | val | int | -| pkg1/tst.go:19:6:19:7 | T4 | pkg1/tst.go:19:9:22:1 | struct type | Bar | Bar | -| pkg1/tst.go:19:6:19:7 | T4 | pkg1/tst.go:19:9:22:1 | struct type | Foo | * Foo | -| pkg1/tst.go:19:6:19:7 | T4 | pkg1/tst.go:19:9:22:1 | struct type | flag | bool | -| pkg1/tst.go:19:6:19:7 | T4 | pkg1/tst.go:19:9:22:1 | struct type | val | int | -| pkg1/tst.go:24:6:24:8 | Foo | pkg1/tst.go:24:10:27:1 | struct type | flag | bool | -| pkg1/tst.go:24:6:24:8 | Foo | pkg1/tst.go:24:10:27:1 | struct type | val | int | -| pkg1/tst.go:29:6:29:8 | Bar | pkg1/tst.go:29:10:31:1 | struct type | flag | bool | +| pkg1/tst.go:5:6:5:6 | T | pkg1/tst.go:5:8:9:1 | struct type | Bar | Bar | +| pkg1/tst.go:5:6:5:6 | T | pkg1/tst.go:5:8:9:1 | struct type | Foo | Foo | +| pkg1/tst.go:5:6:5:6 | T | pkg1/tst.go:5:8:9:1 | struct type | f | int | +| pkg1/tst.go:5:6:5:6 | T | pkg1/tst.go:5:8:9:1 | struct type | val | int | +| pkg1/tst.go:11:6:11:7 | T2 | pkg1/tst.go:11:9:14:1 | struct type | Bar | Bar | +| pkg1/tst.go:11:6:11:7 | T2 | pkg1/tst.go:11:9:14:1 | struct type | Foo | Foo | +| pkg1/tst.go:11:6:11:7 | T2 | pkg1/tst.go:11:9:14:1 | struct type | flag | bool | +| pkg1/tst.go:16:6:16:7 | T3 | pkg1/tst.go:16:9:19:1 | struct type | Bar | * Bar | +| pkg1/tst.go:16:6:16:7 | T3 | pkg1/tst.go:16:9:19:1 | struct type | Foo | * Foo | +| pkg1/tst.go:16:6:16:7 | T3 | pkg1/tst.go:16:9:19:1 | struct type | val | int | +| pkg1/tst.go:21:6:21:7 | T4 | pkg1/tst.go:21:9:24:1 | struct type | Bar | Bar | +| pkg1/tst.go:21:6:21:7 | T4 | pkg1/tst.go:21:9:24:1 | struct type | Foo | * Foo | +| pkg1/tst.go:21:6:21:7 | T4 | pkg1/tst.go:21:9:24:1 | struct type | flag | bool | +| pkg1/tst.go:21:6:21:7 | T4 | pkg1/tst.go:21:9:24:1 | struct type | val | int | +| pkg1/tst.go:26:6:26:8 | Foo | pkg1/tst.go:26:10:29:1 | struct type | flag | bool | +| pkg1/tst.go:26:6:26:8 | Foo | pkg1/tst.go:26:10:29:1 | struct type | val | int | +| pkg1/tst.go:31:6:31:8 | Bar | pkg1/tst.go:31:10:33:1 | struct type | flag | bool | +| pkg1/tst.go:61:6:61:14 | NameClash | pkg1/tst.go:61:16:63:1 | struct type | NCField | string | +| pkg1/tst.go:61:6:61:14 | NameClash | pkg1/tst.go:61:16:63:1 | struct type | NameClash | NameClash | | pkg2/tst.go:3:6:3:6 | T | pkg2/tst.go:3:8:5:1 | struct type | g | int | | pkg2/tst.go:3:6:3:6 | T | pkg2/tst.go:7:8:9:1 | struct type | g | int | | pkg2/tst.go:7:6:7:6 | G | pkg2/tst.go:3:8:5:1 | struct type | g | int | | pkg2/tst.go:7:6:7:6 | G | pkg2/tst.go:7:8:9:1 | struct type | g | int | +| pkg2/tst.go:16:6:16:14 | NameClash | pkg2/tst.go:16:16:18:1 | struct type | NCField | string | | struct_tags.go:3:6:3:7 | S1 | struct_tags.go:3:9:6:1 | struct type | field1 | int | | struct_tags.go:3:6:3:7 | S1 | struct_tags.go:3:9:6:1 | struct type | field2 | int | | struct_tags.go:8:6:8:7 | S2 | struct_tags.go:8:9:11:1 | struct type | field1 | int | diff --git a/go/ql/test/library-tests/semmle/go/Types/Types.expected b/go/ql/test/library-tests/semmle/go/Types/Types.expected index 9c04442d7aa..ab34dd4d8ee 100644 --- a/go/ql/test/library-tests/semmle/go/Types/Types.expected +++ b/go/ql/test/library-tests/semmle/go/Types/Types.expected @@ -9,7 +9,7 @@ | depth.go:18:6:18:6 | d | d | | embedded.go:3:6:3:8 | Baz | Baz | | embedded.go:7:6:7:8 | Qux | Qux | -| embedded.go:12:6:12:14 | EmbedsBaz | EmbedsBaz | +| embedded.go:11:6:11:14 | EmbedsBaz | EmbedsBaz | | generic.go:3:6:3:19 | GenericStruct1 | GenericStruct1 | | generic.go:11:6:11:27 | CircularGenericStruct1 | CircularGenericStruct1 | | generic.go:15:6:15:31 | UsesCircularGenericStruct1 | UsesCircularGenericStruct1 | @@ -77,6 +77,7 @@ | interface.go:136:6:136:21 | testComparable21 | testComparable21 | | interface.go:137:6:137:21 | testComparable22 | testComparable22 | | interface.go:138:6:138:21 | testComparable23 | testComparable23 | +| main.go:17:6:17:20 | EmbedsNameClash | EmbedsNameClash | | pkg1/embedding.go:8:6:8:9 | base | base | | pkg1/embedding.go:19:6:19:13 | embedder | embedder | | pkg1/embedding.go:22:6:22:16 | ptrembedder | ptrembedder | @@ -95,14 +96,16 @@ | pkg1/promotedStructs.go:13:6:13:6 | P | P | | pkg1/promotedStructs.go:22:6:22:12 | SEmbedS | SEmbedS | | pkg1/promotedStructs.go:25:6:25:12 | SEmbedP | SEmbedP | -| pkg1/tst.go:3:6:3:6 | T | T | -| pkg1/tst.go:9:6:9:7 | T2 | T2 | -| pkg1/tst.go:14:6:14:7 | T3 | T3 | -| pkg1/tst.go:19:6:19:7 | T4 | T4 | -| pkg1/tst.go:24:6:24:8 | Foo | Foo | -| pkg1/tst.go:29:6:29:8 | Bar | Bar | +| pkg1/tst.go:5:6:5:6 | T | T | +| pkg1/tst.go:11:6:11:7 | T2 | T2 | +| pkg1/tst.go:16:6:16:7 | T3 | T3 | +| pkg1/tst.go:21:6:21:7 | T4 | T4 | +| pkg1/tst.go:26:6:26:8 | Foo | Foo | +| pkg1/tst.go:31:6:31:8 | Bar | Bar | +| pkg1/tst.go:61:6:61:14 | NameClash | NameClash | | pkg2/tst.go:3:6:3:6 | T | T | | pkg2/tst.go:7:6:7:6 | G | G | | pkg2/tst.go:11:6:11:24 | MixedExportedAndNot | MixedExportedAndNot | +| pkg2/tst.go:16:6:16:14 | NameClash | NameClash | | struct_tags.go:3:6:3:7 | S1 | S1 | | struct_tags.go:8:6:8:7 | S2 | S2 | diff --git a/go/ql/test/library-tests/semmle/go/Types/embedded.go b/go/ql/test/library-tests/semmle/go/Types/embedded.go index c9c2cf46c2b..413290dbf1a 100644 --- a/go/ql/test/library-tests/semmle/go/Types/embedded.go +++ b/go/ql/test/library-tests/semmle/go/Types/embedded.go @@ -8,7 +8,6 @@ type Qux struct { *Baz } -// EmbedsBaz should have a field A but does not type EmbedsBaz struct { Qux Baz string diff --git a/go/ql/test/library-tests/semmle/go/Types/main.go b/go/ql/test/library-tests/semmle/go/Types/main.go index 1c7e1684725..de11cbd152f 100644 --- a/go/ql/test/library-tests/semmle/go/Types/main.go +++ b/go/ql/test/library-tests/semmle/go/Types/main.go @@ -1,6 +1,10 @@ package main -import "regexp" +import ( + "regexp" + + "github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg1" +) func test(r *regexp.Regexp) {} @@ -9,3 +13,7 @@ func swap(x int, y int) (int, int) { } func main() {} + +type EmbedsNameClash struct { + pkg1.NameClash +} diff --git a/go/ql/test/library-tests/semmle/go/Types/pkg1/tst.go b/go/ql/test/library-tests/semmle/go/Types/pkg1/tst.go index 1b1920ff33a..598e711ff2c 100644 --- a/go/ql/test/library-tests/semmle/go/Types/pkg1/tst.go +++ b/go/ql/test/library-tests/semmle/go/Types/pkg1/tst.go @@ -1,5 +1,7 @@ package pkg1 +import "github.com/github/codeql-go/ql/test/library-tests/semmle/go/Types/pkg2" + type T struct { f int Foo @@ -55,3 +57,7 @@ func test(t T, t2 T2) { // methods of T2 // illegal: t2.half() } + +type NameClash struct { + pkg2.NameClash +} diff --git a/go/ql/test/library-tests/semmle/go/Types/pkg2/tst.go b/go/ql/test/library-tests/semmle/go/Types/pkg2/tst.go index af91e514b77..d1634851b6b 100644 --- a/go/ql/test/library-tests/semmle/go/Types/pkg2/tst.go +++ b/go/ql/test/library-tests/semmle/go/Types/pkg2/tst.go @@ -12,3 +12,9 @@ type MixedExportedAndNot interface { Exported() notExported() } + +type NameClash struct { + NCField string +} + +func (t NameClash) NCMethod() {} diff --git a/go/ql/test/library-tests/semmle/go/concepts/HTTP/Handler.expected b/go/ql/test/library-tests/semmle/go/concepts/HTTP/Handler.expected index 48de9172b36..e69de29bb2d 100644 --- a/go/ql/test/library-tests/semmle/go/concepts/HTTP/Handler.expected +++ b/go/ql/test/library-tests/semmle/go/concepts/HTTP/Handler.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/go/ql/test/library-tests/semmle/go/concepts/LoggerCall/LoggerCall.expected b/go/ql/test/library-tests/semmle/go/concepts/LoggerCall/LoggerCall.expected index 105b7026d0c..42831abaf15 100644 --- a/go/ql/test/library-tests/semmle/go/concepts/LoggerCall/LoggerCall.expected +++ b/go/ql/test/library-tests/semmle/go/concepts/LoggerCall/LoggerCall.expected @@ -1,3 +1,2 @@ -failures invalidModelRow testFailures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_I1_subtypes_false.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_I1_subtypes_false.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_I1_subtypes_false.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_I1_subtypes_false.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_I1_subtypes_true.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_I1_subtypes_true.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_I1_subtypes_true.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_I1_subtypes_true.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_I2_subtypes_false.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_I2_subtypes_false.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_I2_subtypes_false.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_I2_subtypes_false.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_I2_subtypes_true.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_I2_subtypes_true.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_I2_subtypes_true.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_I2_subtypes_true.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_IEmbedI1_subtypes_true.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_IEmbedI1_subtypes_true.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_IEmbedI1_subtypes_true.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_IEmbedI1_subtypes_true.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_IEmbedI2_subtypes_true.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_IEmbedI2_subtypes_true.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_IEmbedI2_subtypes_true.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_IEmbedI2_subtypes_true.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_PImplEmbedI1_subtypes_true.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_PImplEmbedI1_subtypes_true.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_PImplEmbedI1_subtypes_true.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_PImplEmbedI1_subtypes_true.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_PImplEmbedI2_subtypes_true.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_PImplEmbedI2_subtypes_true.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_PImplEmbedI2_subtypes_true.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_PImplEmbedI2_subtypes_true.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_S1_subtypes_false.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_S1_subtypes_false.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_S1_subtypes_false.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_S1_subtypes_false.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_S1_subtypes_true.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_S1_subtypes_true.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_S1_subtypes_true.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_S1_subtypes_true.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedI1_subtypes_true.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedI1_subtypes_true.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedI1_subtypes_true.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedI1_subtypes_true.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedI2_subtypes_true.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedI2_subtypes_true.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedI2_subtypes_true.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedI2_subtypes_true.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedP1_subtypes_true.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedP1_subtypes_true.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedP1_subtypes_true.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedP1_subtypes_true.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedP2_subtypes_true.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedP2_subtypes_true.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedP2_subtypes_true.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedP2_subtypes_true.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedPtrP1_subtypes_true.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedPtrP1_subtypes_true.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedPtrP1_subtypes_true.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedPtrP1_subtypes_true.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedPtrP2_subtypes_true.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedPtrP2_subtypes_true.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedPtrP2_subtypes_true.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedPtrP2_subtypes_true.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedPtrS1_subtypes_true.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedPtrS1_subtypes_true.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedPtrS1_subtypes_true.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedPtrS1_subtypes_true.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedPtrS2_subtypes_true.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedPtrS2_subtypes_true.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedPtrS2_subtypes_true.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedPtrS2_subtypes_true.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedS1_subtypes_true.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedS1_subtypes_true.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedS1_subtypes_true.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedS1_subtypes_true.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedS2_subtypes_true.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedS2_subtypes_true.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedS2_subtypes_true.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SEmbedS2_subtypes_true.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SImplEmbedI1_subtypes_true.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SImplEmbedI1_subtypes_true.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SImplEmbedI1_subtypes_true.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SImplEmbedI1_subtypes_true.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SImplEmbedI2_subtypes_true.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SImplEmbedI2_subtypes_true.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SImplEmbedI2_subtypes_true.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SImplEmbedI2_subtypes_true.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SImplEmbedS1_subtypes_true.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SImplEmbedS1_subtypes_true.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SImplEmbedS1_subtypes_true.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SImplEmbedS1_subtypes_true.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SImplEmbedS2_subtypes_true.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SImplEmbedS2_subtypes_true.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SImplEmbedS2_subtypes_true.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/mad_SImplEmbedS2_subtypes_true.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_I1.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_I1.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_I1.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_I1.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_P1.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_P1.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_P1.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_P1.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_S1.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_S1.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_S1.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowInheritance/ql_S1.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/completetest.ext.yml b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/completetest.ext.yml index 79bf9128ef5..d89a9e04e16 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/completetest.ext.yml +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/completetest.ext.yml @@ -35,10 +35,12 @@ extensions: pack: codeql/go-all extensible: sourceModel data: + - ["github.com/nonexistent/test", "", False, "SourceVariable", "", "", "", "qltest", "manual"] - ["github.com/nonexistent/test", "A", False, "Src1", "", "", "ReturnValue", "qltest", "manual"] - addsTo: pack: codeql/go-all extensible: sinkModel data: + - ["github.com/nonexistent/test", "", False, "SinkVariable", "", "", "", "qltest", "manual"] - ["github.com/nonexistent/test", "B", False, "Sink1", "", "", "Argument[0]", "qltest", "manual"] - ["github.com/nonexistent/test", "B", False, "SinkManyArgs", "", "", "Argument[0..2]", "qltest", "manual"] diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/sinks.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/sinks.expected index fc9adff8942..755c3f82279 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/sinks.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/sinks.expected @@ -43,3 +43,4 @@ invalidModelRow | test.go:199:17:199:20 | arg1 | qltest | | test.go:199:23:199:26 | arg2 | qltest | | test.go:199:29:199:32 | arg3 | qltest | +| test.go:202:22:202:25 | temp | qltest | diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/sinks.ext.yml b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/sinks.ext.yml index 426e094c00c..ec19b822a8c 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/sinks.ext.yml +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/sinks.ext.yml @@ -3,6 +3,7 @@ extensions: pack: codeql/go-all extensible: sinkModel data: + - ["github.com/nonexistent/test", "", False, "SinkVariable", "", "", "", "qltest", "manual"] - ["github.com/nonexistent/test", "B", False, "Sink1", "", "", "Argument[0]", "qltest", "manual"] - ["github.com/nonexistent/test", "B", False, "SinkMethod", "", "", "Argument[receiver]", "qltest", "manual"] - ["github.com/nonexistent/test", "B", False, "SinkManyArgs", "", "", "Argument[0..2]", "qltest", "manual"] diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/srcs.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/srcs.expected index d63fedba3fd..bd1525a984b 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/srcs.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/srcs.expected @@ -21,3 +21,4 @@ invalidModelRow | test.go:183:17:183:24 | call to Src1 | qltest | | test.go:187:24:187:31 | call to Src1 | qltest | | test.go:191:24:191:31 | call to Src1 | qltest | +| test.go:201:10:201:28 | selection of SourceVariable | qltest | diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/srcs.ext.yml b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/srcs.ext.yml index 5493650132c..cda2183894c 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/srcs.ext.yml +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/srcs.ext.yml @@ -3,9 +3,10 @@ extensions: pack: codeql/go-all extensible: sourceModel data: + - ["github.com/nonexistent/test", "", False, "SourceVariable", "", "", "", "qltest", "manual"] - ["github.com/nonexistent/test", "A", False, "Src1", "", "", "ReturnValue", "qltest", "manual"] - ["github.com/nonexistent/test", "A", False, "Src2", "", "", "ReturnValue", "qltest", "manual"] - ["github.com/nonexistent/test", "A", True, "Src2", "", "", "ReturnValue", "qltest-w-subtypes", "manual"] - ["github.com/nonexistent/test", "A", False, "SrcArg", "", "", "Argument[0]", "qltest-arg", "manual"] - ["github.com/nonexistent/test", "A", False, "Src3", "", "", "ReturnValue[0]", "qltest", "manual"] - - ["github.com/nonexistent/test", "A", True, "Src3", "", "", "ReturnValue[1]", "qltest-w-subtypes", "manual"] \ No newline at end of file + - ["github.com/nonexistent/test", "A", True, "Src3", "", "", "ReturnValue[1]", "qltest-w-subtypes", "manual"] diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/test.go b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/test.go index 33e980dac99..29ed066cd50 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/test.go +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/test.go @@ -197,6 +197,9 @@ func simpleflow() { arg3 := src arg4 := src b.SinkManyArgs(arg1, arg2, arg3, arg4) // $ hasTaintFlow="arg1" hasTaintFlow="arg2" hasTaintFlow="arg3" + + temp := test.SourceVariable + test.SinkVariable = temp // $ hasTaintFlow="temp" } type mapstringstringtype map[string]string diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/vendor/github.com/nonexistent/test/stub.go b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/vendor/github.com/nonexistent/test/stub.go index 05a5f741d76..72681cf7238 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/vendor/github.com/nonexistent/test/stub.go +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/vendor/github.com/nonexistent/test/stub.go @@ -72,3 +72,6 @@ func (c C) Get() string { return "" } func (c *C) SetThroughPointer(f string) {} func (c *C) GetThroughPointer() string { return "" } + +var SourceVariable string +var SinkVariable string diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/completetest.ext.yml b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/completetest.ext.yml index 8fbc26ff6cd..924e19a8a73 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/completetest.ext.yml +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/completetest.ext.yml @@ -35,10 +35,12 @@ extensions: pack: codeql/go-all extensible: sourceModel data: + - ["github.com/nonexistent/test", "", False, "SourceVariable", "", "", "", "qltest", "manual"] - ["github.com/nonexistent/test", "A", False, "Src1", "", "", "ReturnValue", "qltest", "manual"] - addsTo: pack: codeql/go-all extensible: sinkModel data: + - ["github.com/nonexistent/test", "", False, "SinkVariable", "", "", "", "qltest", "manual"] - ["github.com/nonexistent/test", "B", False, "Sink1", "", "", "Argument[0]", "qltest", "manual"] - ["github.com/nonexistent/test", "B", False, "SinkManyArgs", "", "", "Argument[0..2]", "qltest", "manual"] diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/sinks.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/sinks.expected index 0fe3a614e11..c9940e181c8 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/sinks.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/sinks.expected @@ -49,3 +49,4 @@ invalidModelRow | test.go:205:10:205:26 | call to min | qltest | | test.go:206:10:206:26 | call to min | qltest | | test.go:207:10:207:26 | call to min | qltest | +| test.go:210:22:210:25 | temp | qltest | diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/sinks.ext.yml b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/sinks.ext.yml index 426e094c00c..ec19b822a8c 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/sinks.ext.yml +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/sinks.ext.yml @@ -3,6 +3,7 @@ extensions: pack: codeql/go-all extensible: sinkModel data: + - ["github.com/nonexistent/test", "", False, "SinkVariable", "", "", "", "qltest", "manual"] - ["github.com/nonexistent/test", "B", False, "Sink1", "", "", "Argument[0]", "qltest", "manual"] - ["github.com/nonexistent/test", "B", False, "SinkMethod", "", "", "Argument[receiver]", "qltest", "manual"] - ["github.com/nonexistent/test", "B", False, "SinkManyArgs", "", "", "Argument[0..2]", "qltest", "manual"] diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/srcs.expected b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/srcs.expected index d63fedba3fd..6fcfcc2a3bc 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/srcs.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/srcs.expected @@ -21,3 +21,4 @@ invalidModelRow | test.go:183:17:183:24 | call to Src1 | qltest | | test.go:187:24:187:31 | call to Src1 | qltest | | test.go:191:24:191:31 | call to Src1 | qltest | +| test.go:209:10:209:28 | selection of SourceVariable | qltest | diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/srcs.ext.yml b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/srcs.ext.yml index 5493650132c..cda2183894c 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/srcs.ext.yml +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/srcs.ext.yml @@ -3,9 +3,10 @@ extensions: pack: codeql/go-all extensible: sourceModel data: + - ["github.com/nonexistent/test", "", False, "SourceVariable", "", "", "", "qltest", "manual"] - ["github.com/nonexistent/test", "A", False, "Src1", "", "", "ReturnValue", "qltest", "manual"] - ["github.com/nonexistent/test", "A", False, "Src2", "", "", "ReturnValue", "qltest", "manual"] - ["github.com/nonexistent/test", "A", True, "Src2", "", "", "ReturnValue", "qltest-w-subtypes", "manual"] - ["github.com/nonexistent/test", "A", False, "SrcArg", "", "", "Argument[0]", "qltest-arg", "manual"] - ["github.com/nonexistent/test", "A", False, "Src3", "", "", "ReturnValue[0]", "qltest", "manual"] - - ["github.com/nonexistent/test", "A", True, "Src3", "", "", "ReturnValue[1]", "qltest-w-subtypes", "manual"] \ No newline at end of file + - ["github.com/nonexistent/test", "A", True, "Src3", "", "", "ReturnValue[1]", "qltest-w-subtypes", "manual"] diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/test.go b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/test.go index 82419ae7d59..72c4db35248 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/test.go +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/test.go @@ -205,6 +205,9 @@ func simpleflow() { b.Sink1(min(srcInt, 0, 1)) // $ hasValueFlow="call to min" b.Sink1(min(0, srcInt, 1)) // $ hasValueFlow="call to min" b.Sink1(min(0, 1, srcInt)) // $ hasValueFlow="call to min" + + temp := test.SourceVariable + test.SinkVariable = temp // $ hasValueFlow="temp" } type mapstringstringtype map[string]string diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/vendor/github.com/nonexistent/test/stub.go b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/vendor/github.com/nonexistent/test/stub.go index 05a5f741d76..72681cf7238 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/vendor/github.com/nonexistent/test/stub.go +++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalValueFlow/vendor/github.com/nonexistent/test/stub.go @@ -72,3 +72,6 @@ func (c C) Get() string { return "" } func (c *C) SetThroughPointer(f string) {} func (c *C) GetThroughPointer() string { return "" } + +var SourceVariable string +var SinkVariable string diff --git a/go/ql/test/library-tests/semmle/go/dataflow/PromotedMethods/DataFlowConfig.expected b/go/ql/test/library-tests/semmle/go/dataflow/PromotedMethods/DataFlowConfig.expected index 105b7026d0c..42831abaf15 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/PromotedMethods/DataFlowConfig.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/PromotedMethods/DataFlowConfig.expected @@ -1,3 +1,2 @@ -failures invalidModelRow testFailures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/flowsources/local/environment/test.expected b/go/ql/test/library-tests/semmle/go/dataflow/flowsources/local/environment/test.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/flowsources/local/environment/test.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/flowsources/local/environment/test.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/flowsources/local/file/test.expected b/go/ql/test/library-tests/semmle/go/dataflow/flowsources/local/file/test.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/flowsources/local/file/test.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/flowsources/local/file/test.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/dataflow/flowsources/local/stdin/source.expected b/go/ql/test/library-tests/semmle/go/dataflow/flowsources/local/stdin/source.expected index db33d6d2504..55e9aed2e93 100644 --- a/go/ql/test/library-tests/semmle/go/dataflow/flowsources/local/stdin/source.expected +++ b/go/ql/test/library-tests/semmle/go/dataflow/flowsources/local/stdin/source.expected @@ -1,3 +1,2 @@ testFailures invalidModelRow -failures diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Afero/Query.expected b/go/ql/test/library-tests/semmle/go/frameworks/Afero/Query.expected index 08c5eee5289..42831abaf15 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Afero/Query.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/Afero/Query.expected @@ -1,3 +1,2 @@ invalidModelRow testFailures -failures diff --git a/go/ql/test/library-tests/semmle/go/frameworks/BeegoOrm/QueryString.expected b/go/ql/test/library-tests/semmle/go/frameworks/BeegoOrm/QueryString.expected index 105b7026d0c..42831abaf15 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/BeegoOrm/QueryString.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/BeegoOrm/QueryString.expected @@ -1,3 +1,2 @@ -failures invalidModelRow testFailures diff --git a/go/ql/test/library-tests/semmle/go/frameworks/BeegoOrm/SqlInjection.expected b/go/ql/test/library-tests/semmle/go/frameworks/BeegoOrm/SqlInjection.expected index 6cc1e09486b..1198f8d41a9 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/BeegoOrm/SqlInjection.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/BeegoOrm/SqlInjection.expected @@ -32,40 +32,61 @@ | test.go:59:31:59:39 | untrusted | test.go:57:15:57:41 | call to UserAgent | test.go:59:31:59:39 | untrusted | This query depends on a $@. | test.go:57:15:57:41 | call to UserAgent | user-provided value | | test.go:65:19:65:27 | untrusted | test.go:63:15:63:41 | call to UserAgent | test.go:65:19:65:27 | untrusted | This query depends on a $@. | test.go:63:15:63:41 | call to UserAgent | user-provided value | edges -| test.go:11:15:11:41 | call to UserAgent | test.go:13:11:13:19 | untrusted | provenance | Src:MaD:1 | -| test.go:11:15:11:41 | call to UserAgent | test.go:14:23:14:31 | untrusted | provenance | Src:MaD:1 | -| test.go:11:15:11:41 | call to UserAgent | test.go:15:14:15:22 | untrusted | provenance | Src:MaD:1 | -| test.go:11:15:11:41 | call to UserAgent | test.go:16:26:16:34 | untrusted | provenance | Src:MaD:1 | -| test.go:11:15:11:41 | call to UserAgent | test.go:17:12:17:20 | untrusted | provenance | Src:MaD:1 | -| test.go:11:15:11:41 | call to UserAgent | test.go:18:24:18:32 | untrusted | provenance | Src:MaD:1 | -| test.go:11:15:11:41 | call to UserAgent | test.go:19:15:19:23 | untrusted | provenance | Src:MaD:1 | -| test.go:11:15:11:41 | call to UserAgent | test.go:20:27:20:35 | untrusted | provenance | Src:MaD:1 | -| test.go:25:15:25:41 | call to UserAgent | test.go:28:12:28:20 | untrusted | provenance | Src:MaD:1 | -| test.go:25:15:25:41 | call to UserAgent | test.go:29:10:29:18 | untrusted | provenance | Src:MaD:1 | -| test.go:25:15:25:41 | call to UserAgent | test.go:30:15:30:23 | untrusted | provenance | Src:MaD:1 | -| test.go:25:15:25:41 | call to UserAgent | test.go:31:14:31:22 | untrusted | provenance | Src:MaD:1 | -| test.go:25:15:25:41 | call to UserAgent | test.go:32:15:32:23 | untrusted | provenance | Src:MaD:1 | -| test.go:25:15:25:41 | call to UserAgent | test.go:33:8:33:16 | untrusted | provenance | Src:MaD:1 | -| test.go:25:15:25:41 | call to UserAgent | test.go:34:11:34:19 | untrusted | provenance | Src:MaD:1 | -| test.go:25:15:25:41 | call to UserAgent | test.go:35:9:35:17 | untrusted | provenance | Src:MaD:1 | -| test.go:25:15:25:41 | call to UserAgent | test.go:36:8:36:16 | untrusted | provenance | Src:MaD:1 | -| test.go:25:15:25:41 | call to UserAgent | test.go:37:8:37:16 | untrusted | provenance | Src:MaD:1 | -| test.go:25:15:25:41 | call to UserAgent | test.go:38:13:38:21 | untrusted | provenance | Src:MaD:1 | -| test.go:25:15:25:41 | call to UserAgent | test.go:39:13:39:21 | untrusted | provenance | Src:MaD:1 | -| test.go:25:15:25:41 | call to UserAgent | test.go:40:12:40:20 | untrusted | provenance | Src:MaD:1 | -| test.go:25:15:25:41 | call to UserAgent | test.go:41:12:41:20 | untrusted | provenance | Src:MaD:1 | -| test.go:25:15:25:41 | call to UserAgent | test.go:42:9:42:17 | untrusted | provenance | Src:MaD:1 | -| test.go:25:15:25:41 | call to UserAgent | test.go:43:12:43:20 | untrusted | provenance | Src:MaD:1 | -| test.go:25:15:25:41 | call to UserAgent | test.go:44:16:44:24 | untrusted | provenance | Src:MaD:1 | -| test.go:25:15:25:41 | call to UserAgent | test.go:45:12:45:20 | untrusted | provenance | Src:MaD:1 | -| test.go:25:15:25:41 | call to UserAgent | test.go:46:14:46:22 | untrusted | provenance | Src:MaD:1 | -| test.go:26:16:26:42 | call to UserAgent | test.go:44:27:44:36 | untrusted2 | provenance | Src:MaD:1 | -| test.go:26:16:26:42 | call to UserAgent | test.go:46:25:46:34 | untrusted2 | provenance | Src:MaD:1 | -| test.go:50:15:50:41 | call to UserAgent | test.go:52:12:52:20 | untrusted | provenance | Src:MaD:1 | -| test.go:57:15:57:41 | call to UserAgent | test.go:59:31:59:39 | untrusted | provenance | Src:MaD:1 | -| test.go:63:15:63:41 | call to UserAgent | test.go:65:19:65:27 | untrusted | provenance | Src:MaD:1 | +| test.go:11:15:11:41 | call to UserAgent | test.go:13:11:13:19 | untrusted | provenance | Src:MaD:22 Sink:MaD:2 | +| test.go:11:15:11:41 | call to UserAgent | test.go:14:23:14:31 | untrusted | provenance | Src:MaD:22 Sink:MaD:3 | +| test.go:11:15:11:41 | call to UserAgent | test.go:15:14:15:22 | untrusted | provenance | Src:MaD:22 Sink:MaD:4 | +| test.go:11:15:11:41 | call to UserAgent | test.go:16:26:16:34 | untrusted | provenance | Src:MaD:22 Sink:MaD:5 | +| test.go:11:15:11:41 | call to UserAgent | test.go:17:12:17:20 | untrusted | provenance | Src:MaD:22 Sink:MaD:6 | +| test.go:11:15:11:41 | call to UserAgent | test.go:18:24:18:32 | untrusted | provenance | Src:MaD:22 Sink:MaD:7 | +| test.go:11:15:11:41 | call to UserAgent | test.go:19:15:19:23 | untrusted | provenance | Src:MaD:22 Sink:MaD:8 | +| test.go:11:15:11:41 | call to UserAgent | test.go:20:27:20:35 | untrusted | provenance | Src:MaD:22 Sink:MaD:9 | +| test.go:25:15:25:41 | call to UserAgent | test.go:28:12:28:20 | untrusted | provenance | Src:MaD:22 | +| test.go:25:15:25:41 | call to UserAgent | test.go:29:10:29:18 | untrusted | provenance | Src:MaD:22 | +| test.go:25:15:25:41 | call to UserAgent | test.go:30:15:30:23 | untrusted | provenance | Src:MaD:22 Sink:MaD:13 | +| test.go:25:15:25:41 | call to UserAgent | test.go:31:14:31:22 | untrusted | provenance | Src:MaD:22 Sink:MaD:15 | +| test.go:25:15:25:41 | call to UserAgent | test.go:32:15:32:23 | untrusted | provenance | Src:MaD:22 Sink:MaD:18 | +| test.go:25:15:25:41 | call to UserAgent | test.go:33:8:33:16 | untrusted | provenance | Src:MaD:22 Sink:MaD:16 | +| test.go:25:15:25:41 | call to UserAgent | test.go:34:11:34:19 | untrusted | provenance | Src:MaD:22 Sink:MaD:20 | +| test.go:25:15:25:41 | call to UserAgent | test.go:35:9:35:17 | untrusted | provenance | Src:MaD:22 Sink:MaD:11 | +| test.go:25:15:25:41 | call to UserAgent | test.go:36:8:36:16 | untrusted | provenance | Src:MaD:22 Sink:MaD:17 | +| test.go:25:15:25:41 | call to UserAgent | test.go:37:8:37:16 | untrusted | provenance | Src:MaD:22 | +| test.go:25:15:25:41 | call to UserAgent | test.go:38:13:38:21 | untrusted | provenance | Src:MaD:22 | +| test.go:25:15:25:41 | call to UserAgent | test.go:39:13:39:21 | untrusted | provenance | Src:MaD:22 | +| test.go:25:15:25:41 | call to UserAgent | test.go:40:12:40:20 | untrusted | provenance | Src:MaD:22 Sink:MaD:12 | +| test.go:25:15:25:41 | call to UserAgent | test.go:41:12:41:20 | untrusted | provenance | Src:MaD:22 | +| test.go:25:15:25:41 | call to UserAgent | test.go:42:9:42:17 | untrusted | provenance | Src:MaD:22 | +| test.go:25:15:25:41 | call to UserAgent | test.go:43:12:43:20 | untrusted | provenance | Src:MaD:22 | +| test.go:25:15:25:41 | call to UserAgent | test.go:44:16:44:24 | untrusted | provenance | Src:MaD:22 Sink:MaD:14 | +| test.go:25:15:25:41 | call to UserAgent | test.go:45:12:45:20 | untrusted | provenance | Src:MaD:22 | +| test.go:25:15:25:41 | call to UserAgent | test.go:46:14:46:22 | untrusted | provenance | Src:MaD:22 Sink:MaD:19 | +| test.go:26:16:26:42 | call to UserAgent | test.go:44:27:44:36 | untrusted2 | provenance | Src:MaD:22 | +| test.go:26:16:26:42 | call to UserAgent | test.go:46:25:46:34 | untrusted2 | provenance | Src:MaD:22 Sink:MaD:19 | +| test.go:50:15:50:41 | call to UserAgent | test.go:52:12:52:20 | untrusted | provenance | Src:MaD:22 Sink:MaD:10 | +| test.go:57:15:57:41 | call to UserAgent | test.go:59:31:59:39 | untrusted | provenance | Src:MaD:22 Sink:MaD:21 | +| test.go:63:15:63:41 | call to UserAgent | test.go:65:19:65:27 | untrusted | provenance | Src:MaD:22 Sink:MaD:1 | models -| 1 | Source: net/http; Request; true; UserAgent; ; ; ReturnValue; remote; manual | +| 1 | Sink: group:beego-orm; Condition; true; Raw; ; ; Argument[1]; sql-injection; manual | +| 2 | Sink: group:beego-orm; DB; true; Exec; ; ; Argument[0]; sql-injection; manual | +| 3 | Sink: group:beego-orm; DB; true; ExecContext; ; ; Argument[1]; sql-injection; manual | +| 4 | Sink: group:beego-orm; DB; true; Prepare; ; ; Argument[0]; sql-injection; manual | +| 5 | Sink: group:beego-orm; DB; true; PrepareContext; ; ; Argument[1]; sql-injection; manual | +| 6 | Sink: group:beego-orm; DB; true; Query; ; ; Argument[0]; sql-injection; manual | +| 7 | Sink: group:beego-orm; DB; true; QueryContext; ; ; Argument[1]; sql-injection; manual | +| 8 | Sink: group:beego-orm; DB; true; QueryRow; ; ; Argument[0]; sql-injection; manual | +| 9 | Sink: group:beego-orm; DB; true; QueryRowContext; ; ; Argument[1]; sql-injection; manual | +| 10 | Sink: group:beego-orm; Ormer; true; Raw; ; ; Argument[0]; sql-injection; manual | +| 11 | Sink: group:beego-orm; QueryBuilder; true; And; ; ; Argument[0]; sql-injection; manual | +| 12 | Sink: group:beego-orm; QueryBuilder; true; Having; ; ; Argument[0]; sql-injection; manual | +| 13 | Sink: group:beego-orm; QueryBuilder; true; InnerJoin; ; ; Argument[0]; sql-injection; manual | +| 14 | Sink: group:beego-orm; QueryBuilder; true; InsertInto; ; ; Argument[0..1]; sql-injection; manual | +| 15 | Sink: group:beego-orm; QueryBuilder; true; LeftJoin; ; ; Argument[0]; sql-injection; manual | +| 16 | Sink: group:beego-orm; QueryBuilder; true; On; ; ; Argument[0]; sql-injection; manual | +| 17 | Sink: group:beego-orm; QueryBuilder; true; Or; ; ; Argument[0]; sql-injection; manual | +| 18 | Sink: group:beego-orm; QueryBuilder; true; RightJoin; ; ; Argument[0]; sql-injection; manual | +| 19 | Sink: group:beego-orm; QueryBuilder; true; Subquery; ; ; Argument[0..1]; sql-injection; manual | +| 20 | Sink: group:beego-orm; QueryBuilder; true; Where; ; ; Argument[0]; sql-injection; manual | +| 21 | Sink: group:beego-orm; QuerySeter; true; FilterRaw; ; ; Argument[1]; sql-injection; manual | +| 22 | Source: net/http; Request; true; UserAgent; ; ; ReturnValue; remote; manual | nodes | test.go:11:15:11:41 | call to UserAgent | semmle.label | call to UserAgent | | test.go:13:11:13:19 | untrusted | semmle.label | untrusted | diff --git a/go/ql/test/library-tests/semmle/go/frameworks/CouchbaseV1/test.expected b/go/ql/test/library-tests/semmle/go/frameworks/CouchbaseV1/test.expected index 105b7026d0c..42831abaf15 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/CouchbaseV1/test.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/CouchbaseV1/test.expected @@ -1,3 +1,2 @@ -failures invalidModelRow testFailures diff --git a/go/ql/test/library-tests/semmle/go/frameworks/ElazarlGoproxy/test.expected b/go/ql/test/library-tests/semmle/go/frameworks/ElazarlGoproxy/test.expected index 105b7026d0c..42831abaf15 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/ElazarlGoproxy/test.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/ElazarlGoproxy/test.expected @@ -1,3 +1,2 @@ -failures invalidModelRow testFailures diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Fasthttp/EscapeFunction.expected b/go/ql/test/library-tests/semmle/go/frameworks/Fasthttp/EscapeFunction.expected index 8ec8033d086..e69de29bb2d 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Fasthttp/EscapeFunction.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/Fasthttp/EscapeFunction.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Fasthttp/FileSystemAccess.expected b/go/ql/test/library-tests/semmle/go/frameworks/Fasthttp/FileSystemAccess.expected index 8ec8033d086..e69de29bb2d 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Fasthttp/FileSystemAccess.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/Fasthttp/FileSystemAccess.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Fasthttp/OpenRedirect.expected b/go/ql/test/library-tests/semmle/go/frameworks/Fasthttp/OpenRedirect.expected index 8ec8033d086..e69de29bb2d 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Fasthttp/OpenRedirect.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/Fasthttp/OpenRedirect.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Fasthttp/RemoteFlowSources.expected b/go/ql/test/library-tests/semmle/go/frameworks/Fasthttp/RemoteFlowSources.expected index 8ec8033d086..e69de29bb2d 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Fasthttp/RemoteFlowSources.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/Fasthttp/RemoteFlowSources.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Fasthttp/SSRF.expected b/go/ql/test/library-tests/semmle/go/frameworks/Fasthttp/SSRF.expected index 8ec8033d086..e69de29bb2d 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Fasthttp/SSRF.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/Fasthttp/SSRF.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Fasthttp/Xss.expected b/go/ql/test/library-tests/semmle/go/frameworks/Fasthttp/Xss.expected index 8ec8033d086..e69de29bb2d 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Fasthttp/Xss.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/Fasthttp/Xss.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Fiber/Query.expected b/go/ql/test/library-tests/semmle/go/frameworks/Fiber/Query.expected index 105b7026d0c..42831abaf15 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Fiber/Query.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/Fiber/Query.expected @@ -1,3 +1,2 @@ -failures invalidModelRow testFailures diff --git a/go/ql/test/library-tests/semmle/go/frameworks/GoKit/RemoteFlowSources.expected b/go/ql/test/library-tests/semmle/go/frameworks/GoKit/RemoteFlowSources.expected index 105b7026d0c..42831abaf15 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/GoKit/RemoteFlowSources.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/GoKit/RemoteFlowSources.expected @@ -1,3 +1,2 @@ -failures invalidModelRow testFailures diff --git a/go/ql/test/library-tests/semmle/go/frameworks/GoMicro/gomicro.expected b/go/ql/test/library-tests/semmle/go/frameworks/GoMicro/gomicro.expected index 105b7026d0c..42831abaf15 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/GoMicro/gomicro.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/GoMicro/gomicro.expected @@ -1,3 +1,2 @@ -failures invalidModelRow testFailures diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Iris/Query.expected b/go/ql/test/library-tests/semmle/go/frameworks/Iris/Query.expected index 105b7026d0c..42831abaf15 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Iris/Query.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/Iris/Query.expected @@ -1,3 +1,2 @@ -failures invalidModelRow testFailures diff --git a/go/ql/test/library-tests/semmle/go/frameworks/K8sIoClientGo/SecretInterfaceSource.expected b/go/ql/test/library-tests/semmle/go/frameworks/K8sIoClientGo/SecretInterfaceSource.expected index 105b7026d0c..42831abaf15 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/K8sIoClientGo/SecretInterfaceSource.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/K8sIoClientGo/SecretInterfaceSource.expected @@ -1,3 +1,2 @@ -failures invalidModelRow testFailures diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Macaron/Sources.expected b/go/ql/test/library-tests/semmle/go/frameworks/Macaron/Sources.expected index 105b7026d0c..42831abaf15 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Macaron/Sources.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/Macaron/Sources.expected @@ -1,3 +1,2 @@ -failures invalidModelRow testFailures diff --git a/go/ql/test/library-tests/semmle/go/frameworks/NoSQL/Query.expected b/go/ql/test/library-tests/semmle/go/frameworks/NoSQL/Query.expected index 105b7026d0c..42831abaf15 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/NoSQL/Query.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/NoSQL/Query.expected @@ -1,3 +1,2 @@ -failures invalidModelRow testFailures diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Revel/test.expected b/go/ql/test/library-tests/semmle/go/frameworks/Revel/test.expected index 48de9172b36..e69de29bb2d 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Revel/test.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/Revel/test.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/QueryString.expected b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/QueryString.expected new file mode 100644 index 00000000000..55e9aed2e93 --- /dev/null +++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/QueryString.expected @@ -0,0 +1,2 @@ +testFailures +invalidModelRow diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/QueryString.ql b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/QueryString.ql new file mode 100644 index 00000000000..eeb43a82fad --- /dev/null +++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/QueryString.ql @@ -0,0 +1,60 @@ +import go +import semmle.go.dataflow.ExternalFlow +import ModelValidation +import TestUtilities.InlineExpectationsTest + +module SqlTest implements TestSig { + string getARelevantTag() { result = "query" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "query" and + exists(SQL::Query q, SQL::QueryString qs | qs = q.getAQueryString() | + q.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), + location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and + element = q.toString() and + value = qs.toString() + ) + } +} + +module QueryString implements TestSig { + string getARelevantTag() { result = "querystring" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "querystring" and + element = "" and + exists(SQL::QueryString qs | not exists(SQL::Query q | qs = q.getAQueryString()) | + qs.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), + location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and + value = qs.toString() + ) + } +} + +module Config implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node n) { n.asExpr() instanceof StringLit } + + predicate isSink(DataFlow::Node n) { + n = any(DataFlow::CallNode cn | cn.getTarget().getName() = "sink").getAnArgument() + } +} + +module Flow = TaintTracking::Global; + +module TaintFlow implements TestSig { + string getARelevantTag() { result = "flowfrom" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "flowfrom" and + element = "" and + exists(DataFlow::Node fromNode, DataFlow::Node toNode | + toNode + .hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), + location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and + Flow::flow(fromNode, toNode) and + value = fromNode.asExpr().(StringLit).getValue() + ) + } +} + +import MakeTest> diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/gorm.expected b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/gorm.expected deleted file mode 100644 index ca70ed07c33..00000000000 --- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/gorm.expected +++ /dev/null @@ -1,25 +0,0 @@ -| gorm.go:20:12:20:20 | untrusted | github.com/jinzhu/gorm | DB | Where | -| gorm.go:21:10:21:18 | untrusted | github.com/jinzhu/gorm | DB | Raw | -| gorm.go:22:10:22:18 | untrusted | github.com/jinzhu/gorm | DB | Not | -| gorm.go:23:12:23:20 | untrusted | github.com/jinzhu/gorm | DB | Order | -| gorm.go:24:9:24:17 | untrusted | github.com/jinzhu/gorm | DB | Or | -| gorm.go:25:13:25:21 | untrusted | github.com/jinzhu/gorm | DB | Select | -| gorm.go:26:12:26:20 | untrusted | github.com/jinzhu/gorm | DB | Table | -| gorm.go:27:12:27:20 | untrusted | github.com/jinzhu/gorm | DB | Group | -| gorm.go:28:13:28:21 | untrusted | github.com/jinzhu/gorm | DB | Having | -| gorm.go:29:12:29:20 | untrusted | github.com/jinzhu/gorm | DB | Joins | -| gorm.go:30:11:30:19 | untrusted | github.com/jinzhu/gorm | DB | Exec | -| gorm.go:31:12:31:20 | untrusted | github.com/jinzhu/gorm | DB | Pluck | -| gorm.go:34:12:34:20 | untrusted | gorm.io/gorm | DB | Where | -| gorm.go:35:10:35:18 | untrusted | gorm.io/gorm | DB | Raw | -| gorm.go:36:10:36:18 | untrusted | gorm.io/gorm | DB | Not | -| gorm.go:37:12:37:20 | untrusted | gorm.io/gorm | DB | Order | -| gorm.go:38:9:38:17 | untrusted | gorm.io/gorm | DB | Or | -| gorm.go:39:13:39:21 | untrusted | gorm.io/gorm | DB | Select | -| gorm.go:40:12:40:20 | untrusted | gorm.io/gorm | DB | Table | -| gorm.go:41:12:41:20 | untrusted | gorm.io/gorm | DB | Group | -| gorm.go:42:13:42:21 | untrusted | gorm.io/gorm | DB | Having | -| gorm.go:43:12:43:20 | untrusted | gorm.io/gorm | DB | Joins | -| gorm.go:44:11:44:19 | untrusted | gorm.io/gorm | DB | Exec | -| gorm.go:45:15:45:23 | untrusted | gorm.io/gorm | DB | Distinct | -| gorm.go:46:12:46:20 | untrusted | gorm.io/gorm | DB | Pluck | diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/gorm.go b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/gorm.go index bee8edbf7af..2d736e2407c 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/gorm.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/gorm.go @@ -13,36 +13,35 @@ func getUntrustedString() string { } func main() { - untrusted := getUntrustedString() db1 := gorm1.DB{} - db1.Where(untrusted) - db1.Raw(untrusted) - db1.Not(untrusted) - db1.Order(untrusted) - db1.Or(untrusted) - db1.Select(untrusted) - db1.Table(untrusted) - db1.Group(untrusted) - db1.Having(untrusted) - db1.Joins(untrusted) - db1.Exec(untrusted) - db1.Pluck(untrusted, nil) + db1.Where(untrusted) // $ querystring=untrusted + db1.Raw(untrusted) // $ querystring=untrusted + db1.Not(untrusted) // $ querystring=untrusted + db1.Order(untrusted) // $ querystring=untrusted + db1.Or(untrusted) // $ querystring=untrusted + db1.Select(untrusted) // $ querystring=untrusted + db1.Table(untrusted) // $ querystring=untrusted + db1.Group(untrusted) // $ querystring=untrusted + db1.Having(untrusted) // $ querystring=untrusted + db1.Joins(untrusted) // $ querystring=untrusted + db1.Exec(untrusted) // $ querystring=untrusted + db1.Pluck(untrusted, nil) // $ querystring=untrusted db2 := gorm2.DB{} - db2.Where(untrusted) - db2.Raw(untrusted) - db2.Not(untrusted) - db2.Order(untrusted) - db2.Or(untrusted) - db2.Select(untrusted) - db2.Table(untrusted) - db2.Group(untrusted) - db2.Having(untrusted) - db2.Joins(untrusted) - db2.Exec(untrusted) - db2.Distinct(untrusted) - db2.Pluck(untrusted, nil) + db2.Where(untrusted) // $ querystring=untrusted + db2.Raw(untrusted) // $ querystring=untrusted + db2.Not(untrusted) // $ querystring=untrusted + db2.Order(untrusted) // $ querystring=untrusted + db2.Or(untrusted) // $ querystring=untrusted + db2.Select(untrusted) // $ querystring=untrusted + db2.Table(untrusted) // $ querystring=untrusted + db2.Group(untrusted) // $ querystring=untrusted + db2.Having(untrusted) // $ querystring=untrusted + db2.Joins(untrusted) // $ querystring=untrusted + db2.Exec(untrusted) // $ querystring=untrusted + db2.Distinct(untrusted) // $ querystring=untrusted + db2.Pluck(untrusted, nil) // $ querystring=untrusted } diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/gorm.ql b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/gorm.ql deleted file mode 100644 index e08b506deaf..00000000000 --- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/gorm.ql +++ /dev/null @@ -1,5 +0,0 @@ -import go - -from SQL::QueryString qs, Method meth, string a, string b, string c -where meth.hasQualifiedName(a, b, c) and qs = meth.getACall().getSyntacticArgument(0) -select qs, a, b, c diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/QueryString.expected b/go/ql/test/library-tests/semmle/go/frameworks/SQL/QueryString.expected index 105b7026d0c..42831abaf15 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/QueryString.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/QueryString.expected @@ -1,3 +1,2 @@ -failures invalidModelRow testFailures diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/QueryString.expected b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/QueryString.expected new file mode 100644 index 00000000000..55e9aed2e93 --- /dev/null +++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/QueryString.expected @@ -0,0 +1,2 @@ +testFailures +invalidModelRow diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/QueryString.ql b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/QueryString.ql new file mode 100644 index 00000000000..eeb43a82fad --- /dev/null +++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/QueryString.ql @@ -0,0 +1,60 @@ +import go +import semmle.go.dataflow.ExternalFlow +import ModelValidation +import TestUtilities.InlineExpectationsTest + +module SqlTest implements TestSig { + string getARelevantTag() { result = "query" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "query" and + exists(SQL::Query q, SQL::QueryString qs | qs = q.getAQueryString() | + q.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), + location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and + element = q.toString() and + value = qs.toString() + ) + } +} + +module QueryString implements TestSig { + string getARelevantTag() { result = "querystring" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "querystring" and + element = "" and + exists(SQL::QueryString qs | not exists(SQL::Query q | qs = q.getAQueryString()) | + qs.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), + location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and + value = qs.toString() + ) + } +} + +module Config implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node n) { n.asExpr() instanceof StringLit } + + predicate isSink(DataFlow::Node n) { + n = any(DataFlow::CallNode cn | cn.getTarget().getName() = "sink").getAnArgument() + } +} + +module Flow = TaintTracking::Global; + +module TaintFlow implements TestSig { + string getARelevantTag() { result = "flowfrom" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "flowfrom" and + element = "" and + exists(DataFlow::Node fromNode, DataFlow::Node toNode | + toNode + .hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), + location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and + Flow::flow(fromNode, toNode) and + value = fromNode.asExpr().(StringLit).getValue() + ) + } +} + +import MakeTest> diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/sqlx.expected b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/sqlx.expected deleted file mode 100644 index 0540a78fb34..00000000000 --- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/sqlx.expected +++ /dev/null @@ -1,12 +0,0 @@ -| sqlx.go:15:17:15:25 | untrusted | -| sqlx.go:16:14:16:22 | untrusted | -| sqlx.go:17:14:17:22 | untrusted | -| sqlx.go:18:12:18:20 | untrusted | -| sqlx.go:19:15:19:23 | untrusted | -| sqlx.go:20:16:20:24 | untrusted | -| sqlx.go:23:17:23:25 | untrusted | -| sqlx.go:24:14:24:22 | untrusted | -| sqlx.go:25:14:25:22 | untrusted | -| sqlx.go:26:12:26:20 | untrusted | -| sqlx.go:27:15:27:23 | untrusted | -| sqlx.go:28:16:28:24 | untrusted | diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/sqlx.go b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/sqlx.go index edc29c4d4ee..e4e8d43395b 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/sqlx.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/sqlx.go @@ -12,19 +12,19 @@ func main() { db := sqlx.DB{} untrusted := getUntrustedString() - db.Select(nil, untrusted) - db.Get(nil, untrusted) - db.MustExec(untrusted) - db.Queryx(untrusted) - db.NamedExec(untrusted, nil) - db.NamedQuery(untrusted, nil) + db.Select(nil, untrusted) // $ querystring=untrusted + db.Get(nil, untrusted) // $ querystring=untrusted + db.MustExec(untrusted) // $ querystring=untrusted + db.Queryx(untrusted) // $ querystring=untrusted + db.NamedExec(untrusted, nil) // $ querystring=untrusted + db.NamedQuery(untrusted, nil) // $ querystring=untrusted tx := sqlx.Tx{} - tx.Select(nil, untrusted) - tx.Get(nil, untrusted) - tx.MustExec(untrusted) - tx.Queryx(untrusted) - tx.NamedExec(untrusted, nil) - tx.NamedQuery(untrusted, nil) + tx.Select(nil, untrusted) // $ querystring=untrusted + tx.Get(nil, untrusted) // $ querystring=untrusted + tx.MustExec(untrusted) // $ querystring=untrusted + tx.Queryx(untrusted) // $ querystring=untrusted + tx.NamedExec(untrusted, nil) // $ querystring=untrusted + tx.NamedQuery(untrusted, nil) // $ querystring=untrusted } diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/sqlx.ql b/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/sqlx.ql deleted file mode 100644 index 7b56fd97441..00000000000 --- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/Sqlx/sqlx.ql +++ /dev/null @@ -1,4 +0,0 @@ -import go - -from SQL::QueryString qs -select qs diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/bun/QueryString.expected b/go/ql/test/library-tests/semmle/go/frameworks/SQL/bun/QueryString.expected new file mode 100644 index 00000000000..42831abaf15 --- /dev/null +++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/bun/QueryString.expected @@ -0,0 +1,2 @@ +invalidModelRow +testFailures diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/bun/QueryString.ql b/go/ql/test/library-tests/semmle/go/frameworks/SQL/bun/QueryString.ql new file mode 100644 index 00000000000..eeb43a82fad --- /dev/null +++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/bun/QueryString.ql @@ -0,0 +1,60 @@ +import go +import semmle.go.dataflow.ExternalFlow +import ModelValidation +import TestUtilities.InlineExpectationsTest + +module SqlTest implements TestSig { + string getARelevantTag() { result = "query" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "query" and + exists(SQL::Query q, SQL::QueryString qs | qs = q.getAQueryString() | + q.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), + location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and + element = q.toString() and + value = qs.toString() + ) + } +} + +module QueryString implements TestSig { + string getARelevantTag() { result = "querystring" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "querystring" and + element = "" and + exists(SQL::QueryString qs | not exists(SQL::Query q | qs = q.getAQueryString()) | + qs.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), + location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and + value = qs.toString() + ) + } +} + +module Config implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node n) { n.asExpr() instanceof StringLit } + + predicate isSink(DataFlow::Node n) { + n = any(DataFlow::CallNode cn | cn.getTarget().getName() = "sink").getAnArgument() + } +} + +module Flow = TaintTracking::Global; + +module TaintFlow implements TestSig { + string getARelevantTag() { result = "flowfrom" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "flowfrom" and + element = "" and + exists(DataFlow::Node fromNode, DataFlow::Node toNode | + toNode + .hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), + location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and + Flow::flow(fromNode, toNode) and + value = fromNode.asExpr().(StringLit).getValue() + ) + } +} + +import MakeTest> diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/bun/bun.go b/go/ql/test/library-tests/semmle/go/frameworks/SQL/bun/bun.go index 8ce4e5b0826..44a2e2c2fce 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/bun/bun.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/bun/bun.go @@ -22,28 +22,28 @@ func main() { panic(err) } db := bun.NewDB(sqlite, sqlitedialect.New()) - bun.NewRawQuery(db, untrusted) + bun.NewRawQuery(db, untrusted) // $ querystring=untrusted - db.ExecContext(ctx, untrusted) - db.PrepareContext(ctx, untrusted) - db.QueryContext(ctx, untrusted) - db.QueryRowContext(ctx, untrusted) + db.ExecContext(ctx, untrusted) // $ querystring=untrusted + db.PrepareContext(ctx, untrusted) // $ querystring=untrusted + db.QueryContext(ctx, untrusted) // $ querystring=untrusted + db.QueryRowContext(ctx, untrusted) // $ querystring=untrusted - db.Exec(untrusted) - db.NewRaw(untrusted) - db.Prepare(untrusted) - db.Query(untrusted) - db.QueryRow(untrusted) - db.Raw(untrusted) + db.Exec(untrusted) // $ querystring=untrusted + db.NewRaw(untrusted) // $ querystring=untrusted + db.Prepare(untrusted) // $ querystring=untrusted + db.Query(untrusted) // $ querystring=untrusted + db.QueryRow(untrusted) // $ querystring=untrusted + db.Raw(untrusted) // $ querystring=untrusted - db.NewSelect().ColumnExpr(untrusted) - db.NewSelect().DistinctOn(untrusted) - db.NewSelect().For(untrusted) - db.NewSelect().GroupExpr(untrusted) - db.NewSelect().Having(untrusted) - db.NewSelect().ModelTableExpr(untrusted) - db.NewSelect().OrderExpr(untrusted) - db.NewSelect().TableExpr(untrusted) - db.NewSelect().Where(untrusted) - db.NewSelect().WhereOr(untrusted) + db.NewSelect().ColumnExpr(untrusted) // $ querystring=untrusted + db.NewSelect().DistinctOn(untrusted) // $ querystring=untrusted + db.NewSelect().For(untrusted) // $ querystring=untrusted + db.NewSelect().GroupExpr(untrusted) // $ querystring=untrusted + db.NewSelect().Having(untrusted) // $ querystring=untrusted + db.NewSelect().ModelTableExpr(untrusted) // $ querystring=untrusted + db.NewSelect().OrderExpr(untrusted) // $ querystring=untrusted + db.NewSelect().TableExpr(untrusted) // $ querystring=untrusted + db.NewSelect().Where(untrusted) // $ querystring=untrusted + db.NewSelect().WhereOr(untrusted) // $ querystring=untrusted } diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/QueryString.expected b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/QueryString.expected new file mode 100644 index 00000000000..55e9aed2e93 --- /dev/null +++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/QueryString.expected @@ -0,0 +1,2 @@ +testFailures +invalidModelRow diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/QueryString.ql b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/QueryString.ql new file mode 100644 index 00000000000..eeb43a82fad --- /dev/null +++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/QueryString.ql @@ -0,0 +1,60 @@ +import go +import semmle.go.dataflow.ExternalFlow +import ModelValidation +import TestUtilities.InlineExpectationsTest + +module SqlTest implements TestSig { + string getARelevantTag() { result = "query" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "query" and + exists(SQL::Query q, SQL::QueryString qs | qs = q.getAQueryString() | + q.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), + location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and + element = q.toString() and + value = qs.toString() + ) + } +} + +module QueryString implements TestSig { + string getARelevantTag() { result = "querystring" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "querystring" and + element = "" and + exists(SQL::QueryString qs | not exists(SQL::Query q | qs = q.getAQueryString()) | + qs.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), + location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and + value = qs.toString() + ) + } +} + +module Config implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node n) { n.asExpr() instanceof StringLit } + + predicate isSink(DataFlow::Node n) { + n = any(DataFlow::CallNode cn | cn.getTarget().getName() = "sink").getAnArgument() + } +} + +module Flow = TaintTracking::Global; + +module TaintFlow implements TestSig { + string getARelevantTag() { result = "flowfrom" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "flowfrom" and + element = "" and + exists(DataFlow::Node fromNode, DataFlow::Node toNode | + toNode + .hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), + location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and + Flow::flow(fromNode, toNode) and + value = fromNode.asExpr().(StringLit).getValue() + ) + } +} + +import MakeTest> diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/gogf.expected b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/gogf.expected deleted file mode 100644 index f4e3e4f15b0..00000000000 --- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/gogf.expected +++ /dev/null @@ -1,47 +0,0 @@ -| gogf.go:12:9:12:11 | sql | -| gogf.go:13:11:13:13 | sql | -| gogf.go:14:13:14:15 | sql | -| gogf.go:15:13:15:15 | sql | -| gogf.go:16:11:16:13 | sql | -| gogf.go:17:13:17:15 | sql | -| gogf.go:18:12:18:14 | sql | -| gogf.go:19:10:19:12 | sql | -| gogf.go:20:8:20:10 | sql | -| gogf.go:21:17:21:19 | sql | -| gogf.go:22:19:22:21 | sql | -| gogf.go:23:20:23:22 | sql | -| gogf.go:24:23:24:25 | sql | -| gogf.go:25:21:25:23 | sql | -| gogf.go:26:23:26:25 | sql | -| gogf.go:27:22:27:24 | sql | -| gogf.go:28:24:28:26 | sql | -| gogf.go:32:9:32:11 | sql | -| gogf.go:33:11:33:13 | sql | -| gogf.go:34:13:34:15 | sql | -| gogf.go:35:13:35:15 | sql | -| gogf.go:36:11:36:13 | sql | -| gogf.go:37:13:37:15 | sql | -| gogf.go:38:12:38:14 | sql | -| gogf.go:39:10:39:12 | sql | -| gogf.go:40:8:40:10 | sql | -| gogf.go:41:17:41:19 | sql | -| gogf.go:42:23:42:25 | sql | -| gogf.go:43:21:43:23 | sql | -| gogf.go:44:23:44:25 | sql | -| gogf.go:45:22:45:24 | sql | -| gogf.go:46:24:46:26 | sql | -| gogf.go:51:9:51:11 | sql | -| gogf.go:52:11:52:13 | sql | -| gogf.go:53:13:53:15 | sql | -| gogf.go:54:13:54:15 | sql | -| gogf.go:55:11:55:13 | sql | -| gogf.go:56:13:56:15 | sql | -| gogf.go:57:12:57:14 | sql | -| gogf.go:58:10:58:12 | sql | -| gogf.go:59:8:59:10 | sql | -| gogf.go:60:17:60:19 | sql | -| gogf.go:61:23:61:25 | sql | -| gogf.go:62:21:62:23 | sql | -| gogf.go:63:23:63:25 | sql | -| gogf.go:64:22:64:24 | sql | -| gogf.go:65:24:65:26 | sql | diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/gogf.go b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/gogf.go index d0eceaf862c..e2db8016cf0 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/gogf.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/gogf.go @@ -4,11 +4,13 @@ package main //go:generate depstubber -vendor github.com/gogf/gf/database/gdb DB,Core,TX "" import ( + "context" + "github.com/gogf/gf/database/gdb" "github.com/gogf/gf/frame/g" ) -func gogfCoreTest(sql string, c *gdb.Core) { +func gogfCoreTest(sql string, c *gdb.Core, ctx context.Context) { c.Exec(sql, nil) // $ querystring=sql c.GetAll(sql, nil) // $ querystring=sql c.GetArray(sql, nil) // $ querystring=sql @@ -21,14 +23,14 @@ func gogfCoreTest(sql string, c *gdb.Core) { c.GetScan(nil, sql, nil) // $ querystring=sql c.GetStruct(nil, sql, nil) // $ querystring=sql c.GetStructs(nil, sql, nil) // $ querystring=sql - c.DoCommit(nil, nil, sql, nil) // $ querystring=sql - c.DoExec(nil, nil, sql, nil) // $ querystring=sql - c.DoGetAll(nil, nil, sql, nil) // $ querystring=sql - c.DoQuery(nil, nil, sql, nil) // $ querystring=sql - c.DoPrepare(nil, nil, sql) // $ querystring=sql + c.DoCommit(ctx, nil, sql, nil) // $ querystring=sql + c.DoExec(ctx, nil, sql, nil) // $ querystring=sql + c.DoGetAll(ctx, nil, sql, nil) // $ querystring=sql + c.DoQuery(ctx, nil, sql, nil) // $ querystring=sql + c.DoPrepare(ctx, nil, sql) // $ querystring=sql } -func gogfDbtest(sql string, c gdb.DB) { +func gogfDbtest(sql string, c gdb.DB, ctx context.Context) { c.Exec(sql, nil) // $ querystring=sql c.GetAll(sql, nil) // $ querystring=sql c.GetArray(sql, nil) // $ querystring=sql @@ -39,14 +41,14 @@ func gogfDbtest(sql string, c gdb.DB) { c.Query(sql, nil) // $ querystring=sql c.Raw(sql, nil) // $ querystring=sql c.GetScan(nil, sql, nil) // $ querystring=sql - c.DoCommit(nil, nil, sql, nil) // $ querystring=sql - c.DoExec(nil, nil, sql, nil) // $ querystring=sql - c.DoGetAll(nil, nil, sql, nil) // $ querystring=sql - c.DoQuery(nil, nil, sql, nil) // $ querystring=sql - c.DoPrepare(nil, nil, sql) // $ querystring=sql + c.DoCommit(ctx, nil, sql, nil) // $ querystring=sql + c.DoExec(ctx, nil, sql, nil) // $ querystring=sql + c.DoGetAll(ctx, nil, sql, nil) // $ querystring=sql + c.DoQuery(ctx, nil, sql, nil) // $ querystring=sql + c.DoPrepare(ctx, nil, sql) // $ querystring=sql } -func gogfGTest(sql string) { +func gogfGTest(sql string, ctx context.Context) { c := g.DB("ad") c.Exec(sql, nil) // $ querystring=sql c.GetAll(sql, nil) // $ querystring=sql @@ -58,11 +60,11 @@ func gogfGTest(sql string) { c.Query(sql, nil) // $ querystring=sql c.Raw(sql, nil) // $ querystring=sql c.GetScan(nil, sql, nil) // $ querystring=sql - c.DoCommit(nil, nil, sql, nil) // $ querystring=sql - c.DoExec(nil, nil, sql, nil) // $ querystring=sql - c.DoGetAll(nil, nil, sql, nil) // $ querystring=sql - c.DoQuery(nil, nil, sql, nil) // $ querystring=sql - c.DoPrepare(nil, nil, sql) // $ querystring=sql + c.DoCommit(ctx, nil, sql, nil) // $ querystring=sql + c.DoExec(ctx, nil, sql, nil) // $ querystring=sql + c.DoGetAll(ctx, nil, sql, nil) // $ querystring=sql + c.DoQuery(ctx, nil, sql, nil) // $ querystring=sql + c.DoPrepare(ctx, nil, sql) // $ querystring=sql } func main() { diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/gogf.ql b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/gogf.ql deleted file mode 100644 index 7b56fd97441..00000000000 --- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gogf/gogf.ql +++ /dev/null @@ -1,4 +0,0 @@ -import go - -from SQL::QueryString qs -select qs diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/QueryString.expected b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/QueryString.expected new file mode 100644 index 00000000000..55e9aed2e93 --- /dev/null +++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/QueryString.expected @@ -0,0 +1,2 @@ +testFailures +invalidModelRow diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/QueryString.ql b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/QueryString.ql new file mode 100644 index 00000000000..eeb43a82fad --- /dev/null +++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/QueryString.ql @@ -0,0 +1,60 @@ +import go +import semmle.go.dataflow.ExternalFlow +import ModelValidation +import TestUtilities.InlineExpectationsTest + +module SqlTest implements TestSig { + string getARelevantTag() { result = "query" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "query" and + exists(SQL::Query q, SQL::QueryString qs | qs = q.getAQueryString() | + q.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), + location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and + element = q.toString() and + value = qs.toString() + ) + } +} + +module QueryString implements TestSig { + string getARelevantTag() { result = "querystring" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "querystring" and + element = "" and + exists(SQL::QueryString qs | not exists(SQL::Query q | qs = q.getAQueryString()) | + qs.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), + location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and + value = qs.toString() + ) + } +} + +module Config implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node n) { n.asExpr() instanceof StringLit } + + predicate isSink(DataFlow::Node n) { + n = any(DataFlow::CallNode cn | cn.getTarget().getName() = "sink").getAnArgument() + } +} + +module Flow = TaintTracking::Global; + +module TaintFlow implements TestSig { + string getARelevantTag() { result = "flowfrom" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "flowfrom" and + element = "" and + exists(DataFlow::Node fromNode, DataFlow::Node toNode | + toNode + .hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(), + location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and + Flow::flow(fromNode, toNode) and + value = fromNode.asExpr().(StringLit).getValue() + ) + } +} + +import MakeTest> diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/go.mod b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/go.mod index 1f243775658..826ed0eb1c0 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/go.mod +++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/go.mod @@ -2,4 +2,4 @@ module main go 1.18 -require github.com/rqlite/gorqlite v0.0.0-20220528150909-c4e99ae96be6 +require github.com/rqlite/gorqlite v0.0.0-20240808172217-12ae7d03ef19 diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/gorqlite.expected b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/gorqlite.expected deleted file mode 100644 index cbd8166ea5e..00000000000 --- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/gorqlite.expected +++ /dev/null @@ -1,6 +0,0 @@ -| gorqlite.go:11:13:11:16 | sqls | -| gorqlite.go:12:13:12:16 | sqls | -| gorqlite.go:13:13:13:16 | sqls | -| gorqlite.go:14:16:14:18 | sql | -| gorqlite.go:15:16:15:18 | sql | -| gorqlite.go:16:16:16:18 | sql | diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/gorqlite.go b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/gorqlite.go index 9b60c6684e6..ebd6e5fd9f3 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/gorqlite.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/gorqlite.go @@ -1,20 +1,49 @@ package main -//go:generate depstubber -vendor github.com/rqlite/gorqlite Connection Open +//go:generate depstubber -vendor github.com/rqlite/gorqlite Connection,ParameterizedStatement Open import ( + "context" + "github.com/rqlite/gorqlite" ) -func gorqlitetest(sql string, sqls []string) { +func gorqlitetest(sql string, sqls []string, param_sql gorqlite.ParameterizedStatement, param_sqls []gorqlite.ParameterizedStatement, ctx context.Context) { conn, _ := gorqlite.Open("dbUrl") - conn.Query(sqls) // $ querystring=sqls - conn.Queue(sqls) // $ querystring=sqls - conn.Write(sqls) // $ querystring=sqls + + conn.Query(sqls) // $ querystring=sqls + conn.Queue(sqls) // $ querystring=sqls + conn.Write(sqls) // $ querystring=sqls + conn.QueryOne(sql) // $ querystring=sql conn.QueueOne(sql) // $ querystring=sql conn.WriteOne(sql) // $ querystring=sql + + conn.QueryParameterized(param_sqls) // $ querystring=param_sqls + conn.QueueParameterized(param_sqls) // $ querystring=param_sqls + conn.WriteParameterized(param_sqls) // $ querystring=param_sqls + + conn.QueryOneParameterized(param_sql) // $ querystring=param_sql + conn.QueueOneParameterized(param_sql) // $ querystring=param_sql + conn.WriteOneParameterized(param_sql) // $ querystring=param_sql + + conn.QueryContext(ctx, sqls) // $ querystring=sqls + conn.QueueContext(ctx, sqls) // $ querystring=sqls + conn.WriteContext(ctx, sqls) // $ querystring=sqls + + conn.QueryOneContext(ctx, sql) // $ querystring=sql + conn.QueueOneContext(ctx, sql) // $ querystring=sql + conn.WriteOneContext(ctx, sql) // $ querystring=sql + + conn.QueryParameterizedContext(ctx, param_sqls) // $ querystring=param_sqls + conn.QueueParameterizedContext(ctx, param_sqls) // $ querystring=param_sqls + conn.WriteParameterizedContext(ctx, param_sqls) // $ querystring=param_sqls + + conn.QueryOneParameterizedContext(ctx, param_sql) // $ querystring=param_sql + conn.QueueOneParameterizedContext(ctx, param_sql) // $ querystring=param_sql + conn.WriteOneParameterizedContext(ctx, param_sql) // $ querystring=param_sql } + func main() { return } diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/gorqlite.ql b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/gorqlite.ql deleted file mode 100644 index 7b56fd97441..00000000000 --- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/gorqlite.ql +++ /dev/null @@ -1,4 +0,0 @@ -import go - -from SQL::QueryString qs -select qs diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/vendor/github.com/rqlite/gorqlite/stub.go b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/vendor/github.com/rqlite/gorqlite/stub.go index f6f4ca18ec1..0572097582e 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/vendor/github.com/rqlite/gorqlite/stub.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/vendor/github.com/rqlite/gorqlite/stub.go @@ -2,11 +2,15 @@ // This is a simple stub for github.com/rqlite/gorqlite, strictly for use in testing. // See the LICENSE file for information about the licensing of the original library. -// Source: github.com/rqlite/gorqlite (exports: Connection; functions: Open) +// Source: github.com/rqlite/gorqlite (exports: Connection,ParameterizedStatement; functions: Open) // Package gorqlite is a stub of github.com/rqlite/gorqlite, generated by depstubber. package gorqlite +import ( + context "context" +) + type Connection struct { ID string } @@ -29,19 +33,83 @@ func (_ *Connection) Query(_ []string) ([]QueryResult, error) { return nil, nil } +func (_ *Connection) QueryContext(_ context.Context, _ []string) ([]QueryResult, error) { + return nil, nil +} + func (_ *Connection) QueryOne(_ string) (QueryResult, error) { return QueryResult{}, nil } +func (_ *Connection) QueryOneContext(_ context.Context, _ string) (QueryResult, error) { + return QueryResult{}, nil +} + +func (_ *Connection) QueryOneParameterized(_ ParameterizedStatement) (QueryResult, error) { + return QueryResult{}, nil +} + +func (_ *Connection) QueryOneParameterizedContext(_ context.Context, _ ParameterizedStatement) (QueryResult, error) { + return QueryResult{}, nil +} + +func (_ *Connection) QueryParameterized(_ []ParameterizedStatement) ([]QueryResult, error) { + return nil, nil +} + +func (_ *Connection) QueryParameterizedContext(_ context.Context, _ []ParameterizedStatement) ([]QueryResult, error) { + return nil, nil +} + func (_ *Connection) Queue(_ []string) (int64, error) { return 0, nil } +func (_ *Connection) QueueContext(_ context.Context, _ []string) (int64, error) { + return 0, nil +} + func (_ *Connection) QueueOne(_ string) (int64, error) { return 0, nil } -func (_ *Connection) SetConsistencyLevel(_ string) error { +func (_ *Connection) QueueOneContext(_ context.Context, _ string) (int64, error) { + return 0, nil +} + +func (_ *Connection) QueueOneParameterized(_ ParameterizedStatement) (int64, error) { + return 0, nil +} + +func (_ *Connection) QueueOneParameterizedContext(_ context.Context, _ ParameterizedStatement) (int64, error) { + return 0, nil +} + +func (_ *Connection) QueueParameterized(_ []ParameterizedStatement) (int64, error) { + return 0, nil +} + +func (_ *Connection) QueueParameterizedContext(_ context.Context, _ []ParameterizedStatement) (int64, error) { + return 0, nil +} + +func (_ *Connection) Request(_ []string) ([]RequestResult, error) { + return nil, nil +} + +func (_ *Connection) RequestContext(_ context.Context, _ []string) ([]RequestResult, error) { + return nil, nil +} + +func (_ *Connection) RequestParameterized(_ []ParameterizedStatement) ([]RequestResult, error) { + return nil, nil +} + +func (_ *Connection) RequestParameterizedContext(_ context.Context, _ []ParameterizedStatement) ([]RequestResult, error) { + return nil, nil +} + +func (_ *Connection) SetConsistencyLevel(_ interface{}) error { return nil } @@ -53,12 +121,41 @@ func (_ *Connection) Write(_ []string) ([]WriteResult, error) { return nil, nil } +func (_ *Connection) WriteContext(_ context.Context, _ []string) ([]WriteResult, error) { + return nil, nil +} + func (_ *Connection) WriteOne(_ string) (WriteResult, error) { return WriteResult{}, nil } -func Open(_ string) (Connection, error) { - return Connection{}, nil +func (_ *Connection) WriteOneContext(_ context.Context, _ string) (WriteResult, error) { + return WriteResult{}, nil +} + +func (_ *Connection) WriteOneParameterized(_ ParameterizedStatement) (WriteResult, error) { + return WriteResult{}, nil +} + +func (_ *Connection) WriteOneParameterizedContext(_ context.Context, _ ParameterizedStatement) (WriteResult, error) { + return WriteResult{}, nil +} + +func (_ *Connection) WriteParameterized(_ []ParameterizedStatement) ([]WriteResult, error) { + return nil, nil +} + +func (_ *Connection) WriteParameterizedContext(_ context.Context, _ []ParameterizedStatement) ([]WriteResult, error) { + return nil, nil +} + +func Open(_ string) (*Connection, error) { + return nil, nil +} + +type ParameterizedStatement struct { + Query string + Arguments []interface{} } type QueryResult struct { @@ -90,10 +187,20 @@ func (_ *QueryResult) Scan(_ ...interface{}) error { return nil } +func (_ *QueryResult) Slice() ([]interface{}, error) { + return nil, nil +} + func (_ *QueryResult) Types() []string { return nil } +type RequestResult struct { + Err error + Query *QueryResult + Write *WriteResult +} + type WriteResult struct { Err error Timing float64 diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/vendor/modules.txt b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/vendor/modules.txt index f5e5b9989ed..dafb7c6d1a9 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/vendor/modules.txt +++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/gorqlite/vendor/modules.txt @@ -1,3 +1,3 @@ -# github.com/rqlite/gorqlite v0.0.0-20220528150909-c4e99ae96be6 +# github.com/rqlite/gorqlite v0.0.0-20240808172217-12ae7d03ef19 ## explicit github.com/rqlite/gorqlite diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/squirrel.go b/go/ql/test/library-tests/semmle/go/frameworks/SQL/squirrel.go index 15b687c7ad1..d0350643bb0 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/squirrel.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/squirrel.go @@ -1,6 +1,6 @@ package main -//go:generate depstubber -vendor github.com/Masterminds/squirrel DeleteBuilder,InsertBuilder,SelectBuilder,UpdateBuilder Delete,Expr,Insert,Select,Update +//go:generate depstubber -vendor github.com/Masterminds/squirrel DeleteBuilder,Eq,InsertBuilder,SelectBuilder,UpdateBuilder Delete,Expr,Insert,Select,Update import ( "github.com/Masterminds/squirrel" @@ -10,38 +10,44 @@ func squirrelTest(querypart string) { squirrel.Expr(querypart) // $ querystring=querypart deleteBuilder := squirrel.Delete(querypart) // $ querystring=querypart deleteBuilder.From(querypart) // $ querystring=querypart - deleteBuilder.OrderBy(querypart) // $ querystring=[]type{args} + deleteBuilder.OrderBy(querypart) // $ querystring=querypart deleteBuilder.Prefix(querypart) // $ querystring=querypart deleteBuilder.Suffix(querypart) // $ querystring=querypart deleteBuilder.Where(querypart) // $ querystring=querypart insertBuilder := squirrel.Insert(querypart) // $ querystring=querypart - insertBuilder.Columns(querypart) // $ querystring=[]type{args} - insertBuilder.Options(querypart) // $ querystring=[]type{args} + insertBuilder.Columns(querypart) // $ querystring=querypart + insertBuilder.Options(querypart) // $ querystring=querypart insertBuilder.Prefix(querypart) // $ querystring=querypart insertBuilder.Suffix(querypart) // $ querystring=querypart insertBuilder.Into(querypart) // $ querystring=querypart - selectBuilder := squirrel.Select(querypart) // $ querystring=[]type{args} - selectBuilder.Columns(querypart) // $ querystring=[]type{args} + selectBuilder := squirrel.Select(querypart) // $ querystring=querypart + selectBuilder.Columns(querypart) // $ querystring=querypart selectBuilder.From(querypart) // $ querystring=querypart - selectBuilder.Options(querypart) // $ querystring=[]type{args} - selectBuilder.OrderBy(querypart) // $ querystring=[]type{args} + selectBuilder.Options(querypart) // $ querystring=querypart + selectBuilder.OrderBy(querypart) // $ querystring=querypart selectBuilder.Prefix(querypart) // $ querystring=querypart selectBuilder.Suffix(querypart) // $ querystring=querypart selectBuilder.Where(querypart) // $ querystring=querypart selectBuilder.CrossJoin(querypart) // $ querystring=querypart - selectBuilder.GroupBy(querypart) // $ querystring=[]type{args} + selectBuilder.GroupBy(querypart) // $ querystring=querypart selectBuilder.InnerJoin(querypart) // $ querystring=querypart selectBuilder.LeftJoin(querypart) // $ querystring=querypart selectBuilder.RightJoin(querypart) // $ querystring=querypart updateBuilder := squirrel.Update(querypart) // $ querystring=querypart updateBuilder.From(querypart) // $ querystring=querypart - updateBuilder.OrderBy(querypart) // $ querystring=[]type{args} + updateBuilder.OrderBy(querypart) // $ querystring=querypart updateBuilder.Prefix(querypart) // $ querystring=querypart updateBuilder.Suffix(querypart) // $ querystring=querypart updateBuilder.Where(querypart) // $ querystring=querypart updateBuilder.Set(querypart, "") // $ querystring=querypart updateBuilder.Table(querypart) // $ querystring=querypart + + // safe + wrapped := squirrel.Eq{"id": querypart} + deleteBuilder.Where(wrapped) + selectBuilder.Where(wrapped) + updateBuilder.Where(wrapped) } diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/vendor/github.com/Masterminds/squirrel/stub.go b/go/ql/test/library-tests/semmle/go/frameworks/SQL/vendor/github.com/Masterminds/squirrel/stub.go index 96a30e49d4e..1a9e5ca0e9b 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/vendor/github.com/Masterminds/squirrel/stub.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/vendor/github.com/Masterminds/squirrel/stub.go @@ -2,7 +2,7 @@ // This is a simple stub for github.com/Masterminds/squirrel, strictly for use in testing. // See the LICENSE file for information about the licensing of the original library. -// Source: github.com/Masterminds/squirrel (exports: DeleteBuilder,InsertBuilder,SelectBuilder,UpdateBuilder; functions: Delete,Expr,Insert,Select,Update) +// Source: github.com/Masterminds/squirrel (exports: DeleteBuilder,Eq,InsertBuilder,SelectBuilder,UpdateBuilder; functions: Delete,Expr,Insert,Select,Update) // Package squirrel is a stub of github.com/Masterminds/squirrel, generated by depstubber. package squirrel @@ -99,6 +99,12 @@ func (_ DeleteBuilder) Where(_ interface{}, _ ...interface{}) DeleteBuilder { return DeleteBuilder{} } +type Eq map[string]interface{} + +func (_ Eq) ToSql() (string, []interface{}, error) { + return "", nil, nil +} + func Expr(_ string, _ ...interface{}) Sqlizer { return nil } diff --git a/go/ql/test/library-tests/semmle/go/frameworks/SQL/xorm.go b/go/ql/test/library-tests/semmle/go/frameworks/SQL/xorm.go index 6b4dbb116ee..f63b33a0e09 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/SQL/xorm.go +++ b/go/ql/test/library-tests/semmle/go/frameworks/SQL/xorm.go @@ -10,68 +10,73 @@ import ( func xormtest() { query := "UntrustedString" + arg := "arg" engine1 := xorm1.Engine{} - engine1.Query(query) // $ querystring=query - engine1.QueryString(query) // $ querystring=query - engine1.QueryInterface(query) // $ querystring=query - engine1.SQL(query) // $ querystring=query - engine1.Where(query) // $ querystring=query - engine1.Alias(query) // $ querystring=query - engine1.NotIn(query) // $ querystring=query - engine1.In(query) // $ querystring=query - engine1.Select(query) // $ querystring=query - engine1.SetExpr(query, nil) // $ querystring=query - engine1.OrderBy(query) // $ querystring=query - engine1.Having(query) // $ querystring=query - engine1.GroupBy(query) // $ querystring=query + engine1.Query(query, arg) // $ querystring=query + engine1.Exec(query, arg) // $ querystring=query + engine1.QueryString(query, arg) // $ querystring=query + engine1.QueryInterface(query, arg) // $ querystring=query + engine1.SQL(query) // $ querystring=query + engine1.Where(query) // $ querystring=query + engine1.Alias(query) // $ querystring=query + engine1.NotIn(query) // $ querystring=query + engine1.In(query) // $ querystring=query + engine1.Select(query) // $ querystring=query + engine1.SetExpr(query, nil) // $ querystring=query + engine1.OrderBy(query) // $ querystring=query + engine1.Having(query) // $ querystring=query + engine1.GroupBy(query) // $ querystring=query engine2 := xorm2.Engine{} - engine2.Query(query) // $ querystring=query - engine2.QueryString(query) // $ querystring=query - engine2.QueryInterface(query) // $ querystring=query - engine2.SQL(query) // $ querystring=query - engine2.Where(query) // $ querystring=query - engine2.Alias(query) // $ querystring=query - engine2.NotIn(query) // $ querystring=query - engine2.In(query) // $ querystring=query - engine2.Select(query) // $ querystring=query - engine2.SetExpr(query, nil) // $ querystring=query - engine2.OrderBy(query) // $ querystring=query - engine2.Having(query) // $ querystring=query - engine2.GroupBy(query) // $ querystring=query + engine2.Query(query, arg) // $ querystring=query + engine2.Exec(query, arg) // $ querystring=query + engine2.QueryString(query, arg) // $ querystring=query + engine2.QueryInterface(query, arg) // $ querystring=query + engine2.SQL(query) // $ querystring=query + engine2.Where(query) // $ querystring=query + engine2.Alias(query) // $ querystring=query + engine2.NotIn(query) // $ querystring=query + engine2.In(query) // $ querystring=query + engine2.Select(query) // $ querystring=query + engine2.SetExpr(query, nil) // $ querystring=query + engine2.OrderBy(query) // $ querystring=query + engine2.Having(query) // $ querystring=query + engine2.GroupBy(query) // $ querystring=query session1 := xorm1.Session{} - session1.Query(query) // $ querystring=query - session1.QueryString(query) // $ querystring=query - session1.QueryInterface(query) // $ querystring=query - session1.SQL(query) // $ querystring=query - session1.Where(query) // $ querystring=query - session1.Alias(query) // $ querystring=query - session1.NotIn(query) // $ querystring=query - session1.In(query) // $ querystring=query - session1.Select(query) // $ querystring=query - session1.SetExpr(query, nil) // $ querystring=query - session1.OrderBy(query) // $ querystring=query - session1.Having(query) // $ querystring=query - session1.GroupBy(query) // $ querystring=query - session1.And(query) // $ querystring=query - session1.Or(query) // $ querystring=query + session1.Query(query, arg) // $ querystring=query + session1.Exec(query, arg) // $ querystring=query + session1.QueryString(query, arg) // $ querystring=query + session1.QueryInterface(query, arg) // $ querystring=query + session1.SQL(query) // $ querystring=query + session1.Where(query) // $ querystring=query + session1.Alias(query) // $ querystring=query + session1.NotIn(query) // $ querystring=query + session1.In(query) // $ querystring=query + session1.Select(query) // $ querystring=query + session1.SetExpr(query, nil) // $ querystring=query + session1.OrderBy(query) // $ querystring=query + session1.Having(query) // $ querystring=query + session1.GroupBy(query) // $ querystring=query + session1.And(query) // $ querystring=query + session1.Or(query) // $ querystring=query session2 := xorm2.Session{} - session2.Query(query) // $ querystring=query - session2.QueryString(query) // $ querystring=query - session2.QueryInterface(query) // $ querystring=query - session2.SQL(query) // $ querystring=query - session2.Where(query) // $ querystring=query - session2.Alias(query) // $ querystring=query - session2.NotIn(query) // $ querystring=query - session2.In(query) // $ querystring=query - session2.Select(query) // $ querystring=query - session2.SetExpr(query, nil) // $ querystring=query - session2.OrderBy(query) // $ querystring=query - session2.Having(query) // $ querystring=query - session2.GroupBy(query) // $ querystring=query - session2.And(query) // $ querystring=query - session2.Or(query) // $ querystring=query + session2.Query(query, arg) // $ querystring=query + session2.Exec(query, arg) // $ querystring=query + session2.QueryString(query, arg) // $ querystring=query + session2.QueryInterface(query, arg) // $ querystring=query + session2.SQL(query) // $ querystring=query + session2.Where(query) // $ querystring=query + session2.Alias(query) // $ querystring=query + session2.NotIn(query) // $ querystring=query + session2.In(query) // $ querystring=query + session2.Select(query) // $ querystring=query + session2.SetExpr(query, nil) // $ querystring=query + session2.OrderBy(query) // $ querystring=query + session2.Having(query) // $ querystring=query + session2.GroupBy(query) // $ querystring=query + session2.And(query) // $ querystring=query + session2.Or(query) // $ querystring=query } diff --git a/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Slices.go b/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Slices.go new file mode 100644 index 00000000000..6ecc98c0a2d --- /dev/null +++ b/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Slices.go @@ -0,0 +1,193 @@ +package main + +import ( + "cmp" + "slices" + "strings" +) + +func TaintStepTest_SlicesClip(fromStringSlice []string) []string { + toStringSlice := slices.Clip(fromStringSlice) + return toStringSlice +} + +func TaintStepTest_SlicesClone(fromStringSlice []string) []string { + toStringSlice := slices.Clone(fromStringSlice) + return toStringSlice +} + +func TaintStepTest_SlicesCompact(fromStringSlice []string) []string { + toStringSlice := slices.Compact(fromStringSlice) + return toStringSlice +} + +func TaintStepTest_SlicesCompactFunc(fromStringSlice []string) []string { + toStringSlice := slices.CompactFunc(fromStringSlice, strings.EqualFold) + return toStringSlice +} + +func TaintStepTest_SlicesConcat0(fromStringSlice []string) []string { + toStringSlice := slices.Concat(fromStringSlice, []string{"a", "b", "c"}) + return toStringSlice +} + +func TaintStepTest_SlicesConcat1(fromStringSlice []string) []string { + toStringSlice := slices.Concat([]string{"a", "b", "c"}, fromStringSlice) + return toStringSlice +} + +func TaintStepTest_SlicesDelete(fromStringSlice []string) []string { + toStringSlice := slices.Delete(fromStringSlice, 0, 1) + return toStringSlice +} + +func TaintStepTest_SlicesDeleteFunc(fromStringSlice []string) []string { + deleteEmptyString := func(str string) bool { + return str == "" + } + toStringSlice := slices.DeleteFunc(fromStringSlice, deleteEmptyString) + return toStringSlice +} + +func TaintStepTest_SlicesGrow(fromStringSlice []string) []string { + toStringSlice := slices.Grow(fromStringSlice, 1) + return toStringSlice +} + +func TaintStepTest_SlicesInsert0(fromStringSlice []string) []string { + toStringSlice := slices.Insert(fromStringSlice, 1, "a", "b") + return toStringSlice +} + +func TaintStepTest_SlicesInsert2(fromString string) []string { + toStringSlice := slices.Insert([]string{}, 0, fromString, "b") + return toStringSlice +} + +func TaintStepTest_SlicesMax(fromStringSlice []string) string { + toString := slices.Max(fromStringSlice) + return toString +} + +func TaintStepTest_SlicesMaxFunc(fromStringSlice []string) string { + toString := slices.MaxFunc(fromStringSlice, cmp.Compare) + return toString +} + +func TaintStepTest_SlicesMin(fromStringSlice []string) string { + toString := slices.Min(fromStringSlice) + return toString +} + +func TaintStepTest_SlicesMinFunc(fromStringSlice []string) string { + toString := slices.MinFunc(fromStringSlice, cmp.Compare) + return toString +} + +func TaintStepTest_SlicesRepeat(fromStringSlice []string) []string { + toStringSlice := slices.Repeat(fromStringSlice, 2) + return toStringSlice +} + +func TaintStepTest_SlicesReplace0(fromStringSlice []string) []string { + toStringSlice := slices.Replace(fromStringSlice, 1, 2, "a") + return toStringSlice +} + +func TaintStepTest_SlicesReplace3(fromString string) []string { + toStringSlice := slices.Replace([]string{}, 1, 3, fromString, "b") + return toStringSlice +} + +func RunAllTaints_Slices() { + { + source := []string{newSource(0).(string)} + out := TaintStepTest_SlicesClip(source) + sink(0, out[0]) + } + { + source := []string{newSource(1).(string)} + out := TaintStepTest_SlicesClone(source) + sink(1, out[0]) + } + { + source := []string{newSource(2).(string)} + out := TaintStepTest_SlicesCompact(source) + sink(2, out[0]) + } + { + source := []string{newSource(3).(string)} + out := TaintStepTest_SlicesCompactFunc(source) + sink(3, out[0]) + } + { + source := []string{newSource(4).(string)} + out := TaintStepTest_SlicesConcat0(source) + sink(4, out[0]) + } + { + source := []string{newSource(5).(string)} + out := TaintStepTest_SlicesConcat1(source) + sink(5, out[0]) + } + { + source := []string{newSource(6).(string)} + out := TaintStepTest_SlicesDelete(source) + sink(6, out[0]) + } + { + source := []string{newSource(7).(string)} + out := TaintStepTest_SlicesDeleteFunc(source) + sink(7, out[0]) + } + { + source := []string{newSource(8).(string)} + out := TaintStepTest_SlicesGrow(source) + sink(8, out[0]) + } + { + source := []string{newSource(9).(string)} + out := TaintStepTest_SlicesInsert0(source) + sink(9, out[0]) + } + { + source := newSource(10).(string) + out := TaintStepTest_SlicesInsert2(source) + sink(10, out[0]) + } + { + source := []string{newSource(11).(string)} + out := TaintStepTest_SlicesMax(source) + sink(11, out) + } + { + source := []string{newSource(12).(string)} + out := TaintStepTest_SlicesMaxFunc(source) + sink(12, out) + } + { + source := []string{newSource(13).(string)} + out := TaintStepTest_SlicesMin(source) + sink(13, out) + } + { + source := []string{newSource(14).(string)} + out := TaintStepTest_SlicesMinFunc(source) + sink(14, out) + } + { + source := []string{newSource(15).(string)} + out := TaintStepTest_SlicesRepeat(source) + sink(15, out[0]) + } + { + source := []string{newSource(16).(string)} + out := TaintStepTest_SlicesReplace0(source) + sink(16, out[0]) + } + { + source := newSource(17).(string) + out := TaintStepTest_SlicesReplace3(source) + sink(17, out[0]) + } +} diff --git a/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/go.mod b/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/go.mod index 1481ec9caf6..4168c0a398b 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/go.mod +++ b/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/go.mod @@ -1,6 +1,6 @@ module example.com/m -go 1.20 +go 1.23 require ( golang.org/x/net v0.0.0-20201010224723-4f7140c49acb diff --git a/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/test.expected b/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/test.expected index 105b7026d0c..42831abaf15 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/test.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/test.expected @@ -1,3 +1,2 @@ -failures invalidModelRow testFailures diff --git a/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/vendor/modules.txt b/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/vendor/modules.txt index fe5007e8ae1..b11be0ff1d2 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/vendor/modules.txt +++ b/go/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/vendor/modules.txt @@ -1,3 +1,3 @@ # golang.org/x/net v0.0.0-20201010224723-4f7140c49acb -## explicit -golang.org/x/net +## explicit; go 1.11 +golang.org/x/net/context diff --git a/go/ql/test/library-tests/semmle/go/frameworks/XNetHtml/SqlInjection.expected b/go/ql/test/library-tests/semmle/go/frameworks/XNetHtml/SqlInjection.expected index c28b1058e7c..8b2f05c297f 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/XNetHtml/SqlInjection.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/XNetHtml/SqlInjection.expected @@ -1,11 +1,12 @@ #select | test.go:57:11:57:41 | call to EscapeString | test.go:56:2:56:42 | ... := ...[0] | test.go:57:11:57:41 | call to EscapeString | This query depends on a $@. | test.go:56:2:56:42 | ... := ...[0] | user-provided value | edges -| test.go:56:2:56:42 | ... := ...[0] | test.go:57:29:57:40 | selection of Value | provenance | Src:MaD:1 | -| test.go:57:29:57:40 | selection of Value | test.go:57:11:57:41 | call to EscapeString | provenance | MaD:2 | +| test.go:56:2:56:42 | ... := ...[0] | test.go:57:29:57:40 | selection of Value | provenance | Src:MaD:2 | +| test.go:57:29:57:40 | selection of Value | test.go:57:11:57:41 | call to EscapeString | provenance | MaD:3 Sink:MaD:1 | models -| 1 | Source: net/http; Request; true; Cookie; ; ; ReturnValue[0]; remote; manual | -| 2 | Summary: golang.org/x/net/html; ; false; EscapeString; ; ; Argument[0]; ReturnValue; taint; manual | +| 1 | Sink: database/sql; DB; true; Query; ; ; Argument[0]; sql-injection; manual | +| 2 | Source: net/http; Request; true; Cookie; ; ; ReturnValue[0]; remote; manual | +| 3 | Summary: golang.org/x/net/html; ; false; EscapeString; ; ; Argument[0]; ReturnValue; taint; manual | nodes | test.go:56:2:56:42 | ... := ...[0] | semmle.label | ... := ...[0] | | test.go:57:11:57:41 | call to EscapeString | semmle.label | call to EscapeString | diff --git a/go/ql/test/library-tests/semmle/go/frameworks/Yaml/tests.expected b/go/ql/test/library-tests/semmle/go/frameworks/Yaml/tests.expected index 105b7026d0c..42831abaf15 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/Yaml/tests.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/Yaml/tests.expected @@ -1,3 +1,2 @@ -failures invalidModelRow testFailures diff --git a/go/ql/test/library-tests/semmle/go/frameworks/gqlgen/gqlgen.expected b/go/ql/test/library-tests/semmle/go/frameworks/gqlgen/gqlgen.expected index 105b7026d0c..42831abaf15 100644 --- a/go/ql/test/library-tests/semmle/go/frameworks/gqlgen/gqlgen.expected +++ b/go/ql/test/library-tests/semmle/go/frameworks/gqlgen/gqlgen.expected @@ -1,3 +1,2 @@ -failures invalidModelRow testFailures diff --git a/go/ql/test/query-tests/Security/CWE-089/SqlInjection.expected b/go/ql/test/query-tests/Security/CWE-089/SqlInjection.expected index 79d8809e19f..1ce8c3d1dcf 100644 --- a/go/ql/test/query-tests/Security/CWE-089/SqlInjection.expected +++ b/go/ql/test/query-tests/Security/CWE-089/SqlInjection.expected @@ -25,53 +25,53 @@ | mongoDB.go:80:22:80:27 | filter | mongoDB.go:40:20:40:30 | call to Referer | mongoDB.go:80:22:80:27 | filter | This query depends on a $@. | mongoDB.go:40:20:40:30 | call to Referer | user-provided value | | mongoDB.go:81:18:81:25 | pipeline | mongoDB.go:40:20:40:30 | call to Referer | mongoDB.go:81:18:81:25 | pipeline | This query depends on a $@. | mongoDB.go:40:20:40:30 | call to Referer | user-provided value | edges -| SqlInjection.go:10:7:11:30 | []type{args} [array] | SqlInjection.go:10:7:11:30 | call to Sprintf | provenance | MaD:7 | -| SqlInjection.go:10:7:11:30 | call to Sprintf | SqlInjection.go:12:11:12:11 | q | provenance | | -| SqlInjection.go:11:3:11:9 | selection of URL | SqlInjection.go:11:3:11:17 | call to Query | provenance | Src:MaD:5 MaD:10 | +| SqlInjection.go:10:7:11:30 | []type{args} [array] | SqlInjection.go:10:7:11:30 | call to Sprintf | provenance | MaD:23 | +| SqlInjection.go:10:7:11:30 | call to Sprintf | SqlInjection.go:12:11:12:11 | q | provenance | Sink:MaD:1 | +| SqlInjection.go:11:3:11:9 | selection of URL | SqlInjection.go:11:3:11:17 | call to Query | provenance | Src:MaD:21 MaD:26 | | SqlInjection.go:11:3:11:17 | call to Query | SqlInjection.go:11:3:11:29 | index expression | provenance | | | SqlInjection.go:11:3:11:29 | index expression | SqlInjection.go:10:7:11:30 | []type{args} [array] | provenance | | | SqlInjection.go:11:3:11:29 | index expression | SqlInjection.go:10:7:11:30 | call to Sprintf | provenance | FunctionModel | | issue48.go:17:2:17:33 | ... := ...[0] | issue48.go:18:17:18:17 | b | provenance | | -| issue48.go:17:25:17:32 | selection of Body | issue48.go:17:2:17:33 | ... := ...[0] | provenance | Src:MaD:1 MaD:8 | -| issue48.go:18:17:18:17 | b | issue48.go:18:20:18:39 | &... | provenance | MaD:6 | +| issue48.go:17:25:17:32 | selection of Body | issue48.go:17:2:17:33 | ... := ...[0] | provenance | Src:MaD:17 MaD:24 | +| issue48.go:18:17:18:17 | b | issue48.go:18:20:18:39 | &... | provenance | MaD:22 | | issue48.go:18:20:18:39 | &... | issue48.go:21:3:21:33 | index expression | provenance | | -| issue48.go:20:8:21:34 | []type{args} [array] | issue48.go:20:8:21:34 | call to Sprintf | provenance | MaD:7 | -| issue48.go:20:8:21:34 | call to Sprintf | issue48.go:22:11:22:12 | q3 | provenance | | +| issue48.go:20:8:21:34 | []type{args} [array] | issue48.go:20:8:21:34 | call to Sprintf | provenance | MaD:23 | +| issue48.go:20:8:21:34 | call to Sprintf | issue48.go:22:11:22:12 | q3 | provenance | Sink:MaD:1 | | issue48.go:21:3:21:33 | index expression | issue48.go:20:8:21:34 | []type{args} [array] | provenance | | | issue48.go:21:3:21:33 | index expression | issue48.go:20:8:21:34 | call to Sprintf | provenance | FunctionModel | | issue48.go:27:2:27:34 | ... := ...[0] | issue48.go:28:17:28:18 | b2 | provenance | | -| issue48.go:27:26:27:33 | selection of Body | issue48.go:27:2:27:34 | ... := ...[0] | provenance | Src:MaD:1 MaD:8 | -| issue48.go:28:17:28:18 | b2 | issue48.go:28:21:28:41 | &... | provenance | MaD:6 | +| issue48.go:27:26:27:33 | selection of Body | issue48.go:27:2:27:34 | ... := ...[0] | provenance | Src:MaD:17 MaD:24 | +| issue48.go:28:17:28:18 | b2 | issue48.go:28:21:28:41 | &... | provenance | MaD:22 | | issue48.go:28:21:28:41 | &... | issue48.go:31:3:31:31 | selection of Category | provenance | | -| issue48.go:30:8:31:32 | []type{args} [array] | issue48.go:30:8:31:32 | call to Sprintf | provenance | MaD:7 | -| issue48.go:30:8:31:32 | call to Sprintf | issue48.go:32:11:32:12 | q4 | provenance | | +| issue48.go:30:8:31:32 | []type{args} [array] | issue48.go:30:8:31:32 | call to Sprintf | provenance | MaD:23 | +| issue48.go:30:8:31:32 | call to Sprintf | issue48.go:32:11:32:12 | q4 | provenance | Sink:MaD:1 | | issue48.go:31:3:31:31 | selection of Category | issue48.go:30:8:31:32 | []type{args} [array] | provenance | | | issue48.go:31:3:31:31 | selection of Category | issue48.go:30:8:31:32 | call to Sprintf | provenance | FunctionModel | -| issue48.go:37:17:37:50 | type conversion | issue48.go:37:53:37:73 | &... | provenance | MaD:6 | -| issue48.go:37:24:37:30 | selection of URL | issue48.go:37:24:37:38 | call to Query | provenance | Src:MaD:5 MaD:10 | +| issue48.go:37:17:37:50 | type conversion | issue48.go:37:53:37:73 | &... | provenance | MaD:22 | +| issue48.go:37:24:37:30 | selection of URL | issue48.go:37:24:37:38 | call to Query | provenance | Src:MaD:21 MaD:26 | | issue48.go:37:24:37:38 | call to Query | issue48.go:37:17:37:50 | type conversion | provenance | | | issue48.go:37:53:37:73 | &... | issue48.go:40:3:40:31 | selection of Category | provenance | | -| issue48.go:39:8:40:32 | []type{args} [array] | issue48.go:39:8:40:32 | call to Sprintf | provenance | MaD:7 | -| issue48.go:39:8:40:32 | call to Sprintf | issue48.go:41:11:41:12 | q5 | provenance | | +| issue48.go:39:8:40:32 | []type{args} [array] | issue48.go:39:8:40:32 | call to Sprintf | provenance | MaD:23 | +| issue48.go:39:8:40:32 | call to Sprintf | issue48.go:41:11:41:12 | q5 | provenance | Sink:MaD:1 | | issue48.go:40:3:40:31 | selection of Category | issue48.go:39:8:40:32 | []type{args} [array] | provenance | | | issue48.go:40:3:40:31 | selection of Category | issue48.go:39:8:40:32 | call to Sprintf | provenance | FunctionModel | -| main.go:11:11:11:16 | selection of Form | main.go:11:11:11:28 | index expression | provenance | Src:MaD:2 | -| main.go:15:11:15:84 | []type{args} [array] | main.go:15:11:15:84 | call to Sprintf | provenance | MaD:7 | -| main.go:15:63:15:67 | selection of URL | main.go:15:63:15:75 | call to Query | provenance | Src:MaD:5 MaD:10 | +| main.go:11:11:11:16 | selection of Form | main.go:11:11:11:28 | index expression | provenance | Src:MaD:18 Sink:MaD:1 | +| main.go:15:11:15:84 | []type{args} [array] | main.go:15:11:15:84 | call to Sprintf | provenance | MaD:23 Sink:MaD:2 | +| main.go:15:63:15:67 | selection of URL | main.go:15:63:15:75 | call to Query | provenance | Src:MaD:21 MaD:26 | | main.go:15:63:15:75 | call to Query | main.go:15:63:15:83 | index expression | provenance | | | main.go:15:63:15:83 | index expression | main.go:15:11:15:84 | []type{args} [array] | provenance | | -| main.go:15:63:15:83 | index expression | main.go:15:11:15:84 | call to Sprintf | provenance | FunctionModel | -| main.go:16:11:16:85 | []type{args} [array] | main.go:16:11:16:85 | call to Sprintf | provenance | MaD:7 | -| main.go:16:63:16:70 | selection of Header | main.go:16:63:16:84 | call to Get | provenance | Src:MaD:3 MaD:9 | +| main.go:15:63:15:83 | index expression | main.go:15:11:15:84 | call to Sprintf | provenance | FunctionModel Sink:MaD:2 | +| main.go:16:11:16:85 | []type{args} [array] | main.go:16:11:16:85 | call to Sprintf | provenance | MaD:23 Sink:MaD:2 | +| main.go:16:63:16:70 | selection of Header | main.go:16:63:16:84 | call to Get | provenance | Src:MaD:19 MaD:25 | | main.go:16:63:16:84 | call to Get | main.go:16:11:16:85 | []type{args} [array] | provenance | | -| main.go:16:63:16:84 | call to Get | main.go:16:11:16:85 | call to Sprintf | provenance | FunctionModel | +| main.go:16:63:16:84 | call to Get | main.go:16:11:16:85 | call to Sprintf | provenance | FunctionModel Sink:MaD:2 | | main.go:28:17:31:2 | &... [pointer, Category] | main.go:34:3:34:13 | RequestData [pointer, Category] | provenance | | | main.go:28:18:31:2 | struct literal [Category] | main.go:28:17:31:2 | &... [pointer, Category] | provenance | | -| main.go:30:13:30:19 | selection of URL | main.go:30:13:30:27 | call to Query | provenance | Src:MaD:5 MaD:10 | +| main.go:30:13:30:19 | selection of URL | main.go:30:13:30:27 | call to Query | provenance | Src:MaD:21 MaD:26 | | main.go:30:13:30:27 | call to Query | main.go:30:13:30:39 | index expression | provenance | | | main.go:30:13:30:39 | index expression | main.go:28:18:31:2 | struct literal [Category] | provenance | | -| main.go:33:7:34:23 | []type{args} [array] | main.go:33:7:34:23 | call to Sprintf | provenance | MaD:7 | -| main.go:33:7:34:23 | call to Sprintf | main.go:35:11:35:11 | q | provenance | | +| main.go:33:7:34:23 | []type{args} [array] | main.go:33:7:34:23 | call to Sprintf | provenance | MaD:23 | +| main.go:33:7:34:23 | call to Sprintf | main.go:35:11:35:11 | q | provenance | Sink:MaD:1 | | main.go:34:3:34:13 | RequestData [pointer, Category] | main.go:34:3:34:13 | implicit dereference [Category] | provenance | | | main.go:34:3:34:13 | implicit dereference [Category] | main.go:34:3:34:22 | selection of Category | provenance | | | main.go:34:3:34:22 | selection of Category | main.go:33:7:34:23 | []type{args} [array] | provenance | | @@ -80,11 +80,11 @@ edges | main.go:39:2:39:12 | definition of RequestData [pointer, Category] | main.go:43:3:43:13 | RequestData [pointer, Category] | provenance | | | main.go:40:2:40:12 | RequestData [pointer, Category] | main.go:40:2:40:12 | implicit dereference [Category] | provenance | | | main.go:40:2:40:12 | implicit dereference [Category] | main.go:39:2:39:12 | definition of RequestData [pointer, Category] | provenance | | -| main.go:40:25:40:31 | selection of URL | main.go:40:25:40:39 | call to Query | provenance | Src:MaD:5 MaD:10 | +| main.go:40:25:40:31 | selection of URL | main.go:40:25:40:39 | call to Query | provenance | Src:MaD:21 MaD:26 | | main.go:40:25:40:39 | call to Query | main.go:40:25:40:51 | index expression | provenance | | | main.go:40:25:40:51 | index expression | main.go:40:2:40:12 | implicit dereference [Category] | provenance | | -| main.go:42:7:43:23 | []type{args} [array] | main.go:42:7:43:23 | call to Sprintf | provenance | MaD:7 | -| main.go:42:7:43:23 | call to Sprintf | main.go:44:11:44:11 | q | provenance | | +| main.go:42:7:43:23 | []type{args} [array] | main.go:42:7:43:23 | call to Sprintf | provenance | MaD:23 | +| main.go:42:7:43:23 | call to Sprintf | main.go:44:11:44:11 | q | provenance | Sink:MaD:1 | | main.go:43:3:43:13 | RequestData [pointer, Category] | main.go:43:3:43:13 | implicit dereference [Category] | provenance | | | main.go:43:3:43:13 | implicit dereference [Category] | main.go:43:3:43:22 | selection of Category | provenance | | | main.go:43:3:43:22 | selection of Category | main.go:42:7:43:23 | []type{args} [array] | provenance | | @@ -93,11 +93,11 @@ edges | main.go:48:2:48:12 | definition of RequestData [pointer, Category] | main.go:52:3:52:13 | RequestData [pointer, Category] | provenance | | | main.go:49:3:49:14 | star expression [Category] | main.go:48:2:48:12 | definition of RequestData [pointer, Category] | provenance | | | main.go:49:4:49:14 | RequestData [pointer, Category] | main.go:49:3:49:14 | star expression [Category] | provenance | | -| main.go:49:28:49:34 | selection of URL | main.go:49:28:49:42 | call to Query | provenance | Src:MaD:5 MaD:10 | +| main.go:49:28:49:34 | selection of URL | main.go:49:28:49:42 | call to Query | provenance | Src:MaD:21 MaD:26 | | main.go:49:28:49:42 | call to Query | main.go:49:28:49:54 | index expression | provenance | | | main.go:49:28:49:54 | index expression | main.go:49:3:49:14 | star expression [Category] | provenance | | -| main.go:51:7:52:23 | []type{args} [array] | main.go:51:7:52:23 | call to Sprintf | provenance | MaD:7 | -| main.go:51:7:52:23 | call to Sprintf | main.go:53:11:53:11 | q | provenance | | +| main.go:51:7:52:23 | []type{args} [array] | main.go:51:7:52:23 | call to Sprintf | provenance | MaD:23 | +| main.go:51:7:52:23 | call to Sprintf | main.go:53:11:53:11 | q | provenance | Sink:MaD:1 | | main.go:52:3:52:13 | RequestData [pointer, Category] | main.go:52:3:52:13 | implicit dereference [Category] | provenance | | | main.go:52:3:52:13 | implicit dereference [Category] | main.go:52:3:52:22 | selection of Category | provenance | | | main.go:52:3:52:22 | selection of Category | main.go:51:7:52:23 | []type{args} [array] | provenance | | @@ -106,44 +106,60 @@ edges | main.go:57:2:57:12 | definition of RequestData [pointer, Category] | main.go:61:5:61:15 | RequestData [pointer, Category] | provenance | | | main.go:58:3:58:14 | star expression [Category] | main.go:57:2:57:12 | definition of RequestData [pointer, Category] | provenance | | | main.go:58:4:58:14 | RequestData [pointer, Category] | main.go:58:3:58:14 | star expression [Category] | provenance | | -| main.go:58:28:58:34 | selection of URL | main.go:58:28:58:42 | call to Query | provenance | Src:MaD:5 MaD:10 | +| main.go:58:28:58:34 | selection of URL | main.go:58:28:58:42 | call to Query | provenance | Src:MaD:21 MaD:26 | | main.go:58:28:58:42 | call to Query | main.go:58:28:58:54 | index expression | provenance | | | main.go:58:28:58:54 | index expression | main.go:58:3:58:14 | star expression [Category] | provenance | | -| main.go:60:7:61:26 | []type{args} [array] | main.go:60:7:61:26 | call to Sprintf | provenance | MaD:7 | -| main.go:60:7:61:26 | call to Sprintf | main.go:62:11:62:11 | q | provenance | | +| main.go:60:7:61:26 | []type{args} [array] | main.go:60:7:61:26 | call to Sprintf | provenance | MaD:23 | +| main.go:60:7:61:26 | call to Sprintf | main.go:62:11:62:11 | q | provenance | Sink:MaD:1 | | main.go:61:3:61:25 | selection of Category | main.go:60:7:61:26 | []type{args} [array] | provenance | | | main.go:61:3:61:25 | selection of Category | main.go:60:7:61:26 | call to Sprintf | provenance | FunctionModel | | main.go:61:4:61:15 | star expression [Category] | main.go:61:3:61:25 | selection of Category | provenance | | | main.go:61:5:61:15 | RequestData [pointer, Category] | main.go:61:4:61:15 | star expression [Category] | provenance | | -| mongoDB.go:40:20:40:30 | call to Referer | mongoDB.go:42:28:42:41 | untrustedInput | provenance | Src:MaD:4 | +| mongoDB.go:40:20:40:30 | call to Referer | mongoDB.go:42:28:42:41 | untrustedInput | provenance | Src:MaD:20 | | mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:50:34:50:39 | filter | provenance | | -| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:61:27:61:32 | filter | provenance | | -| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:63:23:63:28 | filter | provenance | | -| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:64:22:64:27 | filter | provenance | | -| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:66:32:66:37 | filter | provenance | | -| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:69:17:69:22 | filter | provenance | | -| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:70:20:70:25 | filter | provenance | | -| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:71:29:71:34 | filter | provenance | | -| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:72:30:72:35 | filter | provenance | | -| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:73:29:73:34 | filter | provenance | | -| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:78:23:78:28 | filter | provenance | | -| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:79:23:79:28 | filter | provenance | | -| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:80:22:80:27 | filter | provenance | | +| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:61:27:61:32 | filter | provenance | Sink:MaD:4 | +| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:63:23:63:28 | filter | provenance | Sink:MaD:5 | +| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:64:22:64:27 | filter | provenance | Sink:MaD:6 | +| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:66:32:66:37 | filter | provenance | Sink:MaD:7 | +| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:69:17:69:22 | filter | provenance | Sink:MaD:8 | +| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:70:20:70:25 | filter | provenance | Sink:MaD:9 | +| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:71:29:71:34 | filter | provenance | Sink:MaD:10 | +| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:72:30:72:35 | filter | provenance | Sink:MaD:11 | +| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:73:29:73:34 | filter | provenance | Sink:MaD:12 | +| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:78:23:78:28 | filter | provenance | Sink:MaD:13 | +| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:79:23:79:28 | filter | provenance | Sink:MaD:14 | +| mongoDB.go:42:19:42:42 | struct literal | mongoDB.go:80:22:80:27 | filter | provenance | Sink:MaD:15 | | mongoDB.go:42:28:42:41 | untrustedInput | mongoDB.go:42:19:42:42 | struct literal | provenance | Config | -| mongoDB.go:50:23:50:40 | struct literal | mongoDB.go:57:22:57:29 | pipeline | provenance | | -| mongoDB.go:50:23:50:40 | struct literal | mongoDB.go:81:18:81:25 | pipeline | provenance | | +| mongoDB.go:50:23:50:40 | struct literal | mongoDB.go:57:22:57:29 | pipeline | provenance | Sink:MaD:3 | +| mongoDB.go:50:23:50:40 | struct literal | mongoDB.go:81:18:81:25 | pipeline | provenance | Sink:MaD:16 | | mongoDB.go:50:34:50:39 | filter | mongoDB.go:50:23:50:40 | struct literal | provenance | Config | models -| 1 | Source: net/http; Request; true; Body; ; ; ; remote; manual | -| 2 | Source: net/http; Request; true; Form; ; ; ; remote; manual | -| 3 | Source: net/http; Request; true; Header; ; ; ; remote; manual | -| 4 | Source: net/http; Request; true; Referer; ; ; ReturnValue; remote; manual | -| 5 | Source: net/http; Request; true; URL; ; ; ; remote; manual | -| 6 | Summary: encoding/json; ; false; Unmarshal; ; ; Argument[0]; Argument[1]; taint; manual | -| 7 | Summary: fmt; ; false; Sprintf; ; ; Argument[1].ArrayElement; ReturnValue; taint; manual | -| 8 | Summary: io/ioutil; ; false; ReadAll; ; ; Argument[0]; ReturnValue[0]; taint; manual | -| 9 | Summary: net/http; Header; true; Get; ; ; Argument[receiver]; ReturnValue; taint; manual | -| 10 | Summary: net/url; URL; true; Query; ; ; Argument[receiver]; ReturnValue; taint; manual | +| 1 | Sink: database/sql; DB; true; Query; ; ; Argument[0]; sql-injection; manual | +| 2 | Sink: database/sql; Tx; true; Query; ; ; Argument[0]; sql-injection; manual | +| 3 | Sink: go.mongodb.org/mongo-driver/mongo; Collection; true; Aggregate; ; ; Argument[1]; nosql-injection; manual | +| 4 | Sink: go.mongodb.org/mongo-driver/mongo; Collection; true; CountDocuments; ; ; Argument[1]; nosql-injection; manual | +| 5 | Sink: go.mongodb.org/mongo-driver/mongo; Collection; true; DeleteMany; ; ; Argument[1]; nosql-injection; manual | +| 6 | Sink: go.mongodb.org/mongo-driver/mongo; Collection; true; DeleteOne; ; ; Argument[1]; nosql-injection; manual | +| 7 | Sink: go.mongodb.org/mongo-driver/mongo; Collection; true; Distinct; ; ; Argument[2]; nosql-injection; manual | +| 8 | Sink: go.mongodb.org/mongo-driver/mongo; Collection; true; Find; ; ; Argument[1]; nosql-injection; manual | +| 9 | Sink: go.mongodb.org/mongo-driver/mongo; Collection; true; FindOne; ; ; Argument[1]; nosql-injection; manual | +| 10 | Sink: go.mongodb.org/mongo-driver/mongo; Collection; true; FindOneAndDelete; ; ; Argument[1]; nosql-injection; manual | +| 11 | Sink: go.mongodb.org/mongo-driver/mongo; Collection; true; FindOneAndReplace; ; ; Argument[1]; nosql-injection; manual | +| 12 | Sink: go.mongodb.org/mongo-driver/mongo; Collection; true; FindOneAndUpdate; ; ; Argument[1]; nosql-injection; manual | +| 13 | Sink: go.mongodb.org/mongo-driver/mongo; Collection; true; ReplaceOne; ; ; Argument[1]; nosql-injection; manual | +| 14 | Sink: go.mongodb.org/mongo-driver/mongo; Collection; true; UpdateMany; ; ; Argument[1]; nosql-injection; manual | +| 15 | Sink: go.mongodb.org/mongo-driver/mongo; Collection; true; UpdateOne; ; ; Argument[1]; nosql-injection; manual | +| 16 | Sink: go.mongodb.org/mongo-driver/mongo; Collection; true; Watch; ; ; Argument[1]; nosql-injection; manual | +| 17 | Source: net/http; Request; true; Body; ; ; ; remote; manual | +| 18 | Source: net/http; Request; true; Form; ; ; ; remote; manual | +| 19 | Source: net/http; Request; true; Header; ; ; ; remote; manual | +| 20 | Source: net/http; Request; true; Referer; ; ; ReturnValue; remote; manual | +| 21 | Source: net/http; Request; true; URL; ; ; ; remote; manual | +| 22 | Summary: encoding/json; ; false; Unmarshal; ; ; Argument[0]; Argument[1]; taint; manual | +| 23 | Summary: fmt; ; false; Sprintf; ; ; Argument[1].ArrayElement; ReturnValue; taint; manual | +| 24 | Summary: io/ioutil; ; false; ReadAll; ; ; Argument[0]; ReturnValue[0]; taint; manual | +| 25 | Summary: net/http; Header; true; Get; ; ; Argument[receiver]; ReturnValue; taint; manual | +| 26 | Summary: net/url; URL; true; Query; ; ; Argument[receiver]; ReturnValue; taint; manual | nodes | SqlInjection.go:10:7:11:30 | []type{args} [array] | semmle.label | []type{args} [array] | | SqlInjection.go:10:7:11:30 | call to Sprintf | semmle.label | call to Sprintf | diff --git a/go/ql/test/query-tests/Security/CWE-117/LogInjection.go b/go/ql/test/query-tests/Security/CWE-117/LogInjection.go index 4f02cc9aef8..6fb628c4cc3 100644 --- a/go/ql/test/query-tests/Security/CWE-117/LogInjection.go +++ b/go/ql/test/query-tests/Security/CWE-117/LogInjection.go @@ -7,7 +7,7 @@ package main //go:generate depstubber -vendor github.com/davecgh/go-spew/spew "" Dump,Errorf,Print,Printf,Println,Fdump,Fprint,Fprintf,Fprintln //go:generate depstubber -vendor github.com/elazarl/goproxy ProxyCtx "" //go:generate depstubber -vendor github.com/golang/glog Level,Verbose Info,InfoDepth,Infof,Infoln,Error,ErrorDepth,Errorf,Errorln,Fatal,FatalDepth,Fatalf,Fatalln,Exit,ExitDepth,Exitf,Exitln,V -//go:generate depstubber -vendor github.com/sirupsen/logrus Fields,Entry,Logger,Level Debug,Debugf,Debugln,Error,Errorf,Errorln,Fatal,Fatalf,Fatalln,Info,Infof,Infoln,Panic,Panicf,Panicln,Print,Printf,Println,Trace,Tracef,Traceln,Warn,Warnf,Warnln,Warning,Warningf,Warningln,WithFields,WithField +//go:generate depstubber -vendor github.com/sirupsen/logrus FieldLogger,Fields,Entry,Logger,Level Debug,Debugf,Debugln,Error,Errorf,Errorln,Fatal,Fatalf,Fatalln,Info,Infof,Infoln,New,NewEntry,Panic,Panicf,Panicln,Print,Printf,Println,Trace,Tracef,Traceln,Warn,Warnf,Warnln,Warning,Warningf,Warningln,WithError,WithFields,WithField //go:generate depstubber -vendor go.uber.org/zap Logger,SugaredLogger NewProduction import ( @@ -30,6 +30,7 @@ import ( func handler(req *http.Request, ctx *goproxy.ProxyCtx) { username := req.URL.Query()["username"][0] + slice := []any{"username", username} testFlag := req.URL.Query()["testFlag"][0] { @@ -170,129 +171,180 @@ func handler(req *http.Request, ctx *goproxy.ProxyCtx) { } // sirupsen/logrus { - logrus.Debug(username) // $ hasTaintFlow="username" - logrus.Debugf(username, "") // $ hasTaintFlow="username" - logrus.Debugf("", username) // $ hasTaintFlow="username" - logrus.Debugln(username) // $ hasTaintFlow="username" - logrus.Error(username) // $ hasTaintFlow="username" - logrus.Errorf(username, "") // $ hasTaintFlow="username" - logrus.Errorf("", username) // $ hasTaintFlow="username" - logrus.Errorln(username) // $ hasTaintFlow="username" - logrus.Fatal(username) // $ hasTaintFlow="username" - logrus.Fatalf(username, "") // $ hasTaintFlow="username" - logrus.Fatalf("", username) // $ hasTaintFlow="username" - logrus.Fatalln(username) // $ hasTaintFlow="username" - logrus.Info(username) // $ hasTaintFlow="username" - logrus.Infof(username, "") // $ hasTaintFlow="username" - logrus.Infof("", username) // $ hasTaintFlow="username" - logrus.Infoln(username) // $ hasTaintFlow="username" - logrus.Panic(username) // $ hasTaintFlow="username" - logrus.Panicf(username, "") // $ hasTaintFlow="username" - logrus.Panicf("", username) // $ hasTaintFlow="username" - logrus.Panicln(username) // $ hasTaintFlow="username" - logrus.Print(username) // $ hasTaintFlow="username" - logrus.Printf(username, "") // $ hasTaintFlow="username" - logrus.Printf("", username) // $ hasTaintFlow="username" - logrus.Println(username) // $ hasTaintFlow="username" - logrus.Trace(username) // $ hasTaintFlow="username" - logrus.Tracef(username, "") // $ hasTaintFlow="username" - logrus.Tracef("", username) // $ hasTaintFlow="username" - logrus.Traceln(username) // $ hasTaintFlow="username" - logrus.Warn(username) // $ hasTaintFlow="username" - logrus.Warnf(username, "") // $ hasTaintFlow="username" - logrus.Warnf("", username) // $ hasTaintFlow="username" - logrus.Warnln(username) // $ hasTaintFlow="username" - logrus.Warning(username) // $ hasTaintFlow="username" - logrus.Warningf(username, "") // $ hasTaintFlow="username" - logrus.Warningf("", username) // $ hasTaintFlow="username" - logrus.Warningln(username) // $ hasTaintFlow="username" - + err := fmt.Errorf("error: %s", username) fields := make(logrus.Fields) fields["username"] = username - entry := logrus.WithFields(fields) // $ hasTaintFlow="fields" - entry = logrus.WithField("username", username) // $ hasTaintFlow="username" - entry.Debug(username) // $ hasTaintFlow="username" - entry.Debugf(username, "") // $ hasTaintFlow="username" - entry.Debugf("", username) // $ hasTaintFlow="username" - entry.Debugln(username) // $ hasTaintFlow="username" - entry.Error(username) // $ hasTaintFlow="username" - entry.Errorf(username, "") // $ hasTaintFlow="username" - entry.Errorf("", username) // $ hasTaintFlow="username" - entry.Errorln(username) // $ hasTaintFlow="username" - entry.Fatal(username) // $ hasTaintFlow="username" - entry.Fatalf(username, "") // $ hasTaintFlow="username" - entry.Fatalf("", username) // $ hasTaintFlow="username" - entry.Fatalln(username) // $ hasTaintFlow="username" - entry.Info(username) // $ hasTaintFlow="username" - entry.Infof(username, "") // $ hasTaintFlow="username" - entry.Infof("", username) // $ hasTaintFlow="username" - entry.Infoln(username) // $ hasTaintFlow="username" - entry.Log(0, username) // $ hasTaintFlow="username" - entry.Logf(0, username, "") // $ hasTaintFlow="username" - entry.Logf(0, "", username) // $ hasTaintFlow="username" - entry.Logln(0, username) // $ hasTaintFlow="username" - entry.Panic(username) // $ hasTaintFlow="username" - entry.Panicf(username, "") // $ hasTaintFlow="username" - entry.Panicf("", username) // $ hasTaintFlow="username" - entry.Panicln(username) // $ hasTaintFlow="username" - entry.Print(username) // $ hasTaintFlow="username" - entry.Printf(username, "") // $ hasTaintFlow="username" - entry.Printf("", username) // $ hasTaintFlow="username" - entry.Println(username) // $ hasTaintFlow="username" - entry.Trace(username) // $ hasTaintFlow="username" - entry.Tracef(username, "") // $ hasTaintFlow="username" - entry.Tracef("", username) // $ hasTaintFlow="username" - entry.Traceln(username) // $ hasTaintFlow="username" - entry.Warn(username) // $ hasTaintFlow="username" - entry.Warnf(username, "") // $ hasTaintFlow="username" - entry.Warnf("", username) // $ hasTaintFlow="username" - entry.Warnln(username) // $ hasTaintFlow="username" - entry.Warning(username) // $ hasTaintFlow="username" - entry.Warningf(username, "") // $ hasTaintFlow="username" - entry.Warningf("", username) // $ hasTaintFlow="username" - entry.Warningln(username) // $ hasTaintFlow="username" + logger := logrus.New() + entry := logrus.NewEntry(logger) - logger := entry.Logger - logger.Debug(username) // $ hasTaintFlow="username" - logger.Debugf(username, "") // $ hasTaintFlow="username" - logger.Debugf("", username) // $ hasTaintFlow="username" - logger.Debugln(username) // $ hasTaintFlow="username" - logger.Error(username) // $ hasTaintFlow="username" - logger.Errorf(username, "") // $ hasTaintFlow="username" - logger.Errorf("", username) // $ hasTaintFlow="username" - logger.Errorln(username) // $ hasTaintFlow="username" - logger.Fatal(username) // $ hasTaintFlow="username" - logger.Fatalf(username, "") // $ hasTaintFlow="username" - logger.Fatalf("", username) // $ hasTaintFlow="username" - logger.Fatalln(username) // $ hasTaintFlow="username" - logger.Info(username) // $ hasTaintFlow="username" - logger.Infof(username, "") // $ hasTaintFlow="username" - logger.Infof("", username) // $ hasTaintFlow="username" - logger.Infoln(username) // $ hasTaintFlow="username" - logger.Log(0, username) // $ hasTaintFlow="username" - logger.Logf(0, username, "") // $ hasTaintFlow="username" - logger.Logf(0, "", username) // $ hasTaintFlow="username" - logger.Logln(0, username) // $ hasTaintFlow="username" - logger.Panic(username) // $ hasTaintFlow="username" - logger.Panicf(username, "") // $ hasTaintFlow="username" - logger.Panicf("", username) // $ hasTaintFlow="username" - logger.Panicln(username) // $ hasTaintFlow="username" - logger.Print(username) // $ hasTaintFlow="username" - logger.Printf(username, "") // $ hasTaintFlow="username" - logger.Printf("", username) // $ hasTaintFlow="username" - logger.Println(username) // $ hasTaintFlow="username" - logger.Trace(username) // $ hasTaintFlow="username" - logger.Tracef(username, "") // $ hasTaintFlow="username" - logger.Tracef("", username) // $ hasTaintFlow="username" - logger.Traceln(username) // $ hasTaintFlow="username" - logger.Warn(username) // $ hasTaintFlow="username" - logger.Warnf(username, "") // $ hasTaintFlow="username" - logger.Warnf("", username) // $ hasTaintFlow="username" - logger.Warnln(username) // $ hasTaintFlow="username" - logger.Warning(username) // $ hasTaintFlow="username" - logger.Warningf(username, "") // $ hasTaintFlow="username" - logger.Warningf("", username) // $ hasTaintFlow="username" - logger.Warningln(username) // $ hasTaintFlow="username" + logrus.Debug(username) // $ hasTaintFlow="username" + logrus.Debugf(username, "") // $ hasTaintFlow="username" + logrus.Debugf("", username) // $ hasTaintFlow="username" + logrus.Debugln(username) // $ hasTaintFlow="username" + logrus.Error(username) // $ hasTaintFlow="username" + logrus.Errorf(username, "") // $ hasTaintFlow="username" + logrus.Errorf("", username) // $ hasTaintFlow="username" + logrus.Errorln(username) // $ hasTaintFlow="username" + logrus.Fatal(username) // $ hasTaintFlow="username" + logrus.Fatalf(username, "") // $ hasTaintFlow="username" + logrus.Fatalf("", username) // $ hasTaintFlow="username" + logrus.Fatalln(username) // $ hasTaintFlow="username" + logrus.Info(username) // $ hasTaintFlow="username" + logrus.Infof(username, "") // $ hasTaintFlow="username" + logrus.Infof("", username) // $ hasTaintFlow="username" + logrus.Infoln(username) // $ hasTaintFlow="username" + logrus.Panic(username) // $ hasTaintFlow="username" + logrus.Panicf(username, "") // $ hasTaintFlow="username" + logrus.Panicf("", username) // $ hasTaintFlow="username" + logrus.Panicln(username) // $ hasTaintFlow="username" + logrus.Print(username) // $ hasTaintFlow="username" + logrus.Printf(username, "") // $ hasTaintFlow="username" + logrus.Printf("", username) // $ hasTaintFlow="username" + logrus.Println(username) // $ hasTaintFlow="username" + logrus.Trace(username) // $ hasTaintFlow="username" + logrus.Tracef(username, "") // $ hasTaintFlow="username" + logrus.Tracef("", username) // $ hasTaintFlow="username" + logrus.Traceln(username) // $ hasTaintFlow="username" + logrus.Warn(username) // $ hasTaintFlow="username" + logrus.Warnf(username, "") // $ hasTaintFlow="username" + logrus.Warnf("", username) // $ hasTaintFlow="username" + logrus.Warnln(username) // $ hasTaintFlow="username" + logrus.Warning(username) // $ hasTaintFlow="username" + logrus.Warningf(username, "") // $ hasTaintFlow="username" + logrus.Warningf("", username) // $ hasTaintFlow="username" + logrus.Warningln(username) // $ hasTaintFlow="username" + logrus.WithError(err) // $ hasTaintFlow="err" + logrus.WithField(username, "") // $ hasTaintFlow="username" + logrus.WithField("", username) // $ hasTaintFlow="username" + logrus.WithFields(fields) // $ hasTaintFlow="fields" + + entry.Debug(username) // $ hasTaintFlow="username" + entry.Debugf(username, "") // $ hasTaintFlow="username" + entry.Debugf("", username) // $ hasTaintFlow="username" + entry.Debugln(username) // $ hasTaintFlow="username" + entry.Error(username) // $ hasTaintFlow="username" + entry.Errorf(username, "") // $ hasTaintFlow="username" + entry.Errorf("", username) // $ hasTaintFlow="username" + entry.Errorln(username) // $ hasTaintFlow="username" + entry.Fatal(username) // $ hasTaintFlow="username" + entry.Fatalf(username, "") // $ hasTaintFlow="username" + entry.Fatalf("", username) // $ hasTaintFlow="username" + entry.Fatalln(username) // $ hasTaintFlow="username" + entry.Info(username) // $ hasTaintFlow="username" + entry.Infof(username, "") // $ hasTaintFlow="username" + entry.Infof("", username) // $ hasTaintFlow="username" + entry.Infoln(username) // $ hasTaintFlow="username" + entry.Log(0, username) // $ hasTaintFlow="username" + entry.Logf(0, username, "") // $ hasTaintFlow="username" + entry.Logf(0, "", username) // $ hasTaintFlow="username" + entry.Logln(0, username) // $ hasTaintFlow="username" + entry.Panic(username) // $ hasTaintFlow="username" + entry.Panicf(username, "") // $ hasTaintFlow="username" + entry.Panicf("", username) // $ hasTaintFlow="username" + entry.Panicln(username) // $ hasTaintFlow="username" + entry.Print(username) // $ hasTaintFlow="username" + entry.Printf(username, "") // $ hasTaintFlow="username" + entry.Printf("", username) // $ hasTaintFlow="username" + entry.Println(username) // $ hasTaintFlow="username" + entry.Trace(username) // $ hasTaintFlow="username" + entry.Tracef(username, "") // $ hasTaintFlow="username" + entry.Tracef("", username) // $ hasTaintFlow="username" + entry.Traceln(username) // $ hasTaintFlow="username" + entry.Warn(username) // $ hasTaintFlow="username" + entry.Warnf(username, "") // $ hasTaintFlow="username" + entry.Warnf("", username) // $ hasTaintFlow="username" + entry.Warnln(username) // $ hasTaintFlow="username" + entry.Warning(username) // $ hasTaintFlow="username" + entry.Warningf(username, "") // $ hasTaintFlow="username" + entry.Warningf("", username) // $ hasTaintFlow="username" + entry.Warningln(username) // $ hasTaintFlow="username" + entry.WithError(err) // $ hasTaintFlow="err" + entry.WithField(username, "") // $ hasTaintFlow="username" + entry.WithField("", username) // $ hasTaintFlow="username" + entry.WithFields(fields) // $ hasTaintFlow="fields" + + logger.Debug(username) // $ hasTaintFlow="username" + logger.Debugf(username, "") // $ hasTaintFlow="username" + logger.Debugf("", username) // $ hasTaintFlow="username" + logger.Debugln(username) // $ hasTaintFlow="username" + logger.Error(username) // $ hasTaintFlow="username" + logger.Errorf(username, "") // $ hasTaintFlow="username" + logger.Errorf("", username) // $ hasTaintFlow="username" + logger.Errorln(username) // $ hasTaintFlow="username" + logger.Fatal(username) // $ hasTaintFlow="username" + logger.Fatalf(username, "") // $ hasTaintFlow="username" + logger.Fatalf("", username) // $ hasTaintFlow="username" + logger.Fatalln(username) // $ hasTaintFlow="username" + logger.Info(username) // $ hasTaintFlow="username" + logger.Infof(username, "") // $ hasTaintFlow="username" + logger.Infof("", username) // $ hasTaintFlow="username" + logger.Infoln(username) // $ hasTaintFlow="username" + logger.Log(0, username) // $ hasTaintFlow="username" + logger.Logf(0, username, "") // $ hasTaintFlow="username" + logger.Logf(0, "", username) // $ hasTaintFlow="username" + logger.Logln(0, username) // $ hasTaintFlow="username" + logger.Panic(username) // $ hasTaintFlow="username" + logger.Panicf(username, "") // $ hasTaintFlow="username" + logger.Panicf("", username) // $ hasTaintFlow="username" + logger.Panicln(username) // $ hasTaintFlow="username" + logger.Print(username) // $ hasTaintFlow="username" + logger.Printf(username, "") // $ hasTaintFlow="username" + logger.Printf("", username) // $ hasTaintFlow="username" + logger.Println(username) // $ hasTaintFlow="username" + logger.Trace(username) // $ hasTaintFlow="username" + logger.Tracef(username, "") // $ hasTaintFlow="username" + logger.Tracef("", username) // $ hasTaintFlow="username" + logger.Traceln(username) // $ hasTaintFlow="username" + logger.Warn(username) // $ hasTaintFlow="username" + logger.Warnf(username, "") // $ hasTaintFlow="username" + logger.Warnf("", username) // $ hasTaintFlow="username" + logger.Warnln(username) // $ hasTaintFlow="username" + logger.Warning(username) // $ hasTaintFlow="username" + logger.Warningf(username, "") // $ hasTaintFlow="username" + logger.Warningf("", username) // $ hasTaintFlow="username" + logger.Warningln(username) // $ hasTaintFlow="username" + logger.WithError(err) // $ hasTaintFlow="err" + logger.WithField(username, "") // $ hasTaintFlow="username" + logger.WithField("", username) // $ hasTaintFlow="username" + logger.WithFields(fields) // $ hasTaintFlow="fields" + + var fieldlogger logrus.FieldLogger = entry + fieldlogger.Debug(username) // $ hasTaintFlow="username" + fieldlogger.Debugf(username, "") // $ hasTaintFlow="username" + fieldlogger.Debugf("", username) // $ hasTaintFlow="username" + fieldlogger.Debugln(username) // $ hasTaintFlow="username" + fieldlogger.Error(username) // $ hasTaintFlow="username" + fieldlogger.Errorf(username, "") // $ hasTaintFlow="username" + fieldlogger.Errorf("", username) // $ hasTaintFlow="username" + fieldlogger.Errorln(username) // $ hasTaintFlow="username" + fieldlogger.Fatal(username) // $ hasTaintFlow="username" + fieldlogger.Fatalf(username, "") // $ hasTaintFlow="username" + fieldlogger.Fatalf("", username) // $ hasTaintFlow="username" + fieldlogger.Fatalln(username) // $ hasTaintFlow="username" + fieldlogger.Info(username) // $ hasTaintFlow="username" + fieldlogger.Infof(username, "") // $ hasTaintFlow="username" + fieldlogger.Infof("", username) // $ hasTaintFlow="username" + fieldlogger.Infoln(username) // $ hasTaintFlow="username" + fieldlogger.Panic(username) // $ hasTaintFlow="username" + fieldlogger.Panicf(username, "") // $ hasTaintFlow="username" + fieldlogger.Panicf("", username) // $ hasTaintFlow="username" + fieldlogger.Panicln(username) // $ hasTaintFlow="username" + fieldlogger.Print(username) // $ hasTaintFlow="username" + fieldlogger.Printf(username, "") // $ hasTaintFlow="username" + fieldlogger.Printf("", username) // $ hasTaintFlow="username" + fieldlogger.Println(username) // $ hasTaintFlow="username" + fieldlogger.Warn(username) // $ hasTaintFlow="username" + fieldlogger.Warnf(username, "") // $ hasTaintFlow="username" + fieldlogger.Warnf("", username) // $ hasTaintFlow="username" + fieldlogger.Warnln(username) // $ hasTaintFlow="username" + fieldlogger.Warning(username) // $ hasTaintFlow="username" + fieldlogger.Warningf(username, "") // $ hasTaintFlow="username" + fieldlogger.Warningf("", username) // $ hasTaintFlow="username" + fieldlogger.Warningln(username) // $ hasTaintFlow="username" + fieldlogger.WithError(err) // $ hasTaintFlow="err" + fieldlogger.WithField(username, "") // $ hasTaintFlow="username" + fieldlogger.WithField("", username) // $ hasTaintFlow="username" + fieldlogger.WithFields(fields) // $ hasTaintFlow="fields" } // davecgh/go-spew/spew { @@ -361,8 +413,34 @@ func handler(req *http.Request, ctx *goproxy.ProxyCtx) { sLogger.Named(username) // $ hasTaintFlow="username" sLogger.With(username) // $ hasTaintFlow="username" } + // heuristic logger interface + { + logger.Printf(username) // $ hasTaintFlow="username" + logger.Printf("%s", username) // $ hasTaintFlow="username" + simpleLogger.Tracew(username) // $ hasTaintFlow="username" + simpleLogger.Tracew("%s", username) // $ hasTaintFlow="username" + simpleLogger.Debugw("%s %s", slice...) // $ hasTaintFlow="slice" + } + } +type Logger interface { + Printf(string, ...interface{}) +} + +type SimpleLogger interface { + Debugw(msg string, keysAndValues ...any) + Infow(msg string, keysAndValues ...any) + Warnw(msg string, keysAndValues ...any) + Errorw(msg string, keysAndValues ...any) + Tracew(msg string, keysAndValues ...any) +} + +var ( + logger Logger + simpleLogger SimpleLogger +) + // GOOD: The user-provided value is escaped before being written to the log. func handlerGood(req *http.Request) { username := req.URL.Query()["username"][0] @@ -598,5 +676,4 @@ func handlerGood4(req *http.Request, ctx *goproxy.ProxyCtx) { } sLogger.Warnf("user %#q logged in.\n", username) // $ hasTaintFlow="username" } - } diff --git a/go/ql/test/query-tests/Security/CWE-117/go.mod b/go/ql/test/query-tests/Security/CWE-117/go.mod index 57b2077a4ed..906d90f31b6 100644 --- a/go/ql/test/query-tests/Security/CWE-117/go.mod +++ b/go/ql/test/query-tests/Security/CWE-117/go.mod @@ -1,14 +1,33 @@ module main -go 1.14 +go 1.23 require ( github.com/astaxie/beego v1.12.3 + github.com/davecgh/go-spew v1.1.1 github.com/elazarl/goproxy v0.0.0-20211114080932-d06c3be7c11b github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b - github.com/kr/text v0.2.0 // indirect github.com/sirupsen/logrus v1.8.1 - github.com/stretchr/testify v1.6.0 // indirect - golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f // indirect + go.uber.org/zap v1.27.0 k8s.io/klog v1.0.0 ) + +require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.1.1 // indirect + github.com/golang/protobuf v1.4.2 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/prometheus/client_golang v1.7.0 // indirect + github.com/prometheus/client_model v0.2.0 // indirect + github.com/prometheus/common v0.10.0 // indirect + github.com/prometheus/procfs v0.1.3 // indirect + github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect + go.uber.org/multierr v1.10.0 // indirect + golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 // indirect + golang.org/x/net v0.0.0-20190620200207-3b0461eec859 // indirect + golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f // indirect + golang.org/x/text v0.3.0 // indirect + google.golang.org/protobuf v1.23.0 // indirect + gopkg.in/yaml.v2 v2.2.8 // indirect +) diff --git a/go/ql/test/query-tests/Security/CWE-117/vendor/github.com/sirupsen/logrus/stub.go b/go/ql/test/query-tests/Security/CWE-117/vendor/github.com/sirupsen/logrus/stub.go index e8f7bccc446..497d85559bb 100644 --- a/go/ql/test/query-tests/Security/CWE-117/vendor/github.com/sirupsen/logrus/stub.go +++ b/go/ql/test/query-tests/Security/CWE-117/vendor/github.com/sirupsen/logrus/stub.go @@ -2,7 +2,7 @@ // This is a simple stub for github.com/sirupsen/logrus, strictly for use in testing. // See the LICENSE file for information about the licensing of the original library. -// Source: github.com/sirupsen/logrus (exports: Fields,Entry,Logger,Level; functions: Debug,Debugf,Debugln,Error,Errorf,Errorln,Fatal,Fatalf,Fatalln,Info,Infof,Infoln,Panic,Panicf,Panicln,Print,Printf,Println,Trace,Tracef,Traceln,Warn,Warnf,Warnln,Warning,Warningf,Warningln,WithFields,WithField) +// Source: github.com/sirupsen/logrus (exports: FieldLogger,Fields,Entry,Logger,Level; functions: Debug,Debugf,Debugln,Error,Errorf,Errorln,Fatal,Fatalf,Fatalln,Info,Infof,Infoln,New,NewEntry,Panic,Panicf,Panicln,Print,Printf,Println,Trace,Tracef,Traceln,Warn,Warnf,Warnln,Warning,Warningf,Warningln,WithError,WithFields,WithField) // Package logrus is a stub of github.com/sirupsen/logrus, generated by depstubber. package logrus @@ -148,6 +148,36 @@ func Fatalf(_ string, _ ...interface{}) {} func Fatalln(_ ...interface{}) {} +type FieldLogger interface { + Debug(_ ...interface{}) + Debugf(_ string, _ ...interface{}) + Debugln(_ ...interface{}) + Error(_ ...interface{}) + Errorf(_ string, _ ...interface{}) + Errorln(_ ...interface{}) + Fatal(_ ...interface{}) + Fatalf(_ string, _ ...interface{}) + Fatalln(_ ...interface{}) + Info(_ ...interface{}) + Infof(_ string, _ ...interface{}) + Infoln(_ ...interface{}) + Panic(_ ...interface{}) + Panicf(_ string, _ ...interface{}) + Panicln(_ ...interface{}) + Print(_ ...interface{}) + Printf(_ string, _ ...interface{}) + Println(_ ...interface{}) + Warn(_ ...interface{}) + Warnf(_ string, _ ...interface{}) + Warning(_ ...interface{}) + Warningf(_ string, _ ...interface{}) + Warningln(_ ...interface{}) + Warnln(_ ...interface{}) + WithError(_ error) *Entry + WithField(_ string, _ interface{}) *Entry + WithFields(_ Fields) *Entry +} + type Fields map[string]interface{} type Formatter interface { @@ -332,6 +362,14 @@ func (_ *Logger) WriterLevel(_ Level) *io.PipeWriter { return nil } +func New() *Logger { + return nil +} + +func NewEntry(_ *Logger) *Entry { + return nil +} + func Panic(_ ...interface{}) {} func Panicf(_ string, _ ...interface{}) {} @@ -362,6 +400,10 @@ func Warningln(_ ...interface{}) {} func Warnln(_ ...interface{}) {} +func WithError(_ error) *Entry { + return nil +} + func WithField(_ string, _ interface{}) *Entry { return nil } diff --git a/go/ql/test/query-tests/Security/CWE-117/vendor/modules.txt b/go/ql/test/query-tests/Security/CWE-117/vendor/modules.txt index a6227c09a93..fa7cb0a9a82 100644 --- a/go/ql/test/query-tests/Security/CWE-117/vendor/modules.txt +++ b/go/ql/test/query-tests/Security/CWE-117/vendor/modules.txt @@ -1,24 +1,134 @@ # github.com/astaxie/beego v1.12.3 -## explicit +## explicit; go 1.13 github.com/astaxie/beego +github.com/astaxie/beego/config +github.com/astaxie/beego/context +github.com/astaxie/beego/context/param +github.com/astaxie/beego/grace +github.com/astaxie/beego/logs +github.com/astaxie/beego/session +github.com/astaxie/beego/toolbox +github.com/astaxie/beego/utils +# github.com/beorn7/perks v1.0.1 +## explicit; go 1.11 +github.com/beorn7/perks/quantile +# github.com/cespare/xxhash/v2 v2.1.1 +## explicit; go 1.11 +github.com/cespare/xxhash/v2 +# github.com/davecgh/go-spew v1.1.1 +## explicit +github.com/davecgh/go-spew/spew # github.com/elazarl/goproxy v0.0.0-20211114080932-d06c3be7c11b ## explicit github.com/elazarl/goproxy # github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b ## explicit github.com/golang/glog -# github.com/kr/text v0.2.0 +# github.com/golang/protobuf v1.4.2 +## explicit; go 1.9 +github.com/golang/protobuf/proto +github.com/golang/protobuf/ptypes +github.com/golang/protobuf/ptypes/any +github.com/golang/protobuf/ptypes/duration +github.com/golang/protobuf/ptypes/timestamp +# github.com/hashicorp/golang-lru v0.5.4 +## explicit; go 1.12 +github.com/hashicorp/golang-lru +github.com/hashicorp/golang-lru/simplelru +# github.com/matttproud/golang_protobuf_extensions v1.0.1 ## explicit -github.com/kr/text +github.com/matttproud/golang_protobuf_extensions/pbutil +# github.com/prometheus/client_golang v1.7.0 +## explicit; go 1.11 +github.com/prometheus/client_golang/prometheus +github.com/prometheus/client_golang/prometheus/internal +github.com/prometheus/client_golang/prometheus/promhttp +# github.com/prometheus/client_model v0.2.0 +## explicit; go 1.9 +github.com/prometheus/client_model/go +# github.com/prometheus/common v0.10.0 +## explicit; go 1.11 +github.com/prometheus/common/expfmt +github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg +github.com/prometheus/common/model +# github.com/prometheus/procfs v0.1.3 +## explicit; go 1.12 +github.com/prometheus/procfs +github.com/prometheus/procfs/internal/fs +github.com/prometheus/procfs/internal/util +# github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 +## explicit +github.com/shiena/ansicolor # github.com/sirupsen/logrus v1.8.1 -## explicit +## explicit; go 1.13 github.com/sirupsen/logrus -# github.com/stretchr/testify v1.6.0 +# go.uber.org/multierr v1.10.0 +## explicit; go 1.19 +go.uber.org/multierr +# go.uber.org/zap v1.27.0 +## explicit; go 1.19 +go.uber.org/zap +go.uber.org/zap/buffer +go.uber.org/zap/internal +go.uber.org/zap/internal/bufferpool +go.uber.org/zap/internal/color +go.uber.org/zap/internal/exit +go.uber.org/zap/internal/pool +go.uber.org/zap/internal/stacktrace +go.uber.org/zap/zapcore +# golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 ## explicit -github.com/stretchr/testify +golang.org/x/crypto/acme +golang.org/x/crypto/acme/autocert +# golang.org/x/net v0.0.0-20190620200207-3b0461eec859 +## explicit; go 1.11 +golang.org/x/net/idna # golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f +## explicit; go 1.12 +golang.org/x/sys/internal/unsafeheader +golang.org/x/sys/unix +golang.org/x/sys/windows +# golang.org/x/text v0.3.0 ## explicit -golang.org/x/sys +golang.org/x/text/secure/bidirule +golang.org/x/text/transform +golang.org/x/text/unicode/bidi +golang.org/x/text/unicode/norm +# google.golang.org/protobuf v1.23.0 +## explicit; go 1.9 +google.golang.org/protobuf/encoding/prototext +google.golang.org/protobuf/encoding/protowire +google.golang.org/protobuf/internal/descfmt +google.golang.org/protobuf/internal/descopts +google.golang.org/protobuf/internal/detrand +google.golang.org/protobuf/internal/encoding/defval +google.golang.org/protobuf/internal/encoding/messageset +google.golang.org/protobuf/internal/encoding/tag +google.golang.org/protobuf/internal/encoding/text +google.golang.org/protobuf/internal/errors +google.golang.org/protobuf/internal/fieldnum +google.golang.org/protobuf/internal/fieldsort +google.golang.org/protobuf/internal/filedesc +google.golang.org/protobuf/internal/filetype +google.golang.org/protobuf/internal/flags +google.golang.org/protobuf/internal/genname +google.golang.org/protobuf/internal/impl +google.golang.org/protobuf/internal/mapsort +google.golang.org/protobuf/internal/pragma +google.golang.org/protobuf/internal/set +google.golang.org/protobuf/internal/strs +google.golang.org/protobuf/internal/version +google.golang.org/protobuf/proto +google.golang.org/protobuf/reflect/protoreflect +google.golang.org/protobuf/reflect/protoregistry +google.golang.org/protobuf/runtime/protoiface +google.golang.org/protobuf/runtime/protoimpl +google.golang.org/protobuf/types/known/anypb +google.golang.org/protobuf/types/known/durationpb +google.golang.org/protobuf/types/known/timestamppb +# gopkg.in/yaml.v2 v2.2.8 +## explicit +gopkg.in/yaml.v2 # k8s.io/klog v1.0.0 -## explicit +## explicit; go 1.12 k8s.io/klog diff --git a/go/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected b/go/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected index 105b7026d0c..42831abaf15 100644 --- a/go/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected +++ b/go/ql/test/query-tests/Security/CWE-681/IncorrectIntegerConversion.expected @@ -1,3 +1,2 @@ -failures invalidModelRow testFailures diff --git a/java/ql/automodel/publish.sh b/java/ql/automodel/publish.sh deleted file mode 100755 index 7304f0da180..00000000000 --- a/java/ql/automodel/publish.sh +++ /dev/null @@ -1,197 +0,0 @@ -#!/bin/bash -set -e - -help="Usage: ./publish [--override-release] [--dry-run] -Publish the automodel query pack. - -If no arguments are provided, publish the version of the codeql repo specified by the latest official release of the codeml-automodel repo. -If the --override-release argument is provided, your current local HEAD is used (for unofficial releases or patching). -If the --dry-run argument is provided, the release is not published (for testing purposes)." - -# Echo the help message -if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then - echo "$help" - exit 0 -fi - -# Check the number of arguments are valid -if [ $# -gt 2 ]; then - echo "Error: Invalid arguments provided" - echo "$help" - exit 1 -fi - -OVERRIDE_RELEASE=0 -DRY_RUN=0 -for arg in "$@" -do - case $arg in - --override-release) - OVERRIDE_RELEASE=1 - shift # Remove --override-release from processing - ;; - --dry-run) - DRY_RUN=1 - shift # Remove --dry-run from processing - ;; - *) - echo "Error: Invalid argument provided: $arg" - echo "$help" - exit 1 - ;; - esac -done - -# Describe what we're about to do based on the command-line arguments -if [ $OVERRIDE_RELEASE = 1 ]; then - echo "Publishing the current HEAD of the automodel repo" -else - echo "Publishing the version of the automodel repo specified by the latest official release of the codeml-automodel repo" -fi -if [ $DRY_RUN = 1 ]; then - echo "Dry run: we will step through the process but we won't publish the query pack" -else - echo "Not a dry run! Publishing the query pack" -fi - -# If we're publishing the codeml-automodel release then we will checkout the sha specified in the release. -# So we need to check that there are no uncommitted changes in the local branch. -# And, if we're publishing the current HEAD, it's cleaner to ensure that there are no uncommitted changes. -if ! git diff --quiet; then - echo "Error: Uncommitted changes exist. Please commit or stash your changes before publishing." - exit 1 -fi - -# Check the above environment variables are set -if [ -z "${GITHUB_TOKEN}" ]; then - echo "Error: GITHUB_TOKEN environment variable not set. Please set this to a token with package:write permissions to codeql." - exit 1 -fi -if [ -z "${GH_TOKEN}" ]; then - echo "Error: GH_TOKEN environment variable not set. Please set this to a token with repo permissions to github/codeml-automodel." - exit 1 -fi - -# Get the sha of the previous release, i.e. the last commit to the main branch that updated the query pack version -PREVIOUS_RELEASE_SHA=$(git rev-list -n 1 main -- ./src/qlpack.yml) -if [ -z "$PREVIOUS_RELEASE_SHA" ]; then - echo "Error: Could not get the sha of the previous release of codeml-automodel query pack" - exit 1 -else - echo "Previous query-pack release sha: $PREVIOUS_RELEASE_SHA" -fi - -CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) -CURRENT_SHA=$(git rev-parse HEAD) - -if [ $OVERRIDE_RELEASE = 1 ]; then - # Check that the current HEAD is downstream from PREVIOUS_RELEASE_SHA - if ! git merge-base --is-ancestor "$PREVIOUS_RELEASE_SHA" "$CURRENT_SHA"; then - echo "Error: The current HEAD is not downstream from the previous release" - exit 1 - fi -else - # Get the latest release of codeml-automodel - TAG_NAME=$(gh api -H 'Accept: application/vnd.github+json' -H 'X-GitHub-Api-Version: 2022-11-28' /repos/github/codeml-automodel/releases/latest | jq -r .tag_name) - # Check TAG_NAME is not empty - if [ -z "$TAG_NAME" ]; then - echo "Error: Could not get latest release of codeml-automodel" - exit 1 - fi - echo "Updating to latest automodel release: $TAG_NAME" - # Before downloading, delete any existing release.zip, and ignore failure if not present - rm release.zip || true - gh release download $TAG_NAME -A zip -O release.zip --repo 'https://github.com/github/codeml-automodel' - # Before unzipping, delete any existing release directory, and ignore failure if not present - rm -rf release || true - unzip -o release.zip -d release - REVISION=$(jq -r '.["codeql-sha"]' release/codeml-automodel*/codeml-automodel-release.json) - echo "The latest codeml-automodel release specifies the codeql sha $REVISION" - # Check that REVISION is downstream from PREVIOUS_RELEASE_SHA - if ! git merge-base --is-ancestor "$PREVIOUS_RELEASE_SHA" "$REVISION"; then - echo "Error: The codeql version $REVISION is not downstream of the query-pack version $PREVIOUS_RELEASE_SHA" - exit 1 - fi - # Get the version of the codeql code specified by the codeml-automodel release - git checkout "$REVISION" -fi - -# Get the absolute path of the automodel repo -AUTOMODEL_ROOT="$(readlink -f "$(dirname $0)")" -# Get the absolute path of the workspace root -WORKSPACE_ROOT="$AUTOMODEL_ROOT/../../.." -# Specify the groups of queries to test and publish -GRPS="automodel,-test" - -# Install the codeql gh extension -gh extensions install github/gh-codeql - -pushd "$AUTOMODEL_ROOT" -echo Testing automodel queries -gh codeql test run test -popd - -pushd "$WORKSPACE_ROOT" -echo "Preparing the release" -gh codeql pack release --groups $GRPS -v - -if [ $DRY_RUN = 1 ]; then - echo "Dry run: not publishing the query pack" - gh codeql pack publish --groups $GRPS --dry-run -v -else - echo "Not a dry run! Publishing the query pack" - gh codeql pack publish --groups $GRPS -v -fi - -echo "Bumping versions" -gh codeql pack post-release --groups $GRPS -v -popd - -# The above commands update -# ./src/CHANGELOG.md -# ./src/codeql-pack.release.yml -# ./src/qlpack.yml -# and add a new file -# ./src/change-notes/released/.md - -# Get the filename of the most recently created file in ./src/change-notes/released/*.md -# This will be the file for the new release -NEW_CHANGE_NOTES_FILE=$(ls -t ./src/change-notes/released/*.md | head -n 1) - -# Make a copy of the modified files -mv ./src/CHANGELOG.md ./src/CHANGELOG.md.dry-run -mv ./src/codeql-pack.release.yml ./src/codeql-pack.release.yml.dry-run -mv ./src/qlpack.yml ./src/qlpack.yml.dry-run -mv "$NEW_CHANGE_NOTES_FILE" ./src/change-notes/released.md.dry-run - -if [ $OVERRIDE_RELEASE = 1 ]; then - # Restore the original files - git checkout ./src/CHANGELOG.md - git checkout ./src/codeql-pack.release.yml - git checkout ./src/qlpack.yml -else - # Restore the original files - git checkout "$CURRENT_BRANCH" --force -fi - -if [ $DRY_RUN = 1 ]; then - echo "Inspect the updated dry-run version files:" - ls -l ./src/*.dry-run - ls -l ./src/change-notes/*.dry-run -else - # Add the updated files to the current branch - echo "Adding the version changes" - mv -f ./src/CHANGELOG.md.dry-run ./src/CHANGELOG.md - mv -f ./src/codeql-pack.release.yml.dry-run ./src/codeql-pack.release.yml - mv -f ./src/qlpack.yml.dry-run ./src/qlpack.yml - mv -f ./src/change-notes/released.md.dry-run "$NEW_CHANGE_NOTES_FILE" - git add ./src/CHANGELOG.md - git add ./src/codeql-pack.release.yml - git add ./src/qlpack.yml - git add "$NEW_CHANGE_NOTES_FILE" - echo "Added the following updated version files to the current branch:" - git status -s - echo "To complete the release, please commit these files and merge to the main branch" -fi - -echo "Done" \ No newline at end of file diff --git a/java/ql/automodel/src/AutomodelAlertSinkUtil.qll b/java/ql/automodel/src/AutomodelAlertSinkUtil.qll deleted file mode 100644 index f20c8e57b6c..00000000000 --- a/java/ql/automodel/src/AutomodelAlertSinkUtil.qll +++ /dev/null @@ -1,183 +0,0 @@ -private import java -private import semmle.code.java.dataflow.ExternalFlow as ExternalFlow -private import semmle.code.java.dataflow.TaintTracking -private import semmle.code.java.security.RequestForgeryConfig -private import semmle.code.java.security.CommandLineQuery -private import semmle.code.java.security.SqlConcatenatedQuery -private import semmle.code.java.security.SqlInjectionQuery -private import semmle.code.java.security.UrlRedirectQuery -private import semmle.code.java.security.TaintedPathQuery -private import semmle.code.java.security.SqlInjectionQuery -private import AutomodelJavaUtil - -private newtype TSinkModel = - MkSinkModel( - string package, string type, boolean subtypes, string name, string signature, string ext, - string input, string kind, string provenance - ) { - ExternalFlow::sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance, - _) - } - -class SinkModel extends TSinkModel { - string package; - string type; - boolean subtypes; - string name; - string signature; - string ext; - string input; - string kind; - string provenance; - - SinkModel() { - this = MkSinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance) - } - - /** Gets the package for this sink model. */ - string getPackage() { result = package } - - /** Gets the type for this sink model. */ - string getType() { result = type } - - /** Gets whether this sink model considers subtypes. */ - boolean getSubtypes() { result = subtypes } - - /** Gets the name for this sink model. */ - string getName() { result = name } - - /** Gets the signature for this sink model. */ - string getSignature() { result = signature } - - /** Gets the input for this sink model. */ - string getInput() { result = input } - - /** Gets the extension for this sink model. */ - string getExt() { result = ext } - - /** Gets the kind for this sink model. */ - string getKind() { result = kind } - - /** Gets the provenance for this sink model. */ - string getProvenance() { result = provenance } - - /** Gets the number of instances of this sink model. */ - int getInstanceCount() { result = count(PotentialSinkModelExpr p | p.getSinkModel() = this) } - - /** Gets a string representation of this sink model. */ - string toString() { - result = - "SinkModel(" + package + ", " + type + ", " + subtypes + ", " + name + ", " + signature + ", " - + ext + ", " + input + ", " + kind + ", " + provenance + ")" - } - - /** Gets a string representation of this sink model as it would appear in a Models-as-Data file. */ - string getRepr() { - result = - "\"" + package + "\", \"" + type + "\", " + pyBool(subtypes) + ", \"" + name + "\", \"" + - signature + "\", \"" + ext + "\", \"" + input + "\", \"" + kind + "\", \"" + provenance + - "\"" - } -} - -/** An expression that may correspond to a sink model. */ -class PotentialSinkModelExpr extends Expr { - /** - * Holds if this expression has the given signature. The signature should contain enough - * information to determine a corresponding sink model, if one exists. - */ - pragma[nomagic] - predicate hasSignature( - string package, string type, boolean subtypes, string name, string signature, string input - ) { - exists(Call call, Callable callable, int argIdx | - call.getCallee().getSourceDeclaration() = callable and - ( - this = call.getArgument(argIdx) - or - this = call.getQualifier() and argIdx = -1 - ) and - (if argIdx = -1 then input = "Argument[this]" else input = "Argument[" + argIdx + "]") and - package = callable.getDeclaringType().getPackage().getName() and - type = callable.getDeclaringType().getErasure().(RefType).getNestedName() and - subtypes = considerSubtypes(callable) and - name = callable.getName() and - signature = ExternalFlow::paramsString(callable) - ) - } - - /** Gets a sink model that corresponds to this expression. */ - SinkModel getSinkModel() { - this.hasSignature(result.getPackage(), result.getType(), result.getSubtypes(), result.getName(), - result.getSignature(), result.getInput()) - } -} - -private string pyBool(boolean b) { - b = true and result = "True" - or - b = false and result = "False" -} - -/** - * Gets a string representation of the existing sink model at the expression `e`, in the format in - * which it would appear in a Models-as-Data file. Also restricts the provenance of the sink model - * to be `ai-generated`. - */ -string getSinkModelRepr(PotentialSinkModelExpr e) { - result = e.getSinkModel().getRepr() and - e.getSinkModel().getProvenance() = "ai-generated" -} - -/** - * Gets the string representation of a sink model in a format suitable for appending to an alert - * message. - */ -string getSinkModelQueryRepr(PotentialSinkModelExpr e) { - result = "\nsinkModel: " + getSinkModelRepr(e) -} - -/** - * A parameterised module that takes a dataflow config, and exposes a predicate for counting the - * number of AI-generated sink models that appear in alerts for that query. - */ -private module SinkTallier { - module ConfigFlow = TaintTracking::Global; - - predicate getSinkModelCount(int c, SinkModel s) { - s = any(ConfigFlow::PathNode sink).getNode().asExpr().(PotentialSinkModelExpr).getSinkModel() and - c = - strictcount(ConfigFlow::PathNode sink | - ConfigFlow::flowPath(_, sink) and - s = sink.getNode().asExpr().(PotentialSinkModelExpr).getSinkModel() - ) - } -} - -predicate sinkModelTallyPerQuery(string queryName, int alertCount, SinkModel sinkModel) { - queryName = "java/request-forgery" and - SinkTallier::getSinkModelCount(alertCount, sinkModel) - or - queryName = "java/command-line-injection" and - SinkTallier::getSinkModelCount(alertCount, sinkModel) - or - queryName = "java/concatenated-sql-query" and - SinkTallier::getSinkModelCount(alertCount, sinkModel) - or - queryName = "java/ssrf" and - SinkTallier::getSinkModelCount(alertCount, sinkModel) - or - queryName = "java/path-injection" and - SinkTallier::getSinkModelCount(alertCount, sinkModel) - or - queryName = "java/unvalidated-url-redirection" and - SinkTallier::getSinkModelCount(alertCount, sinkModel) - or - queryName = "java/sql-injection" and - SinkTallier::getSinkModelCount(alertCount, sinkModel) -} - -predicate sinkModelTally(int alertCount, SinkModel sinkModel) { - sinkModelTallyPerQuery(_, _, sinkModel) and - alertCount = sum(int c | sinkModelTallyPerQuery(_, c, sinkModel)) -} diff --git a/java/ql/automodel/src/AutomodelAlertSinks.ql b/java/ql/automodel/src/AutomodelAlertSinks.ql deleted file mode 100644 index e9af51b4d63..00000000000 --- a/java/ql/automodel/src/AutomodelAlertSinks.ql +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @name Number of alerts per sink model - * @description Counts the number of alerts using `ai-generated` sink models. - * @kind table - * @id java/ml/metrics-count-alerts-per-sink-model - * @tags internal automodel metrics - */ - -private import java -private import AutomodelAlertSinkUtil - -from int alertCount, SinkModel s -where sinkModelTally(alertCount, s) and s.getProvenance() = "ai-generated" -select alertCount, s.getPackage() as package, s.getType() as type, s.getSubtypes() as subtypes, - s.getName() as name, s.getSignature() as signature, s.getInput() as input, s.getExt() as ext, - s.getKind() as kind, s.getProvenance() as provenance order by alertCount desc diff --git a/java/ql/automodel/src/AutomodelAlertSinksPerQuery.ql b/java/ql/automodel/src/AutomodelAlertSinksPerQuery.ql deleted file mode 100644 index 64a5038d116..00000000000 --- a/java/ql/automodel/src/AutomodelAlertSinksPerQuery.ql +++ /dev/null @@ -1,19 +0,0 @@ -/** - * @name Number of alerts per sink model and query - * @description Counts the number of alerts per query using `ai-generated` sink models. - * @kind table - * @id java/ml/metrics-count-alerts-per-sink-model-and-query - * @tags internal automodel metrics - */ - -private import java -private import AutomodelAlertSinkUtil - -from string queryId, int alertCount, SinkModel s -where - sinkModelTallyPerQuery(queryId, alertCount, s) and - s.getProvenance() = "ai-generated" -select queryId, alertCount, s.getPackage() as package, s.getType() as type, - s.getSubtypes() as subtypes, s.getName() as name, s.getSignature() as signature, - s.getInput() as input, s.getExt() as ext, s.getKind() as kind, s.getProvenance() as provenance - order by queryId, alertCount desc diff --git a/java/ql/automodel/src/AutomodelApplicationModeCharacteristics.qll b/java/ql/automodel/src/AutomodelApplicationModeCharacteristics.qll deleted file mode 100644 index 750d776891f..00000000000 --- a/java/ql/automodel/src/AutomodelApplicationModeCharacteristics.qll +++ /dev/null @@ -1,677 +0,0 @@ -/** - * For internal use only. - */ - -private import java -private import semmle.code.Location as Location -private import semmle.code.java.dataflow.DataFlow -private import semmle.code.java.dataflow.TaintTracking -private import semmle.code.java.dataflow.ExternalFlow as ExternalFlow -private import semmle.code.java.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl -private import semmle.code.java.security.ExternalAPIs as ExternalAPIs -private import semmle.code.java.Expr as Expr -private import semmle.code.java.security.QueryInjection -private import semmle.code.java.dataflow.internal.ModelExclusions as ModelExclusions -private import AutomodelJavaUtil as AutomodelJavaUtil -private import semmle.code.java.security.PathSanitizer as PathSanitizer -import AutomodelSharedCharacteristics as SharedCharacteristics -import AutomodelEndpointTypes as AutomodelEndpointTypes - -newtype JavaRelatedLocationType = - CallContext() or - MethodDoc() or - ClassDoc() - -newtype TApplicationModeEndpoint = - TExplicitArgument(Call call, DataFlow::Node arg) { - AutomodelJavaUtil::isFromSource(call) and - exists(Argument argExpr | - arg.asExpr() = argExpr and call = argExpr.getCall() and not argExpr.isVararg() - ) and - not AutomodelJavaUtil::isUnexploitableType(arg.getType()) - } or - TInstanceArgument(Call call, DataFlow::Node arg) { - AutomodelJavaUtil::isFromSource(call) and - arg = DataFlow::getInstanceArgument(call) and - not call instanceof ConstructorCall and - not AutomodelJavaUtil::isUnexploitableType(arg.getType()) - } or - TImplicitVarargsArray(Call call, DataFlow::ImplicitVarargsArray arg, int idx) { - AutomodelJavaUtil::isFromSource(call) and - call = arg.getCall() and - idx = call.getCallee().getVaragsParameterIndex() and - not AutomodelJavaUtil::isUnexploitableType(arg.getType()) - } or - TMethodReturnValue(MethodCall call) { - AutomodelJavaUtil::isFromSource(call) and - not AutomodelJavaUtil::isUnexploitableType(call.getType()) - } or - TOverriddenParameter(Parameter p, Method overriddenMethod) { - AutomodelJavaUtil::isFromSource(p) and - p.getCallable().(Method).overrides(overriddenMethod) - } - -/** - * An endpoint is a node that is a candidate for modeling. - */ -abstract private class ApplicationModeEndpoint extends TApplicationModeEndpoint { - /** - * Gets the callable to be modeled that this endpoint represents. - */ - abstract Callable getCallable(); - - /** - * Gets the input (if any) for this endpoint, eg.: `Argument[0]`. - * - * For endpoints that are source candidates, this will be `none()`. - */ - abstract string getMaDInput(); - - /** - * Gets the output (if any) for this endpoint, eg.: `ReturnValue`. - * - * For endpoints that are sink candidates, this will be `none()`. - */ - abstract string getMaDOutput(); - - abstract Top asTop(); - - /** - * Converts the endpoint to a node that can be used in a data flow graph. - */ - abstract DataFlow::Node asNode(); - - string getExtensibleType() { - if not exists(this.getMaDInput()) and exists(this.getMaDOutput()) - then result = "sourceModel" - else - if exists(this.getMaDInput()) and not exists(this.getMaDOutput()) - then result = "sinkModel" - else none() // if both exist, it would be a summaryModel (not yet supported) - } - - abstract string toString(); -} - -class TCallArgument = TExplicitArgument or TInstanceArgument or TImplicitVarargsArray; - -/** - * An endpoint that represents an "argument" to a call in a broad sense, including - * both explicit arguments and the instance argument. - */ -abstract class CallArgument extends ApplicationModeEndpoint, TCallArgument { - Call call; - DataFlow::Node arg; - - override Callable getCallable() { result = call.getCallee().getSourceDeclaration() } - - override string getMaDOutput() { none() } - - override DataFlow::Node asNode() { result = arg } - - Call getCall() { result = call } - - override string toString() { result = arg.toString() } -} - -/** - * An endpoint that represents an explicit argument to a call. - */ -class ExplicitArgument extends CallArgument, TExplicitArgument { - ExplicitArgument() { this = TExplicitArgument(call, arg) } - - private int getArgIndex() { this.asTop() = call.getArgument(result) } - - override string getMaDInput() { result = "Argument[" + this.getArgIndex() + "]" } - - override Top asTop() { result = arg.asExpr() } -} - -/** - * An endpoint that represents the instance argument to a call. - */ -class InstanceArgument extends CallArgument, TInstanceArgument { - InstanceArgument() { this = TInstanceArgument(call, arg) } - - override string getMaDInput() { result = "Argument[this]" } - - override Top asTop() { if exists(arg.asExpr()) then result = arg.asExpr() else result = call } - - override string toString() { result = arg.toString() } -} - -/** - * An endpoint that represents an implicit varargs array. - * We choose to represent the varargs array as a single endpoint, rather than as multiple endpoints. - * - * This avoids the problem of having to deal with redundant endpoints downstream. - * - * In order to be able to distinguish between varargs endpoints and regular endpoints, we export the `isVarargsArray` - * meta data field in the extraction queries. - */ -class ImplicitVarargsArray extends CallArgument, TImplicitVarargsArray { - int idx; - - ImplicitVarargsArray() { this = TImplicitVarargsArray(call, arg, idx) } - - override string getMaDInput() { result = "Argument[" + idx + "]" } - - override Top asTop() { result = call } -} - -/** - * An endpoint that represents a method call. The `ReturnValue` of a method call - * may be a source. - */ -class MethodReturnValue extends ApplicationModeEndpoint, TMethodReturnValue { - MethodCall call; - - MethodReturnValue() { this = TMethodReturnValue(call) } - - override Callable getCallable() { result = call.getCallee().getSourceDeclaration() } - - override string getMaDInput() { none() } - - override string getMaDOutput() { result = "ReturnValue" } - - override Top asTop() { result = call } - - override DataFlow::Node asNode() { result.asExpr() = call } - - override string toString() { result = call.toString() } -} - -/** - * An endpoint that represents a parameter of an overridden method that may be - * a source. - */ -class OverriddenParameter extends ApplicationModeEndpoint, TOverriddenParameter { - Parameter p; - Method overriddenMethod; - - OverriddenParameter() { this = TOverriddenParameter(p, overriddenMethod) } - - override Callable getCallable() { - // NB: we're returning the overridden callable here. This means that the - // candidate model will be about the overridden method, not the overriding - // method. This is a more general model, that also applies to other - // subclasses of the overridden class. - result = overriddenMethod.getSourceDeclaration() - } - - private int getArgIndex() { p.getCallable().getParameter(result) = p } - - override string getMaDInput() { none() } - - override string getMaDOutput() { result = "Parameter[" + this.getArgIndex() + "]" } - - override Top asTop() { result = p } - - override DataFlow::Node asNode() { result.(DataFlow::ParameterNode).asParameter() = p } - - override string toString() { result = p.toString() } -} - -/** - * A candidates implementation. - * - * Some important notes: - * - This mode is using arguments as endpoints. - * - We use the `CallContext` (the surrounding call expression) as related location. - */ -module ApplicationCandidatesImpl implements SharedCharacteristics::CandidateSig { - // for documentation of the implementations here, see the QLDoc in the CandidateSig signature module. - class Endpoint = ApplicationModeEndpoint; - - class EndpointType = AutomodelEndpointTypes::EndpointType; - - class SinkType = AutomodelEndpointTypes::SinkType; - - class SourceType = AutomodelEndpointTypes::SourceType; - - class RelatedLocation = Location::Top; - - class RelatedLocationType = JavaRelatedLocationType; - - // Sanitizers are currently not modeled in MaD. TODO: check if this has large negative impact. - predicate isSanitizer(Endpoint e, EndpointType t) { - exists(t) and - AutomodelJavaUtil::isUnexploitableType([ - // for most endpoints, we can get the type from the node - e.asNode().getType(), - // but not for calls to void methods, where we need to go via the AST - e.asTop().(Expr).getType() - ]) - or - t instanceof AutomodelEndpointTypes::PathInjectionSinkType and - e.asNode() instanceof PathSanitizer::PathInjectionSanitizer - } - - RelatedLocation asLocation(Endpoint e) { result = e.asTop() } - - predicate isKnownKind = AutomodelJavaUtil::isKnownKind/2; - - predicate isSink(Endpoint e, string kind, string provenance) { - exists( - string package, string type, boolean subtypes, string name, string signature, string ext, - string input - | - sinkSpec(e, package, type, subtypes, name, signature, ext, input) and - ExternalFlow::sinkModel(package, type, subtypes, name, [signature, ""], ext, input, kind, - provenance, _) - ) - or - isCustomSink(e, kind) and provenance = "custom-sink" - } - - predicate isSource(Endpoint e, string kind, string provenance) { - exists( - string package, string type, boolean subtypes, string name, string signature, string ext, - string output - | - sourceSpec(e, package, type, subtypes, name, signature, ext, output) and - ExternalFlow::sourceModel(package, type, subtypes, name, [signature, ""], ext, output, kind, - provenance, _) - ) - } - - predicate isNeutral(Endpoint e) { - exists(string package, string type, string name, string signature, string endpointType | - sinkSpec(e, package, type, _, name, signature, _, _) and - endpointType = "sink" - or - sourceSpec(e, package, type, _, name, signature, _, _) and - endpointType = "source" - | - ExternalFlow::neutralModel(package, type, name, [signature, ""], endpointType, _) - ) - } - - /** - * Holds if the endpoint concerns a callable with the given package, type, name and signature. - * - * If `subtypes` is `false`, only the exact callable is considered. If `true`, the callable and - * all its overrides are considered. - */ - additional predicate endpointCallable( - Endpoint e, string package, string type, boolean subtypes, string name, string signature - ) { - exists(Callable c | - c = e.getCallable() and subtypes in [true, false] - or - e.getCallable().(Method).getSourceDeclaration().overrides+(c) and subtypes = true - | - c.hasQualifiedName(package, type, name) and - signature = ExternalFlow::paramsString(c) - ) - } - - additional predicate sinkSpec( - Endpoint e, string package, string type, boolean subtypes, string name, string signature, - string ext, string input - ) { - endpointCallable(e, package, type, subtypes, name, signature) and - ext = "" and - input = e.getMaDInput() - } - - additional predicate sourceSpec( - Endpoint e, string package, string type, boolean subtypes, string name, string signature, - string ext, string output - ) { - endpointCallable(e, package, type, subtypes, name, signature) and - ext = "" and - output = e.getMaDOutput() - } - - /** - * Gets the related location for the given endpoint. - * - * The only related location we model is the the call expression surrounding to - * which the endpoint is either argument or qualifier (known as the call context). - */ - RelatedLocation getRelatedLocation(Endpoint e, RelatedLocationType type) { - type = CallContext() and - result = e.(CallArgument).getCall() - or - type = MethodDoc() and - result = e.getCallable().(Documentable).getJavadoc() - or - type = ClassDoc() and - result = e.getCallable().getDeclaringType().(Documentable).getJavadoc() - } -} - -/** - * Contains endpoints that are defined in QL code rather than as a MaD model. Ideally this predicate - * should be empty. - */ -private predicate isCustomSink(Endpoint e, string kind) { - e.asNode() instanceof QueryInjectionSink and kind = "sql" -} - -module CharacteristicsImpl = - SharedCharacteristics::SharedCharacteristics; - -class EndpointCharacteristic = CharacteristicsImpl::EndpointCharacteristic; - -class Endpoint = ApplicationCandidatesImpl::Endpoint; - -/* - * Predicates that are used to surface prompt examples and candidates for classification with an ML model. - */ - -/** - * A MetadataExtractor that extracts metadata for application mode. - */ -class ApplicationModeMetadataExtractor extends string { - ApplicationModeMetadataExtractor() { this = "ApplicationModeMetadataExtractor" } - - predicate hasMetadata( - Endpoint e, string package, string type, string subtypes, string name, string signature, - string input, string output, string isVarargsArray, string alreadyAiModeled, - string extensibleType - ) { - exists(Callable callable | e.getCallable() = callable | - (if exists(e.getMaDInput()) then input = e.getMaDInput() else input = "") and - (if exists(e.getMaDOutput()) then output = e.getMaDOutput() else output = "") and - package = callable.getDeclaringType().getPackage().getName() and - // we're using the erased types because the MaD convention is to not specify type parameters. - // Whether something is or isn't a sink doesn't usually depend on the type parameters. - type = callable.getDeclaringType().getErasure().(RefType).getNestedName() and - subtypes = AutomodelJavaUtil::considerSubtypes(callable).toString() and - name = callable.getName() and - signature = ExternalFlow::paramsString(callable) and - ( - if e instanceof ImplicitVarargsArray - then isVarargsArray = "true" - else isVarargsArray = "false" - ) and - extensibleType = e.getExtensibleType() - ) and - ( - not CharacteristicsImpl::isModeled(e, _, extensibleType, _) and alreadyAiModeled = "" - or - CharacteristicsImpl::isModeled(e, _, extensibleType, alreadyAiModeled) - ) - } -} - -/** - * Holds if the given `endpoint` should be considered a candidate for the `extensibleType`. - * - * The other parameters record various other properties of interest. - */ -predicate isCandidate( - Endpoint endpoint, string package, string type, string subtypes, string name, string signature, - string input, string output, string isVarargs, string extensibleType, string alreadyAiModeled -) { - CharacteristicsImpl::isCandidate(endpoint, _) and - not exists(CharacteristicsImpl::UninterestingToModelCharacteristic u | - u.appliesToEndpoint(endpoint) - ) and - any(ApplicationModeMetadataExtractor meta) - .hasMetadata(endpoint, package, type, subtypes, name, signature, input, output, isVarargs, - alreadyAiModeled, extensibleType) and - // If a node is already modeled in MaD, we don't include it as a candidate. Otherwise, we might include it as a - // candidate for query A, but the model will label it as a sink for one of the sink types of query B, for which it's - // already a known sink. This would result in overlap between our detected sinks and the pre-existing modeling. We - // assume that, if a sink has already been modeled in a MaD model, then it doesn't belong to any additional sink - // types, and we don't need to reexamine it. - alreadyAiModeled.matches(["", "%ai-%"]) and - AutomodelJavaUtil::includeAutomodelCandidate(package, type, name, signature) -} - -/** - * Holds if the given `endpoint` is a negative example for the `extensibleType` - * because of the `characteristic`. - * - * The other parameters record various other properties of interest. - */ -predicate isNegativeExample( - Endpoint endpoint, EndpointCharacteristic characteristic, float confidence, string package, - string type, string subtypes, string name, string signature, string input, string output, - string isVarargsArray, string extensibleType -) { - characteristic.appliesToEndpoint(endpoint) and - // the node is known not to be an endpoint of any appropriate type - forall(AutomodelEndpointTypes::EndpointType tp | - tp = CharacteristicsImpl::getAPotentialType(endpoint) - | - characteristic.hasImplications(tp, false, _) - ) and - // the lowest confidence across all endpoint types should be at least highConfidence - confidence = - min(float c | - characteristic.hasImplications(CharacteristicsImpl::getAPotentialType(endpoint), false, c) - ) and - confidence >= SharedCharacteristics::highConfidence() and - any(ApplicationModeMetadataExtractor meta) - .hasMetadata(endpoint, package, type, subtypes, name, signature, input, output, - isVarargsArray, _, extensibleType) and - // It's valid for a node to be both a potential source/sanitizer and a sink. We don't want to include such nodes - // as negative examples in the prompt, because they're ambiguous and might confuse the model, so we explicitly exclude them here. - not exists(EndpointCharacteristic characteristic2, float confidence2 | - characteristic2 != characteristic - | - characteristic2.appliesToEndpoint(endpoint) and - confidence2 >= SharedCharacteristics::maximalConfidence() and - characteristic2 - .hasImplications(CharacteristicsImpl::getAPotentialType(endpoint), true, confidence2) - ) -} - -/** - * Holds if the given `endpoint` is a positive example for the `endpointType`. - * - * The other parameters record various other properties of interest. - */ -predicate isPositiveExample( - Endpoint endpoint, string endpointType, string package, string type, string subtypes, string name, - string signature, string input, string output, string isVarargsArray, string extensibleType -) { - any(ApplicationModeMetadataExtractor meta) - .hasMetadata(endpoint, package, type, subtypes, name, signature, input, output, - isVarargsArray, _, extensibleType) and - CharacteristicsImpl::isKnownAs(endpoint, endpointType, _) and - exists(CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, CallContext())) -} - -/* - * EndpointCharacteristic classes that are specific to Automodel for Java. - */ - -/** - * A negative characteristic that indicates that parameters of an is-style boolean method should not be considered sinks. - * - * A sink is highly unlikely to be exploitable if its callable's name starts with `is` and the callable has a boolean return - * type (e.g. `isDirectory`). These kinds of calls normally do only checks, and appear before the proper call that does - * the dangerous/interesting thing, so we want the latter to be modeled as the sink. - * - * TODO: this might filter too much, it's possible that methods with more than one parameter contain interesting sinks - */ -private class UnexploitableIsCharacteristic extends CharacteristicsImpl::NotASinkCharacteristic { - UnexploitableIsCharacteristic() { this = "argument of is-style boolean method" } - - override predicate appliesToEndpoint(Endpoint e) { - e.getCallable().getName().matches("is%") and - e.getCallable().getReturnType() instanceof BooleanType and - not ApplicationCandidatesImpl::isSink(e, _, _) - } -} - -/** - * A negative characteristic that indicates that parameters of an existence-checking boolean method should not be - * considered sinks. - * - * A sink is highly unlikely to be exploitable if its callable's name is `exists` or `notExists` and the callable has a - * boolean return type. These kinds of calls normally do only checks, and appear before the proper call that does the - * dangerous/interesting thing, so we want the latter to be modeled as the sink. - */ -private class UnexploitableExistsCharacteristic extends CharacteristicsImpl::NotASinkCharacteristic { - UnexploitableExistsCharacteristic() { this = "argument of existence-checking boolean method" } - - override predicate appliesToEndpoint(Endpoint e) { - exists(Callable callable | callable = e.getCallable() | - callable.getName().toLowerCase() = ["exists", "notexists"] and - callable.getReturnType() instanceof BooleanType - ) - } -} - -/** - * A negative characteristic that indicates that parameters of an exception method or constructor should not be considered sinks, - * and its return value should not be considered a source. - */ -private class ExceptionCharacteristic extends CharacteristicsImpl::NeitherSourceNorSinkCharacteristic -{ - ExceptionCharacteristic() { this = "argument/result of exception-related method" } - - override predicate appliesToEndpoint(Endpoint e) { - e.getCallable().getDeclaringType().getASupertype*() instanceof TypeThrowable and - ( - e.getExtensibleType() = "sinkModel" and - not ApplicationCandidatesImpl::isSink(e, _, _) - or - e.getExtensibleType() = "sourceModel" and - not ApplicationCandidatesImpl::isSource(e, _, _) and - e.getMaDOutput() = "ReturnValue" - ) - } -} - -/** - * A negative characteristic that indicates that an endpoint is a MaD taint step. MaD modeled taint steps are global, - * so they are not sinks for any query. Non-MaD taint steps might be specific to a particular query, so we don't - * filter those out. - */ -private class IsMaDTaintStepCharacteristic extends CharacteristicsImpl::NotASinkCharacteristic { - IsMaDTaintStepCharacteristic() { this = "taint step" } - - override predicate appliesToEndpoint(Endpoint e) { - FlowSummaryImpl::Private::Steps::summaryThroughStepValue(e.asNode(), _, _) - or - FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(e.asNode(), _, _) - or - FlowSummaryImpl::Private::Steps::summaryGetterStep(e.asNode(), _, _, _) - or - FlowSummaryImpl::Private::Steps::summarySetterStep(e.asNode(), _, _, _) - } -} - -/** - * A call to a method that's known locally will not be considered as a candidate to model. - * - * The reason is that we would expect data/taint flow into the method implementation to uncover - * any sinks that are present there. - */ -private class LocalCall extends CharacteristicsImpl::UninterestingToModelCharacteristic { - LocalCall() { this = "local call" } - - override predicate appliesToEndpoint(Endpoint e) { - e.(CallArgument).getCallable().fromSource() - or - e.(MethodReturnValue).getCallable().fromSource() - } -} - -/** - * A characteristic that marks endpoints as uninteresting to model, according to the Java ModelExclusions module. - */ -private class ExcludedFromModeling extends CharacteristicsImpl::UninterestingToModelCharacteristic { - ExcludedFromModeling() { this = "excluded from modeling" } - - override predicate appliesToEndpoint(Endpoint e) { - ModelExclusions::isUninterestingForModels(e.getCallable()) - } -} - -/** - * A negative characteristic that filters out non-public methods. Non-public methods are not interesting to include in - * the standard Java modeling, because they cannot be called from outside the package. - */ -private class NonPublicMethodCharacteristic extends CharacteristicsImpl::UninterestingToModelCharacteristic -{ - NonPublicMethodCharacteristic() { this = "non-public method" } - - override predicate appliesToEndpoint(Endpoint e) { - exists(Callable c | c = e.getCallable() | not c.isPublic()) - } -} - -/** - * A negative characteristic that indicates that an endpoint is a non-sink argument to a method whose sinks have already - * been modeled _manually_. This is restricted to manual sinks only, because only during the manual process do we have - * the expectation that all sinks present in a method have been considered. - * - * WARNING: These endpoints should not be used as negative samples for training, because some sinks may have been missed - * when the method was modeled. Specifically, as we start using ATM to merge in new declarations, we can be less sure - * that a method with one argument modeled as a MaD sink has also had its remaining arguments manually reviewed. The - * ML model might have predicted argument 0 of some method to be a sink but not argument 1, when in fact argument 1 is - * also a sink. - */ -private class OtherArgumentToModeledMethodCharacteristic extends CharacteristicsImpl::LikelyNotASinkCharacteristic -{ - OtherArgumentToModeledMethodCharacteristic() { - this = "other argument to a method that has already been modeled manually" - } - - override predicate appliesToEndpoint(Endpoint e) { - not ApplicationCandidatesImpl::isSink(e, _, _) and - exists(CallArgument otherSink | - ApplicationCandidatesImpl::isSink(otherSink, _, "manual") and - e.(CallArgument).getCall() = otherSink.getCall() and - e != otherSink - ) - } -} - -/** - * Holds if the type of the given expression is annotated with `@FunctionalInterface`. - */ -predicate hasFunctionalInterfaceType(Expr e) { - exists(RefType tp | tp = e.getType().getErasure() | - tp.getAnAssociatedAnnotation().getType().hasQualifiedName("java.lang", "FunctionalInterface") - ) -} - -/** - * A characteristic that marks functional expression as likely not sinks. - * - * These expressions may well _contain_ sinks, but rarely are sinks themselves. - */ -private class FunctionValueCharacteristic extends CharacteristicsImpl::LikelyNotASinkCharacteristic { - FunctionValueCharacteristic() { this = "function value" } - - override predicate appliesToEndpoint(Endpoint e) { - exists(Expr expr | expr = e.asNode().asExpr() | - expr instanceof FunctionalExpr or hasFunctionalInterfaceType(expr) - ) - } -} - -/** - * A negative characteristic that indicates that an endpoint is not a `to` node for any known taint step. Such a node - * cannot be tainted, because taint can't flow into it. - * - * WARNING: These endpoints should not be used as negative samples for training, because they may include sinks for - * which our taint tracking modeling is incomplete. - */ -private class CannotBeTaintedCharacteristic extends CharacteristicsImpl::LikelyNotASinkCharacteristic -{ - CannotBeTaintedCharacteristic() { this = "cannot be tainted" } - - override predicate appliesToEndpoint(Endpoint e) { not this.isKnownOutNodeForStep(e) } - - /** - * Holds if the node `n` is known as the predecessor in a modeled flow step. - */ - private predicate isKnownOutNodeForStep(Endpoint e) { - e.asNode().asExpr() instanceof Call or // we just assume flow in that case - TaintTracking::localTaintStep(_, e.asNode()) or - FlowSummaryImpl::Private::Steps::summaryThroughStepValue(_, e.asNode(), _) or - FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(_, e.asNode(), _) or - FlowSummaryImpl::Private::Steps::summaryGetterStep(_, _, e.asNode(), _) or - FlowSummaryImpl::Private::Steps::summarySetterStep(_, _, e.asNode(), _) - } -} diff --git a/java/ql/automodel/src/AutomodelApplicationModeExtractCandidates.ql b/java/ql/automodel/src/AutomodelApplicationModeExtractCandidates.ql deleted file mode 100644 index a3fa8b9b46f..00000000000 --- a/java/ql/automodel/src/AutomodelApplicationModeExtractCandidates.ql +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Surfaces the endpoints that are not already known to be sinks, and are therefore used as candidates for - * classification with an ML model. - * - * Note: This query does not actually classify the endpoints using the model. - * - * @name Automodel candidates (application mode) - * @description A query to extract automodel candidates in application mode. - * @kind problem - * @problem.severity recommendation - * @id java/ml/extract-automodel-application-candidates - * @tags internal extract automodel application-mode candidates - */ - -import java -private import AutomodelApplicationModeCharacteristics -private import AutomodelJavaUtil - -/** - * Gets a sample of endpoints (of at most `limit` samples) with the given method signature. - * - * The main purpose of this helper predicate is to avoid selecting too many candidates, as this may - * cause the SARIF file to exceed the maximum size limit. - */ -bindingset[limit] -private Endpoint getSampleForSignature( - int limit, string package, string type, string subtypes, string name, string signature, - string input, string output, string isVarargs, string extensibleType, string alreadyAiModeled -) { - exists(int n, int num_endpoints, ApplicationModeMetadataExtractor meta | - num_endpoints = - count(Endpoint e | - meta.hasMetadata(e, package, type, subtypes, name, signature, input, output, isVarargs, - alreadyAiModeled, extensibleType) - ) - | - result = - rank[n](Endpoint e, Location loc | - loc = e.asTop().getLocation() and - meta.hasMetadata(e, package, type, subtypes, name, signature, input, output, isVarargs, - alreadyAiModeled, extensibleType) - | - e - order by - loc.getFile().getAbsolutePath(), loc.getStartLine(), loc.getStartColumn(), - loc.getEndLine(), loc.getEndColumn() - ) and - // To avoid selecting samples that are too close together (as the ranking above goes by file - // path first), we select `limit` evenly spaced samples from the ranked list of endpoints. By - // default this would always include the first sample, so we add a random-chosen prime offset - // to the first sample index, and reduce modulo the number of endpoints. - // Finally, we add 1 to the result, as ranking results in a 1-indexed relation. - n = 1 + (([0 .. limit - 1] * (num_endpoints / limit).floor() + 46337) % num_endpoints) - ) -} - -from - Endpoint endpoint, DollarAtString package, DollarAtString type, DollarAtString subtypes, - DollarAtString name, DollarAtString signature, DollarAtString input, DollarAtString output, - DollarAtString isVarargsArray, DollarAtString alreadyAiModeled, DollarAtString extensibleType -where - isCandidate(endpoint, package, type, subtypes, name, signature, input, output, isVarargsArray, - extensibleType, alreadyAiModeled) and - endpoint = - getSampleForSignature(9, package, type, subtypes, name, signature, input, output, - isVarargsArray, extensibleType, alreadyAiModeled) -select endpoint.asNode(), - "Related locations: $@, $@, $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@.", // - CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, CallContext()), "CallContext", // - CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, MethodDoc()), "MethodDoc", // - CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, ClassDoc()), "ClassDoc", // - package, "package", // - type, "type", // - subtypes, "subtypes", // - name, "name", // method name - signature, "signature", // - input, "input", // - output, "output", // - isVarargsArray, "isVarargsArray", // - alreadyAiModeled, "alreadyAiModeled", // - extensibleType, "extensibleType" diff --git a/java/ql/automodel/src/AutomodelApplicationModeExtractNegativeExamples.ql b/java/ql/automodel/src/AutomodelApplicationModeExtractNegativeExamples.ql deleted file mode 100644 index a399c413fa4..00000000000 --- a/java/ql/automodel/src/AutomodelApplicationModeExtractNegativeExamples.ql +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Surfaces endpoints that are non-sinks with high confidence, for use as negative examples in the prompt. - * - * @name Negative examples (application mode) - * @kind problem - * @problem.severity recommendation - * @id java/ml/extract-automodel-application-negative-examples - * @tags internal extract automodel application-mode negative examples - */ - -private import java -private import AutomodelApplicationModeCharacteristics -private import AutomodelEndpointTypes -private import AutomodelJavaUtil - -/** - * Gets a sample of endpoints (of at most `limit` samples) for which the given characteristic applies. - * - * The main purpose of this helper predicate is to avoid selecting too many samples, as this may - * cause the SARIF file to exceed the maximum size limit. - */ -bindingset[limit] -Endpoint getSampleForCharacteristic(EndpointCharacteristic c, int limit) { - exists(int n, int num_endpoints | num_endpoints = count(Endpoint e | c.appliesToEndpoint(e)) | - result = - rank[n](Endpoint e, Location loc | - loc = e.asTop().getLocation() and c.appliesToEndpoint(e) - | - e - order by - loc.getFile().getAbsolutePath(), loc.getStartLine(), loc.getStartColumn(), - loc.getEndLine(), loc.getEndColumn() - ) and - // To avoid selecting samples that are too close together (as the ranking above goes by file - // path first), we select `limit` evenly spaced samples from the ranked list of endpoints. By - // default this would always include the first sample, so we add a random-chosen prime offset - // to the first sample index, and reduce modulo the number of endpoints. - // Finally, we add 1 to the result, as ranking results in a 1-indexed relation. - n = 1 + (([0 .. limit - 1] * (num_endpoints / limit).floor() + 46337) % num_endpoints) - ) -} - -from - Endpoint endpoint, EndpointCharacteristic characteristic, float confidence, string message, - DollarAtString package, DollarAtString type, DollarAtString subtypes, DollarAtString name, - DollarAtString signature, DollarAtString input, DollarAtString output, - DollarAtString isVarargsArray, DollarAtString extensibleType -where - endpoint = getSampleForCharacteristic(characteristic, 100) and - isNegativeExample(endpoint, characteristic, confidence, package, type, subtypes, name, signature, - input, output, isVarargsArray, extensibleType) and - message = characteristic -select endpoint.asNode(), - message + "\nrelated locations: $@, $@, $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@.", // - CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, CallContext()), "CallContext", // - CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, MethodDoc()), "MethodDoc", // - CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, ClassDoc()), "ClassDoc", // - package, "package", // - type, "type", // - subtypes, "subtypes", // - name, "name", // - signature, "signature", // - input, "input", // - output, "output", // - isVarargsArray, "isVarargsArray", // - extensibleType, "extensibleType" diff --git a/java/ql/automodel/src/AutomodelApplicationModeExtractPositiveExamples.ql b/java/ql/automodel/src/AutomodelApplicationModeExtractPositiveExamples.ql deleted file mode 100644 index faf49b73fc1..00000000000 --- a/java/ql/automodel/src/AutomodelApplicationModeExtractPositiveExamples.ql +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Surfaces endpoints that are sinks with high confidence, for use as positive examples in the prompt. - * - * @name Positive examples (application mode) - * @kind problem - * @problem.severity recommendation - * @id java/ml/extract-automodel-application-positive-examples - * @tags internal extract automodel application-mode positive examples - */ - -private import AutomodelApplicationModeCharacteristics -private import AutomodelEndpointTypes -private import AutomodelJavaUtil - -from - Endpoint endpoint, EndpointType endpointType, ApplicationModeMetadataExtractor meta, - DollarAtString package, DollarAtString type, DollarAtString subtypes, DollarAtString name, - DollarAtString signature, DollarAtString input, DollarAtString output, - DollarAtString isVarargsArray, DollarAtString extensibleType -where - isPositiveExample(endpoint, endpointType, package, type, subtypes, name, signature, input, output, - isVarargsArray, extensibleType) -select endpoint.asNode(), - endpointType + "\nrelated locations: $@, $@, $@." + - "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@.", // - CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, CallContext()), "CallContext", // - CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, MethodDoc()), "MethodDoc", // - CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, ClassDoc()), "ClassDoc", // - package, "package", // - type, "type", // - subtypes, "subtypes", // - name, "name", // - signature, "signature", // - input, "input", // - output, "output", // - isVarargsArray, "isVarargsArray", // - extensibleType, "extensibleType" diff --git a/java/ql/automodel/src/AutomodelCandidateFilter.yml b/java/ql/automodel/src/AutomodelCandidateFilter.yml deleted file mode 100644 index c945ae3206f..00000000000 --- a/java/ql/automodel/src/AutomodelCandidateFilter.yml +++ /dev/null @@ -1,5 +0,0 @@ -extensions: - - addsTo: - pack: codeql/java-automodel-queries - extensible: automodelCandidateFilter - data: [] diff --git a/java/ql/automodel/src/AutomodelCountGeneratedSinks.ql b/java/ql/automodel/src/AutomodelCountGeneratedSinks.ql deleted file mode 100644 index 475e3753810..00000000000 --- a/java/ql/automodel/src/AutomodelCountGeneratedSinks.ql +++ /dev/null @@ -1,19 +0,0 @@ -/** - * @name Number of instances of each sink model - * @description Counts the number of instances of `ai-generated` sink models. - * @kind table - * @id java/ml/metrics-count-instances-per-sink-model - * @tags internal automodel metrics - */ - -private import java -private import AutomodelAlertSinkUtil - -from int instanceCount, SinkModel s -where - instanceCount = s.getInstanceCount() and - instanceCount > 0 and - s.getProvenance() = "ai-generated" -select instanceCount, s.getPackage() as package, s.getType() as type, s.getSubtypes() as subtypes, - s.getName() as name, s.getSignature() as signature, s.getInput() as input, s.getExt() as ext, - s.getKind() as kind, s.getProvenance() as provenance order by instanceCount desc diff --git a/java/ql/automodel/src/AutomodelEndpointTypes.qll b/java/ql/automodel/src/AutomodelEndpointTypes.qll deleted file mode 100644 index f4f7bc8eb7b..00000000000 --- a/java/ql/automodel/src/AutomodelEndpointTypes.qll +++ /dev/null @@ -1,82 +0,0 @@ -/** - * For internal use only. - * - * Defines the set of classes that endpoint scoring models can predict. Endpoint scoring models must - * only predict classes defined within this file. This file is the source of truth for the integer - * representation of each of these classes. - */ - -/** A class that can be predicted by a classifier. */ -abstract class EndpointType extends string { - /** - * Holds when the string matches the name of the sink / source type. - */ - bindingset[this] - EndpointType() { any() } - - /** - * Gets the name of the sink/source kind for this endpoint type as used in models-as-data. - * - * See https://github.com/github/codeql/blob/44213f0144fdd54bb679ca48d68b28dcf820f7a8/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll#LL353C11-L357C31 - * for sink types, and https://github.com/github/codeql/blob/44213f0144fdd54bb679ca48d68b28dcf820f7a8/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll#L365 - * for source types. - */ - final string getKind() { result = this } -} - -/** A class for sink types that can be predicted by a classifier. */ -abstract class SinkType extends EndpointType { - bindingset[this] - SinkType() { any() } -} - -/** A sink relevant to the SQL injection query */ -class SqlInjectionSinkType extends SinkType { - SqlInjectionSinkType() { this = "sql-injection" } -} - -/** A sink relevant to the tainted path injection query. */ -class PathInjectionSinkType extends SinkType { - PathInjectionSinkType() { this = "path-injection" } -} - -/** A sink relevant to the SSRF query. */ -class RequestForgerySinkType extends SinkType { - RequestForgerySinkType() { this = "request-forgery" } -} - -/** A sink relevant to the command injection query. */ -class CommandInjectionSinkType extends SinkType { - CommandInjectionSinkType() { this = "command-injection" } -} - -/** A sink relevant to file storage. */ -class FileContentStoreSinkType extends SinkType { - FileContentStoreSinkType() { this = "file-content-store" } -} - -/** A sink relevant to HTML injection. */ -class HtmlInjectionSinkType extends SinkType { - HtmlInjectionSinkType() { this = "html-injection" } -} - -/** A sink relevant to LDAP injection. */ -class LdapInjectionSinkType extends SinkType { - LdapInjectionSinkType() { this = "ldap-injection" } -} - -/** A sink relevant to URL redirection. */ -class UrlRedirectionSinkType extends SinkType { - UrlRedirectionSinkType() { this = "url-redirection" } -} - -/** A class for source types that can be predicted by a classifier. */ -abstract class SourceType extends EndpointType { - bindingset[this] - SourceType() { any() } -} - -/** A source of remote data. */ -class RemoteSourceType extends SourceType { - RemoteSourceType() { this = "remote" } -} diff --git a/java/ql/automodel/src/AutomodelFrameworkModeCharacteristics.qll b/java/ql/automodel/src/AutomodelFrameworkModeCharacteristics.qll deleted file mode 100644 index 7f385a41d1e..00000000000 --- a/java/ql/automodel/src/AutomodelFrameworkModeCharacteristics.qll +++ /dev/null @@ -1,507 +0,0 @@ -/** - * For internal use only. - */ - -private import java -private import semmle.code.Location as Location -private import semmle.code.java.dataflow.DataFlow -private import semmle.code.java.dataflow.TaintTracking -private import semmle.code.java.dataflow.ExternalFlow as ExternalFlow -private import semmle.code.java.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl -private import semmle.code.java.security.ExternalAPIs as ExternalAPIs -private import semmle.code.java.Expr as Expr -private import semmle.code.java.security.QueryInjection -private import semmle.code.java.security.RequestForgery -private import semmle.code.java.dataflow.internal.ModelExclusions as ModelExclusions -private import AutomodelJavaUtil as AutomodelJavaUtil -import AutomodelSharedCharacteristics as SharedCharacteristics -import AutomodelEndpointTypes as AutomodelEndpointTypes - -newtype JavaRelatedLocationType = - MethodDoc() or - ClassDoc() - -newtype TFrameworkModeEndpoint = - TExplicitParameter(Parameter p) { - AutomodelJavaUtil::isFromSource(p) and - not AutomodelJavaUtil::isUnexploitableType(p.getType()) - } or - TQualifier(Callable c) { AutomodelJavaUtil::isFromSource(c) and not c instanceof Constructor } or - TReturnValue(Callable c) { - AutomodelJavaUtil::isFromSource(c) and - c instanceof Constructor - or - AutomodelJavaUtil::isFromSource(c) and - c instanceof Method and - not AutomodelJavaUtil::isUnexploitableType(c.getReturnType()) - } or - TOverridableParameter(Method m, Parameter p) { - AutomodelJavaUtil::isFromSource(p) and - not AutomodelJavaUtil::isUnexploitableType(p.getType()) and - p.getCallable() = m and - m instanceof ModelExclusions::ModelApi and - AutomodelJavaUtil::isOverridable(m) - } or - TOverridableQualifier(Method m) { - AutomodelJavaUtil::isFromSource(m) and - m instanceof ModelExclusions::ModelApi and - AutomodelJavaUtil::isOverridable(m) - } - -/** - * A framework mode endpoint. - */ -abstract class FrameworkModeEndpoint extends TFrameworkModeEndpoint { - /** - * Gets the input (if any) for this endpoint, eg.: `Argument[0]`. - * - * For endpoints that are source candidates, this will be `none()`. - */ - abstract string getMaDInput(); - - /** - * Gets the output (if any) for this endpoint, eg.: `ReturnValue`. - * - * For endpoints that are sink candidates, this will be `none()`. - */ - abstract string getMaDOutput(); - - /** - * Returns the name of the parameter of the endpoint. - */ - abstract string getParamName(); - - /** - * Returns the callable that contains the endpoint. - */ - abstract Callable getCallable(); - - abstract Top asTop(); - - abstract string getExtensibleType(); - - string toString() { result = this.asTop().toString() } - - Location getLocation() { result = this.asTop().getLocation() } -} - -class ExplicitParameterEndpoint extends FrameworkModeEndpoint, TExplicitParameter { - Parameter param; - - ExplicitParameterEndpoint() { this = TExplicitParameter(param) and param.fromSource() } - - override string getMaDInput() { result = "Argument[" + param.getPosition() + "]" } - - override string getMaDOutput() { none() } - - override string getParamName() { result = param.getName() } - - override Callable getCallable() { result = param.getCallable() } - - override Top asTop() { result = param } - - override string getExtensibleType() { result = "sinkModel" } -} - -class QualifierEndpoint extends FrameworkModeEndpoint, TQualifier { - Callable callable; - - QualifierEndpoint() { - this = TQualifier(callable) and not callable.isStatic() and callable.fromSource() - } - - override string getMaDInput() { result = "Argument[this]" } - - override string getMaDOutput() { none() } - - override string getParamName() { result = "this" } - - override Callable getCallable() { result = callable } - - override Top asTop() { result = callable } - - override string getExtensibleType() { result = "sinkModel" } -} - -class ReturnValue extends FrameworkModeEndpoint, TReturnValue { - Callable callable; - - ReturnValue() { this = TReturnValue(callable) and callable.fromSource() } - - override string getMaDInput() { none() } - - override string getMaDOutput() { result = "ReturnValue" } - - override string getParamName() { none() } - - override Callable getCallable() { result = callable } - - override Top asTop() { result = callable } - - override string getExtensibleType() { result = "sourceModel" } -} - -class OverridableParameter extends FrameworkModeEndpoint, TOverridableParameter { - Method method; - Parameter param; - - OverridableParameter() { this = TOverridableParameter(method, param) } - - override string getMaDInput() { none() } - - override string getMaDOutput() { result = "Parameter[" + param.getPosition() + "]" } - - override string getParamName() { result = param.getName() } - - override Callable getCallable() { result = method } - - override Top asTop() { result = param } - - override string getExtensibleType() { result = "sourceModel" } -} - -class OverridableQualifier extends FrameworkModeEndpoint, TOverridableQualifier { - Method m; - - OverridableQualifier() { this = TOverridableQualifier(m) } - - override string getMaDInput() { none() } - - override string getMaDOutput() { result = "Parameter[this]" } - - override string getParamName() { result = "this" } - - override Callable getCallable() { result = m } - - override Top asTop() { result = m } - - override string getExtensibleType() { result = "sourceModel" } -} - -/** - * A candidates implementation for framework mode. - * - * Some important notes: - * - This mode is using parameters as endpoints. - * - Sink- and neutral-information is being used from MaD models. - * - When available, we use method- and class-java-docs as related locations. - */ -module FrameworkCandidatesImpl implements SharedCharacteristics::CandidateSig { - // for documentation of the implementations here, see the QLDoc in the CandidateSig signature module. - class Endpoint = FrameworkModeEndpoint; - - class EndpointType = AutomodelEndpointTypes::EndpointType; - - class SinkType = AutomodelEndpointTypes::SinkType; - - class SourceType = AutomodelEndpointTypes::SourceType; - - class RelatedLocation = Location::Top; - - class RelatedLocationType = JavaRelatedLocationType; - - // Sanitizers are currently not modeled in MaD. TODO: check if this has large negative impact. - predicate isSanitizer(Endpoint e, EndpointType t) { none() } - - RelatedLocation asLocation(Endpoint e) { result = e.asTop() } - - predicate isKnownKind = AutomodelJavaUtil::isKnownKind/2; - - predicate isSink(Endpoint e, string kind, string provenance) { - exists( - string package, string type, boolean subtypes, string name, string signature, string ext, - string input - | - sinkSpec(e, package, type, subtypes, name, signature, ext, input) and - ExternalFlow::sinkModel(package, type, subtypes, name, [signature, ""], ext, input, kind, - provenance, _) - ) - } - - predicate isSource(Endpoint e, string kind, string provenance) { - exists( - string package, string type, boolean subtypes, string name, string signature, string ext, - string output - | - sourceSpec(e, package, type, subtypes, name, signature, ext, output) and - ExternalFlow::sourceModel(package, type, subtypes, name, [signature, ""], ext, output, kind, - provenance, _) - ) - } - - predicate isNeutral(Endpoint e) { - exists(string package, string type, string name, string signature, string endpointType | - sinkSpec(e, package, type, _, name, signature, _, _) and - endpointType = "sink" - or - sourceSpec(e, package, type, _, name, signature, _, _) and - endpointType = "source" - | - ExternalFlow::neutralModel(package, type, name, [signature, ""], endpointType, _) - ) - } - - /** - * Holds if the endpoint concerns a callable with the given package, type, name and signature. - * - * If `subtypes` is `false`, only the exact callable is considered. If `true`, the callable and - * all its overrides are considered. - */ - additional predicate endpointCallable( - Endpoint e, string package, string type, boolean subtypes, string name, string signature - ) { - exists(Callable c | - c = e.getCallable() and subtypes in [true, false] - or - e.getCallable().(Method).getSourceDeclaration().overrides+(c) and subtypes = true - | - c.hasQualifiedName(package, type, name) and - signature = ExternalFlow::paramsString(c) - ) - } - - additional predicate sinkSpec( - Endpoint e, string package, string type, boolean subtypes, string name, string signature, - string ext, string input - ) { - endpointCallable(e, package, type, subtypes, name, signature) and - ext = "" and - input = e.getMaDInput() - } - - additional predicate sourceSpec( - Endpoint e, string package, string type, boolean subtypes, string name, string signature, - string ext, string output - ) { - endpointCallable(e, package, type, subtypes, name, signature) and - ext = "" and - output = e.getMaDOutput() - } - - /** - * Gets the related location for the given endpoint. - * - * Related locations can be JavaDoc comments of the class or the method. - */ - RelatedLocation getRelatedLocation(Endpoint e, RelatedLocationType type) { - type = MethodDoc() and - result = e.getCallable().(Documentable).getJavadoc() - or - type = ClassDoc() and - result = e.getCallable().getDeclaringType().(Documentable).getJavadoc() - } -} - -module CharacteristicsImpl = SharedCharacteristics::SharedCharacteristics; - -class EndpointCharacteristic = CharacteristicsImpl::EndpointCharacteristic; - -class Endpoint = FrameworkCandidatesImpl::Endpoint; - -/* - * Predicates that are used to surface prompt examples and candidates for classification with an ML model. - */ - -/** - * A MetadataExtractor that extracts metadata for framework mode. - */ -class FrameworkModeMetadataExtractor extends string { - FrameworkModeMetadataExtractor() { this = "FrameworkModeMetadataExtractor" } - - predicate hasMetadata( - Endpoint e, string package, string type, string subtypes, string name, string signature, - string input, string output, string parameterName, string alreadyAiModeled, - string extensibleType - ) { - exists(Callable callable | e.getCallable() = callable | - (if exists(e.getMaDInput()) then input = e.getMaDInput() else input = "") and - (if exists(e.getMaDOutput()) then output = e.getMaDOutput() else output = "") and - package = callable.getDeclaringType().getPackage().getName() and - // we're using the erased types because the MaD convention is to not specify type parameters. - // Whether something is or isn't a sink doesn't usually depend on the type parameters. - type = callable.getDeclaringType().getErasure().(RefType).getNestedName() and - subtypes = AutomodelJavaUtil::considerSubtypes(callable).toString() and - name = callable.getName() and - signature = ExternalFlow::paramsString(callable) and - (if exists(e.getParamName()) then parameterName = e.getParamName() else parameterName = "") and - e.getExtensibleType() = extensibleType - ) and - ( - not CharacteristicsImpl::isModeled(e, _, extensibleType, _) and alreadyAiModeled = "" - or - CharacteristicsImpl::isModeled(e, _, extensibleType, alreadyAiModeled) - ) - } -} - -/** - * Holds if the given `endpoint` should be considered a candidate for the `extensibleType`. - * - * The other parameters record various other properties of interest. - */ -predicate isCandidate( - Endpoint endpoint, string package, string type, string subtypes, string name, string signature, - string input, string output, string parameterName, string extensibleType, string alreadyAiModeled -) { - CharacteristicsImpl::isCandidate(endpoint, _) and - not exists(CharacteristicsImpl::UninterestingToModelCharacteristic u | - u.appliesToEndpoint(endpoint) - ) and - any(FrameworkModeMetadataExtractor meta) - .hasMetadata(endpoint, package, type, subtypes, name, signature, input, output, parameterName, - alreadyAiModeled, extensibleType) and - // If a node is already modeled in MaD, we don't include it as a candidate. Otherwise, we might include it as a - // candidate for query A, but the model will label it as a sink for one of the sink types of query B, for which it's - // already a known sink. This would result in overlap between our detected sinks and the pre-existing modeling. We - // assume that, if a sink has already been modeled in a MaD model, then it doesn't belong to any additional sink - // types, and we don't need to reexamine it. - alreadyAiModeled.matches(["", "%ai-%"]) and - AutomodelJavaUtil::includeAutomodelCandidate(package, type, name, signature) -} - -/** - * Holds if the given `endpoint` is a negative example for the `extensibleType` - * because of the `characteristic`. - * - * The other parameters record various other properties of interest. - */ -predicate isNegativeExample( - Endpoint endpoint, EndpointCharacteristic characteristic, float confidence, string package, - string type, string subtypes, string name, string signature, string input, string output, - string parameterName, string extensibleType -) { - characteristic.appliesToEndpoint(endpoint) and - // the node is known not to be an endpoint of any appropriate type - forall(AutomodelEndpointTypes::EndpointType tp | - tp = CharacteristicsImpl::getAPotentialType(endpoint) - | - characteristic.hasImplications(tp, false, _) - ) and - // the lowest confidence across all endpoint types should be at least highConfidence - confidence = - min(float c | - characteristic.hasImplications(CharacteristicsImpl::getAPotentialType(endpoint), false, c) - ) and - confidence >= SharedCharacteristics::highConfidence() and - any(FrameworkModeMetadataExtractor meta) - .hasMetadata(endpoint, package, type, subtypes, name, signature, input, output, parameterName, - _, extensibleType) and - // It's valid for a node to be both a potential source/sanitizer and a sink. We don't want to include such nodes - // as negative examples in the prompt, because they're ambiguous and might confuse the model, so we explicitly exclude them here. - not exists(EndpointCharacteristic characteristic2, float confidence2 | - characteristic2 != characteristic - | - characteristic2.appliesToEndpoint(endpoint) and - confidence2 >= SharedCharacteristics::maximalConfidence() and - characteristic2 - .hasImplications(CharacteristicsImpl::getAPotentialType(endpoint), true, confidence2) - ) -} - -/** - * Holds if the given `endpoint` is a positive example for the `endpointType`. - * - * The other parameters record various other properties of interest. - */ -predicate isPositiveExample( - Endpoint endpoint, string endpointType, string package, string type, string subtypes, string name, - string signature, string input, string output, string parameterName, string extensibleType -) { - any(FrameworkModeMetadataExtractor meta) - .hasMetadata(endpoint, package, type, subtypes, name, signature, input, output, parameterName, - _, extensibleType) and - CharacteristicsImpl::isKnownAs(endpoint, endpointType, _) -} - -/* - * EndpointCharacteristic classes that are specific to Automodel for Java. - */ - -/** - * A negative characteristic that indicates that parameters of an is-style boolean method should not be considered sinks, - * and its return value should not be considered a source. - * - * A sink is highly unlikely to be exploitable if its callable's name starts with `is` and the callable has a boolean return - * type (e.g. `isDirectory`). These kinds of calls normally do only checks, and appear before the proper call that does - * the dangerous/interesting thing, so we want the latter to be modeled as the sink. - * - * TODO: this might filter too much, it's possible that methods with more than one parameter contain interesting sinks - */ -private class UnexploitableIsCharacteristic extends CharacteristicsImpl::NeitherSourceNorSinkCharacteristic -{ - UnexploitableIsCharacteristic() { this = "argument of is-style boolean method" } - - override predicate appliesToEndpoint(Endpoint e) { - e.getCallable().getName().matches("is%") and - e.getCallable().getReturnType() instanceof BooleanType and - ( - e.getExtensibleType() = "sinkModel" and - not FrameworkCandidatesImpl::isSink(e, _, _) - or - e.getExtensibleType() = "sourceModel" and - not FrameworkCandidatesImpl::isSource(e, _, _) and - e.getMaDOutput() = "ReturnValue" - ) - } -} - -/** - * A negative characteristic that indicates that parameters of an existence-checking boolean method should not be - * considered sinks, and its return value should not be considered a source. - * - * A sink is highly unlikely to be exploitable if its callable's name is `exists` or `notExists` and the callable has a - * boolean return type. These kinds of calls normally do only checks, and appear before the proper call that does the - * dangerous/interesting thing, so we want the latter to be modeled as the sink. - */ -private class UnexploitableExistsCharacteristic extends CharacteristicsImpl::NeitherSourceNorSinkCharacteristic -{ - UnexploitableExistsCharacteristic() { this = "argument of existence-checking boolean method" } - - override predicate appliesToEndpoint(Endpoint e) { - exists(Callable callable | - callable = e.getCallable() and - callable.getName().toLowerCase() = ["exists", "notexists"] and - callable.getReturnType() instanceof BooleanType - | - e.getExtensibleType() = "sinkModel" and - not FrameworkCandidatesImpl::isSink(e, _, _) - or - e.getExtensibleType() = "sourceModel" and - not FrameworkCandidatesImpl::isSource(e, _, _) and - e.getMaDOutput() = "ReturnValue" - ) - } -} - -/** - * A negative characteristic that indicates that parameters of an exception method or constructor should not be considered sinks, - * and its return value should not be considered a source. - */ -private class ExceptionCharacteristic extends CharacteristicsImpl::NeitherSourceNorSinkCharacteristic -{ - ExceptionCharacteristic() { this = "argument/result of exception-related method" } - - override predicate appliesToEndpoint(Endpoint e) { - e.getCallable().getDeclaringType().getASupertype*() instanceof TypeThrowable and - ( - e.getExtensibleType() = "sinkModel" and - not FrameworkCandidatesImpl::isSink(e, _, _) - or - e.getExtensibleType() = "sourceModel" and - not FrameworkCandidatesImpl::isSource(e, _, _) and - e.getMaDOutput() = "ReturnValue" - ) - } -} - -/** - * A characteristic that limits candidates to parameters of methods that are recognized as `ModelApi`, iow., APIs that - * are considered worth modeling. - */ -private class NotAModelApi extends CharacteristicsImpl::UninterestingToModelCharacteristic { - NotAModelApi() { this = "not a model API" } - - override predicate appliesToEndpoint(Endpoint e) { - not e.getCallable() instanceof ModelExclusions::ModelApi - } -} diff --git a/java/ql/automodel/src/AutomodelFrameworkModeExtractCandidates.ql b/java/ql/automodel/src/AutomodelFrameworkModeExtractCandidates.ql deleted file mode 100644 index 83683b4e78f..00000000000 --- a/java/ql/automodel/src/AutomodelFrameworkModeExtractCandidates.ql +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Surfaces the endpoints that are not already known to be sinks, and are therefore used as candidates for - * classification with an ML model. - * - * Note: This query does not actually classify the endpoints using the model. - * - * @name Automodel candidates (framework mode) - * @description A query to extract automodel candidates in framework mode. - * @kind problem - * @problem.severity recommendation - * @id java/ml/extract-automodel-framework-candidates - * @tags internal extract automodel framework-mode candidates - */ - -private import AutomodelFrameworkModeCharacteristics -private import AutomodelJavaUtil - -from - Endpoint endpoint, DollarAtString package, DollarAtString type, DollarAtString subtypes, - DollarAtString name, DollarAtString signature, DollarAtString input, DollarAtString output, - DollarAtString parameterName, DollarAtString alreadyAiModeled, DollarAtString extensibleType -where - isCandidate(endpoint, package, type, subtypes, name, signature, input, output, parameterName, - extensibleType, alreadyAiModeled) -select endpoint, - "Related locations: $@, $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@.", // - CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, MethodDoc()), "MethodDoc", // - CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, ClassDoc()), "ClassDoc", // - package, "package", // - type, "type", // - subtypes, "subtypes", // - name, "name", // - signature, "signature", // - input, "input", // - output, "output", // - parameterName, "parameterName", // - alreadyAiModeled, "alreadyAiModeled", // - extensibleType, "extensibleType" diff --git a/java/ql/automodel/src/AutomodelFrameworkModeExtractNegativeExamples.ql b/java/ql/automodel/src/AutomodelFrameworkModeExtractNegativeExamples.ql deleted file mode 100644 index 05e5951b061..00000000000 --- a/java/ql/automodel/src/AutomodelFrameworkModeExtractNegativeExamples.ql +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Surfaces endpoints that are non-sinks with high confidence, for use as negative examples in the prompt. - * - * @name Negative examples (framework mode) - * @kind problem - * @problem.severity recommendation - * @id java/ml/extract-automodel-framework-negative-examples - * @tags internal extract automodel framework-mode negative examples - */ - -private import AutomodelFrameworkModeCharacteristics -private import AutomodelEndpointTypes -private import AutomodelJavaUtil - -from - Endpoint endpoint, EndpointCharacteristic characteristic, float confidence, - DollarAtString package, DollarAtString type, DollarAtString subtypes, DollarAtString name, - DollarAtString signature, DollarAtString input, DollarAtString output, - DollarAtString parameterName, DollarAtString extensibleType -where - isNegativeExample(endpoint, characteristic, confidence, package, type, subtypes, name, signature, - input, output, parameterName, extensibleType) -select endpoint, - characteristic + "\nrelated locations: $@, $@." + - "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@.", // - CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, MethodDoc()), "MethodDoc", // - CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, ClassDoc()), "ClassDoc", // - package, "package", // - type, "type", // - subtypes, "subtypes", // - name, "name", // - signature, "signature", // - input, "input", // - output, "output", // - parameterName, "parameterName", // - extensibleType, "extensibleType" diff --git a/java/ql/automodel/src/AutomodelFrameworkModeExtractPositiveExamples.ql b/java/ql/automodel/src/AutomodelFrameworkModeExtractPositiveExamples.ql deleted file mode 100644 index 7cb023949ed..00000000000 --- a/java/ql/automodel/src/AutomodelFrameworkModeExtractPositiveExamples.ql +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Surfaces endpoints that are sinks with high confidence, for use as positive examples in the prompt. - * - * @name Positive examples (framework mode) - * @kind problem - * @problem.severity recommendation - * @id java/ml/extract-automodel-framework-positive-examples - * @tags internal extract automodel framework-mode positive examples - */ - -private import AutomodelFrameworkModeCharacteristics -private import AutomodelEndpointTypes -private import AutomodelJavaUtil - -from - Endpoint endpoint, EndpointType endpointType, DollarAtString package, DollarAtString type, - DollarAtString subtypes, DollarAtString name, DollarAtString signature, DollarAtString input, - DollarAtString output, DollarAtString parameterName, DollarAtString extensibleType -where - isPositiveExample(endpoint, endpointType, package, type, subtypes, name, signature, input, output, - parameterName, extensibleType) -select endpoint, - endpointType + "\nrelated locations: $@, $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@.", // - CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, MethodDoc()), "MethodDoc", // - CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, ClassDoc()), "ClassDoc", // - package, "package", // - type, "type", // - subtypes, "subtypes", // - name, "name", // - signature, "signature", // - input, "input", // - output, "output", // - parameterName, "parameterName", // - extensibleType, "extensibleType" diff --git a/java/ql/automodel/src/AutomodelJavaUtil.qll b/java/ql/automodel/src/AutomodelJavaUtil.qll deleted file mode 100644 index 368fb172483..00000000000 --- a/java/ql/automodel/src/AutomodelJavaUtil.qll +++ /dev/null @@ -1,111 +0,0 @@ -private import java -private import AutomodelEndpointTypes as AutomodelEndpointTypes - -/** - * A helper class to represent a string value that can be returned by a query using $@ notation. - * - * It extends `string`, but adds a mock `hasLocationInfo` method that returns the string itself as the file name. - * - * Use this, when you want to return a string value from a query using $@ notation - the string value - * will be included in the sarif file. - * - * - * Background information on `hasLocationInfo`: - * https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/#providing-location-information - */ -class DollarAtString extends string { - bindingset[this] - DollarAtString() { any() } - - bindingset[this] - predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) { - path = this and sl = 1 and sc = 1 and el = 1 and ec = 1 - } -} - -/** - * Holds for all combinations of MaD kinds (`kind`) and their human readable - * descriptions. - */ -predicate isKnownKind(string kind, AutomodelEndpointTypes::EndpointType type) { - kind = type.getKind() -} - -/** - * By convention, the subtypes property of the MaD declaration should only be - * true when there _can_ exist any subtypes with a different implementation. - * - * It would technically be ok to always use the value 'true', but this would - * break convention. - */ -pragma[nomagic] -boolean considerSubtypes(Callable callable) { - if - callable.isStatic() or - callable.getDeclaringType().isStatic() or - callable.isFinal() or - callable.getDeclaringType().isFinal() - then result = false - else result = true -} - -/** - * Holds if the given package, type, name and signature is a candidate for automodeling. - * - * This predicate is extensible, so that different endpoints can be selected at runtime. - */ -extensible predicate automodelCandidateFilter( - string package, string type, string name, string signature -); - -/** - * Holds if the given package, type, name and signature is a candidate for automodeling. - * - * This relies on an extensible predicate, and if that is not supplied then - * all endpoints are considered candidates. - */ -bindingset[package, type, name, signature] -predicate includeAutomodelCandidate(string package, string type, string name, string signature) { - not automodelCandidateFilter(_, _, _, _) or - automodelCandidateFilter(package, type, name, signature) -} - -/** - * Holds if the given program element corresponds to a piece of source code, - * that is, it is not compiler-generated. - * - * Note: This is a stricter check than `Element::fromSource`, which simply - * checks whether the element is in a source file as opposed to a JAR file. - * There can be compiler-generated elements in source files (especially for - * Kotlin), which we also want to exclude. - */ -predicate isFromSource(Element e) { - // from a source file (not a JAR) - e.fromSource() and - // not explicitly marked as compiler-generated - not e.isCompilerGenerated() and - // does not have a dummy location - not e.hasLocationInfo(_, 0, 0, 0, 0) -} - -/** - * Holds if taint cannot flow through the given type (because it is a numeric - * type or some other type with a fixed set of values). - */ -predicate isUnexploitableType(Type tp) { - tp instanceof PrimitiveType or - tp instanceof BoxedType or - tp instanceof NumberType or - tp instanceof VoidType -} - -/** - * Holds if the given method can be overridden, that is, it is not final, - * static, or private. - */ -predicate isOverridable(Method m) { - not m.getDeclaringType().isFinal() and - not m.isFinal() and - not m.isStatic() and - not m.isPrivate() -} diff --git a/java/ql/automodel/src/AutomodelSharedCharacteristics.qll b/java/ql/automodel/src/AutomodelSharedCharacteristics.qll deleted file mode 100644 index 273c5d30dec..00000000000 --- a/java/ql/automodel/src/AutomodelSharedCharacteristics.qll +++ /dev/null @@ -1,412 +0,0 @@ -float maximalConfidence() { result = 1.0 } - -float highConfidence() { result = 0.9 } - -float mediumConfidence() { result = 0.6 } - -/** - * A specification of how to instantiate the shared characteristics for a given candidate class. - * - * The `CandidateSig` implementation specifies a type to use for Endpoints (eg., `ParameterNode`), as well as a type - * to label endpoint classes (the `EndpointType`). One of the endpoint classes needs to be a 'negative' class, meaning - * "not any of the other known endpoint types". - */ -signature module CandidateSig { - /** - * An endpoint is a potential candidate for modeling. This will typically be bound to the language's - * DataFlow node class, or a subtype thereof. - */ - class Endpoint { - /** - * Gets the kind of this endpoint, either "sourceModel" or "sinkModel". - */ - string getExtensibleType(); - - /** - * Gets a string representation of this endpoint. - */ - string toString(); - } - - /** - * A related location for an endpoint. This will typically be bound to the supertype of all AST nodes (eg., `Top`). - */ - class RelatedLocation; - - /** - * A label for a related location. - * - * Eg., method-doc, class-doc, etc. - */ - class RelatedLocationType; - - /** - * An endpoint type considered by this specification. - */ - class EndpointType extends string; - - /** - * A sink endpoint type considered by this specification. - */ - class SinkType extends EndpointType; - - /** - * A source endpoint type considered by this specification. - */ - class SourceType extends EndpointType; - - /** - * Gets the endpoint as a location. - * - * This is a utility function to convert an endpoint to its corresponding location. - */ - RelatedLocation asLocation(Endpoint e); - - /** - * Defines what MaD kinds are known, and what endpoint type they correspond to. - */ - predicate isKnownKind(string kind, EndpointType type); - - /** - * Holds if `e` is a flow sanitizer, and has type `t`. - */ - predicate isSanitizer(Endpoint e, EndpointType t); - - /** - * Holds if `e` is a sink with the label `kind`, and provenance `provenance`. - */ - predicate isSink(Endpoint e, string kind, string provenance); - - /** - * Holds if `e` is a source with the label `kind`, and provenance `provenance`. - */ - predicate isSource(Endpoint e, string kind, string provenance); - - /** - * Holds if `e` is not a source or sink of any kind. - */ - predicate isNeutral(Endpoint e); - - /** - * Gets a related location. - * - * A related location is a source code location that may hold extra information about an endpoint that can be useful - * to the machine learning model. - * - * For example, a related location for a method call may be the documentation comment of a method. - */ - RelatedLocation getRelatedLocation(Endpoint e, RelatedLocationType name); -} - -/** - * A set of shared characteristics for a given candidate class. - * - * This module is language-agnostic, although the `CandidateSig` module will be language-specific. - * - * The language specific implementation can also further extend the behavior of this module by adding additional - * implementations of endpoint characteristics exported by this module. - */ -module SharedCharacteristics { - predicate isSink = Candidate::isSink/3; - - predicate isNeutral = Candidate::isNeutral/1; - - predicate isModeled(Candidate::Endpoint e, string kind, string extensibleKind, string provenance) { - Candidate::isSink(e, kind, provenance) and extensibleKind = "sinkModel" - or - Candidate::isSource(e, kind, provenance) and extensibleKind = "sourceModel" - } - - /** - * Holds if `endpoint` is modeled as `endpointType`. - */ - predicate isKnownAs( - Candidate::Endpoint endpoint, Candidate::EndpointType endpointType, - EndpointCharacteristic characteristic - ) { - // If the list of characteristics includes positive indicators with maximal confidence for this class, then it's a - // known sink for the class. - characteristic.appliesToEndpoint(endpoint) and - characteristic.hasImplications(endpointType, true, maximalConfidence()) - } - - /** - * Gets a potential type of this endpoint to make sure that sources are - * associated with source types and sinks with sink types. - */ - Candidate::EndpointType getAPotentialType(Candidate::Endpoint endpoint) { - endpoint.getExtensibleType() = "sourceModel" and - result instanceof Candidate::SourceType - or - endpoint.getExtensibleType() = "sinkModel" and - result instanceof Candidate::SinkType - } - - /** - * Holds if the given `endpoint` should be considered as a candidate for type `endpointType`, - * and classified by the ML model. - * - * A candidate is an endpoint that cannot be excluded from `endpointType` based on its characteristics. - */ - predicate isCandidate(Candidate::Endpoint endpoint, Candidate::EndpointType endpointType) { - endpointType = getAPotentialType(endpoint) and - not exists(getAnExcludingCharacteristic(endpoint, endpointType)) - } - - /** - * Gets the related location of `e` with name `name`, if it exists. - * Otherwise, gets the candidate itself. - */ - Candidate::RelatedLocation getRelatedLocationOrCandidate( - Candidate::Endpoint e, Candidate::RelatedLocationType type - ) { - if exists(Candidate::getRelatedLocation(e, type)) - then result = Candidate::getRelatedLocation(e, type) - else result = Candidate::asLocation(e) - } - - /** - * Gets a characteristics that disbar `endpoint` from being a candidate for `endpointType` - * with at least medium confidence. - */ - EndpointCharacteristic getAnExcludingCharacteristic( - Candidate::Endpoint endpoint, Candidate::EndpointType endpointType - ) { - result.appliesToEndpoint(endpoint) and - exists(float confidence | - confidence >= mediumConfidence() and - result.hasImplications(endpointType, false, confidence) - ) - } - - /** - * A set of characteristics that a particular endpoint might have. This set of characteristics is used to make decisions - * about whether to include the endpoint in the training set and with what kind, as well as whether to score the - * endpoint at inference time. - */ - abstract class EndpointCharacteristic extends string { - /** - * Holds for the string that is the name of the characteristic. This should describe some property of an endpoint - * that is meaningful for determining whether it's a sink, and if so, of which sink type. - */ - bindingset[this] - EndpointCharacteristic() { any() } - - /** - * Holds for endpoints that have this characteristic. - */ - abstract predicate appliesToEndpoint(Candidate::Endpoint n); - - /** - * This predicate describes what the characteristic tells us about an endpoint. - * - * Params: - * endpointType: The sink/source type. - * isPositiveIndicator: If true, this characteristic indicates that this endpoint _is_ a member of the class; if - * false, it indicates that it _isn't_ a member of the class. - * confidence: A float in [0, 1], which tells us how strong an indicator this characteristic is for the endpoint - * belonging / not belonging to the given class. A confidence near zero means this characteristic is a very weak - * indicator of whether or not the endpoint belongs to the class. A confidence of 1 means that all endpoints with - * this characteristic definitively do/don't belong to the class. - */ - abstract predicate hasImplications( - Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence - ); - - /** Indicators with confidence at or above this threshold are considered to be high-confidence indicators. */ - final float getHighConfidenceThreshold() { result = 0.8 } - } - - /** - * A high-confidence characteristic that indicates that an endpoint is a sink of a specified type. These endpoints can - * be used as positive samples for training or for a few-shot prompt. - */ - abstract class SinkCharacteristic extends EndpointCharacteristic { - bindingset[this] - SinkCharacteristic() { any() } - - abstract Candidate::EndpointType getSinkType(); - - final override predicate hasImplications( - Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence - ) { - endpointType = this.getSinkType() and - isPositiveIndicator = true and - confidence = maximalConfidence() - } - } - - /** - * A high-confidence characteristic that indicates that an endpoint is a source of a specified type. These endpoints can - * be used as positive samples for training or for a few-shot prompt. - */ - abstract class SourceCharacteristic extends EndpointCharacteristic { - bindingset[this] - SourceCharacteristic() { any() } - - abstract Candidate::EndpointType getSourceType(); - - final override predicate hasImplications( - Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence - ) { - endpointType = this.getSourceType() and - isPositiveIndicator = true and - confidence = maximalConfidence() - } - } - - /** - * A high-confidence characteristic that indicates that an endpoint is not a sink of any type. These endpoints can be - * used as negative samples for training or for a few-shot prompt. - */ - abstract class NotASinkCharacteristic extends EndpointCharacteristic { - bindingset[this] - NotASinkCharacteristic() { any() } - - override predicate hasImplications( - Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence - ) { - endpointType instanceof Candidate::SinkType and - isPositiveIndicator = false and - confidence = highConfidence() - } - } - - /** - * A high-confidence characteristic that indicates that an endpoint is not a source of any type. These endpoints can be - * used as negative samples for training or for a few-shot prompt. - */ - abstract class NotASourceCharacteristic extends EndpointCharacteristic { - bindingset[this] - NotASourceCharacteristic() { any() } - - override predicate hasImplications( - Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence - ) { - endpointType instanceof Candidate::SourceType and - isPositiveIndicator = false and - confidence = highConfidence() - } - } - - /** - * A high-confidence characteristic that indicates that an endpoint is neither a source nor a sink of any type. - */ - abstract class NeitherSourceNorSinkCharacteristic extends NotASinkCharacteristic, - NotASourceCharacteristic - { - bindingset[this] - NeitherSourceNorSinkCharacteristic() { any() } - - final override predicate hasImplications( - Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence - ) { - NotASinkCharacteristic.super.hasImplications(endpointType, isPositiveIndicator, confidence) or - NotASourceCharacteristic.super.hasImplications(endpointType, isPositiveIndicator, confidence) - } - } - - /** - * A medium-confidence characteristic that indicates that an endpoint is unlikely to be a sink of any type. These - * endpoints can be excluded from scoring at inference time, both to save time and to avoid false positives. They should - * not, however, be used as negative samples for training or for a few-shot prompt, because they may include a small - * number of sinks. - */ - abstract class LikelyNotASinkCharacteristic extends EndpointCharacteristic { - bindingset[this] - LikelyNotASinkCharacteristic() { any() } - - override predicate hasImplications( - Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence - ) { - endpointType instanceof Candidate::SinkType and - isPositiveIndicator = false and - confidence = mediumConfidence() - } - } - - /** - * A characteristic that indicates not necessarily that an endpoint is not a sink, but rather that it is not a sink - * that's interesting to model in the standard Java libraries. These filters should be removed when extracting sink - * candidates within a user's codebase for customized modeling. - * - * These endpoints should not be used as negative samples for training or for a few-shot prompt, because they are not - * necessarily non-sinks. - */ - abstract class UninterestingToModelCharacteristic extends EndpointCharacteristic { - bindingset[this] - UninterestingToModelCharacteristic() { any() } - - override predicate hasImplications( - Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence - ) { - endpointType instanceof Candidate::SinkType and - isPositiveIndicator = false and - confidence = mediumConfidence() - } - } - - /** - * Contains default implementations that are derived solely from the `CandidateSig` implementation. - */ - private module DefaultCharacteristicImplementations { - /** - * Endpoints identified as sinks by the `CandidateSig` implementation are sinks with maximal confidence. - */ - private class KnownSinkCharacteristic extends SinkCharacteristic { - string madKind; - Candidate::EndpointType endpointType; - string provenance; - - KnownSinkCharacteristic() { - Candidate::isKnownKind(madKind, endpointType) and - // bind "this" to a unique string differing from that of the SinkType classes - this = madKind + "_" + provenance + "_characteristic" and - Candidate::isSink(_, madKind, provenance) - } - - override predicate appliesToEndpoint(Candidate::Endpoint e) { - Candidate::isSink(e, madKind, provenance) - } - - override Candidate::EndpointType getSinkType() { result = endpointType } - } - - private class KnownSourceCharacteristic extends SourceCharacteristic { - string madKind; - Candidate::EndpointType endpointType; - string provenance; - - KnownSourceCharacteristic() { - Candidate::isKnownKind(madKind, endpointType) and - // bind "this" to a unique string differing from that of the SinkType classes - this = madKind + "_" + provenance + "_characteristic" and - Candidate::isSource(_, madKind, provenance) - } - - override predicate appliesToEndpoint(Candidate::Endpoint e) { - Candidate::isSource(e, madKind, provenance) - } - - override Candidate::EndpointType getSourceType() { result = endpointType } - } - - /** - * A negative characteristic that indicates that an endpoint was manually modeled as a neutral model. - */ - private class NeutralModelCharacteristic extends NeitherSourceNorSinkCharacteristic { - NeutralModelCharacteristic() { this = "known non-sink" } - - override predicate appliesToEndpoint(Candidate::Endpoint e) { Candidate::isNeutral(e) } - } - - /** - * A negative characteristic that indicates that an endpoint is a sanitizer, and thus not a source. - */ - private class IsSanitizerCharacteristic extends NotASourceCharacteristic { - IsSanitizerCharacteristic() { this = "known sanitizer" } - - override predicate appliesToEndpoint(Candidate::Endpoint e) { Candidate::isSanitizer(e, _) } - } - } -} diff --git a/java/ql/automodel/src/AutomodelSinkModelMrvaQueries.ql b/java/ql/automodel/src/AutomodelSinkModelMrvaQueries.ql deleted file mode 100644 index ed61ccfbbfd..00000000000 --- a/java/ql/automodel/src/AutomodelSinkModelMrvaQueries.ql +++ /dev/null @@ -1,62 +0,0 @@ -/** - * This file contains query predicates for use when gathering metrics at scale using Multi Repo - * Variant Analysis. - */ - -private import java -private import AutomodelAlertSinkUtil - -/** - * Holds if `alertCount` is the number of alerts for the query with ID `queryId` for which the - * sinks correspond to the given `ai-generated` sink model. - */ -query predicate sinkModelCountPerQuery( - string queryId, int alertCount, string package, string type, boolean subtypes, string name, - string signature, string input, string ext, string kind, string provenance -) { - exists(SinkModel s | - sinkModelTallyPerQuery(queryId, alertCount, s) and - s.getProvenance() = "ai-generated" and - s.getPackage() = package and - s.getType() = type and - s.getSubtypes() = subtypes and - s.getName() = name and - s.getSignature() = signature and - s.getInput() = input and - s.getExt() = ext and - s.getKind() = kind and - s.getProvenance() = provenance - ) -} - -/** - * Holds if `instanceCount` is the number of instances corresponding to the given `ai-generated` - * sink model (as identified by the `package`, `name`, `input`, etc.). - */ -query predicate instanceCount( - int instanceCount, string package, string type, boolean subtypes, string name, string signature, - string input, string ext, string kind, string provenance -) { - exists(SinkModel s | - instanceCount = s.getInstanceCount() and - instanceCount > 0 and - s.getProvenance() = "ai-generated" and - s.getPackage() = package and - s.getType() = type and - s.getSubtypes() = subtypes and - s.getName() = name and - s.getSignature() = signature and - s.getInput() = input and - s.getExt() = ext and - s.getKind() = kind and - s.getProvenance() = provenance - ) -} - -// MRVA requires a select clause, so we repurpose it to tell us which query predicates had results. -from string hadResults -where - sinkModelCountPerQuery(_, _, _, _, _, _, _, _, _, _, _) and hadResults = "sinkModelCountPerQuery" - or - instanceCount(_, _, _, _, _, _, _, _, _, _) and hadResults = "instanceCount" -select hadResults diff --git a/java/ql/automodel/src/change-notes/2024-11-19-drop-automodel.md b/java/ql/automodel/src/change-notes/2024-11-19-drop-automodel.md new file mode 100644 index 00000000000..2b554d6de20 --- /dev/null +++ b/java/ql/automodel/src/change-notes/2024-11-19-drop-automodel.md @@ -0,0 +1,4 @@ +--- +category: breaking +--- +* Dropped the Java Automodel queries. diff --git a/java/ql/automodel/src/codeql-pack.release.yml b/java/ql/automodel/src/codeql-pack.release.yml deleted file mode 100644 index 2036690b201..00000000000 --- a/java/ql/automodel/src/codeql-pack.release.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- -lastReleaseVersion: 1.0.12 diff --git a/java/ql/automodel/src/qlpack.yml b/java/ql/automodel/src/qlpack.yml deleted file mode 100644 index da81981956b..00000000000 --- a/java/ql/automodel/src/qlpack.yml +++ /dev/null @@ -1,10 +0,0 @@ -name: codeql/java-automodel-queries -version: 1.0.13-dev -groups: - - java - - automodel -dependencies: - codeql/java-all: ${workspace} -dataExtensions: - - AutomodelCandidateFilter.yml -warnOnImplicitThis: true \ No newline at end of file diff --git a/java/ql/automodel/test/AutomodelApplicationModeExtraction/AutomodelApplicationModeExtractionTests.expected b/java/ql/automodel/test/AutomodelApplicationModeExtraction/AutomodelApplicationModeExtractionTests.expected deleted file mode 100644 index 8ec8033d086..00000000000 --- a/java/ql/automodel/test/AutomodelApplicationModeExtraction/AutomodelApplicationModeExtractionTests.expected +++ /dev/null @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/java/ql/automodel/test/AutomodelApplicationModeExtraction/AutomodelApplicationModeExtractionTests.ql b/java/ql/automodel/test/AutomodelApplicationModeExtraction/AutomodelApplicationModeExtractionTests.ql deleted file mode 100644 index b7e1efc4532..00000000000 --- a/java/ql/automodel/test/AutomodelApplicationModeExtraction/AutomodelApplicationModeExtractionTests.ql +++ /dev/null @@ -1,35 +0,0 @@ -import java -import AutomodelApplicationModeCharacteristics as Characteristics -import AutomodelExtractionTests - -module TestHelper implements TestHelperSig { - Location getEndpointLocation(Characteristics::Endpoint endpoint) { - result = endpoint.asTop().getLocation() - } - - predicate isCandidate( - Characteristics::Endpoint endpoint, string name, string signature, string input, string output, - string extensibleType - ) { - Characteristics::isCandidate(endpoint, _, _, _, name, signature, input, output, _, - extensibleType, _) - } - - predicate isPositiveExample( - Characteristics::Endpoint endpoint, string endpointType, string name, string signature, - string input, string output, string extensibleType - ) { - Characteristics::isPositiveExample(endpoint, endpointType, _, _, _, name, signature, input, - output, _, extensibleType) - } - - predicate isNegativeExample( - Characteristics::Endpoint endpoint, string name, string signature, string input, string output, - string extensibleType - ) { - Characteristics::isNegativeExample(endpoint, _, _, _, _, _, name, signature, input, output, _, - extensibleType) - } -} - -import MakeTest> diff --git a/java/ql/automodel/test/AutomodelApplicationModeExtraction/PluginImpl.java b/java/ql/automodel/test/AutomodelApplicationModeExtraction/PluginImpl.java deleted file mode 100644 index b0f3482a732..00000000000 --- a/java/ql/automodel/test/AutomodelApplicationModeExtraction/PluginImpl.java +++ /dev/null @@ -1,8 +0,0 @@ -import hudson.Plugin; - -public class PluginImpl extends Plugin { - @Override - public void configure(String name, String value) { // $ sourceModelCandidate=configure(String,String):Parameter[0] sourceModelCandidate=configure(String,String):Parameter[1] - // ... - } -} diff --git a/java/ql/automodel/test/AutomodelApplicationModeExtraction/Test.java b/java/ql/automodel/test/AutomodelApplicationModeExtraction/Test.java deleted file mode 100644 index 9691cf86c15..00000000000 --- a/java/ql/automodel/test/AutomodelApplicationModeExtraction/Test.java +++ /dev/null @@ -1,112 +0,0 @@ -package com.github.codeql.test; - -import java.io.InputStream; -import java.io.PrintWriter; -import java.nio.file.CopyOption; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Supplier; -import java.io.File; -import java.io.FileFilter; -import java.nio.file.FileVisitOption; -import java.net.URLConnection; -import java.util.concurrent.FutureTask; - -class Test { - public static void main(String[] args) throws Exception { - AtomicReference reference = new AtomicReference<>(); // uninteresting (parameterless constructor) - reference.set( // $ sinkModelCandidate=set(Object):Argument[this] - args[0] // $ negativeSinkExample=set(Object):Argument[0] // modeled as a flow step - ); // not a source candidate (return type is void) - } - - public static void callSupplier(Supplier supplier) { - supplier.get(); // not a source candidate (lambda flow) - } - - public static void copyFiles(Path source, Path target, CopyOption option) throws Exception { - Files.copy( - source, // $ positiveSinkExample=copy(Path,Path,CopyOption[]):Argument[0](path-injection) - target, // $ positiveSinkExample=copy(Path,Path,CopyOption[]):Argument[1](path-injection) - option // no candidate (not modeled, but source and target are modeled) - ); // $ sourceModelCandidate=copy(Path,Path,CopyOption[]):ReturnValue - } - - public static InputStream getInputStream(Path openPath) throws Exception { - return Files.newInputStream( - openPath // $ sinkModelCandidate=newInputStream(Path,OpenOption[]):Argument[0] positiveSinkExample=newInputStream(Path,OpenOption[]):Argument[0](path-injection) // sink candidate because "only" ai-modeled, and useful as a candidate in regression testing - ); // $ sourceModelCandidate=newInputStream(Path,OpenOption[]):ReturnValue - } - - public static InputStream getInputStream(String openPath, String otherPath) throws Exception { - return Test.getInputStream( // the call is not a source candidate (argument to local call) - Paths.get( - openPath, // $ negativeSinkExample=get(String,String[]):Argument[0] // modeled as a flow step - otherPath - ) // $ sourceModelCandidate=get(String,String[]):ReturnValue negativeSinkExample=get(String,String[]):Argument[1] - ); - } - - public static int compareFiles(File f1, File f2) { - return f1.compareTo( // $ negativeSinkExample=compareTo(File):Argument[this] - f2 // $ negativeSinkExample=compareTo(File):Argument[0] // modeled as not a sink - ); // not a source candidate (return type is int) - } - - public static void FilesWalkExample(Path p, FileVisitOption o) throws Exception { - Files.walk( - p, // $ negativeSinkExample=walk(Path,FileVisitOption[]):Argument[0] // modeled as a flow step - o, // the implicit varargs array is a candidate, annotated on the last line of the call - o // not a candidate (only the first arg corresponding to a varargs array - // is extracted) - ); // $ sourceModelCandidate=walk(Path,FileVisitOption[]):ReturnValue sinkModelCandidate=walk(Path,FileVisitOption[]):Argument[1] - } - - public static void WebSocketExample(URLConnection c) throws Exception { - c.getInputStream(); // $ sinkModelCandidate=getInputStream():Argument[this] positiveSourceExample=getInputStream():ReturnValue(remote) // not a source candidate (manual modeling) - c.connect(); // $ sinkModelCandidate=connect():Argument[this] // not a source candidate (return type is void) - } - - public static void fileFilterExample(File f, FileFilter ff) { - f.listFiles( // $ sinkModelCandidate=listFiles(FileFilter):Argument[this] - ff - ); // $ sourceModelCandidate=listFiles(FileFilter):ReturnValue - } -} - -class OverrideTest extends Exception { - public void printStackTrace(PrintWriter writer) { // $ sourceModelCandidate=printStackTrace(PrintWriter):Parameter[0] - return; - } - -} - -class TaskUtils { - public FutureTask getTask() { - FutureTask ft = new FutureTask(() -> { - // ^-- no sink candidate for the `this` qualifier of a constructor - return 42; - }); - return ft; - } -} - -class MoreTests { - public static void FilesListExample(Path p) throws Exception { - Files.list( - Files.createDirectories( - p // $ positiveSinkExample=createDirectories(Path,FileAttribute[]):Argument[0](path-injection) - ) // $ sourceModelCandidate=createDirectories(Path,FileAttribute[]):ReturnValue negativeSinkExample=list(Path):Argument[0] // modeled as a flow step - ); // $ sourceModelCandidate=list(Path):ReturnValue - - Files.delete( - p // $ sinkModelCandidate=delete(Path):Argument[0] positiveSinkExample=delete(Path):Argument[0](path-injection) - ); // not a source candidate (return type is void) - - Files.deleteIfExists( - p // $ sinkModelCandidate=deleteIfExists(Path):Argument[0] positiveSinkExample=deleteIfExists(Path):Argument[0](path-injection) - ); // not a source candidate (return type is boolean) - } -} \ No newline at end of file diff --git a/java/ql/automodel/test/AutomodelApplicationModeExtraction/hudson/Plugin.java b/java/ql/automodel/test/AutomodelApplicationModeExtraction/hudson/Plugin.java deleted file mode 100644 index 3ad79abb8df..00000000000 --- a/java/ql/automodel/test/AutomodelApplicationModeExtraction/hudson/Plugin.java +++ /dev/null @@ -1,7 +0,0 @@ -package hudson; - -/** Plugin doc */ -public class Plugin { - /** Configure method doc */ - public void configure(String name, String value) {} -} diff --git a/java/ql/automodel/test/AutomodelExtractionTests.qll b/java/ql/automodel/test/AutomodelExtractionTests.qll deleted file mode 100644 index fbc407c67f0..00000000000 --- a/java/ql/automodel/test/AutomodelExtractionTests.qll +++ /dev/null @@ -1,77 +0,0 @@ -import java -import TestUtilities.InlineExpectationsTest -import AutomodelSharedCharacteristics - -signature module TestHelperSig { - Location getEndpointLocation(Candidate::Endpoint e); - - predicate isCandidate( - Candidate::Endpoint e, string name, string signature, string input, string output, - string extensibleType - ); - - predicate isPositiveExample( - Candidate::Endpoint e, string endpointType, string name, string signature, string input, - string output, string extensibleType - ); - - predicate isNegativeExample( - Candidate::Endpoint e, string name, string signature, string input, string output, - string extensibleType - ); -} - -module Extraction TestHelper> implements TestSig { - string getARelevantTag() { - result in [ - "sourceModelCandidate", "sinkModelCandidate", // a candidate source/sink - "positiveSourceExample", "positiveSinkExample", // a known source/sink - "negativeSourceExample", "negativeSinkExample" // a known non-source/non-sink - ] - } - - /** - * If `extensibleType` is `sourceModel` then the result is `ifSource`, if it - * is `sinkModel` then the result is `ifSink`. - */ - bindingset[extensibleType, ifSource, ifSink] - private string ifSource(string extensibleType, string ifSource, string ifSink) { - extensibleType = "sourceModel" and result = ifSource - or - extensibleType = "sinkModel" and result = ifSink - } - - additional predicate selectEndpoint( - Candidate::Endpoint endpoint, string name, string signature, string input, string output, - string extensibleType, string tag, string suffix - ) { - TestHelper::isCandidate(endpoint, name, signature, input, output, extensibleType) and - tag = ifSource(extensibleType, "sourceModelCandidate", "sinkModelCandidate") and - suffix = "" - or - TestHelper::isNegativeExample(endpoint, name, signature, input, output, extensibleType) and - tag = "negative" + ifSource(extensibleType, "Source", "Sink") + "Example" and - suffix = "" - or - exists(string endpointType | - TestHelper::isPositiveExample(endpoint, endpointType, name, signature, input, output, - extensibleType) and - tag = "positive" + ifSource(extensibleType, "Source", "Sink") + "Example" and - suffix = "(" + endpointType + ")" - ) - } - - predicate hasActualResult(Location location, string element, string tag, string value) { - exists( - Candidate::Endpoint endpoint, string name, string signature, string input, string output, - string extensibleType, string suffix - | - selectEndpoint(endpoint, name, signature, input, output, extensibleType, tag, suffix) - | - TestHelper::getEndpointLocation(endpoint) = location and - endpoint.toString() = element and - // for source models only the output is relevant, and vice versa for sink models - value = name + signature + ":" + ifSource(extensibleType, output, input) + suffix - ) - } -} diff --git a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/AutomodelFrameworkModeExtractionTests.expected b/java/ql/automodel/test/AutomodelFrameworkModeExtraction/AutomodelFrameworkModeExtractionTests.expected deleted file mode 100644 index 8ec8033d086..00000000000 --- a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/AutomodelFrameworkModeExtractionTests.expected +++ /dev/null @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/AutomodelFrameworkModeExtractionTests.ql b/java/ql/automodel/test/AutomodelFrameworkModeExtraction/AutomodelFrameworkModeExtractionTests.ql deleted file mode 100644 index 0d5e8611870..00000000000 --- a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/AutomodelFrameworkModeExtractionTests.ql +++ /dev/null @@ -1,35 +0,0 @@ -import java -import AutomodelFrameworkModeCharacteristics as Characteristics -import AutomodelExtractionTests - -module TestHelper implements TestHelperSig { - Location getEndpointLocation(Characteristics::Endpoint endpoint) { - result = endpoint.asTop().getLocation() - } - - predicate isCandidate( - Characteristics::Endpoint endpoint, string name, string signature, string input, string output, - string extensibleType - ) { - Characteristics::isCandidate(endpoint, _, _, _, name, signature, input, output, _, - extensibleType, _) - } - - predicate isPositiveExample( - Characteristics::Endpoint endpoint, string endpointType, string name, string signature, - string input, string output, string extensibleType - ) { - Characteristics::isPositiveExample(endpoint, endpointType, _, _, _, name, signature, input, - output, _, extensibleType) - } - - predicate isNegativeExample( - Characteristics::Endpoint endpoint, string name, string signature, string input, string output, - string extensibleType - ) { - Characteristics::isNegativeExample(endpoint, _, _, _, _, _, name, signature, input, output, _, - extensibleType) - } -} - -import MakeTest> diff --git a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/com/github/codeql/test/MyWriter.java b/java/ql/automodel/test/AutomodelFrameworkModeExtraction/com/github/codeql/test/MyWriter.java deleted file mode 100644 index 62bd773cc2e..00000000000 --- a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/com/github/codeql/test/MyWriter.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.github.codeql.test; - -public class MyWriter extends java.io.Writer { - @Override - public void write(char[] cbuf, int off, int len) { // $ sinkModelCandidate=write(char[],int,int):Argument[this] positiveSinkExample=write(char[],int,int):Argument[0](file-content-store) sourceModelCandidate=write(char[],int,int):Parameter[this] sourceModelCandidate=write(char[],int,int):Parameter[0] - } - - @Override - public void close() { // $ sinkModelCandidate=close():Argument[this] sourceModelCandidate=close():Parameter[this] - } - - @Override - public void flush() { // $ sinkModelCandidate=flush():Argument[this] sourceModelCandidate=flush():Parameter[this] - } -} diff --git a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/com/github/codeql/test/NonPublicClass.java b/java/ql/automodel/test/AutomodelFrameworkModeExtraction/com/github/codeql/test/NonPublicClass.java deleted file mode 100644 index b106d3da594..00000000000 --- a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/com/github/codeql/test/NonPublicClass.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.github.codeql.test; - -/** - * No candidates in this class, as it's not public! - */ -class NonPublicClass { - public void noCandidates(String here) { - System.out.println(here); - } -} diff --git a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/com/github/codeql/test/PublicClass.java b/java/ql/automodel/test/AutomodelFrameworkModeExtraction/com/github/codeql/test/PublicClass.java deleted file mode 100644 index 79fabff0664..00000000000 --- a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/com/github/codeql/test/PublicClass.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.github.codeql.test; - -public class PublicClass { - public void stuff(String arg) { // $ sinkModelCandidate=stuff(String):Argument[this] sourceModelCandidate=stuff(String):Parameter[this] sinkModelCandidate=stuff(String):Argument[0] sourceModelCandidate=stuff(String):Parameter[0] // source candidates because it is an overrideable method - System.out.println(arg); - } - - public static void staticStuff(String arg) { // $ sinkModelCandidate=staticStuff(String):Argument[0] // `arg` is not a source candidate (not overrideabe); `this` is not a candidate (static method) - System.out.println(arg); - } - - protected void nonPublicStuff(String arg) { // $ sinkModelCandidate=nonPublicStuff(String):Argument[this] sourceModelCandidate=nonPublicStuff(String):Parameter[this] sinkModelCandidate=nonPublicStuff(String):Argument[0] sourceModelCandidate=nonPublicStuff(String):Parameter[0] - System.out.println(arg); - } - - void packagePrivateStuff(String arg) { // no candidates because the method is not public - System.out.println(arg); - } - - public PublicClass(Object input) { // $ sourceModelCandidate=PublicClass(Object):ReturnValue sinkModelCandidate=PublicClass(Object):Argument[0] // `this` is not a candidate because it is a constructor - } - - // `input` and `input` are source candidates, but not sink candidates (is-style method) - public Boolean isIgnored(Object input) { // $ negativeSinkExample=isIgnored(Object):Argument[this] sourceModelCandidate=isIgnored(Object):Parameter[this] negativeSinkExample=isIgnored(Object):Argument[0] sourceModelCandidate=isIgnored(Object):Parameter[0] - return false; - } -} diff --git a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/com/github/codeql/test/PublicInterface.java b/java/ql/automodel/test/AutomodelFrameworkModeExtraction/com/github/codeql/test/PublicInterface.java deleted file mode 100644 index d4f80b3c698..00000000000 --- a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/com/github/codeql/test/PublicInterface.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.github.codeql.test; - -public interface PublicInterface { - public int stuff(String arg); // $ sinkModelCandidate=stuff(String):Argument[this] sourceModelCandidate=stuff(String):Parameter[this] sinkModelCandidate=stuff(String):Argument[0] sourceModelCandidate=stuff(String):Parameter[0] // result is _not_ a source candidate source (primitive return type) - - public static void staticStuff(String arg) { // $ sinkModelCandidate=staticStuff(String):Argument[0] // not a source candidate (static method) - System.out.println(arg); - } -} diff --git a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/java/io/File.java b/java/ql/automodel/test/AutomodelFrameworkModeExtraction/java/io/File.java deleted file mode 100644 index 8bfe83e2339..00000000000 --- a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/java/io/File.java +++ /dev/null @@ -1,13 +0,0 @@ -package java.io; - -public class File { - public int compareTo( // $ negativeSinkExample=compareTo(File):Argument[this] sourceModelCandidate=compareTo(File):Parameter[this] // modeled as neutral for sinks - File pathname // $ negativeSinkExample=compareTo(File):Argument[0] sourceModelCandidate=compareTo(File):Parameter[0] // modeled as neutral for sinks - ) { - return 0; - } - - public boolean setLastModified(long time) { // $ sinkModelCandidate=setLastModified(long):Argument[this] sourceModelCandidate=setLastModified(long):Parameter[this] // time is not a candidate (primitive type) - return false; - } // return value is not a source candidate because it's a primitive -} diff --git a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/java/nio/file/Files.java b/java/ql/automodel/test/AutomodelFrameworkModeExtraction/java/nio/file/Files.java deleted file mode 100644 index a833ba5f6e2..00000000000 --- a/java/ql/automodel/test/AutomodelFrameworkModeExtraction/java/nio/file/Files.java +++ /dev/null @@ -1,31 +0,0 @@ -package java.nio.file; - -import java.io.InputStream; -import java.io.FileInputStream; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.io.IOException; -import java.io.OutputStream; -import java.nio.file.OpenOption; - -public class Files { - public static void copy( // method result is not a candidate source (void) - Path source, // $ positiveSinkExample=copy(Path,OutputStream):Argument[0](path-injection) // manual model exists - OutputStream out // $ sinkModelCandidate=copy(Path,OutputStream):Argument[1] - /* NB: may be worthwhile to implement the - same behavior as in application mode where out would not be a - candidate because there already is a model for another parameter of - the same method and we assume that methods are always modeled - completely. - */ - ) throws IOException { - // ... - } - - public static InputStream newInputStream( // $ sourceModelCandidate=newInputStream(Path,OpenOption[]):ReturnValue - Path openPath, // $ positiveSinkExample=newInputStream(Path,OpenOption[]):Argument[0](path-injection) sinkModelCandidate=newInputStream(Path,OpenOption[]):Argument[0] // known sink, but still a candidate (ai-modeled, and useful as a candidate in regression testing) - OpenOption... options // $ sinkModelCandidate=newInputStream(Path,OpenOption[]):Argument[1] - ) throws IOException { - return new FileInputStream(openPath.toFile()); - } -} diff --git a/java/ql/automodel/test/change-notes/2024-05-23-Version1.md b/java/ql/automodel/test/change-notes/2024-05-23-Version1.md deleted file mode 100644 index 5840e51017b..00000000000 --- a/java/ql/automodel/test/change-notes/2024-05-23-Version1.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -category: breaking ---- -* CodeQL package management is now generally available, and all GitHub-produced CodeQL packages have had their version numbers increased to 1.0.0. diff --git a/java/ql/automodel/test/qlpack.yml b/java/ql/automodel/test/qlpack.yml deleted file mode 100644 index 46138d9435c..00000000000 --- a/java/ql/automodel/test/qlpack.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: codeql/java-automodel-tests -version: 1.0.0-dev -groups: - - java - - automodel - - test -dependencies: - codeql/java-all: ${workspace} - codeql/java-automodel-queries: ${workspace} - codeql/java-tests: ${workspace} -extractor: java -tests: . -warnOnImplicitThis: true \ No newline at end of file diff --git a/java/ql/integration-tests/kotlin/all-platforms/default-parameter-mad-flow/test.expected b/java/ql/integration-tests/kotlin/all-platforms/default-parameter-mad-flow/test.expected index 8ec8033d086..e69de29bb2d 100644 --- a/java/ql/integration-tests/kotlin/all-platforms/default-parameter-mad-flow/test.expected +++ b/java/ql/integration-tests/kotlin/all-platforms/default-parameter-mad-flow/test.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/java/ql/lib/change-notes/2024-11-04-list-of-constants-sanitizer.md b/java/ql/lib/change-notes/2024-11-04-list-of-constants-sanitizer.md new file mode 100644 index 00000000000..dea1e7ff81e --- /dev/null +++ b/java/ql/lib/change-notes/2024-11-04-list-of-constants-sanitizer.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Calling `coll.contains(x)` is now a taint sanitizer (for any query) for the value `x`, where `coll` is a collection of constants. diff --git a/java/ql/lib/change-notes/2024-12-03-remove-dataflow-config-class-api.md b/java/ql/lib/change-notes/2024-12-03-remove-dataflow-config-class-api.md new file mode 100644 index 00000000000..d09ec528c99 --- /dev/null +++ b/java/ql/lib/change-notes/2024-12-03-remove-dataflow-config-class-api.md @@ -0,0 +1,4 @@ +--- +category: breaking +--- +* Deleted the old deprecated data flow API that was based on extending a configuration class. See https://github.blog/changelog/2023-08-14-new-dataflow-api-for-writing-custom-codeql-queries for instructions on migrating your queries to use the new API. diff --git a/java/ql/lib/semmle/code/java/dataflow/DataFlow.qll b/java/ql/lib/semmle/code/java/dataflow/DataFlow.qll index 66a7a847c33..ab48577c02e 100644 --- a/java/ql/lib/semmle/code/java/dataflow/DataFlow.qll +++ b/java/ql/lib/semmle/code/java/dataflow/DataFlow.qll @@ -9,5 +9,5 @@ module DataFlow { private import semmle.code.java.dataflow.internal.DataFlowImplSpecific private import codeql.dataflow.DataFlow import DataFlowMake - import semmle.code.java.dataflow.internal.DataFlowImpl1 + import Public } diff --git a/java/ql/lib/semmle/code/java/dataflow/DataFlow2.qll b/java/ql/lib/semmle/code/java/dataflow/DataFlow2.qll deleted file mode 100644 index 92003314778..00000000000 --- a/java/ql/lib/semmle/code/java/dataflow/DataFlow2.qll +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) data flow analyses. - */ - -import java - -module DataFlow2 { - import semmle.code.java.dataflow.internal.DataFlowImpl2 -} diff --git a/java/ql/lib/semmle/code/java/dataflow/DataFlow3.qll b/java/ql/lib/semmle/code/java/dataflow/DataFlow3.qll deleted file mode 100644 index c8d614e0879..00000000000 --- a/java/ql/lib/semmle/code/java/dataflow/DataFlow3.qll +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) data flow analyses. - */ - -import java - -module DataFlow3 { - import semmle.code.java.dataflow.internal.DataFlowImpl3 -} diff --git a/java/ql/lib/semmle/code/java/dataflow/DataFlow4.qll b/java/ql/lib/semmle/code/java/dataflow/DataFlow4.qll deleted file mode 100644 index 852cfd9f813..00000000000 --- a/java/ql/lib/semmle/code/java/dataflow/DataFlow4.qll +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) data flow analyses. - */ - -import java - -module DataFlow4 { - import semmle.code.java.dataflow.internal.DataFlowImpl4 -} diff --git a/java/ql/lib/semmle/code/java/dataflow/DataFlow5.qll b/java/ql/lib/semmle/code/java/dataflow/DataFlow5.qll deleted file mode 100644 index f8986a03524..00000000000 --- a/java/ql/lib/semmle/code/java/dataflow/DataFlow5.qll +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) data flow analyses. - */ - -import java - -module DataFlow5 { - import semmle.code.java.dataflow.internal.DataFlowImpl5 -} diff --git a/java/ql/lib/semmle/code/java/dataflow/DataFlow6.qll b/java/ql/lib/semmle/code/java/dataflow/DataFlow6.qll deleted file mode 100644 index 28fa11da475..00000000000 --- a/java/ql/lib/semmle/code/java/dataflow/DataFlow6.qll +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) data flow analyses. - */ - -import java - -module DataFlow6 { - import semmle.code.java.dataflow.internal.DataFlowImpl6 -} diff --git a/java/ql/lib/semmle/code/java/dataflow/FlowSteps.qll b/java/ql/lib/semmle/code/java/dataflow/FlowSteps.qll index e7d34d166b1..c931817e00b 100644 --- a/java/ql/lib/semmle/code/java/dataflow/FlowSteps.qll +++ b/java/ql/lib/semmle/code/java/dataflow/FlowSteps.qll @@ -28,6 +28,7 @@ private module Frameworks { private import semmle.code.java.frameworks.ThreadLocal private import semmle.code.java.frameworks.ratpack.RatpackExec private import semmle.code.java.frameworks.stapler.Stapler + private import semmle.code.java.security.ListOfConstantsSanitizer } /** @@ -189,3 +190,8 @@ private class NumberTaintPreservingCallable extends TaintPreservingCallable { * map-key and map-value content, so that e.g. a tainted `Map` is assumed to have tainted keys and values. */ abstract class TaintInheritingContent extends DataFlow::Content { } + +/** + * A sanitizer in all global taint flow configurations but not in local taint. + */ +abstract class DefaultTaintSanitizer extends DataFlow::Node { } diff --git a/java/ql/lib/semmle/code/java/dataflow/TaintTracking.qll b/java/ql/lib/semmle/code/java/dataflow/TaintTracking.qll index ed13837a312..e62850fbc38 100644 --- a/java/ql/lib/semmle/code/java/dataflow/TaintTracking.qll +++ b/java/ql/lib/semmle/code/java/dataflow/TaintTracking.qll @@ -4,14 +4,12 @@ */ import semmle.code.java.dataflow.DataFlow -import semmle.code.java.dataflow.DataFlow2 import semmle.code.java.dataflow.internal.TaintTrackingUtil::StringBuilderVarModule module TaintTracking { - import semmle.code.java.dataflow.internal.tainttracking1.TaintTrackingParameter::Public + import semmle.code.java.dataflow.internal.TaintTrackingUtil private import semmle.code.java.dataflow.internal.DataFlowImplSpecific private import semmle.code.java.dataflow.internal.TaintTrackingImplSpecific private import codeql.dataflow.TaintTracking import TaintFlowMake - import semmle.code.java.dataflow.internal.tainttracking1.TaintTrackingImpl } diff --git a/java/ql/lib/semmle/code/java/dataflow/TaintTracking2.qll b/java/ql/lib/semmle/code/java/dataflow/TaintTracking2.qll deleted file mode 100644 index abd909dba2b..00000000000 --- a/java/ql/lib/semmle/code/java/dataflow/TaintTracking2.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) taint-tracking analyses. - */ -module TaintTracking2 { - import semmle.code.java.dataflow.internal.tainttracking2.TaintTrackingImpl -} diff --git a/java/ql/lib/semmle/code/java/dataflow/TaintTracking3.qll b/java/ql/lib/semmle/code/java/dataflow/TaintTracking3.qll deleted file mode 100644 index 49c43ed1418..00000000000 --- a/java/ql/lib/semmle/code/java/dataflow/TaintTracking3.qll +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) taint-tracking analyses. - */ -module TaintTracking3 { - import semmle.code.java.dataflow.internal.tainttracking3.TaintTrackingImpl -} diff --git a/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll b/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll index c548c5db38b..9e05b69db4a 100644 --- a/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll +++ b/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll @@ -13,24 +13,27 @@ private import semmle.code.java.dispatch.VirtualDispatch private import semmle.code.java.dataflow.internal.BaseSSA private import semmle.code.java.controlflow.Guards private import codeql.typeflow.TypeFlow +private import codeql.typeflow.UniversalFlow as UniversalFlow -private module Input implements TypeFlowInput { - private newtype TTypeFlowNode = +/** Gets `t` if it is a `RefType` or the boxed type if `t` is a primitive type. */ +private RefType boxIfNeeded(J::Type t) { + t.(PrimitiveType).getBoxedType() = result or + result = t +} + +/** Provides the input types and predicates for instantiation of `UniversalFlow`. */ +module FlowStepsInput implements UniversalFlow::UniversalFlowInput { + private newtype TFlowNode = TField(Field f) { not f.getType() instanceof PrimitiveType } or TSsa(BaseSsaVariable ssa) { not ssa.getSourceVariable().getType() instanceof PrimitiveType } or TExpr(Expr e) or TMethod(Method m) { not m.getReturnType() instanceof PrimitiveType } - /** Gets `t` if it is a `RefType` or the boxed type if `t` is a primitive type. */ - private RefType boxIfNeeded(J::Type t) { - t.(PrimitiveType).getBoxedType() = result or - result = t - } - /** * A `Field`, `BaseSsaVariable`, `Expr`, or `Method`. */ - class TypeFlowNode extends TTypeFlowNode { + class FlowNode extends TFlowNode { + /** Gets a textual representation of this element. */ string toString() { result = this.asField().toString() or result = this.asSsa().toString() or @@ -38,6 +41,7 @@ private module Input implements TypeFlowInput { result = this.asMethod().toString() } + /** Gets the source location for this element. */ Location getLocation() { result = this.asField().getLocation() or result = this.asSsa().getLocation() or @@ -45,14 +49,19 @@ private module Input implements TypeFlowInput { result = this.asMethod().getLocation() } + /** Gets the field corresponding to this node, if any. */ Field asField() { this = TField(result) } + /** Gets the SSA variable corresponding to this node, if any. */ BaseSsaVariable asSsa() { this = TSsa(result) } + /** Gets the expression corresponding to this node, if any. */ Expr asExpr() { this = TExpr(result) } + /** Gets the method corresponding to this node, if any. */ Method asMethod() { this = TMethod(result) } + /** Gets the type of this node. */ RefType getType() { result = this.asField().getType() or result = this.asSsa().getSourceVariable().getType() or @@ -61,8 +70,6 @@ private module Input implements TypeFlowInput { } } - class Type = RefType; - private SrcCallable viableCallable_v1(Call c) { result = viableImpl_v1(c) or @@ -88,7 +95,7 @@ private module Input implements TypeFlowInput { * * For a given `n2`, this predicate must include all possible `n1` that can flow to `n2`. */ - predicate step(TypeFlowNode n1, TypeFlowNode n2) { + predicate step(FlowNode n1, FlowNode n2) { n2.asExpr().(ChooseExpr).getAResultExpr() = n1.asExpr() or exists(Field f, Expr e | @@ -134,7 +141,7 @@ private module Input implements TypeFlowInput { /** * Holds if `null` is the only value that flows to `n`. */ - predicate isNullValue(TypeFlowNode n) { + predicate isNullValue(FlowNode n) { n.asExpr() instanceof NullLiteral or exists(LocalVariableDeclExpr decl | @@ -144,11 +151,21 @@ private module Input implements TypeFlowInput { ) } - predicate isExcludedFromNullAnalysis(TypeFlowNode n) { + predicate isExcludedFromNullAnalysis(FlowNode n) { // Fields that are never assigned a non-null value are probably set by // reflection and are thus not always null. exists(n.asField()) } +} + +private module Input implements TypeFlowInput { + import FlowStepsInput + + class TypeFlowNode = FlowNode; + + predicate isExcludedFromNullAnalysis = FlowStepsInput::isExcludedFromNullAnalysis/1; + + class Type = RefType; predicate exactTypeBase(TypeFlowNode n, RefType t) { exists(ClassInstanceExpr e | diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/BaseSSA.qll b/java/ql/lib/semmle/code/java/dataflow/internal/BaseSSA.qll index f33a6d7195f..79f12e57f6a 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/BaseSSA.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/BaseSSA.qll @@ -38,6 +38,7 @@ class BaseSsaSourceVariable extends TBaseSsaSourceVariable { /** Gets the `Callable` in which this `BaseSsaSourceVariable` is defined. */ Callable getEnclosingCallable() { this = TLocalVar(result, _) } + /** Gets a textual representation of this element. */ string toString() { exists(LocalScopeVariable v, Callable c | this = TLocalVar(c, v) | if c = v.getCallable() @@ -46,6 +47,7 @@ class BaseSsaSourceVariable extends TBaseSsaSourceVariable { ) } + /** Gets the source location for this element. */ Location getLocation() { exists(LocalScopeVariable v | this = TLocalVar(_, v) and result = v.getLocation()) } @@ -482,8 +484,10 @@ class BaseSsaVariable extends TBaseSsaVariable { this = TSsaEntryDef(_, result) } + /** Gets a textual representation of this element. */ string toString() { none() } + /** Gets the source location for this element. */ Location getLocation() { result = this.getCfgNode().getLocation() } /** Gets the `BasicBlock` in which this SSA variable is defined. */ diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl1.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl1.qll deleted file mode 100644 index 17def0c431d..00000000000 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl1.qll +++ /dev/null @@ -1,361 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * Provides a `Configuration` class backwards-compatible interface to the data - * flow library. - */ - -private import DataFlowImplCommon -private import DataFlowImplSpecific::Private -import DataFlowImplSpecific::Public -private import DataFlowImpl -import DataFlowImplCommonPublic -deprecated import FlowStateString -private import codeql.util.Unit - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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 sink, 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() } - - /** - * 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. - * - * These features are generally not relevant for typical end-to-end data flow - * queries, but should only be used for constructing paths that need to - * somehow be pluggable in another path context. - */ - FlowFeature getAFeature() { none() } - - /** Holds if sources should be grouped in the result of `hasFlowPath`. */ - predicate sourceGrouping(Node source, string sourceGroup) { none() } - - /** Holds if sinks should be grouped in the result of `hasFlowPath`. */ - predicate sinkGrouping(Node sink, string sinkGroup) { none() } - - /** - * Holds if data may flow from `source` to `sink` for this configuration. - */ - predicate hasFlow(Node source, Node sink) { hasFlow(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) { hasFlowPath(source, sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } - - /** - * 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() } -} - -/** - * 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 deprecated 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) - } -} - -deprecated private FlowState relevantState(Configuration config) { - config.isSource(_, result) or - config.isSink(_, result) or - config.isBarrier(_, result) or - config.isAdditionalFlowStep(_, result, _, _) or - config.isAdditionalFlowStep(_, _, _, result) -} - -private newtype TConfigState = - deprecated TMkConfigState(Configuration config, FlowState state) { - state = relevantState(config) or state instanceof FlowStateEmpty - } - -deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) } - -deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) } - -deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) } - -deprecated private module Config implements FullStateConfigSig { - class FlowState = TConfigState; - - predicate isSource(Node source, FlowState state) { - getConfig(state).isSource(source, getState(state)) - or - getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty - } - - predicate isSink(Node sink) { none() } - - predicate isSink(Node sink, FlowState state) { - getConfig(state).isSink(sink, getState(state)) - or - getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty - } - - predicate isBarrier(Node node) { none() } - - predicate isBarrier(Node node, FlowState state) { - getConfig(state).isBarrier(node, getState(state)) or - getConfig(state).isBarrier(node) - } - - predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) } - - predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) } - - predicate isBarrierIn(Node node, FlowState state) { none() } - - predicate isBarrierOut(Node node, FlowState state) { none() } - - predicate isAdditionalFlowStep(Node node1, Node node2, string model) { - singleConfiguration() and - any(Configuration config).isAdditionalFlowStep(node1, node2) and - model = "" - } - - predicate isAdditionalFlowStep( - Node node1, FlowState state1, Node node2, FlowState state2, string model - ) { - getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and - getConfig(state2) = getConfig(state1) and - model = "" - or - not singleConfiguration() and - getConfig(state1).isAdditionalFlowStep(node1, node2) and - state2 = state1 and - model = "" - } - - predicate allowImplicitRead(Node node, ContentSet c) { - any(Configuration config).allowImplicitRead(node, c) - } - - predicate neverSkip(Node node) { none() } - - int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) } - - int accessPathLimit() { result = 5 } - - FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } - - predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } - - predicate observeDiffInformedIncrementalMode() { none() } -} - -deprecated private import Impl as I - -/** - * 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, and which can reach a sink, are generated. - */ -deprecated class PathNode instanceof I::PathNode { - /** Gets a textual representation of this element. */ - final string toString() { result = super.toString() } - - /** - * Gets a textual representation of this element, including a textual - * representation of the call context. - */ - final string toStringWithContext() { result = super.toStringWithContext() } - - /** - * 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/). - */ - final predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - /** Gets the underlying `Node`. */ - final Node getNode() { result = super.getNode() } - - /** Gets the `FlowState` of this node. */ - deprecated final FlowState getState() { result = getState(super.getState()) } - - /** Gets the associated configuration. */ - deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) } - - /** Gets a successor of this node, if any. */ - final PathNode getASuccessor() { result = super.getASuccessor() } - - /** Holds if this node is a source. */ - final predicate isSource() { super.isSource() } - - /** Holds if this node is a grouping of source nodes. */ - final predicate isSourceGroup(string group) { super.isSourceGroup(group) } - - /** Holds if this node is a grouping of sink nodes. */ - final predicate isSinkGroup(string group) { super.isSinkGroup(group) } -} - -deprecated module PathGraph = I::PathGraph; - -deprecated private predicate hasFlow(Node source, Node sink, Configuration config) { - exists(PathNode source0, PathNode sink0 | - hasFlowPath(source0, sink0, config) and - source0.getNode() = source and - sink0.getNode() = sink - ) -} - -deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) { - I::flowPath(source, sink) and source.getConfiguration() = config -} - -deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) } - -deprecated predicate flowsTo = hasFlow/3; diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll deleted file mode 100644 index 17def0c431d..00000000000 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ /dev/null @@ -1,361 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * Provides a `Configuration` class backwards-compatible interface to the data - * flow library. - */ - -private import DataFlowImplCommon -private import DataFlowImplSpecific::Private -import DataFlowImplSpecific::Public -private import DataFlowImpl -import DataFlowImplCommonPublic -deprecated import FlowStateString -private import codeql.util.Unit - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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 sink, 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() } - - /** - * 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. - * - * These features are generally not relevant for typical end-to-end data flow - * queries, but should only be used for constructing paths that need to - * somehow be pluggable in another path context. - */ - FlowFeature getAFeature() { none() } - - /** Holds if sources should be grouped in the result of `hasFlowPath`. */ - predicate sourceGrouping(Node source, string sourceGroup) { none() } - - /** Holds if sinks should be grouped in the result of `hasFlowPath`. */ - predicate sinkGrouping(Node sink, string sinkGroup) { none() } - - /** - * Holds if data may flow from `source` to `sink` for this configuration. - */ - predicate hasFlow(Node source, Node sink) { hasFlow(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) { hasFlowPath(source, sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } - - /** - * 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() } -} - -/** - * 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 deprecated 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) - } -} - -deprecated private FlowState relevantState(Configuration config) { - config.isSource(_, result) or - config.isSink(_, result) or - config.isBarrier(_, result) or - config.isAdditionalFlowStep(_, result, _, _) or - config.isAdditionalFlowStep(_, _, _, result) -} - -private newtype TConfigState = - deprecated TMkConfigState(Configuration config, FlowState state) { - state = relevantState(config) or state instanceof FlowStateEmpty - } - -deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) } - -deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) } - -deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) } - -deprecated private module Config implements FullStateConfigSig { - class FlowState = TConfigState; - - predicate isSource(Node source, FlowState state) { - getConfig(state).isSource(source, getState(state)) - or - getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty - } - - predicate isSink(Node sink) { none() } - - predicate isSink(Node sink, FlowState state) { - getConfig(state).isSink(sink, getState(state)) - or - getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty - } - - predicate isBarrier(Node node) { none() } - - predicate isBarrier(Node node, FlowState state) { - getConfig(state).isBarrier(node, getState(state)) or - getConfig(state).isBarrier(node) - } - - predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) } - - predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) } - - predicate isBarrierIn(Node node, FlowState state) { none() } - - predicate isBarrierOut(Node node, FlowState state) { none() } - - predicate isAdditionalFlowStep(Node node1, Node node2, string model) { - singleConfiguration() and - any(Configuration config).isAdditionalFlowStep(node1, node2) and - model = "" - } - - predicate isAdditionalFlowStep( - Node node1, FlowState state1, Node node2, FlowState state2, string model - ) { - getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and - getConfig(state2) = getConfig(state1) and - model = "" - or - not singleConfiguration() and - getConfig(state1).isAdditionalFlowStep(node1, node2) and - state2 = state1 and - model = "" - } - - predicate allowImplicitRead(Node node, ContentSet c) { - any(Configuration config).allowImplicitRead(node, c) - } - - predicate neverSkip(Node node) { none() } - - int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) } - - int accessPathLimit() { result = 5 } - - FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } - - predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } - - predicate observeDiffInformedIncrementalMode() { none() } -} - -deprecated private import Impl as I - -/** - * 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, and which can reach a sink, are generated. - */ -deprecated class PathNode instanceof I::PathNode { - /** Gets a textual representation of this element. */ - final string toString() { result = super.toString() } - - /** - * Gets a textual representation of this element, including a textual - * representation of the call context. - */ - final string toStringWithContext() { result = super.toStringWithContext() } - - /** - * 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/). - */ - final predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - /** Gets the underlying `Node`. */ - final Node getNode() { result = super.getNode() } - - /** Gets the `FlowState` of this node. */ - deprecated final FlowState getState() { result = getState(super.getState()) } - - /** Gets the associated configuration. */ - deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) } - - /** Gets a successor of this node, if any. */ - final PathNode getASuccessor() { result = super.getASuccessor() } - - /** Holds if this node is a source. */ - final predicate isSource() { super.isSource() } - - /** Holds if this node is a grouping of source nodes. */ - final predicate isSourceGroup(string group) { super.isSourceGroup(group) } - - /** Holds if this node is a grouping of sink nodes. */ - final predicate isSinkGroup(string group) { super.isSinkGroup(group) } -} - -deprecated module PathGraph = I::PathGraph; - -deprecated private predicate hasFlow(Node source, Node sink, Configuration config) { - exists(PathNode source0, PathNode sink0 | - hasFlowPath(source0, sink0, config) and - source0.getNode() = source and - sink0.getNode() = sink - ) -} - -deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) { - I::flowPath(source, sink) and source.getConfiguration() = config -} - -deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) } - -deprecated predicate flowsTo = hasFlow/3; diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll deleted file mode 100644 index 17def0c431d..00000000000 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ /dev/null @@ -1,361 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * Provides a `Configuration` class backwards-compatible interface to the data - * flow library. - */ - -private import DataFlowImplCommon -private import DataFlowImplSpecific::Private -import DataFlowImplSpecific::Public -private import DataFlowImpl -import DataFlowImplCommonPublic -deprecated import FlowStateString -private import codeql.util.Unit - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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 sink, 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() } - - /** - * 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. - * - * These features are generally not relevant for typical end-to-end data flow - * queries, but should only be used for constructing paths that need to - * somehow be pluggable in another path context. - */ - FlowFeature getAFeature() { none() } - - /** Holds if sources should be grouped in the result of `hasFlowPath`. */ - predicate sourceGrouping(Node source, string sourceGroup) { none() } - - /** Holds if sinks should be grouped in the result of `hasFlowPath`. */ - predicate sinkGrouping(Node sink, string sinkGroup) { none() } - - /** - * Holds if data may flow from `source` to `sink` for this configuration. - */ - predicate hasFlow(Node source, Node sink) { hasFlow(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) { hasFlowPath(source, sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } - - /** - * 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() } -} - -/** - * 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 deprecated 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) - } -} - -deprecated private FlowState relevantState(Configuration config) { - config.isSource(_, result) or - config.isSink(_, result) or - config.isBarrier(_, result) or - config.isAdditionalFlowStep(_, result, _, _) or - config.isAdditionalFlowStep(_, _, _, result) -} - -private newtype TConfigState = - deprecated TMkConfigState(Configuration config, FlowState state) { - state = relevantState(config) or state instanceof FlowStateEmpty - } - -deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) } - -deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) } - -deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) } - -deprecated private module Config implements FullStateConfigSig { - class FlowState = TConfigState; - - predicate isSource(Node source, FlowState state) { - getConfig(state).isSource(source, getState(state)) - or - getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty - } - - predicate isSink(Node sink) { none() } - - predicate isSink(Node sink, FlowState state) { - getConfig(state).isSink(sink, getState(state)) - or - getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty - } - - predicate isBarrier(Node node) { none() } - - predicate isBarrier(Node node, FlowState state) { - getConfig(state).isBarrier(node, getState(state)) or - getConfig(state).isBarrier(node) - } - - predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) } - - predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) } - - predicate isBarrierIn(Node node, FlowState state) { none() } - - predicate isBarrierOut(Node node, FlowState state) { none() } - - predicate isAdditionalFlowStep(Node node1, Node node2, string model) { - singleConfiguration() and - any(Configuration config).isAdditionalFlowStep(node1, node2) and - model = "" - } - - predicate isAdditionalFlowStep( - Node node1, FlowState state1, Node node2, FlowState state2, string model - ) { - getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and - getConfig(state2) = getConfig(state1) and - model = "" - or - not singleConfiguration() and - getConfig(state1).isAdditionalFlowStep(node1, node2) and - state2 = state1 and - model = "" - } - - predicate allowImplicitRead(Node node, ContentSet c) { - any(Configuration config).allowImplicitRead(node, c) - } - - predicate neverSkip(Node node) { none() } - - int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) } - - int accessPathLimit() { result = 5 } - - FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } - - predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } - - predicate observeDiffInformedIncrementalMode() { none() } -} - -deprecated private import Impl as I - -/** - * 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, and which can reach a sink, are generated. - */ -deprecated class PathNode instanceof I::PathNode { - /** Gets a textual representation of this element. */ - final string toString() { result = super.toString() } - - /** - * Gets a textual representation of this element, including a textual - * representation of the call context. - */ - final string toStringWithContext() { result = super.toStringWithContext() } - - /** - * 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/). - */ - final predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - /** Gets the underlying `Node`. */ - final Node getNode() { result = super.getNode() } - - /** Gets the `FlowState` of this node. */ - deprecated final FlowState getState() { result = getState(super.getState()) } - - /** Gets the associated configuration. */ - deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) } - - /** Gets a successor of this node, if any. */ - final PathNode getASuccessor() { result = super.getASuccessor() } - - /** Holds if this node is a source. */ - final predicate isSource() { super.isSource() } - - /** Holds if this node is a grouping of source nodes. */ - final predicate isSourceGroup(string group) { super.isSourceGroup(group) } - - /** Holds if this node is a grouping of sink nodes. */ - final predicate isSinkGroup(string group) { super.isSinkGroup(group) } -} - -deprecated module PathGraph = I::PathGraph; - -deprecated private predicate hasFlow(Node source, Node sink, Configuration config) { - exists(PathNode source0, PathNode sink0 | - hasFlowPath(source0, sink0, config) and - source0.getNode() = source and - sink0.getNode() = sink - ) -} - -deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) { - I::flowPath(source, sink) and source.getConfiguration() = config -} - -deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) } - -deprecated predicate flowsTo = hasFlow/3; diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll deleted file mode 100644 index 17def0c431d..00000000000 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ /dev/null @@ -1,361 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * Provides a `Configuration` class backwards-compatible interface to the data - * flow library. - */ - -private import DataFlowImplCommon -private import DataFlowImplSpecific::Private -import DataFlowImplSpecific::Public -private import DataFlowImpl -import DataFlowImplCommonPublic -deprecated import FlowStateString -private import codeql.util.Unit - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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 sink, 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() } - - /** - * 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. - * - * These features are generally not relevant for typical end-to-end data flow - * queries, but should only be used for constructing paths that need to - * somehow be pluggable in another path context. - */ - FlowFeature getAFeature() { none() } - - /** Holds if sources should be grouped in the result of `hasFlowPath`. */ - predicate sourceGrouping(Node source, string sourceGroup) { none() } - - /** Holds if sinks should be grouped in the result of `hasFlowPath`. */ - predicate sinkGrouping(Node sink, string sinkGroup) { none() } - - /** - * Holds if data may flow from `source` to `sink` for this configuration. - */ - predicate hasFlow(Node source, Node sink) { hasFlow(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) { hasFlowPath(source, sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } - - /** - * 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() } -} - -/** - * 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 deprecated 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) - } -} - -deprecated private FlowState relevantState(Configuration config) { - config.isSource(_, result) or - config.isSink(_, result) or - config.isBarrier(_, result) or - config.isAdditionalFlowStep(_, result, _, _) or - config.isAdditionalFlowStep(_, _, _, result) -} - -private newtype TConfigState = - deprecated TMkConfigState(Configuration config, FlowState state) { - state = relevantState(config) or state instanceof FlowStateEmpty - } - -deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) } - -deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) } - -deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) } - -deprecated private module Config implements FullStateConfigSig { - class FlowState = TConfigState; - - predicate isSource(Node source, FlowState state) { - getConfig(state).isSource(source, getState(state)) - or - getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty - } - - predicate isSink(Node sink) { none() } - - predicate isSink(Node sink, FlowState state) { - getConfig(state).isSink(sink, getState(state)) - or - getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty - } - - predicate isBarrier(Node node) { none() } - - predicate isBarrier(Node node, FlowState state) { - getConfig(state).isBarrier(node, getState(state)) or - getConfig(state).isBarrier(node) - } - - predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) } - - predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) } - - predicate isBarrierIn(Node node, FlowState state) { none() } - - predicate isBarrierOut(Node node, FlowState state) { none() } - - predicate isAdditionalFlowStep(Node node1, Node node2, string model) { - singleConfiguration() and - any(Configuration config).isAdditionalFlowStep(node1, node2) and - model = "" - } - - predicate isAdditionalFlowStep( - Node node1, FlowState state1, Node node2, FlowState state2, string model - ) { - getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and - getConfig(state2) = getConfig(state1) and - model = "" - or - not singleConfiguration() and - getConfig(state1).isAdditionalFlowStep(node1, node2) and - state2 = state1 and - model = "" - } - - predicate allowImplicitRead(Node node, ContentSet c) { - any(Configuration config).allowImplicitRead(node, c) - } - - predicate neverSkip(Node node) { none() } - - int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) } - - int accessPathLimit() { result = 5 } - - FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } - - predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } - - predicate observeDiffInformedIncrementalMode() { none() } -} - -deprecated private import Impl as I - -/** - * 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, and which can reach a sink, are generated. - */ -deprecated class PathNode instanceof I::PathNode { - /** Gets a textual representation of this element. */ - final string toString() { result = super.toString() } - - /** - * Gets a textual representation of this element, including a textual - * representation of the call context. - */ - final string toStringWithContext() { result = super.toStringWithContext() } - - /** - * 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/). - */ - final predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - /** Gets the underlying `Node`. */ - final Node getNode() { result = super.getNode() } - - /** Gets the `FlowState` of this node. */ - deprecated final FlowState getState() { result = getState(super.getState()) } - - /** Gets the associated configuration. */ - deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) } - - /** Gets a successor of this node, if any. */ - final PathNode getASuccessor() { result = super.getASuccessor() } - - /** Holds if this node is a source. */ - final predicate isSource() { super.isSource() } - - /** Holds if this node is a grouping of source nodes. */ - final predicate isSourceGroup(string group) { super.isSourceGroup(group) } - - /** Holds if this node is a grouping of sink nodes. */ - final predicate isSinkGroup(string group) { super.isSinkGroup(group) } -} - -deprecated module PathGraph = I::PathGraph; - -deprecated private predicate hasFlow(Node source, Node sink, Configuration config) { - exists(PathNode source0, PathNode sink0 | - hasFlowPath(source0, sink0, config) and - source0.getNode() = source and - sink0.getNode() = sink - ) -} - -deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) { - I::flowPath(source, sink) and source.getConfiguration() = config -} - -deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) } - -deprecated predicate flowsTo = hasFlow/3; diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll deleted file mode 100644 index 17def0c431d..00000000000 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ /dev/null @@ -1,361 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * Provides a `Configuration` class backwards-compatible interface to the data - * flow library. - */ - -private import DataFlowImplCommon -private import DataFlowImplSpecific::Private -import DataFlowImplSpecific::Public -private import DataFlowImpl -import DataFlowImplCommonPublic -deprecated import FlowStateString -private import codeql.util.Unit - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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 sink, 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() } - - /** - * 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. - * - * These features are generally not relevant for typical end-to-end data flow - * queries, but should only be used for constructing paths that need to - * somehow be pluggable in another path context. - */ - FlowFeature getAFeature() { none() } - - /** Holds if sources should be grouped in the result of `hasFlowPath`. */ - predicate sourceGrouping(Node source, string sourceGroup) { none() } - - /** Holds if sinks should be grouped in the result of `hasFlowPath`. */ - predicate sinkGrouping(Node sink, string sinkGroup) { none() } - - /** - * Holds if data may flow from `source` to `sink` for this configuration. - */ - predicate hasFlow(Node source, Node sink) { hasFlow(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) { hasFlowPath(source, sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } - - /** - * 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() } -} - -/** - * 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 deprecated 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) - } -} - -deprecated private FlowState relevantState(Configuration config) { - config.isSource(_, result) or - config.isSink(_, result) or - config.isBarrier(_, result) or - config.isAdditionalFlowStep(_, result, _, _) or - config.isAdditionalFlowStep(_, _, _, result) -} - -private newtype TConfigState = - deprecated TMkConfigState(Configuration config, FlowState state) { - state = relevantState(config) or state instanceof FlowStateEmpty - } - -deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) } - -deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) } - -deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) } - -deprecated private module Config implements FullStateConfigSig { - class FlowState = TConfigState; - - predicate isSource(Node source, FlowState state) { - getConfig(state).isSource(source, getState(state)) - or - getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty - } - - predicate isSink(Node sink) { none() } - - predicate isSink(Node sink, FlowState state) { - getConfig(state).isSink(sink, getState(state)) - or - getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty - } - - predicate isBarrier(Node node) { none() } - - predicate isBarrier(Node node, FlowState state) { - getConfig(state).isBarrier(node, getState(state)) or - getConfig(state).isBarrier(node) - } - - predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) } - - predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) } - - predicate isBarrierIn(Node node, FlowState state) { none() } - - predicate isBarrierOut(Node node, FlowState state) { none() } - - predicate isAdditionalFlowStep(Node node1, Node node2, string model) { - singleConfiguration() and - any(Configuration config).isAdditionalFlowStep(node1, node2) and - model = "" - } - - predicate isAdditionalFlowStep( - Node node1, FlowState state1, Node node2, FlowState state2, string model - ) { - getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and - getConfig(state2) = getConfig(state1) and - model = "" - or - not singleConfiguration() and - getConfig(state1).isAdditionalFlowStep(node1, node2) and - state2 = state1 and - model = "" - } - - predicate allowImplicitRead(Node node, ContentSet c) { - any(Configuration config).allowImplicitRead(node, c) - } - - predicate neverSkip(Node node) { none() } - - int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) } - - int accessPathLimit() { result = 5 } - - FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } - - predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } - - predicate observeDiffInformedIncrementalMode() { none() } -} - -deprecated private import Impl as I - -/** - * 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, and which can reach a sink, are generated. - */ -deprecated class PathNode instanceof I::PathNode { - /** Gets a textual representation of this element. */ - final string toString() { result = super.toString() } - - /** - * Gets a textual representation of this element, including a textual - * representation of the call context. - */ - final string toStringWithContext() { result = super.toStringWithContext() } - - /** - * 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/). - */ - final predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - /** Gets the underlying `Node`. */ - final Node getNode() { result = super.getNode() } - - /** Gets the `FlowState` of this node. */ - deprecated final FlowState getState() { result = getState(super.getState()) } - - /** Gets the associated configuration. */ - deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) } - - /** Gets a successor of this node, if any. */ - final PathNode getASuccessor() { result = super.getASuccessor() } - - /** Holds if this node is a source. */ - final predicate isSource() { super.isSource() } - - /** Holds if this node is a grouping of source nodes. */ - final predicate isSourceGroup(string group) { super.isSourceGroup(group) } - - /** Holds if this node is a grouping of sink nodes. */ - final predicate isSinkGroup(string group) { super.isSinkGroup(group) } -} - -deprecated module PathGraph = I::PathGraph; - -deprecated private predicate hasFlow(Node source, Node sink, Configuration config) { - exists(PathNode source0, PathNode sink0 | - hasFlowPath(source0, sink0, config) and - source0.getNode() = source and - sink0.getNode() = sink - ) -} - -deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) { - I::flowPath(source, sink) and source.getConfiguration() = config -} - -deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) } - -deprecated predicate flowsTo = hasFlow/3; diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll deleted file mode 100644 index 17def0c431d..00000000000 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll +++ /dev/null @@ -1,361 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * Provides a `Configuration` class backwards-compatible interface to the data - * flow library. - */ - -private import DataFlowImplCommon -private import DataFlowImplSpecific::Private -import DataFlowImplSpecific::Public -private import DataFlowImpl -import DataFlowImplCommonPublic -deprecated import FlowStateString -private import codeql.util.Unit - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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 sink, 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() } - - /** - * 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. - * - * These features are generally not relevant for typical end-to-end data flow - * queries, but should only be used for constructing paths that need to - * somehow be pluggable in another path context. - */ - FlowFeature getAFeature() { none() } - - /** Holds if sources should be grouped in the result of `hasFlowPath`. */ - predicate sourceGrouping(Node source, string sourceGroup) { none() } - - /** Holds if sinks should be grouped in the result of `hasFlowPath`. */ - predicate sinkGrouping(Node sink, string sinkGroup) { none() } - - /** - * Holds if data may flow from `source` to `sink` for this configuration. - */ - predicate hasFlow(Node source, Node sink) { hasFlow(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) { hasFlowPath(source, sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) } - - /** - * Holds if data may flow from some source to `sink` for this configuration. - */ - predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) } - - /** - * 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() } -} - -/** - * 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 deprecated 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) - } -} - -deprecated private FlowState relevantState(Configuration config) { - config.isSource(_, result) or - config.isSink(_, result) or - config.isBarrier(_, result) or - config.isAdditionalFlowStep(_, result, _, _) or - config.isAdditionalFlowStep(_, _, _, result) -} - -private newtype TConfigState = - deprecated TMkConfigState(Configuration config, FlowState state) { - state = relevantState(config) or state instanceof FlowStateEmpty - } - -deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) } - -deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) } - -deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) } - -deprecated private module Config implements FullStateConfigSig { - class FlowState = TConfigState; - - predicate isSource(Node source, FlowState state) { - getConfig(state).isSource(source, getState(state)) - or - getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty - } - - predicate isSink(Node sink) { none() } - - predicate isSink(Node sink, FlowState state) { - getConfig(state).isSink(sink, getState(state)) - or - getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty - } - - predicate isBarrier(Node node) { none() } - - predicate isBarrier(Node node, FlowState state) { - getConfig(state).isBarrier(node, getState(state)) or - getConfig(state).isBarrier(node) - } - - predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) } - - predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) } - - predicate isBarrierIn(Node node, FlowState state) { none() } - - predicate isBarrierOut(Node node, FlowState state) { none() } - - predicate isAdditionalFlowStep(Node node1, Node node2, string model) { - singleConfiguration() and - any(Configuration config).isAdditionalFlowStep(node1, node2) and - model = "" - } - - predicate isAdditionalFlowStep( - Node node1, FlowState state1, Node node2, FlowState state2, string model - ) { - getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and - getConfig(state2) = getConfig(state1) and - model = "" - or - not singleConfiguration() and - getConfig(state1).isAdditionalFlowStep(node1, node2) and - state2 = state1 and - model = "" - } - - predicate allowImplicitRead(Node node, ContentSet c) { - any(Configuration config).allowImplicitRead(node, c) - } - - predicate neverSkip(Node node) { none() } - - int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) } - - int accessPathLimit() { result = 5 } - - FlowFeature getAFeature() { result = any(Configuration config).getAFeature() } - - predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() } - - predicate observeDiffInformedIncrementalMode() { none() } -} - -deprecated private import Impl as I - -/** - * 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, and which can reach a sink, are generated. - */ -deprecated class PathNode instanceof I::PathNode { - /** Gets a textual representation of this element. */ - final string toString() { result = super.toString() } - - /** - * Gets a textual representation of this element, including a textual - * representation of the call context. - */ - final string toStringWithContext() { result = super.toStringWithContext() } - - /** - * 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/). - */ - final predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - /** Gets the underlying `Node`. */ - final Node getNode() { result = super.getNode() } - - /** Gets the `FlowState` of this node. */ - deprecated final FlowState getState() { result = getState(super.getState()) } - - /** Gets the associated configuration. */ - deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) } - - /** Gets a successor of this node, if any. */ - final PathNode getASuccessor() { result = super.getASuccessor() } - - /** Holds if this node is a source. */ - final predicate isSource() { super.isSource() } - - /** Holds if this node is a grouping of source nodes. */ - final predicate isSourceGroup(string group) { super.isSourceGroup(group) } - - /** Holds if this node is a grouping of sink nodes. */ - final predicate isSinkGroup(string group) { super.isSinkGroup(group) } -} - -deprecated module PathGraph = I::PathGraph; - -deprecated private predicate hasFlow(Node source, Node sink, Configuration config) { - exists(PathNode source0, PathNode sink0 | - hasFlowPath(source0, sink0, config) and - source0.getNode() = source and - sink0.getNode() = sink - ) -} - -deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) { - I::flowPath(source, sink) and source.getConfiguration() = config -} - -deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) } - -deprecated predicate flowsTo = hasFlow/3; diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowUtil.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowUtil.qll index c1fc51bff04..bb71ed25c73 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowUtil.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowUtil.qll @@ -160,11 +160,8 @@ predicate localMustFlowStep(Node node1, Node node2) { or node2.asExpr().(AssignExpr).getSource() = node1.asExpr() or - node1 = - unique(FlowSummaryNode n1 | - FlowSummaryImpl::Private::Steps::summaryLocalStep(n1.getSummaryNode(), - node2.(FlowSummaryNode).getSummaryNode(), true, _) - ) + FlowSummaryImpl::Private::Steps::summaryLocalMustFlowStep(node1.(FlowSummaryNode).getSummaryNode(), + node2.(FlowSummaryNode).getSummaryNode()) } import Cached 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 ad770b75a3e..1c7db851a2c 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll @@ -161,6 +161,7 @@ private module Cached { */ cached predicate defaultTaintSanitizer(DataFlow::Node node) { + node instanceof DefaultTaintSanitizer or // Ignore paths through test code. node.getEnclosingCallable().getDeclaringType() instanceof NonSecurityTestClass or node.asExpr() instanceof ValidatedVariableAccess diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll b/java/ql/lib/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll deleted file mode 100644 index 75e7856fd26..00000000000 --- a/java/ql/lib/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll +++ /dev/null @@ -1,168 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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) } - - /** - * 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/java/ql/lib/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingParameter.qll b/java/ql/lib/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingParameter.qll deleted file mode 100644 index 2608adffda3..00000000000 --- a/java/ql/lib/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingParameter.qll +++ /dev/null @@ -1,6 +0,0 @@ -import semmle.code.java.dataflow.internal.TaintTrackingUtil as Public - -module Private { - import semmle.code.java.dataflow.DataFlow::DataFlow as DataFlow - import semmle.code.java.dataflow.internal.DataFlowImpl as DataFlowInternal -} diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll b/java/ql/lib/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll deleted file mode 100644 index 75e7856fd26..00000000000 --- a/java/ql/lib/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll +++ /dev/null @@ -1,168 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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) } - - /** - * 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/java/ql/lib/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingParameter.qll b/java/ql/lib/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingParameter.qll deleted file mode 100644 index 5a9c924b6bd..00000000000 --- a/java/ql/lib/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingParameter.qll +++ /dev/null @@ -1,5 +0,0 @@ -import semmle.code.java.dataflow.internal.TaintTrackingUtil as Public - -module Private { - import semmle.code.java.dataflow.DataFlow2::DataFlow2 as DataFlow -} diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingImpl.qll b/java/ql/lib/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingImpl.qll deleted file mode 100644 index 75e7856fd26..00000000000 --- a/java/ql/lib/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingImpl.qll +++ /dev/null @@ -1,168 +0,0 @@ -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 - -/** - * DEPRECATED: Use `Global` and `GlobalWithState` instead. - * - * 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 deprecated 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) } - - /** - * 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/java/ql/lib/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingParameter.qll b/java/ql/lib/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingParameter.qll deleted file mode 100644 index 10fb6b09fa8..00000000000 --- a/java/ql/lib/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingParameter.qll +++ /dev/null @@ -1,5 +0,0 @@ -import semmle.code.java.dataflow.internal.TaintTrackingUtil as Public - -module Private { - import semmle.code.java.dataflow.DataFlow3::DataFlow3 as DataFlow -} diff --git a/java/ql/lib/semmle/code/java/frameworks/JsonIo.qll b/java/ql/lib/semmle/code/java/frameworks/JsonIo.qll index d40e7ebf81e..85f3a5ef06b 100644 --- a/java/ql/lib/semmle/code/java/frameworks/JsonIo.qll +++ b/java/ql/lib/semmle/code/java/frameworks/JsonIo.qll @@ -5,8 +5,6 @@ import java import semmle.code.java.Maps import semmle.code.java.dataflow.DataFlow -deprecated import semmle.code.java.dataflow.DataFlow2 -private import semmle.code.java.dataflow.DataFlow2 /** * The class `com.cedarsoftware.util.io.JsonReader`. diff --git a/java/ql/lib/semmle/code/java/security/AndroidIntentRedirectionQuery.qll b/java/ql/lib/semmle/code/java/security/AndroidIntentRedirectionQuery.qll index 109300458d2..7625f9d7da4 100644 --- a/java/ql/lib/semmle/code/java/security/AndroidIntentRedirectionQuery.qll +++ b/java/ql/lib/semmle/code/java/security/AndroidIntentRedirectionQuery.qll @@ -2,9 +2,7 @@ import java import semmle.code.java.dataflow.FlowSources -deprecated import semmle.code.java.dataflow.DataFlow2 import semmle.code.java.dataflow.TaintTracking -deprecated import semmle.code.java.dataflow.TaintTracking3 import semmle.code.java.security.AndroidIntentRedirection /** A taint tracking configuration for tainted Intents being used to start Android components. */ diff --git a/java/ql/lib/semmle/code/java/security/CleartextStorageCookieQuery.qll b/java/ql/lib/semmle/code/java/security/CleartextStorageCookieQuery.qll index a36a4754584..1f262ad57d6 100644 --- a/java/ql/lib/semmle/code/java/security/CleartextStorageCookieQuery.qll +++ b/java/ql/lib/semmle/code/java/security/CleartextStorageCookieQuery.qll @@ -2,7 +2,6 @@ import java import semmle.code.java.dataflow.DataFlow -deprecated import semmle.code.java.dataflow.DataFlow3 import semmle.code.java.security.CleartextStorageQuery private import semmle.code.java.dataflow.FlowSinks private import semmle.code.java.dataflow.FlowSources diff --git a/java/ql/lib/semmle/code/java/security/Encryption.qll b/java/ql/lib/semmle/code/java/security/Encryption.qll index 6fc7f6b7d16..7c9c5ec60db 100644 --- a/java/ql/lib/semmle/code/java/security/Encryption.qll +++ b/java/ql/lib/semmle/code/java/security/Encryption.qll @@ -223,10 +223,7 @@ string getAnInsecureHashAlgorithmName() { } private string rankedInsecureAlgorithm(int i) { - // In this case we know these are being used for encryption, so we want to match - // weak hash algorithms too. - result = - rank[i](string s | s = getAnInsecureAlgorithmName() or s = getAnInsecureHashAlgorithmName()) + result = rank[i](string s | s = getAnInsecureAlgorithmName()) } private string insecureAlgorithmString(int i) { @@ -249,8 +246,8 @@ string getInsecureAlgorithmRegex() { string getASecureAlgorithmName() { result = [ - "RSA", "SHA-?256", "SHA-?512", "CCM", "GCM", "AES(?![^a-zA-Z](ECB|CBC/PKCS[57]Padding))", - "Blowfish", "ECIES" + "RSA", "SHA-?(256|384|512)", "CCM", "GCM", "AES(?![^a-zA-Z](ECB|CBC/PKCS[57]Padding))", + "Blowfish", "ECIES", "SHA3-(256|384|512)" ] } diff --git a/java/ql/lib/semmle/code/java/security/HardcodedCredentialsSourceCallQuery.qll b/java/ql/lib/semmle/code/java/security/HardcodedCredentialsSourceCallQuery.qll index 2192c5c70de..06d7869ce99 100644 --- a/java/ql/lib/semmle/code/java/security/HardcodedCredentialsSourceCallQuery.qll +++ b/java/ql/lib/semmle/code/java/security/HardcodedCredentialsSourceCallQuery.qll @@ -4,8 +4,6 @@ import java import semmle.code.java.dataflow.DataFlow -deprecated import semmle.code.java.dataflow.DataFlow2 -private import semmle.code.java.dataflow.DataFlow2 import HardcodedCredentials /** diff --git a/java/ql/lib/semmle/code/java/security/ImplicitPendingIntents.qll b/java/ql/lib/semmle/code/java/security/ImplicitPendingIntents.qll index a5d8f256b03..650527e88e4 100644 --- a/java/ql/lib/semmle/code/java/security/ImplicitPendingIntents.qll +++ b/java/ql/lib/semmle/code/java/security/ImplicitPendingIntents.qll @@ -26,24 +26,10 @@ class NoState extends PendingIntentState, TNoState { } /** A source for an implicit `PendingIntent` flow. */ -abstract class ImplicitPendingIntentSource extends ApiSourceNode { - /** - * DEPRECATED: Open-ended flow state is not intended to be part of the extension points. - * - * Holds if this source has the specified `state`. - */ - deprecated predicate hasState(DataFlow::FlowState state) { state = "" } -} +abstract class ImplicitPendingIntentSource extends ApiSourceNode { } /** A sink that sends an implicit and mutable `PendingIntent` to a third party. */ -abstract class ImplicitPendingIntentSink extends DataFlow::Node { - /** - * DEPRECATED: Open-ended flow state is not intended to be part of the extension points. - * - * Holds if this sink has the specified `state`. - */ - deprecated predicate hasState(DataFlow::FlowState state) { state = "" } -} +abstract class ImplicitPendingIntentSink extends DataFlow::Node { } /** * A unit class for adding additional taint steps. @@ -62,21 +48,6 @@ class ImplicitPendingIntentAdditionalTaintStep extends Unit { * Holds if the step from `node1` to `node2` creates a mutable `PendingIntent`. */ predicate mutablePendingIntentCreation(DataFlow::Node node1, DataFlow::Node node2) { none() } - - /** - * DEPRECATED: Open-ended flow state is not intended to be part of the extension points. - * Use `mutablePendingIntentCreation` instead. - * - * Holds if the step from `node1` to `node2` should be considered a taint - * step for flows related to the use of implicit `PendingIntent`s. This step is only applicable - * in `state1` and updates the flow state to `state2`. - */ - deprecated predicate step( - DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2, - DataFlow::FlowState state2 - ) { - none() - } } private class IntentCreationSource extends ImplicitPendingIntentSource { diff --git a/java/ql/lib/semmle/code/java/security/ListOfConstantsSanitizer.qll b/java/ql/lib/semmle/code/java/security/ListOfConstantsSanitizer.qll new file mode 100644 index 00000000000..cc57fbce648 --- /dev/null +++ b/java/ql/lib/semmle/code/java/security/ListOfConstantsSanitizer.qll @@ -0,0 +1,263 @@ +/** + * Provides a default taint sanitizer identifying comparisons against lists of + * compile-time constants. + */ + +import java +private import codeql.typeflow.UniversalFlow as UniversalFlow +private import semmle.code.java.Collections +private import semmle.code.java.controlflow.Guards +private import semmle.code.java.dataflow.internal.BaseSSA +private import semmle.code.java.dataflow.TaintTracking +private import semmle.code.java.dataflow.TypeFlow +private import semmle.code.java.dispatch.VirtualDispatch + +private class FlowNode = FlowStepsInput::FlowNode; + +/** + * Holds if `n2` is an unmodifiable collection constructed from input `n1`, + * which is either another collection or a number of elements. + */ +private predicate unmodifiableCollectionStep(FlowNode n1, FlowNode n2) { + exists(Call c, Callable tgt | + n2.asExpr() = c and + n1.asExpr() = c.getAnArgument() and + c.getCallee().getSourceDeclaration() = tgt + | + tgt.hasQualifiedName("java.util", "Collections", + ["unmodifiableCollection", "unmodifiableList", "unmodifiableSet"]) + or + tgt.hasQualifiedName("java.util", ["List", "Set"], ["copyOf", "of"]) + or + tgt.hasQualifiedName("com.google.common.collect", ["ImmutableList", "ImmutableSet"], + ["copyOf", "of"]) + ) +} + +/** + * Holds if `n2` is a collection or array constructed from input `n1`, which is + * either a collection, an array, or a number of elements. + */ +private predicate collectionStep(FlowNode n1, FlowNode n2) { + n2.asExpr().(ArrayInit).getAnInit() = n1.asExpr() + or + n2.asExpr().(ArrayCreationExpr).getInit() = n1.asExpr() + or + unmodifiableCollectionStep(n1, n2) + or + exists(Call c, Callable tgt | + n2.asExpr() = c and + n1.asExpr() = c.getAnArgument() and + c.getCallee().getSourceDeclaration() = tgt + | + tgt.hasQualifiedName("java.util", "Arrays", "asList") + or + tgt.isStatic() and + tgt.hasName(["copyOf", "of"]) and + tgt.getDeclaringType().getASourceSupertype+().hasQualifiedName("java.util", "Collection") + or + tgt instanceof Constructor and + tgt.getNumberOfParameters() = 1 and + tgt.getParameterType(0) instanceof CollectionType and + tgt.getDeclaringType() instanceof CollectionType + ) +} + +private module BaseUniversalFlow = UniversalFlow::Make; + +private module UnmodifiableProp implements BaseUniversalFlow::NullaryPropertySig { + predicate hasPropertyBase(FlowNode n) { unmodifiableCollectionStep(_, n) } +} + +/** Holds if the given node is an unmodifiable collection. */ +private predicate unmodifiableCollection = + BaseUniversalFlow::FlowNullary::hasProperty/1; + +/** + * Holds if `v` is a collection or array with an access, `coll`, at which the + * element `e` gets added. + */ +private predicate collectionAddition(Variable v, VarAccess coll, Expr e) { + exists(MethodCall mc, Method m, int arg | + mc.getMethod().getSourceDeclaration().overridesOrInstantiates*(m) and + mc.getQualifier() = coll and + v.getAnAccess() = coll and + mc.getArgument(arg) = e + | + m.hasQualifiedName("java.util", "Collection", ["add", "addAll"]) and + m.getNumberOfParameters() = 1 and + arg = 0 + or + m.hasQualifiedName("java.util", "List", ["add", "addAll"]) and + m.getNumberOfParameters() = 2 and + arg = 1 + or + m.hasQualifiedName("java.util", "SequencedCollection", ["addFirst", "addLast"]) and + m.getNumberOfParameters() = 1 and + arg = 0 + ) + or + v.getAnAccess() = coll and + exists(Assignment assign | assign.getSource() = e | + coll = assign.getDest().(ArrayAccess).getArray() + ) +} + +/** + * Holds if `n` represents a definition of `v` and `v` is a collection or + * array that has additions occurring as side-effects after its definition. + */ +private predicate nodeWithAddition(FlowNode n, Variable v) { + collectionAddition(v, _, _) and + ( + n.asField() = v + or + n.asSsa().getSourceVariable().getVariable() = v and + (n.asSsa() instanceof BaseSsaUpdate or n.asSsa().(BaseSsaImplicitInit).isParameterDefinition(_)) + ) +} + +/** Holds if `c` does not add elements to the given collection. */ +private predicate safeCallable(Callable c) { + c instanceof CollectionQueryMethod + or + c instanceof CollectionMethod and + c.hasName(["clear", "remove", "removeAll", "stream", "iterator", "toArray"]) + or + c.hasQualifiedName("org.apache.commons.lang3", "StringUtils", "join") +} + +/** + * Holds if `n` might be mutated in ways that adds elements that are not + * tracked by the `collectionAddition` predicate. + */ +private predicate collectionWithPossibleMutation(FlowNode n) { + not unmodifiableCollection(n) and + ( + exists(Expr e | + n.asExpr() = e and + (e.getType() instanceof CollectionType or e.getType() instanceof Array) and + not collectionAddition(_, e, _) and + not collectionStep(n, _) + | + exists(ArrayAccess aa | e = aa.getArray()) + or + exists(Call c, Callable tgt | c.getAnArgument() = e or c.getQualifier() = e | + tgt = c.getCallee().getSourceDeclaration() and + not safeCallable(tgt) + ) + ) + or + exists(FlowNode mid | + FlowStepsInput::step(n, mid) and + collectionWithPossibleMutation(mid) + ) + ) +} + +/** + * A collection constructor that constructs an empty mutable collection. + */ +private class EmptyCollectionConstructor extends Constructor { + EmptyCollectionConstructor() { + this.getDeclaringType() instanceof CollectionType and + forall(Type t | t = this.getAParamType() | t instanceof PrimitiveType) + } +} + +private module CollectionFlowStepsInput implements UniversalFlow::UniversalFlowInput { + import FlowStepsInput + + /** + * Holds if `n2` is a collection/array/constant whose value(s) are + * determined completely from the range of `n1` nodes. + */ + predicate step(FlowNode n1, FlowNode n2) { + // Exclude the regular input constraints for those nodes that are covered + // completely by `collectionStep`. + FlowStepsInput::step(n1, n2) and + not collectionStep(_, n2) + or + // For collections with side-effects in the form of additions, we add the + // sources of those additions as additional input that need to originate + // from constants. + exists(Variable v | + nodeWithAddition(n2, v) and + collectionAddition(v, _, n1.asExpr()) + ) + or + // Include various forms of collection transformation. + collectionStep(n1, n2) + } + + predicate isExcludedFromNullAnalysis = FlowStepsInput::isExcludedFromNullAnalysis/1; +} + +private module CollectionUniversalFlow = UniversalFlow::Make; + +private module ConstantCollectionProp implements CollectionUniversalFlow::NullaryPropertySig { + /** + * Holds if `n` forms the base case for finding collections of constants. + * These are individual constants and empty collections. + */ + predicate hasPropertyBase(FlowNode n) { + n.asExpr().isCompileTimeConstant() or + n.asExpr().(ConstructorCall).getConstructor() instanceof EmptyCollectionConstructor + } + + predicate barrier = collectionWithPossibleMutation/1; +} + +/** + * Holds if the given node is either a constant or a collection/array of + * constants. + */ +private predicate constantCollection = + CollectionUniversalFlow::FlowNullary::hasProperty/1; + +/** Gets the result of a case normalization call of `arg`. */ +private MethodCall normalizeCaseCall(Expr arg) { + exists(Method changecase | result.getMethod() = changecase | + changecase.hasName(["toUpperCase", "toLowerCase"]) and + changecase.getDeclaringType() instanceof TypeString and + arg = result.getQualifier() + or + changecase + .hasQualifiedName(["org.apache.commons.lang", "org.apache.commons.lang3"], "StringUtils", + ["lowerCase", "upperCase"]) and + arg = result.getArgument(0) + or + changecase + .hasQualifiedName("org.apache.hadoop.util", "StringUtils", ["toLowerCase", "toUpperCase"]) and + arg = result.getArgument(0) + ) +} + +/** + * Holds if the guard `g` ensures that the expression `e` is one of a set of + * known constants upon evaluating to `branch`. + */ +private predicate constantCollectionContainsCheck(Guard g, Expr e, boolean branch) { + exists(MethodCall mc, Method m, FlowNode n, Expr checked | + g = mc and + mc.getMethod().getSourceDeclaration().overridesOrInstantiates*(m) and + m.hasQualifiedName("java.util", "Collection", "contains") and + n.asExpr() = mc.getQualifier() and + constantCollection(n) and + checked = mc.getAnArgument() and + branch = true + | + checked = e or + checked = normalizeCaseCall(e) + ) +} + +/** + * A comparison against a list of compile-time constants, sanitizing taint by + * restricting to a set of known values. + */ +private class ListOfConstantsComparisonSanitizerGuard extends TaintTracking::DefaultTaintSanitizer { + ListOfConstantsComparisonSanitizerGuard() { + this = DataFlow::BarrierGuard::getABarrierNode() + } +} diff --git a/java/ql/lib/semmle/code/java/security/MaybeBrokenCryptoAlgorithmQuery.qll b/java/ql/lib/semmle/code/java/security/MaybeBrokenCryptoAlgorithmQuery.qll index 1533b61dd5e..060a30f87e6 100644 --- a/java/ql/lib/semmle/code/java/security/MaybeBrokenCryptoAlgorithmQuery.qll +++ b/java/ql/lib/semmle/code/java/security/MaybeBrokenCryptoAlgorithmQuery.qll @@ -30,7 +30,11 @@ class InsecureAlgoLiteral extends InsecureAlgorithm, ShortStringLiteral { s.length() > 1 and not s.regexpMatch(getSecureAlgorithmRegex()) and // Exclude results covered by another query. - not s.regexpMatch(getInsecureAlgorithmRegex()) + not s.regexpMatch(getInsecureAlgorithmRegex()) and + // Exclude results covered by `InsecureAlgoProperty`. + // This removes duplicates when a string literal is a default value for the property, + // such as "MD5" in the following: `props.getProperty("hashAlg2", "MD5")`. + not exists(InsecureAlgoProperty insecAlgoProp | this = insecAlgoProp.getAnArgument()) ) } diff --git a/java/ql/lib/semmle/code/java/security/TemplateInjection.qll b/java/ql/lib/semmle/code/java/security/TemplateInjection.qll index a74f4db8030..0b703780a03 100644 --- a/java/ql/lib/semmle/code/java/security/TemplateInjection.qll +++ b/java/ql/lib/semmle/code/java/security/TemplateInjection.qll @@ -9,30 +9,12 @@ private import semmle.code.java.security.Sanitizers /** * A source for server-side template injection (SST) vulnerabilities. */ -abstract class TemplateInjectionSource extends DataFlow::Node { - /** - * DEPRECATED: Open-ended flow state is not intended to be part of the extension points. - * - * Holds if this source has the specified `state`. - */ - deprecated predicate hasState(DataFlow::FlowState state) { - state instanceof DataFlow::FlowStateEmpty - } -} +abstract class TemplateInjectionSource extends DataFlow::Node { } /** * A sink for server-side template injection (SST) vulnerabilities. */ -abstract class TemplateInjectionSink extends DataFlow::Node { - /** - * DEPRECATED: Open-ended flow state is not intended to be part of the extension points. - * - * Holds if this sink has the specified `state`. - */ - deprecated predicate hasState(DataFlow::FlowState state) { - state instanceof DataFlow::FlowStateEmpty - } -} +abstract class TemplateInjectionSink extends DataFlow::Node { } /** * A unit class for adding additional taint steps. @@ -46,20 +28,6 @@ class TemplateInjectionAdditionalTaintStep extends Unit { * step for flows related to server-side template injection (SST) vulnerabilities. */ predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() } - - /** - * DEPRECATED: Open-ended flow state is not intended to be part of the extension points. - * - * Holds if the step from `node1` to `node2` should be considered a taint - * step for flows related toserver-side template injection (SST) vulnerabilities. - * This step is only applicable in `state1` and updates the flow state to `state2`. - */ - deprecated predicate isAdditionalTaintStep( - DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2, - DataFlow::FlowState state2 - ) { - none() - } } /** @@ -67,22 +35,6 @@ class TemplateInjectionAdditionalTaintStep extends Unit { */ abstract class TemplateInjectionSanitizer extends DataFlow::Node { } -/** - * DEPRECATED: Open-ended flow state is not intended to be part of the extension points. - * - * A sanitizer for server-side template injection (SST) vulnerabilities. - * This sanitizer is only applicable when `TemplateInjectionSanitizerWithState::hasState` - * holds for the flow state. - */ -abstract deprecated class TemplateInjectionSanitizerWithState extends DataFlow::Node { - /** - * DEPRECATED: Open-ended flow state is not intended to be part of the extension points. - * - * Holds if this sanitizer has the specified `state`. - */ - abstract deprecated predicate hasState(DataFlow::FlowState state); -} - private class DefaultTemplateInjectionSource extends TemplateInjectionSource instanceof ActiveThreatModelSource { } diff --git a/java/ql/lib/semmle/code/java/security/UnsafeDeserializationQuery.qll b/java/ql/lib/semmle/code/java/security/UnsafeDeserializationQuery.qll index 9a627d54c5a..cb76ee37c7b 100644 --- a/java/ql/lib/semmle/code/java/security/UnsafeDeserializationQuery.qll +++ b/java/ql/lib/semmle/code/java/security/UnsafeDeserializationQuery.qll @@ -4,7 +4,6 @@ import semmle.code.java.dataflow.FlowSources private import semmle.code.java.dataflow.FlowSinks -private import semmle.code.java.dataflow.TaintTracking2 private import semmle.code.java.dispatch.VirtualDispatch private import semmle.code.java.frameworks.Kryo private import semmle.code.java.frameworks.XStream diff --git a/java/ql/lib/semmle/code/java/security/XmlParsers.qll b/java/ql/lib/semmle/code/java/security/XmlParsers.qll index 4a5b7121e60..fc0b52b6f78 100644 --- a/java/ql/lib/semmle/code/java/security/XmlParsers.qll +++ b/java/ql/lib/semmle/code/java/security/XmlParsers.qll @@ -2,8 +2,6 @@ import java import semmle.code.java.dataflow.DataFlow -deprecated import semmle.code.java.dataflow.DataFlow3 -private import semmle.code.java.dataflow.DataFlow3 private import semmle.code.java.dataflow.RangeUtils private module Frameworks { diff --git a/java/ql/src/change-notes/2024-10-29-weak-crypto-hash.md b/java/ql/src/change-notes/2024-10-29-weak-crypto-hash.md new file mode 100644 index 00000000000..b4ac88bcdc6 --- /dev/null +++ b/java/ql/src/change-notes/2024-10-29-weak-crypto-hash.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The `java/weak-cryptographic-algorithm` query has been updated to no longer report uses of hash functions such as `MD5` and `SHA1` even if they are known to be weak. These hash algorithms are used very often in non-sensitive contexts, making the query too imprecise in practice. The `java/potentially-weak-cryptographic-algorithm` query has been updated to report these uses instead. diff --git a/java/ql/src/change-notes/2024-11-22-sha3.md b/java/ql/src/change-notes/2024-11-22-sha3.md new file mode 100644 index 00000000000..61dbc35162e --- /dev/null +++ b/java/ql/src/change-notes/2024-11-22-sha3.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added SHA3 to the list of secure hashing algorithms. As a result the `java/potentially-weak-cryptographic-algorithm` query should no longer flag up uses of SHA3. diff --git a/java/ql/src/change-notes/2024-11-24-sha2.md b/java/ql/src/change-notes/2024-11-24-sha2.md new file mode 100644 index 00000000000..395ea04b782 --- /dev/null +++ b/java/ql/src/change-notes/2024-11-24-sha2.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added SHA-384 to the list of secure hashing algorithms. As a result the `java/potentially-weak-cryptographic-algorithm` query should no longer flag up uses of SHA-384. diff --git a/java/ql/src/experimental/Security/CWE/CWE-208/NonConstantTimeCheckOnSignatureQuery.qll b/java/ql/src/experimental/Security/CWE/CWE-208/NonConstantTimeCheckOnSignatureQuery.qll index 8e545a5e8f0..5972db67495 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-208/NonConstantTimeCheckOnSignatureQuery.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-208/NonConstantTimeCheckOnSignatureQuery.qll @@ -95,7 +95,7 @@ private class ProduceCiphertextCall extends ProduceCryptoCall { } /** Holds if `fromNode` to `toNode` is a dataflow step that updates a cryptographic operation. */ -private predicate updateCryptoOperationStep(DataFlow2::Node fromNode, DataFlow2::Node toNode) { +private predicate updateCryptoOperationStep(DataFlow::Node fromNode, DataFlow::Node toNode) { exists(MethodCall call, Method m | m = call.getMethod() and call.getQualifier() = toNode.asExpr() and @@ -111,7 +111,7 @@ private predicate updateCryptoOperationStep(DataFlow2::Node fromNode, DataFlow2: } /** Holds if `fromNode` to `toNode` is a dataflow step that creates a hash. */ -private predicate createMessageDigestStep(DataFlow2::Node fromNode, DataFlow2::Node toNode) { +private predicate createMessageDigestStep(DataFlow::Node fromNode, DataFlow::Node toNode) { exists(MethodCall ma, Method m | m = ma.getMethod() | m.getDeclaringType().hasQualifiedName("java.security", "MessageDigest") and m.hasStringSignature("digest()") and @@ -135,7 +135,7 @@ private predicate createMessageDigestStep(DataFlow2::Node fromNode, DataFlow2::N } /** Holds if `fromNode` to `toNode` is a dataflow step that updates a hash. */ -private predicate updateMessageDigestStep(DataFlow2::Node fromNode, DataFlow2::Node toNode) { +private predicate updateMessageDigestStep(DataFlow::Node fromNode, DataFlow::Node toNode) { exists(MethodCall ma, Method m | m = ma.getMethod() | m.hasQualifiedName("java.security", "MessageDigest", "update") and ma.getArgument(0) = fromNode.asExpr() and @@ -154,7 +154,7 @@ private module UserInputInCryptoOperationConfig implements DataFlow::ConfigSig { exists(ProduceCryptoCall call | call.getQualifier() = sink.asExpr()) } - predicate isAdditionalFlowStep(DataFlow2::Node fromNode, DataFlow2::Node toNode) { + predicate isAdditionalFlowStep(DataFlow::Node fromNode, DataFlow::Node toNode) { updateCryptoOperationStep(fromNode, toNode) or createMessageDigestStep(fromNode, toNode) diff --git a/java/ql/src/experimental/Security/CWE/CWE-625/PermissiveDotRegexQuery.qll b/java/ql/src/experimental/Security/CWE/CWE-625/PermissiveDotRegexQuery.qll index 925fd5632a3..5f015732cb3 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-625/PermissiveDotRegexQuery.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-625/PermissiveDotRegexQuery.qll @@ -94,11 +94,11 @@ private class CompileRegexSink extends DataFlow::ExprNode { * A data flow configuration for regular expressions that include permissive dots. */ private module PermissiveDotRegexConfig implements DataFlow::ConfigSig { - predicate isSource(DataFlow2::Node src) { src.asExpr() instanceof PermissiveDotStr } + predicate isSource(DataFlow::Node src) { src.asExpr() instanceof PermissiveDotStr } - predicate isSink(DataFlow2::Node sink) { sink instanceof CompileRegexSink } + predicate isSink(DataFlow::Node sink) { sink instanceof CompileRegexSink } - predicate isBarrier(DataFlow2::Node node) { + predicate isBarrier(DataFlow::Node node) { exists( MethodCall ma, Field f // Pattern.compile(PATTERN, Pattern.DOTALL) | diff --git a/java/ql/src/experimental/semmle/code/java/security/SpringUrlRedirect.qll b/java/ql/src/experimental/semmle/code/java/security/SpringUrlRedirect.qll index d437c8fa3cc..c068dfbb7e3 100644 --- a/java/ql/src/experimental/semmle/code/java/security/SpringUrlRedirect.qll +++ b/java/ql/src/experimental/semmle/code/java/security/SpringUrlRedirect.qll @@ -53,7 +53,7 @@ private class SpringViewUrlRedirectSink extends SpringUrlRedirectSink { ) or exists(MethodCall ma, RedirectAppendCall rac | - DataFlow2::localExprFlow(rac.getQualifier(), ma.getQualifier()) and + DataFlow::localExprFlow(rac.getQualifier(), ma.getQualifier()) and ma.getMethod().hasName("append") and ma.getArgument(0) = this.asExpr() and any(SpringRequestMappingMethod sqmm).polyCalls*(this.getEnclosingCallable()) diff --git a/java/ql/test/library-tests/dataflow/callback-dispatch/test.expected b/java/ql/test/library-tests/dataflow/callback-dispatch/test.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/library-tests/dataflow/callback-dispatch/test.expected +++ b/java/ql/test/library-tests/dataflow/callback-dispatch/test.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/library-tests/dataflow/entrypoint-types/EntryPointTypesTest.expected b/java/ql/test/library-tests/dataflow/entrypoint-types/EntryPointTypesTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/library-tests/dataflow/entrypoint-types/EntryPointTypesTest.expected +++ b/java/ql/test/library-tests/dataflow/entrypoint-types/EntryPointTypesTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/library-tests/dataflow/flowfeature/flow.expected b/java/ql/test/library-tests/dataflow/flowfeature/flow.expected index 8ec8033d086..e69de29bb2d 100644 --- a/java/ql/test/library-tests/dataflow/flowfeature/flow.expected +++ b/java/ql/test/library-tests/dataflow/flowfeature/flow.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/java/ql/test/library-tests/dataflow/getter/getter.expected b/java/ql/test/library-tests/dataflow/getter/getter.expected index b5af3f91a59..9a36107f198 100644 --- a/java/ql/test/library-tests/dataflow/getter/getter.expected +++ b/java/ql/test/library-tests/dataflow/getter/getter.expected @@ -1,6 +1,5 @@ | A.java:5:12:5:15 | this | A.java:5:12:5:19 | this.foo | A.java:2:7:2:9 | foo | | A.java:21:13:21:13 | a | A.java:21:13:21:22 | getFoo(...) | A.java:2:7:2:9 | foo | | A.java:23:9:23:9 | a | A.java:23:9:23:19 | aGetter(...) | A.java:2:7:2:9 | foo | -| A.java:24:9:24:10 | a2 | A.java:24:9:24:23 | notAGetter(...) | A.java:2:7:2:9 | foo | | A.java:45:12:45:38 | maybeIdWrap(...) | A.java:45:12:45:42 | maybeIdWrap(...).foo | A.java:2:7:2:9 | foo | | A.java:49:12:49:38 | maybeIdWrap(...) | A.java:49:12:49:42 | maybeIdWrap(...).foo | A.java:2:7:2:9 | foo | diff --git a/java/ql/test/library-tests/dataflow/range-analysis-inline/B.java b/java/ql/test/library-tests/dataflow/range-analysis-inline/B.java new file mode 100644 index 00000000000..01c8656deea --- /dev/null +++ b/java/ql/test/library-tests/dataflow/range-analysis-inline/B.java @@ -0,0 +1,158 @@ +public class B { + + // Use this method to mark non-integer bounds + // that should also be annotated. + static void bound(int b) { } + + public int forLoop() { + int result = 0; + for (int i = 0; + i < 10; // $ bound="i in [0..10]" + i++) { // $ bound="i in [0..9]" + result = i; // $ bound="i in [0..9]" + } + return result; // $ bound="result in [0..9]" + } + + public int forLoopExit() { + int result = 0; + for (; result < 10;) { // $ bound="result in [0..10]" + result += 1; // $ bound="result in [0..9]" + } + return result; // $ bound="result = 10" + } + + public int forLoopExitStep() { + int result = 0; + for (; result < 10;) { // $ bound="result in [0..12]" + result += 3; // $ bound="result in [0..9]" + } + return result; // $ bound="result = 12" + } + + public int forLoopExitUpd() { + int result = 0; + for (; result < 10; // $ bound="result in [0..10]" + result++) { // $ bound="result in [0..9]" + } + return result; // $ bound="result = 10" + } + + public int forLoopExitNested() { + int result = 0; + for (; result < 10;) { + int i = 0; + for (; i < 3;) { // $ bound="i in [0..3]" + i += 1; // $ bound="i in [0..2]" + } + result += i; // $ bound="result in [0..9]" bound="i = 3" + } + return result; // $ MISSING:bound="result = 12" + } + + public int emptyForLoop() { + int result = 0; + for (int i = 0; i < 0; // $ bound="i = 0" + i++) { // $ bound="i in [0..-1]" + result = i; // $ bound="i in [0..-1]" + } + return result; // $ bound="result = 0" + } + + public int noLoop() { + int result = 0; + result += 1; // $ bound="result = 0" + return result; // $ bound="result = 1" + } + + public int foreachLoop() { + int result = 0; + for (int i : new int[] {1, 2, 3, 4, 5}) { + result = i; + } + return result; + } + + public int emptyForeachLoop() { + int result = 0; + for (int i : new int[] {}) { + result = i; + } + return result; + } + + public int whileLoop() { + int result = 100; + while (result > 5) { // $ bound="result in [4..100]" + result = result - 2; // $ bound="result in [6..100]" + } + return result; // $ bound="result = 4" + } + + public int oddWhileLoop() { + int result = 101; + while (result > 5) { // $ bound="result in [5..101]" + result = result - 2; // $ bound="result in [7..101]" + } + return result; // $ bound="result = 5" + } + + static void arrayLength(int[] arr) { + bound(arr.length); + for (int i = 0; + i < arr.length; + i++) { // $ bound="i <= arr.length - 1" + arr[i]++; // $ bound="i <= arr.length - 1" + } + } + + static int varBound(int b) { + bound(b); + int result = 0; + for (int i = 0; + i < b; + i++) { // $ bound="i <= b - 1" + result = i; // $ bound="i <= b - 1" + } + return result; // We cannot conclude anything here, since we do not know that b > 0 + } + + static int varBoundPositiveGuard(int b) { + bound(b); + if (b > 0) { + int result = 0; + for (int i = 0; + i < b; + i++) { // $ bound="i <= b - 1" + result = i; // $ bound="i <= b - 1" + } + return result; // $ MISSING: bound="result <= b - 1" + } else { + return 0; + } + } + + static int varBoundPositiveGuardEarlyReturn(int b) { + bound(b); + if (b <= 0) return 0; + int result = 0; + for (int i = 0; + i < b; + i++) { // $ bound="i <= b - 1" + result = i; // $ bound="i <= b - 1" + } + return result; // $ MISSING: bound="result <= b - 1" + } + + static int varBoundPositiveAssert(int b) { + bound(b); + assert b > 0; + int result = 0; + for (int i = 0; + i < b; + i++) { // $ bound="i <= b - 1" + result = i; // $ bound="i <= b - 1" + } + return result; // $ MISSING: bound="result <= b - 1" + } +} \ No newline at end of file diff --git a/rust/ql/test/extractor-tests/generated/ArrayExpr/ArrayExpr_getAttr.expected b/java/ql/test/library-tests/dataflow/range-analysis-inline/range.expected similarity index 100% rename from rust/ql/test/extractor-tests/generated/ArrayExpr/ArrayExpr_getAttr.expected rename to java/ql/test/library-tests/dataflow/range-analysis-inline/range.expected diff --git a/java/ql/test/library-tests/dataflow/range-analysis-inline/range.ql b/java/ql/test/library-tests/dataflow/range-analysis-inline/range.ql new file mode 100644 index 00000000000..b0fcc1710d4 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/range-analysis-inline/range.ql @@ -0,0 +1,71 @@ +/** + * Inline range analysis tests for Java. + * See `shared/util/codeql/dataflow/test/InlineFlowTest.qll` + */ + +import java +import semmle.code.java.dataflow.RangeAnalysis +private import TestUtilities.InlineExpectationsTest as IET + +module RangeTest implements IET::TestSig { + string getARelevantTag() { result = "bound" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "bound" and + ( + // simple integer bounds (`ZeroBound`s) + exists(Expr e, int lower, int upper | + constrained(e, lower, upper) and + e instanceof VarRead and + e.getCompilationUnit().fromSource() + | + location = e.getLocation() and + element = e.toString() and + if lower = upper + then value = "\"" + e.toString() + " = " + lower.toString() + "\"" + else + value = "\"" + e.toString() + " in [" + lower.toString() + ".." + upper.toString() + "]\"" + ) + or + // advanced bounds + exists(Expr e, int delta, string deltaStr, boolean upper, string cmp, Expr boundExpr | + annotatedBound(e, _, boundExpr, delta, upper) and + e instanceof VarRead and + e.getCompilationUnit().fromSource() and + ( + if delta = 0 + then deltaStr = "" + else + if delta > 0 + then deltaStr = " + " + delta.toString() + else deltaStr = " - " + delta.abs().toString() + ) and + if upper = true then cmp = "<=" else cmp = ">=" + | + location = e.getLocation() and + element = e.toString() and + value = "\"" + e.toString() + " " + cmp + " " + boundExpr.toString() + deltaStr + "\"" + ) + ) + } + + private predicate constrained(Expr e, int lower, int upper) { + bounded(e, any(ZeroBound z), lower, false, _) and + bounded(e, any(ZeroBound z), upper, true, _) + } + + private predicate annotatedBound(Expr e, Bound b, Expr boundExpr, int delta, boolean upper) { + bounded(e, b, delta, upper, _) and + // the expression for the bound is explicitly requested as being annotated + // via a call such as + // ```java + // bound(expr); + // ``` + boundExpr = b.getExpr() and + exists(Call c | c.getCallee().getName() = "bound" and c.getArgument(0) = boundExpr) and + // non-trivial bound + not e = b.getExpr() + } +} + +import IET::MakeTest diff --git a/java/ql/test/library-tests/dataflow/state/test.expected b/java/ql/test/library-tests/dataflow/state/test.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/library-tests/dataflow/state/test.expected +++ b/java/ql/test/library-tests/dataflow/state/test.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/library-tests/dataflow/taintsources/local.expected b/java/ql/test/library-tests/dataflow/taintsources/local.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/library-tests/dataflow/taintsources/local.expected +++ b/java/ql/test/library-tests/dataflow/taintsources/local.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/library-tests/dataflow/taintsources/remote.expected b/java/ql/test/library-tests/dataflow/taintsources/remote.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/library-tests/dataflow/taintsources/remote.expected +++ b/java/ql/test/library-tests/dataflow/taintsources/remote.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/library-tests/dataflow/taintsources/reversedns.expected b/java/ql/test/library-tests/dataflow/taintsources/reversedns.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/library-tests/dataflow/taintsources/reversedns.expected +++ b/java/ql/test/library-tests/dataflow/taintsources/reversedns.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/library-tests/frameworks/JaxWs/JaxRs.expected b/java/ql/test/library-tests/frameworks/JaxWs/JaxRs.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/library-tests/frameworks/JaxWs/JaxRs.expected +++ b/java/ql/test/library-tests/frameworks/JaxWs/JaxRs.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/library-tests/frameworks/JaxWs/JaxWsEndpoint.expected b/java/ql/test/library-tests/frameworks/JaxWs/JaxWsEndpoint.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/library-tests/frameworks/JaxWs/JaxWsEndpoint.expected +++ b/java/ql/test/library-tests/frameworks/JaxWs/JaxWsEndpoint.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/library-tests/frameworks/android/taint-database/flowSteps.expected b/java/ql/test/library-tests/frameworks/android/taint-database/flowSteps.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/library-tests/frameworks/android/taint-database/flowSteps.expected +++ b/java/ql/test/library-tests/frameworks/android/taint-database/flowSteps.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/library-tests/frameworks/android/taint-database/sinks.expected b/java/ql/test/library-tests/frameworks/android/taint-database/sinks.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/library-tests/frameworks/android/taint-database/sinks.expected +++ b/java/ql/test/library-tests/frameworks/android/taint-database/sinks.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/library-tests/frameworks/guava/handwritten/flow.expected b/java/ql/test/library-tests/frameworks/guava/handwritten/flow.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/library-tests/frameworks/guava/handwritten/flow.expected +++ b/java/ql/test/library-tests/frameworks/guava/handwritten/flow.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/library-tests/frameworks/jms/FlowTest.expected b/java/ql/test/library-tests/frameworks/jms/FlowTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/library-tests/frameworks/jms/FlowTest.expected +++ b/java/ql/test/library-tests/frameworks/jms/FlowTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/library-tests/frameworks/jms/RemoteSourcesTest.expected b/java/ql/test/library-tests/frameworks/jms/RemoteSourcesTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/library-tests/frameworks/jms/RemoteSourcesTest.expected +++ b/java/ql/test/library-tests/frameworks/jms/RemoteSourcesTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/library-tests/frameworks/rabbitmq/SourceTest.expected b/java/ql/test/library-tests/frameworks/rabbitmq/SourceTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/library-tests/frameworks/rabbitmq/SourceTest.expected +++ b/java/ql/test/library-tests/frameworks/rabbitmq/SourceTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/library-tests/listofconstants/A.java b/java/ql/test/library-tests/listofconstants/A.java new file mode 100644 index 00000000000..74129692d71 --- /dev/null +++ b/java/ql/test/library-tests/listofconstants/A.java @@ -0,0 +1,35 @@ +import java.util.*; + +public class A { + private static final Set SEPARATORS = + Collections.unmodifiableSet( + new HashSet<>(Arrays.asList("\t", "\n", ";"))); + + public static void sink(String s) { } + + private void checkSeparator(String separator) { + if (SEPARATORS.contains(separator)) { + sink(separator); + } + } + + public static final String URI1 = "yarn.io/gpu"; + public static final String URI2 = "yarn.io/fpga"; + + public static final Set SCHEMAS = Set.of(URI1, URI2, "s3a", "wasb"); + + private void checkSchema(String schema) { + if (SCHEMAS.contains(schema)) { + sink(schema); + } + } + + private void testAdd(String inp) { + Set s = new HashSet<>(); + s.add("AA"); + s.add("BB"); + if (s.contains(inp.toUpperCase())) { + sink(inp); + } + } +} diff --git a/java/ql/test/library-tests/listofconstants/CONSISTENCY/typeParametersInScope.expected b/java/ql/test/library-tests/listofconstants/CONSISTENCY/typeParametersInScope.expected new file mode 100644 index 00000000000..1ea902154a6 --- /dev/null +++ b/java/ql/test/library-tests/listofconstants/CONSISTENCY/typeParametersInScope.expected @@ -0,0 +1 @@ +| Type A uses out-of-scope type variable E. Note the Java extractor is known to sometimes do this; the Kotlin extractor should not. | diff --git a/java/ql/test/library-tests/listofconstants/test.expected b/java/ql/test/library-tests/listofconstants/test.expected new file mode 100644 index 00000000000..203d64cd46d --- /dev/null +++ b/java/ql/test/library-tests/listofconstants/test.expected @@ -0,0 +1,3 @@ +| A.java:12:12:12:20 | separator | +| A.java:23:12:23:17 | schema | +| A.java:32:12:32:14 | inp | diff --git a/java/ql/test/library-tests/listofconstants/test.ql b/java/ql/test/library-tests/listofconstants/test.ql new file mode 100644 index 00000000000..f56dfc0f11f --- /dev/null +++ b/java/ql/test/library-tests/listofconstants/test.ql @@ -0,0 +1,5 @@ +import java +import semmle.code.java.dataflow.FlowSteps + +from DefaultTaintSanitizer e +select e diff --git a/java/ql/test/library-tests/neutrals/neutralsinks/NeutralSinksTest.expected b/java/ql/test/library-tests/neutrals/neutralsinks/NeutralSinksTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/library-tests/neutrals/neutralsinks/NeutralSinksTest.expected +++ b/java/ql/test/library-tests/neutrals/neutralsinks/NeutralSinksTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/library-tests/xml/XMLTest.expected b/java/ql/test/library-tests/xml/XMLTest.expected index 191aad0a6e2..cbdfca1fc67 100644 --- a/java/ql/test/library-tests/xml/XMLTest.expected +++ b/java/ql/test/library-tests/xml/XMLTest.expected @@ -1,4 +1,2 @@ -testFailures | test.xml:4:5:4:32 | attribute=value | Unexpected result: hasXmlResult | | test.xml:5:29:5:52 | $ hasXmlResult | Missing result: hasXmlResult | -failures diff --git a/java/ql/test/query-tests/security/CWE-023/semmle/tests/PartialPathTraversalFromRemoteTest.expected b/java/ql/test/query-tests/security/CWE-023/semmle/tests/PartialPathTraversalFromRemoteTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-023/semmle/tests/PartialPathTraversalFromRemoteTest.expected +++ b/java/ql/test/query-tests/security/CWE-023/semmle/tests/PartialPathTraversalFromRemoteTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-074/JndiInjectionTest.expected b/java/ql/test/query-tests/security/CWE-074/JndiInjectionTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-074/JndiInjectionTest.expected +++ b/java/ql/test/query-tests/security/CWE-074/JndiInjectionTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-074/XsltInjectionTest.expected b/java/ql/test/query-tests/security/CWE-074/XsltInjectionTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-074/XsltInjectionTest.expected +++ b/java/ql/test/query-tests/security/CWE-074/XsltInjectionTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-079/semmle/tests/XSS.expected b/java/ql/test/query-tests/security/CWE-079/semmle/tests/XSS.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-079/semmle/tests/XSS.expected +++ b/java/ql/test/query-tests/security/CWE-079/semmle/tests/XSS.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-089/semmle/examples/AllowListSanitizerWithJavaUtilList.java b/java/ql/test/query-tests/security/CWE-089/semmle/examples/AllowListSanitizerWithJavaUtilList.java new file mode 100644 index 00000000000..285f9bc49cb --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-089/semmle/examples/AllowListSanitizerWithJavaUtilList.java @@ -0,0 +1,306 @@ +// Test cases for CWE-089 (SQL injection and Java Persistence query injection) +// http://cwe.mitre.org/data/definitions/89.html +package test.cwe089.semmle.tests; + +import java.io.IOException; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.function.Consumer; + +class AllowListSanitizerWithJavaUtilList { + public static Connection connection; + public static final List goodAllowList1 = List.of("allowed1", "allowed2", "allowed3"); + public static final List goodAllowList2 = Collections.unmodifiableList(Arrays.asList("allowed1")); + public static final List goodAllowList3; + public static final List goodAllowList4; + public static final List goodAllowList5; + public static final List badAllowList1 = List.of("allowed1", "allowed2", getNonConstantString()); + public static final List badAllowList2 = Collections.unmodifiableList(Arrays.asList("allowed1", getNonConstantString())); + public static final List badAllowList3; + public static final List badAllowList4; + public static List badAllowList6 = List.of("allowed1", "allowed2", "allowed3"); + public final List goodAllowList7 = List.of("allowed1", "allowed2", "allowed3"); + + static { + goodAllowList3 = List.of("allowed1", "allowed2", "allowed3"); + goodAllowList4 = Collections.unmodifiableList(Arrays.asList("allowed1", "allowed2")); + badAllowList3 = List.of(getNonConstantString(), "allowed2", "allowed3"); + badAllowList4 = Collections.unmodifiableList(Arrays.asList("allowed1", getNonConstantString())); + goodAllowList5 = new ArrayList(); + goodAllowList5.add("allowed1"); + goodAllowList5.add("allowed2"); + goodAllowList5.add("allowed3"); + } + + public static String getNonConstantString() { + return String.valueOf(System.currentTimeMillis()); + } + + public static void main(String[] args) throws IOException, SQLException { + badAllowList6 = List.of("allowed1", getNonConstantString(), "allowed3"); + testStaticFields(args); + testLocal(args); + var x = new AllowListSanitizerWithJavaUtilList(); + x.testNonStaticFields(args); + testMultipleSources(args); + testEscape(args); + } + + private static void testStaticFields(String[] args) throws IOException, SQLException { + String tainted = args[1]; + // GOOD: an allowlist is used with constant strings + if(goodAllowList1.contains(tainted.toLowerCase())){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + // GOOD: an allowlist is used with constant strings + if(goodAllowList2.contains(tainted.toUpperCase())){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + // GOOD: an allowlist is used with constant strings + if(goodAllowList3.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + // GOOD: an allowlist is used with constant strings + if(goodAllowList4.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + // BAD: an allowlist is used with constant strings + if(badAllowList1.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + // BAD: an allowlist is used with constant strings + if(badAllowList2.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + // BAD: an allowlist is used with constant strings + if(badAllowList3.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + // BAD: an allowlist is used with constant strings + if(badAllowList4.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + // GOOD: an allowlist is used with constant strings + if(goodAllowList5.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + // BAD: the allowlist is in a non-final field + if(badAllowList6.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + + private void testNonStaticFields(String[] args) throws IOException, SQLException { + String tainted = args[0]; + // GOOD: the allowlist is in a non-static field + if(goodAllowList7.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + + private static void testLocal(String[] args) throws IOException, SQLException { + String tainted = args[1]; + // GOOD: an allowlist is used with constant strings + { + List allowlist = List.of("allowed1", "allowed2", "allowed3"); + if(allowlist.contains(tainted.toLowerCase())){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + // BAD: an allowlist is used but one of the entries is not a compile-time constant + { + List allowlist = List.of("allowed1", "allowed2", args[2]); + if(allowlist.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + // GOOD: an allowlist is used with constant strings + { + String[] allowedArray = {"allowed1", "allowed2", "allowed3"}; + List allowlist = List.of(allowedArray); + if(allowlist.contains(tainted.toUpperCase())){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + // BAD: an allowlist is used but one of the entries is not a compile-time constant + { + String[] allowedArray = {"allowed1", "allowed2", args[2]}; + List allowlist = List.of(allowedArray); + if(allowlist.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + // GOOD: an allowlist is used with constant strings + { + List allowlist = Collections.unmodifiableList(Arrays.asList("allowed1")); + if(allowlist.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + // BAD: an allowlist is used but one of the entries is not a compile-time constant + { + List allowlist = Collections.unmodifiableList(Arrays.asList("allowed1", "allowed2", args[2])); + if(allowlist.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + // GOOD: an allowlist is used with constant strings + { + String[] allowedArray = {"allowed1", "allowed2", "allowed3"}; + List allowlist = Collections.unmodifiableList(Arrays.asList(allowedArray)); + if(allowlist.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + // BAD: an allowlist is used but one of the entries is not a compile-time constant + { + String[] allowedArray = {"allowed1", "allowed2", args[2]}; + List allowlist = Collections.unmodifiableList(Arrays.asList(allowedArray)); + if(allowlist.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + // GOOD: an allowlist is used with constant string + { + List allowlist = new ArrayList(); + allowlist.add("allowed1"); + allowlist.add("allowed2"); + allowlist.add("allowed3"); + if(allowlist.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + // BAD: an allowlist is used but one of the entries is not a compile-time constant + { + List allowlist = new ArrayList(); + allowlist.add("allowed1"); + allowlist.add(getNonConstantString()); + allowlist.add("allowed3"); + if(allowlist.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + // BAD: an allowlist is used but it contains a non-compile-time constant element + { + List allowlist = new ArrayList(); + allowlist.add("allowed1"); + addNonConstantStringDirectly(allowlist); + if(allowlist.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + } + + private static void testMultipleSources(String[] args) throws IOException, SQLException { + String tainted = args[1]; + boolean b = args[2] == "True"; + { + // BAD: an allowlist is used which might contain constant strings + List allowlist = new ArrayList(); + allowlist.add("allowed1"); + if (b) { + allowlist.add(getNonConstantString()); + } + if(allowlist.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + { + // BAD: an allowlist is used which might contain constant strings + List allowlist = b ? goodAllowList1 : badAllowList1; + if(allowlist.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + { + // BAD: an allowlist is used which might contain constant strings + List allowlist = b ? goodAllowList1 : List.of("allowed1", "allowed2", args[2]);; + if(allowlist.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + } + + private static void testEscape(String[] args) throws IOException, SQLException { + String tainted = args[1]; + boolean b = args[2] == "True"; + { + // BAD: an allowlist is used which contains constant strings + List allowlist = new ArrayList(); + addNonConstantStringViaLambda(e -> allowlist.add(e)); + if(allowlist.contains(tainted)){ // missing result + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + } + + private static void addNonConstantStringDirectly(List list) { + list.add(getNonConstantString()); + } + + private static void addNonConstantStringViaLambda(Consumer adder) { + adder.accept(getNonConstantString()); + } + +} diff --git a/java/ql/test/query-tests/security/CWE-089/semmle/examples/AllowListSanitizerWithJavaUtilSet.java b/java/ql/test/query-tests/security/CWE-089/semmle/examples/AllowListSanitizerWithJavaUtilSet.java new file mode 100644 index 00000000000..e1a5f889c6f --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-089/semmle/examples/AllowListSanitizerWithJavaUtilSet.java @@ -0,0 +1,305 @@ +// Test cases for CWE-089 (SQL injection and Java Persistence query injection) +// http://cwe.mitre.org/data/definitions/89.html +package test.cwe089.semmle.tests; + +import java.io.IOException; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.HashSet; +import java.util.List; +import java.util.Arrays; +import java.util.Collections; +import java.util.Set; +import java.util.function.Consumer; + +class AllowListSanitizerWithJavaUtilSet { + public static Connection connection; + public static final Set goodAllowList1 = Set.of("allowed1", "allowed2", "allowed3"); + public static final Set goodAllowList2 = Collections.unmodifiableSet(new HashSet(Arrays.asList("allowed1","allowed2"))); + public static final Set goodAllowList3; + public static final Set goodAllowList4; + public static final Set goodAllowList5; + public static final Set badAllowList1 = Set.of("allowed1", "allowed2", getNonConstantString()); + public static final Set badAllowList2 = Collections.unmodifiableSet(new HashSet(Arrays.asList("allowed1", getNonConstantString()))); + public static final Set badAllowList3; + public static final Set badAllowList4; + public static Set badAllowList6 = Set.of("allowed1", "allowed2", "allowed3"); + public final Set goodAllowList7 = Set.of("allowed1", "allowed2", "allowed3"); + + static { + goodAllowList3 = Set.of("allowed1", "allowed2", "allowed3"); + goodAllowList4 = Collections.unmodifiableSet(new HashSet(Arrays.asList("allowed1", "allowed2"))); + badAllowList3 = Set.of(getNonConstantString(), "allowed2", "allowed3"); + badAllowList4 = Collections.unmodifiableSet(new HashSet(Arrays.asList("allowed1", getNonConstantString()))); + goodAllowList5 = new HashSet(); + goodAllowList5.add("allowed1"); + goodAllowList5.add("allowed2"); + goodAllowList5.add("allowed3"); + } + + public static String getNonConstantString() { + return String.valueOf(System.currentTimeMillis()); + } + + public static void main(String[] args) throws IOException, SQLException { + badAllowList6 = Set.of("allowed1", getNonConstantString(), "allowed3"); + testStaticFields(args); + testLocal(args); + var x = new AllowListSanitizerWithJavaUtilSet(); + x.testNonStaticFields(args); + testMultipleSources(args); + testEscape(args); + } + + private static void testStaticFields(String[] args) throws IOException, SQLException { + String tainted = args[1]; + // GOOD: an allowlist is used with constant strings + if(goodAllowList1.contains(tainted.toLowerCase())){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + // GOOD: an allowlist is used with constant strings + if(goodAllowList2.contains(tainted.toUpperCase())){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + // GOOD: an allowlist is used with constant strings + if(goodAllowList3.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + // GOOD: an allowlist is used with constant strings + if(goodAllowList4.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + // BAD: an allowlist is used with constant strings + if(badAllowList1.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + // BAD: an allowlist is used with constant strings + if(badAllowList2.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + // BAD: an allowlist is used with constant strings + if(badAllowList3.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + // BAD: an allowlist is used with constant strings + if(badAllowList4.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + // GOOD: an allowlist is used with constant strings + if(goodAllowList5.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + // BAD: the allowlist is in a non-final field + if(badAllowList6.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + + private void testNonStaticFields(String[] args) throws IOException, SQLException { + String tainted = args[1]; + // GOOD: the allowlist is in a non-static field + if(goodAllowList7.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + + private static void testLocal(String[] args) throws IOException, SQLException { + String tainted = args[1]; + // GOOD: an allowlist is used with constant strings + { + Set allowlist = Set.of("allowed1", "allowed2", "allowed3"); + if(allowlist.contains(tainted.toLowerCase())){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + // BAD: an allowlist is used but one of the entries is not a compile-time constant + { + Set allowlist = Set.of("allowed1", "allowed2", args[2]); + if(allowlist.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + // GOOD: an allowlist is used with constant strings + { + String[] allowedArray = {"allowed1", "allowed2", "allowed3"}; + Set allowlist = Set.of(allowedArray); + if(allowlist.contains(tainted.toUpperCase())){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + // BAD: an allowlist is used but one of the entries is not a compile-time constant + { + String[] allowedArray = {"allowed1", "allowed2", args[2]}; + Set allowlist = Set.of(allowedArray); + if(allowlist.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + // GOOD: an allowlist is used with constant strings + { + Set allowlist = Collections.unmodifiableSet(new HashSet<>(Arrays.asList("allowed1"))); + if(allowlist.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + // BAD: an allowlist is used but one of the entries is not a compile-time constant + { + Set allowlist = Collections.unmodifiableSet(new HashSet<>(Arrays.asList("allowed1", "allowed2", args[2]))); + if(allowlist.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + // GOOD: an allowlist is used with constant strings + { + String[] allowedArray = {"allowed1", "allowed2", "allowed3"}; + Set allowlist = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(allowedArray))); + if(allowlist.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + // BAD: an allowlist is used but one of the entries is not a compile-time constant + { + String[] allowedArray = {"allowed1", "allowed2", args[2]}; + Set allowlist = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(allowedArray))); + if(allowlist.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + // GOOD: an allowlist is used with constant string + { + Set allowlist = new HashSet(); + allowlist.add("allowed1"); + allowlist.add("allowed2"); + allowlist.add("allowed3"); + if(allowlist.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + // BAD: an allowlist is used but one of the entries is not a compile-time constant + { + Set allowlist = new HashSet(); + allowlist.add("allowed1"); + allowlist.add(getNonConstantString()); + allowlist.add("allowed3"); + if(allowlist.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + // BAD: an allowlist is used but it contains a non-compile-time constant element + { + Set allowlist = new HashSet(); + allowlist.add("allowed1"); + addNonConstantStringDirectly(allowlist); + if(allowlist.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + } + + private static void testMultipleSources(String[] args) throws IOException, SQLException { + String tainted = args[1]; + boolean b = args[2] == "True"; + { + // BAD: an allowlist is used which might contain constant strings + Set allowlist = new HashSet(); + allowlist.add("allowed1"); + if (b) { + allowlist.add(getNonConstantString()); + } + if(allowlist.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + { + // BAD: an allowlist is used which might contain constant strings + Set allowlist = b ? goodAllowList1 : badAllowList1; + if(allowlist.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + { + // BAD: an allowlist is used which might contain constant strings + Set allowlist = b ? goodAllowList1 : Set.of("allowed1", "allowed2", args[2]);; + if(allowlist.contains(tainted)){ + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + } + + private static void testEscape(String[] args) throws IOException, SQLException { + String tainted = args[1]; + boolean b = args[2] == "True"; + { + // BAD: an allowlist is used which contains constant strings + Set allowlist = new HashSet(); + addNonConstantStringViaLambda(e -> allowlist.add(e)); + if(allowlist.contains(tainted)){ // missing result + String query = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" + + tainted + "' ORDER BY PRICE"; + ResultSet results = connection.createStatement().executeQuery(query); + } + } + } + + private static void addNonConstantStringDirectly(Set set) { + set.add(getNonConstantString()); + } + + private static void addNonConstantStringViaLambda(Consumer adder) { + adder.accept(getNonConstantString()); + } + +} diff --git a/java/ql/test/query-tests/security/CWE-089/semmle/examples/CONSISTENCY/typeParametersInScope.expected b/java/ql/test/query-tests/security/CWE-089/semmle/examples/CONSISTENCY/typeParametersInScope.expected new file mode 100644 index 00000000000..1f8028eff60 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-089/semmle/examples/CONSISTENCY/typeParametersInScope.expected @@ -0,0 +1 @@ +| Type AllowListSanitizerWithJavaUtilSet uses out-of-scope type variable E. Note the Java extractor is known to sometimes do this; the Kotlin extractor should not. | diff --git a/java/ql/test/query-tests/security/CWE-089/semmle/examples/SqlConcatenated.expected b/java/ql/test/query-tests/security/CWE-089/semmle/examples/SqlConcatenated.expected index fc1d87f06b1..1e560f03c3b 100644 --- a/java/ql/test/query-tests/security/CWE-089/semmle/examples/SqlConcatenated.expected +++ b/java/ql/test/query-tests/security/CWE-089/semmle/examples/SqlConcatenated.expected @@ -1,3 +1,55 @@ +| AllowListSanitizerWithJavaUtilList.java:64:66:64:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:63:8:63:14 | tainted | this expression | +| AllowListSanitizerWithJavaUtilList.java:70:66:70:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:69:8:69:14 | tainted | this expression | +| AllowListSanitizerWithJavaUtilList.java:76:66:76:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:75:8:75:14 | tainted | this expression | +| AllowListSanitizerWithJavaUtilList.java:82:66:82:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:81:8:81:14 | tainted | this expression | +| AllowListSanitizerWithJavaUtilList.java:88:66:88:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:87:8:87:14 | tainted | this expression | +| AllowListSanitizerWithJavaUtilList.java:94:66:94:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:93:8:93:14 | tainted | this expression | +| AllowListSanitizerWithJavaUtilList.java:100:66:100:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:99:8:99:14 | tainted | this expression | +| AllowListSanitizerWithJavaUtilList.java:106:66:106:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:105:8:105:14 | tainted | this expression | +| AllowListSanitizerWithJavaUtilList.java:112:66:112:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:111:8:111:14 | tainted | this expression | +| AllowListSanitizerWithJavaUtilList.java:118:66:118:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:117:8:117:14 | tainted | this expression | +| AllowListSanitizerWithJavaUtilList.java:128:66:128:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:127:8:127:14 | tainted | this expression | +| AllowListSanitizerWithJavaUtilList.java:140:67:140:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:139:9:139:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilList.java:149:67:149:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:148:9:148:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilList.java:159:67:159:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:158:9:158:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilList.java:169:67:169:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:168:9:168:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilList.java:178:67:178:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:177:9:177:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilList.java:187:67:187:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:186:9:186:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilList.java:197:67:197:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:196:9:196:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilList.java:207:67:207:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:206:9:206:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilList.java:219:67:219:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:218:9:218:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilList.java:231:67:231:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:230:9:230:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilList.java:242:67:242:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:241:9:241:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilList.java:260:67:260:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:259:9:259:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilList.java:269:67:269:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:268:9:268:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilList.java:278:67:278:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:277:9:277:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilList.java:293:67:293:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilList.java:292:9:292:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilSet.java:63:66:63:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:62:8:62:14 | tainted | this expression | +| AllowListSanitizerWithJavaUtilSet.java:69:66:69:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:68:8:68:14 | tainted | this expression | +| AllowListSanitizerWithJavaUtilSet.java:75:66:75:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:74:8:74:14 | tainted | this expression | +| AllowListSanitizerWithJavaUtilSet.java:81:66:81:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:80:8:80:14 | tainted | this expression | +| AllowListSanitizerWithJavaUtilSet.java:87:66:87:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:86:8:86:14 | tainted | this expression | +| AllowListSanitizerWithJavaUtilSet.java:93:66:93:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:92:8:92:14 | tainted | this expression | +| AllowListSanitizerWithJavaUtilSet.java:99:66:99:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:98:8:98:14 | tainted | this expression | +| AllowListSanitizerWithJavaUtilSet.java:105:66:105:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:104:8:104:14 | tainted | this expression | +| AllowListSanitizerWithJavaUtilSet.java:111:66:111:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:110:8:110:14 | tainted | this expression | +| AllowListSanitizerWithJavaUtilSet.java:117:66:117:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:116:8:116:14 | tainted | this expression | +| AllowListSanitizerWithJavaUtilSet.java:127:66:127:70 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:126:8:126:14 | tainted | this expression | +| AllowListSanitizerWithJavaUtilSet.java:139:67:139:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:138:9:138:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilSet.java:148:67:148:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:147:9:147:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilSet.java:158:67:158:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:157:9:157:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilSet.java:168:67:168:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:167:9:167:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilSet.java:177:67:177:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:176:9:176:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilSet.java:186:67:186:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:185:9:185:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilSet.java:196:67:196:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:195:9:195:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilSet.java:206:67:206:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:205:9:205:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilSet.java:218:67:218:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:217:9:217:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilSet.java:230:67:230:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:229:9:229:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilSet.java:241:67:241:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:240:9:240:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilSet.java:259:67:259:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:258:9:258:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilSet.java:268:67:268:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:267:9:267:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilSet.java:277:67:277:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:276:9:276:15 | tainted | this expression | +| AllowListSanitizerWithJavaUtilSet.java:292:67:292:71 | query | Query built by concatenation with $@, which may be untrusted. | AllowListSanitizerWithJavaUtilSet.java:291:9:291:15 | tainted | this expression | | Test.java:36:47:36:52 | query1 | Query built by concatenation with $@, which may be untrusted. | Test.java:35:8:35:15 | category | this expression | | Test.java:42:57:42:62 | query2 | Query built by concatenation with $@, which may be untrusted. | Test.java:41:51:41:52 | id | this expression | | Test.java:50:62:50:67 | query3 | Query built by concatenation with $@, which may be untrusted. | Test.java:49:8:49:15 | category | this expression | diff --git a/java/ql/test/query-tests/security/CWE-089/semmle/examples/SqlTainted.expected b/java/ql/test/query-tests/security/CWE-089/semmle/examples/SqlTainted.expected index d54bbdaec05..a45f58bd54d 100644 --- a/java/ql/test/query-tests/security/CWE-089/semmle/examples/SqlTainted.expected +++ b/java/ql/test/query-tests/security/CWE-089/semmle/examples/SqlTainted.expected @@ -1,4 +1,34 @@ #select +| AllowListSanitizerWithJavaUtilList.java:88:66:88:70 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:88:66:88:70 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilList.java:94:66:94:70 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:94:66:94:70 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilList.java:100:66:100:70 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:100:66:100:70 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilList.java:106:66:106:70 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:106:66:106:70 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilList.java:118:66:118:70 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:118:66:118:70 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilList.java:149:67:149:71 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:149:67:149:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilList.java:169:67:169:71 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:169:67:169:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilList.java:187:67:187:71 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:187:67:187:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilList.java:207:67:207:71 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:207:67:207:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilList.java:231:67:231:71 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:231:67:231:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilList.java:242:67:242:71 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:242:67:242:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilList.java:260:67:260:71 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:260:67:260:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilList.java:269:67:269:71 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:269:67:269:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilList.java:278:67:278:71 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:278:67:278:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilList.java:293:67:293:71 | query | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:293:67:293:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilSet.java:87:66:87:70 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:87:66:87:70 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilSet.java:93:66:93:70 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:93:66:93:70 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilSet.java:99:66:99:70 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:99:66:99:70 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilSet.java:105:66:105:70 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:105:66:105:70 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilSet.java:117:66:117:70 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:117:66:117:70 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilSet.java:148:67:148:71 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:148:67:148:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilSet.java:168:67:168:71 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:168:67:168:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilSet.java:186:67:186:71 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:186:67:186:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilSet.java:206:67:206:71 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:206:67:206:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilSet.java:230:67:230:71 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:230:67:230:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilSet.java:241:67:241:71 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:241:67:241:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilSet.java:259:67:259:71 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:259:67:259:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilSet.java:268:67:268:71 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:268:67:268:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilSet.java:277:67:277:71 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:277:67:277:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value | +| AllowListSanitizerWithJavaUtilSet.java:292:67:292:71 | query | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:292:67:292:71 | query | This query depends on a $@. | AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args | user-provided value | | Mongo.java:17:45:17:67 | parse(...) | Mongo.java:10:29:10:41 | args : String[] | Mongo.java:17:45:17:67 | parse(...) | This query depends on a $@. | Mongo.java:10:29:10:41 | args | user-provided value | | Mongo.java:21:49:21:52 | json | Mongo.java:10:29:10:41 | args : String[] | Mongo.java:21:49:21:52 | json | This query depends on a $@. | Mongo.java:10:29:10:41 | args | user-provided value | | Test.java:36:47:36:52 | query1 | Test.java:227:26:227:38 | args : String[] | Test.java:36:47:36:52 | query1 | This query depends on a $@. | Test.java:227:26:227:38 | args | user-provided value | @@ -10,6 +40,52 @@ | Test.java:209:47:209:68 | queryWithUserTableName | Test.java:227:26:227:38 | args : String[] | Test.java:209:47:209:68 | queryWithUserTableName | This query depends on a $@. | Test.java:227:26:227:38 | args | user-provided value | | Test.java:221:81:221:111 | ... + ... | Test.java:227:26:227:38 | args : String[] | Test.java:221:81:221:111 | ... + ... | This query depends on a $@. | Test.java:227:26:227:38 | args | user-provided value | edges +| AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:50:20:50:23 | args : String[] | provenance | | +| AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:51:13:51:16 | args : String[] | provenance | | +| AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:54:23:54:26 | args : String[] | provenance | | +| AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | AllowListSanitizerWithJavaUtilList.java:55:14:55:17 | args : String[] | provenance | | +| AllowListSanitizerWithJavaUtilList.java:50:20:50:23 | args : String[] | AllowListSanitizerWithJavaUtilList.java:58:39:58:51 | args : String[] | provenance | | +| AllowListSanitizerWithJavaUtilList.java:51:13:51:16 | args : String[] | AllowListSanitizerWithJavaUtilList.java:132:32:132:44 | args : String[] | provenance | | +| AllowListSanitizerWithJavaUtilList.java:54:23:54:26 | args : String[] | AllowListSanitizerWithJavaUtilList.java:247:42:247:54 | args : String[] | provenance | | +| AllowListSanitizerWithJavaUtilList.java:55:14:55:17 | args : String[] | AllowListSanitizerWithJavaUtilList.java:283:33:283:45 | args : String[] | provenance | | +| AllowListSanitizerWithJavaUtilList.java:58:39:58:51 | args : String[] | AllowListSanitizerWithJavaUtilList.java:88:66:88:70 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilList.java:58:39:58:51 | args : String[] | AllowListSanitizerWithJavaUtilList.java:94:66:94:70 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilList.java:58:39:58:51 | args : String[] | AllowListSanitizerWithJavaUtilList.java:100:66:100:70 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilList.java:58:39:58:51 | args : String[] | AllowListSanitizerWithJavaUtilList.java:106:66:106:70 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilList.java:58:39:58:51 | args : String[] | AllowListSanitizerWithJavaUtilList.java:118:66:118:70 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilList.java:132:32:132:44 | args : String[] | AllowListSanitizerWithJavaUtilList.java:149:67:149:71 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilList.java:132:32:132:44 | args : String[] | AllowListSanitizerWithJavaUtilList.java:169:67:169:71 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilList.java:132:32:132:44 | args : String[] | AllowListSanitizerWithJavaUtilList.java:187:67:187:71 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilList.java:132:32:132:44 | args : String[] | AllowListSanitizerWithJavaUtilList.java:207:67:207:71 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilList.java:132:32:132:44 | args : String[] | AllowListSanitizerWithJavaUtilList.java:231:67:231:71 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilList.java:132:32:132:44 | args : String[] | AllowListSanitizerWithJavaUtilList.java:242:67:242:71 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilList.java:247:42:247:54 | args : String[] | AllowListSanitizerWithJavaUtilList.java:260:67:260:71 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilList.java:247:42:247:54 | args : String[] | AllowListSanitizerWithJavaUtilList.java:269:67:269:71 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilList.java:247:42:247:54 | args : String[] | AllowListSanitizerWithJavaUtilList.java:278:67:278:71 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilList.java:283:33:283:45 | args : String[] | AllowListSanitizerWithJavaUtilList.java:293:67:293:71 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:49:20:49:23 | args : String[] | provenance | | +| AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:50:13:50:16 | args : String[] | provenance | | +| AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:53:23:53:26 | args : String[] | provenance | | +| AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:54:14:54:17 | args : String[] | provenance | | +| AllowListSanitizerWithJavaUtilSet.java:49:20:49:23 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:57:39:57:51 | args : String[] | provenance | | +| AllowListSanitizerWithJavaUtilSet.java:50:13:50:16 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:131:32:131:44 | args : String[] | provenance | | +| AllowListSanitizerWithJavaUtilSet.java:53:23:53:26 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:246:42:246:54 | args : String[] | provenance | | +| AllowListSanitizerWithJavaUtilSet.java:54:14:54:17 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:282:33:282:45 | args : String[] | provenance | | +| AllowListSanitizerWithJavaUtilSet.java:57:39:57:51 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:87:66:87:70 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilSet.java:57:39:57:51 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:93:66:93:70 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilSet.java:57:39:57:51 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:99:66:99:70 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilSet.java:57:39:57:51 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:105:66:105:70 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilSet.java:57:39:57:51 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:117:66:117:70 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilSet.java:131:32:131:44 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:148:67:148:71 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilSet.java:131:32:131:44 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:168:67:168:71 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilSet.java:131:32:131:44 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:186:67:186:71 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilSet.java:131:32:131:44 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:206:67:206:71 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilSet.java:131:32:131:44 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:230:67:230:71 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilSet.java:131:32:131:44 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:241:67:241:71 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilSet.java:246:42:246:54 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:259:67:259:71 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilSet.java:246:42:246:54 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:268:67:268:71 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilSet.java:246:42:246:54 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:277:67:277:71 | query | provenance | Sink:MaD:4 | +| AllowListSanitizerWithJavaUtilSet.java:282:33:282:45 | args : String[] | AllowListSanitizerWithJavaUtilSet.java:292:67:292:71 | query | provenance | Sink:MaD:4 | | Mongo.java:10:29:10:41 | args : String[] | Mongo.java:17:56:17:66 | stringQuery : String | provenance | | | Mongo.java:10:29:10:41 | args : String[] | Mongo.java:21:49:21:52 | json | provenance | | | Mongo.java:17:56:17:66 | stringQuery : String | Mongo.java:17:45:17:67 | parse(...) | provenance | Config | @@ -40,6 +116,54 @@ models | 6 | Summary: java.lang; AbstractStringBuilder; true; append; ; ; Argument[0]; Argument[this]; taint; manual | | 7 | Summary: java.lang; CharSequence; true; toString; ; ; Argument[this]; ReturnValue; taint; manual | nodes +| AllowListSanitizerWithJavaUtilList.java:48:26:48:38 | args : String[] | semmle.label | args : String[] | +| AllowListSanitizerWithJavaUtilList.java:50:20:50:23 | args : String[] | semmle.label | args : String[] | +| AllowListSanitizerWithJavaUtilList.java:51:13:51:16 | args : String[] | semmle.label | args : String[] | +| AllowListSanitizerWithJavaUtilList.java:54:23:54:26 | args : String[] | semmle.label | args : String[] | +| AllowListSanitizerWithJavaUtilList.java:55:14:55:17 | args : String[] | semmle.label | args : String[] | +| AllowListSanitizerWithJavaUtilList.java:58:39:58:51 | args : String[] | semmle.label | args : String[] | +| AllowListSanitizerWithJavaUtilList.java:88:66:88:70 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilList.java:94:66:94:70 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilList.java:100:66:100:70 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilList.java:106:66:106:70 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilList.java:118:66:118:70 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilList.java:132:32:132:44 | args : String[] | semmle.label | args : String[] | +| AllowListSanitizerWithJavaUtilList.java:149:67:149:71 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilList.java:169:67:169:71 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilList.java:187:67:187:71 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilList.java:207:67:207:71 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilList.java:231:67:231:71 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilList.java:242:67:242:71 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilList.java:247:42:247:54 | args : String[] | semmle.label | args : String[] | +| AllowListSanitizerWithJavaUtilList.java:260:67:260:71 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilList.java:269:67:269:71 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilList.java:278:67:278:71 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilList.java:283:33:283:45 | args : String[] | semmle.label | args : String[] | +| AllowListSanitizerWithJavaUtilList.java:293:67:293:71 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilSet.java:47:26:47:38 | args : String[] | semmle.label | args : String[] | +| AllowListSanitizerWithJavaUtilSet.java:49:20:49:23 | args : String[] | semmle.label | args : String[] | +| AllowListSanitizerWithJavaUtilSet.java:50:13:50:16 | args : String[] | semmle.label | args : String[] | +| AllowListSanitizerWithJavaUtilSet.java:53:23:53:26 | args : String[] | semmle.label | args : String[] | +| AllowListSanitizerWithJavaUtilSet.java:54:14:54:17 | args : String[] | semmle.label | args : String[] | +| AllowListSanitizerWithJavaUtilSet.java:57:39:57:51 | args : String[] | semmle.label | args : String[] | +| AllowListSanitizerWithJavaUtilSet.java:87:66:87:70 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilSet.java:93:66:93:70 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilSet.java:99:66:99:70 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilSet.java:105:66:105:70 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilSet.java:117:66:117:70 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilSet.java:131:32:131:44 | args : String[] | semmle.label | args : String[] | +| AllowListSanitizerWithJavaUtilSet.java:148:67:148:71 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilSet.java:168:67:168:71 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilSet.java:186:67:186:71 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilSet.java:206:67:206:71 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilSet.java:230:67:230:71 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilSet.java:241:67:241:71 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilSet.java:246:42:246:54 | args : String[] | semmle.label | args : String[] | +| AllowListSanitizerWithJavaUtilSet.java:259:67:259:71 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilSet.java:268:67:268:71 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilSet.java:277:67:277:71 | query | semmle.label | query | +| AllowListSanitizerWithJavaUtilSet.java:282:33:282:45 | args : String[] | semmle.label | args : String[] | +| AllowListSanitizerWithJavaUtilSet.java:292:67:292:71 | query | semmle.label | query | | Mongo.java:10:29:10:41 | args : String[] | semmle.label | args : String[] | | Mongo.java:17:45:17:67 | parse(...) | semmle.label | parse(...) | | Mongo.java:17:56:17:66 | stringQuery : String | semmle.label | stringQuery : String | diff --git a/java/ql/test/query-tests/security/CWE-089/semmle/examples/springjdbc.expected b/java/ql/test/query-tests/security/CWE-089/semmle/examples/springjdbc.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-089/semmle/examples/springjdbc.expected +++ b/java/ql/test/query-tests/security/CWE-089/semmle/examples/springjdbc.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-094/ApkInstallationTest.expected b/java/ql/test/query-tests/security/CWE-094/ApkInstallationTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-094/ApkInstallationTest.expected +++ b/java/ql/test/query-tests/security/CWE-094/ApkInstallationTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-094/GroovyInjectionTest.expected b/java/ql/test/query-tests/security/CWE-094/GroovyInjectionTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-094/GroovyInjectionTest.expected +++ b/java/ql/test/query-tests/security/CWE-094/GroovyInjectionTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-094/JexlInjectionTest.expected b/java/ql/test/query-tests/security/CWE-094/JexlInjectionTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-094/JexlInjectionTest.expected +++ b/java/ql/test/query-tests/security/CWE-094/JexlInjectionTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-094/MvelInjectionTest.expected b/java/ql/test/query-tests/security/CWE-094/MvelInjectionTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-094/MvelInjectionTest.expected +++ b/java/ql/test/query-tests/security/CWE-094/MvelInjectionTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-094/SpelInjectionTest.expected b/java/ql/test/query-tests/security/CWE-094/SpelInjectionTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-094/SpelInjectionTest.expected +++ b/java/ql/test/query-tests/security/CWE-094/SpelInjectionTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-094/TemplateInjectionTest.expected b/java/ql/test/query-tests/security/CWE-094/TemplateInjectionTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-094/TemplateInjectionTest.expected +++ b/java/ql/test/query-tests/security/CWE-094/TemplateInjectionTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-1204/StaticInitializationVectorTest.expected b/java/ql/test/query-tests/security/CWE-1204/StaticInitializationVectorTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-1204/StaticInitializationVectorTest.expected +++ b/java/ql/test/query-tests/security/CWE-1204/StaticInitializationVectorTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/SensitiveNotification/test.expected b/java/ql/test/query-tests/security/CWE-200/semmle/tests/SensitiveNotification/test.expected index 8ec8033d086..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/SensitiveNotification/test.expected +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/SensitiveNotification/test.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/SensitiveTextView/test.expected b/java/ql/test/query-tests/security/CWE-200/semmle/tests/SensitiveTextView/test.expected index 8ec8033d086..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/SensitiveTextView/test.expected +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/SensitiveTextView/test.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/java/ql/test/query-tests/security/CWE-273/UnsafeCertTrustTest.expected b/java/ql/test/query-tests/security/CWE-273/UnsafeCertTrustTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-273/UnsafeCertTrustTest.expected +++ b/java/ql/test/query-tests/security/CWE-273/UnsafeCertTrustTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-287/InsecureKeys/Test1/InsecureKeys.expected b/java/ql/test/query-tests/security/CWE-287/InsecureKeys/Test1/InsecureKeys.expected index 8ec8033d086..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-287/InsecureKeys/Test1/InsecureKeys.expected +++ b/java/ql/test/query-tests/security/CWE-287/InsecureKeys/Test1/InsecureKeys.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/java/ql/test/query-tests/security/CWE-287/InsecureKeys/Test2/InsecureKeys.expected b/java/ql/test/query-tests/security/CWE-287/InsecureKeys/Test2/InsecureKeys.expected index 8ec8033d086..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-287/InsecureKeys/Test2/InsecureKeys.expected +++ b/java/ql/test/query-tests/security/CWE-287/InsecureKeys/Test2/InsecureKeys.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/java/ql/test/query-tests/security/CWE-287/InsecureLocalAuth/InsecureLocalAuth.expected b/java/ql/test/query-tests/security/CWE-287/InsecureLocalAuth/InsecureLocalAuth.expected index 8ec8033d086..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-287/InsecureLocalAuth/InsecureLocalAuth.expected +++ b/java/ql/test/query-tests/security/CWE-287/InsecureLocalAuth/InsecureLocalAuth.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning/Test1/test.expected b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning/Test1/test.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning/Test1/test.expected +++ b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning/Test1/test.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning/Test2/test.expected b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning/Test2/test.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning/Test2/test.expected +++ b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning/Test2/test.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning/Test3/test.expected b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning/Test3/test.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning/Test3/test.expected +++ b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning/Test3/test.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning/Test4/test.expected b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning/Test4/test.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning/Test4/test.expected +++ b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning/Test4/test.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning/Test5/test.expected b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning/Test5/test.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning/Test5/test.expected +++ b/java/ql/test/query-tests/security/CWE-295/AndroidMissingCertificatePinning/Test5/test.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-295/ImproperWebVeiwCertificateValidation/test.expected b/java/ql/test/query-tests/security/CWE-295/ImproperWebVeiwCertificateValidation/test.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-295/ImproperWebVeiwCertificateValidation/test.expected +++ b/java/ql/test/query-tests/security/CWE-295/ImproperWebVeiwCertificateValidation/test.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-295/InsecureTrustManager/InsecureTrustManagerTest.expected b/java/ql/test/query-tests/security/CWE-295/InsecureTrustManager/InsecureTrustManagerTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-295/InsecureTrustManager/InsecureTrustManagerTest.expected +++ b/java/ql/test/query-tests/security/CWE-295/InsecureTrustManager/InsecureTrustManagerTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-297/InsecureJavaMailTest.expected b/java/ql/test/query-tests/security/CWE-297/InsecureJavaMailTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-297/InsecureJavaMailTest.expected +++ b/java/ql/test/query-tests/security/CWE-297/InsecureJavaMailTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-312/android/CleartextStorage/CleartextStorageAndroidDatabaseTest.expected b/java/ql/test/query-tests/security/CWE-312/android/CleartextStorage/CleartextStorageAndroidDatabaseTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-312/android/CleartextStorage/CleartextStorageAndroidDatabaseTest.expected +++ b/java/ql/test/query-tests/security/CWE-312/android/CleartextStorage/CleartextStorageAndroidDatabaseTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-312/android/CleartextStorage/CleartextStorageAndroidFilesystemTest.expected b/java/ql/test/query-tests/security/CWE-312/android/CleartextStorage/CleartextStorageAndroidFilesystemTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-312/android/CleartextStorage/CleartextStorageAndroidFilesystemTest.expected +++ b/java/ql/test/query-tests/security/CWE-312/android/CleartextStorage/CleartextStorageAndroidFilesystemTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-312/android/CleartextStorage/CleartextStorageSharedPrefsTest.expected b/java/ql/test/query-tests/security/CWE-312/android/CleartextStorage/CleartextStorageSharedPrefsTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-312/android/CleartextStorage/CleartextStorageSharedPrefsTest.expected +++ b/java/ql/test/query-tests/security/CWE-312/android/CleartextStorage/CleartextStorageSharedPrefsTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-326/InsufficientKeySizeTest.expected b/java/ql/test/query-tests/security/CWE-326/InsufficientKeySizeTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-326/InsufficientKeySizeTest.expected +++ b/java/ql/test/query-tests/security/CWE-326/InsufficientKeySizeTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-327/semmle/tests/BrokenCryptoAlgorithm.expected b/java/ql/test/query-tests/security/CWE-327/semmle/tests/BrokenCryptoAlgorithm.expected index 612e1c73054..94719b47739 100644 --- a/java/ql/test/query-tests/security/CWE-327/semmle/tests/BrokenCryptoAlgorithm.expected +++ b/java/ql/test/query-tests/security/CWE-327/semmle/tests/BrokenCryptoAlgorithm.expected @@ -1,14 +1,8 @@ #select | Test.java:19:20:19:50 | getInstance(...) | Test.java:19:45:19:49 | "DES" | Test.java:19:45:19:49 | "DES" | Cryptographic algorithm $@ is weak and should not be used. | Test.java:19:45:19:49 | "DES" | DES | | Test.java:42:14:42:38 | getInstance(...) | Test.java:42:33:42:37 | "RC2" | Test.java:42:33:42:37 | "RC2" | Cryptographic algorithm $@ is weak and should not be used. | Test.java:42:33:42:37 | "RC2" | RC2 | -| WeakHashing.java:21:30:21:92 | getInstance(...) | WeakHashing.java:21:86:21:90 | "MD5" : String | WeakHashing.java:21:56:21:91 | getProperty(...) | Cryptographic algorithm $@ is weak and should not be used. | WeakHashing.java:21:86:21:90 | "MD5" | MD5 | edges -| WeakHashing.java:21:86:21:90 | "MD5" : String | WeakHashing.java:21:56:21:91 | getProperty(...) | provenance | MaD:1 | -models -| 1 | Summary: java.util; Properties; true; getProperty; (String,String); ; Argument[1]; ReturnValue; value; manual | nodes | Test.java:19:45:19:49 | "DES" | semmle.label | "DES" | | Test.java:42:33:42:37 | "RC2" | semmle.label | "RC2" | -| WeakHashing.java:21:56:21:91 | getProperty(...) | semmle.label | getProperty(...) | -| WeakHashing.java:21:86:21:90 | "MD5" : String | semmle.label | "MD5" : String | subpaths diff --git a/java/ql/test/query-tests/security/CWE-327/semmle/tests/WeakHashing.java b/java/ql/test/query-tests/security/CWE-327/semmle/tests/WeakHashing.java index 6a3565fc141..c79c025a41c 100644 --- a/java/ql/test/query-tests/security/CWE-327/semmle/tests/WeakHashing.java +++ b/java/ql/test/query-tests/security/CWE-327/semmle/tests/WeakHashing.java @@ -19,11 +19,17 @@ public class WeakHashing { // BAD: Using a strong hashing algorithm but with a weak default MessageDigest bad3 = MessageDigest.getInstance(props.getProperty("hashAlg2", "MD5")); - + // GOOD: Using a strong hashing algorithm MessageDigest ok = MessageDigest.getInstance(props.getProperty("hashAlg2")); // OK: Property does not exist and default is secure MessageDigest ok2 = MessageDigest.getInstance(props.getProperty("hashAlg3", "SHA-256")); + + // GOOD: Using a strong hashing algorithm + MessageDigest ok3 = MessageDigest.getInstance("SHA3-512"); + + // GOOD: Using a strong hashing algorithm + MessageDigest ok4 = MessageDigest.getInstance("SHA384"); } -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/security/CWE-330/InsecureRandomnessTest.expected b/java/ql/test/query-tests/security/CWE-330/InsecureRandomnessTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-330/InsecureRandomnessTest.expected +++ b/java/ql/test/query-tests/security/CWE-330/InsecureRandomnessTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-347/MissingJWTSignatureCheckTest.expected b/java/ql/test/query-tests/security/CWE-347/MissingJWTSignatureCheckTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-347/MissingJWTSignatureCheckTest.expected +++ b/java/ql/test/query-tests/security/CWE-347/MissingJWTSignatureCheckTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-352/SpringCsrfProtectionTest.expected b/java/ql/test/query-tests/security/CWE-352/SpringCsrfProtectionTest.expected index a74f2c23cda..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-352/SpringCsrfProtectionTest.expected +++ b/java/ql/test/query-tests/security/CWE-352/SpringCsrfProtectionTest.expected @@ -1,2 +0,0 @@ -testFailures -failures \ No newline at end of file diff --git a/java/ql/test/query-tests/security/CWE-470/FragmentInjectionInPreferenceActivityTest.expected b/java/ql/test/query-tests/security/CWE-470/FragmentInjectionInPreferenceActivityTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-470/FragmentInjectionInPreferenceActivityTest.expected +++ b/java/ql/test/query-tests/security/CWE-470/FragmentInjectionInPreferenceActivityTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-489/debuggable-attribute/DebuggableAttributeEnabledTest.expected b/java/ql/test/query-tests/security/CWE-489/debuggable-attribute/DebuggableAttributeEnabledTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-489/debuggable-attribute/DebuggableAttributeEnabledTest.expected +++ b/java/ql/test/query-tests/security/CWE-489/debuggable-attribute/DebuggableAttributeEnabledTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected b/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected +++ b/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-522/InsecureBasicAuthTest.expected b/java/ql/test/query-tests/security/CWE-522/InsecureBasicAuthTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-522/InsecureBasicAuthTest.expected +++ b/java/ql/test/query-tests/security/CWE-522/InsecureBasicAuthTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-522/InsecureLdapAuthTest.expected b/java/ql/test/query-tests/security/CWE-522/InsecureLdapAuthTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-522/InsecureLdapAuthTest.expected +++ b/java/ql/test/query-tests/security/CWE-522/InsecureLdapAuthTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-524/SensitiveKeyboardCache.expected b/java/ql/test/query-tests/security/CWE-524/SensitiveKeyboardCache.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-524/SensitiveKeyboardCache.expected +++ b/java/ql/test/query-tests/security/CWE-524/SensitiveKeyboardCache.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-643/XPathInjectionTest.expected b/java/ql/test/query-tests/security/CWE-643/XPathInjectionTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-643/XPathInjectionTest.expected +++ b/java/ql/test/query-tests/security/CWE-643/XPathInjectionTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-730/PolynomialReDoS.expected b/java/ql/test/query-tests/security/CWE-730/PolynomialReDoS.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-730/PolynomialReDoS.expected +++ b/java/ql/test/query-tests/security/CWE-730/PolynomialReDoS.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-730/ReDoS.expected b/java/ql/test/query-tests/security/CWE-730/ReDoS.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-730/ReDoS.expected +++ b/java/ql/test/query-tests/security/CWE-730/ReDoS.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-730/RegexInjectionTest.expected b/java/ql/test/query-tests/security/CWE-730/RegexInjectionTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-730/RegexInjectionTest.expected +++ b/java/ql/test/query-tests/security/CWE-730/RegexInjectionTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-749/UnsafeAndroidAccessTest.expected b/java/ql/test/query-tests/security/CWE-749/UnsafeAndroidAccessTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-749/UnsafeAndroidAccessTest.expected +++ b/java/ql/test/query-tests/security/CWE-749/UnsafeAndroidAccessTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsApiCall.expected b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsApiCall.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsApiCall.expected +++ b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsApiCall.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsComparison.expected b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsComparison.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsComparison.expected +++ b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsComparison.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsSourceCall.expected b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsSourceCall.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsSourceCall.expected +++ b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsSourceCall.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedPasswordField.expected b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedPasswordField.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedPasswordField.expected +++ b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedPasswordField.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypassTest.expected b/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypassTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypassTest.expected +++ b/java/ql/test/query-tests/security/CWE-807/semmle/tests/ConditionalBypassTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-917/OgnlInjectionTest.expected b/java/ql/test/query-tests/security/CWE-917/OgnlInjectionTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-917/OgnlInjectionTest.expected +++ b/java/ql/test/query-tests/security/CWE-917/OgnlInjectionTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-918/RequestForgery.expected b/java/ql/test/query-tests/security/CWE-918/RequestForgery.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-918/RequestForgery.expected +++ b/java/ql/test/query-tests/security/CWE-918/RequestForgery.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-925/ImproperIntentVerification.expected b/java/ql/test/query-tests/security/CWE-925/ImproperIntentVerification.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-925/ImproperIntentVerification.expected +++ b/java/ql/test/query-tests/security/CWE-925/ImproperIntentVerification.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-926/ImplicitlyExportedAndroidComponentTest.expected b/java/ql/test/query-tests/security/CWE-926/ImplicitlyExportedAndroidComponentTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-926/ImplicitlyExportedAndroidComponentTest.expected +++ b/java/ql/test/query-tests/security/CWE-926/ImplicitlyExportedAndroidComponentTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-926/incomplete_provider_permissions/ContentProviderIncompletePermissionsTest.expected b/java/ql/test/query-tests/security/CWE-926/incomplete_provider_permissions/ContentProviderIncompletePermissionsTest.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-926/incomplete_provider_permissions/ContentProviderIncompletePermissionsTest.expected +++ b/java/ql/test/query-tests/security/CWE-926/incomplete_provider_permissions/ContentProviderIncompletePermissionsTest.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/java/ql/test/query-tests/security/CWE-927/ImplicitPendingIntentsTest.expected b/java/ql/test/query-tests/security/CWE-927/ImplicitPendingIntentsTest.expected index 8ec8033d086..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-927/ImplicitPendingIntentsTest.expected +++ b/java/ql/test/query-tests/security/CWE-927/ImplicitPendingIntentsTest.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/java/ql/test/query-tests/security/CWE-927/SensitiveResultReceiver.expected b/java/ql/test/query-tests/security/CWE-927/SensitiveResultReceiver.expected index 48de9172b36..e69de29bb2d 100644 --- a/java/ql/test/query-tests/security/CWE-927/SensitiveResultReceiver.expected +++ b/java/ql/test/query-tests/security/CWE-927/SensitiveResultReceiver.expected @@ -1,2 +0,0 @@ -failures -testFailures diff --git a/javascript/extractor/lib/typescript/package-lock.json b/javascript/extractor/lib/typescript/package-lock.json index 50a9e0a66ca..1978e396324 100644 --- a/javascript/extractor/lib/typescript/package-lock.json +++ b/javascript/extractor/lib/typescript/package-lock.json @@ -6,7 +6,7 @@ "": { "name": "typescript-parser-wrapper", "dependencies": { - "typescript": "^5.6.2" + "typescript": "^5.7.2" }, "devDependencies": { "@types/node": "18.15.3" @@ -20,9 +20,9 @@ "license": "MIT" }, "node_modules/typescript": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", - "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", diff --git a/javascript/extractor/lib/typescript/package.json b/javascript/extractor/lib/typescript/package.json index bf650ec457a..9d77f4ab740 100644 --- a/javascript/extractor/lib/typescript/package.json +++ b/javascript/extractor/lib/typescript/package.json @@ -2,7 +2,7 @@ "name": "typescript-parser-wrapper", "private": true, "dependencies": { - "typescript": "5.6.2" + "typescript": "^5.7.2" }, "scripts": { "build": "tsc --project tsconfig.json", diff --git a/javascript/ql/integration-tests/diagnostics/internal-error/src/my_failure.ts b/javascript/ql/integration-tests/diagnostics/internal-error/src/my_failure.ts index 29e78b136e8..f2a1644e18f 100644 --- a/javascript/ql/integration-tests/diagnostics/internal-error/src/my_failure.ts +++ b/javascript/ql/integration-tests/diagnostics/internal-error/src/my_failure.ts @@ -1,17 +1,3022 @@ -type Output = { - (...args: S): any; -}; - -declare function createThing( - type: K, - fn: (...args: S) => any -): Output; - -const one = createThing("one", () => ({})); - -const two = createThing("two", () => ({})); - -const three = createThing("three", (cursor: string) => null); -const four = createThing("four", (error: number) => null); - -type Events = Array; +console.log( + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 + + 1 +); diff --git a/javascript/ql/lib/change-notes/2024-11-18-ES2022-find-functions.md b/javascript/ql/lib/change-notes/2024-11-18-ES2022-find-functions.md new file mode 100644 index 00000000000..e3fe3b6aef2 --- /dev/null +++ b/javascript/ql/lib/change-notes/2024-11-18-ES2022-find-functions.md @@ -0,0 +1,5 @@ +--- +category: minorAnalysis +--- +* Added taint-steps for `Array.prototype.findLast` +* Added taint-steps for `Array.prototype.findLastIndex` diff --git a/javascript/ql/lib/change-notes/2024-11-20-ES2023-string-protytpe-toWellFormed.md b/javascript/ql/lib/change-notes/2024-11-20-ES2023-string-protytpe-toWellFormed.md new file mode 100644 index 00000000000..dda4d878760 --- /dev/null +++ b/javascript/ql/lib/change-notes/2024-11-20-ES2023-string-protytpe-toWellFormed.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added taint-steps for `String.prototype.toWellFormed`. diff --git a/javascript/ql/lib/change-notes/2024-11-20-ES2024-group-functions.md b/javascript/ql/lib/change-notes/2024-11-20-ES2024-group-functions.md new file mode 100644 index 00000000000..8511727f8e7 --- /dev/null +++ b/javascript/ql/lib/change-notes/2024-11-20-ES2024-group-functions.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added taint-steps for `Map.groupBy` and `Object.groupBy`. diff --git a/javascript/ql/lib/change-notes/2024-11-28-regexp-unknown-flags.md b/javascript/ql/lib/change-notes/2024-11-28-regexp-unknown-flags.md new file mode 100644 index 00000000000..e1db79e5c86 --- /dev/null +++ b/javascript/ql/lib/change-notes/2024-11-28-regexp-unknown-flags.md @@ -0,0 +1,6 @@ +--- +category: majorAnalysis +--- +* The `js/incomplete-sanitization` query now also checks regular expressions constructed using `new RegExp(..)`. Previously it only checked regular expression literals. +* Regular expression-based sanitisers implemented with `new RegExp(..)` are now detected in more cases. +* Regular expression related queries now account for unknown flags. diff --git a/javascript/ql/lib/semmle/javascript/Arrays.qll b/javascript/ql/lib/semmle/javascript/Arrays.qll index 7ce37130996..bec711b835a 100644 --- a/javascript/ql/lib/semmle/javascript/Arrays.qll +++ b/javascript/ql/lib/semmle/javascript/Arrays.qll @@ -384,10 +384,10 @@ private module ArrayLibraries { } /** - * Gets a call to `Array.prototype.find` or a polyfill implementing the same functionality. + * Gets a call to `Array.prototype.find` or `Array.prototype.findLast` or a polyfill implementing the same functionality. */ DataFlow::CallNode arrayFindCall(DataFlow::Node array) { - result.(DataFlow::MethodCallNode).getMethodName() = "find" and + result.(DataFlow::MethodCallNode).getMethodName() in ["find", "findLast"] and array = result.getReceiver() or result = DataFlow::moduleImport(["array.prototype.find", "array-find"]).getACall() and @@ -483,4 +483,31 @@ private module ArrayLibraries { ) } } + + /** + * Defines a data flow step that tracks the flow of data through callback functions in arrays. + */ + private class ArrayCallBackDataFlowStep extends PreCallGraphStep { + override predicate loadStep(DataFlow::Node obj, DataFlow::Node element, string prop) { + exists(DataFlow::MethodCallNode call | + call.getMethodName() = ["findLast", "find", "findLastIndex"] and + prop = arrayLikeElement() and + obj = call.getReceiver() and + element = call.getCallback(0).getParameter(0) + ) + } + } + + /** + * This step models the propagation of data from the array to the callback function's parameter. + */ + private class ArrayCallBackDataTaintStep extends TaintTracking::SharedTaintStep { + override predicate step(DataFlow::Node obj, DataFlow::Node element) { + exists(DataFlow::MethodCallNode call | + call.getMethodName() = ["findLast", "find", "findLastIndex"] and + obj = call.getReceiver() and + element = call.getCallback(0).getParameter(0) + ) + } + } } diff --git a/javascript/ql/lib/semmle/javascript/Collections.qll b/javascript/ql/lib/semmle/javascript/Collections.qll index a0e251554ff..028c3abe4b3 100644 --- a/javascript/ql/lib/semmle/javascript/Collections.qll +++ b/javascript/ql/lib/semmle/javascript/Collections.qll @@ -151,4 +151,32 @@ private module CollectionDataFlow { ) } } + + /** + * A step for a call to `groupBy` on an iterable object. + */ + private class GroupByTaintStep extends TaintTracking::SharedTaintStep { + override predicate heapStep(DataFlow::Node pred, DataFlow::Node succ) { + exists(DataFlow::MethodCallNode call | + call = DataFlow::globalVarRef(["Map", "Object"]).getAMemberCall("groupBy") and + pred = call.getArgument(0) and + (succ = call.getCallback(1).getParameter(0) or succ = call) + ) + } + } + + /** + * A step for handling data flow and taint tracking for the groupBy method on iterable objects. + * Ensures propagation of taint and data flow through the groupBy operation. + */ + private class GroupByDataFlowStep extends PreCallGraphStep { + override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { + exists(DataFlow::MethodCallNode call | + call = DataFlow::globalVarRef("Map").getAMemberCall("groupBy") and + pred = call.getArgument(0) and + succ = call and + prop = mapValueUnknownKey() + ) + } + } } diff --git a/javascript/ql/lib/semmle/javascript/StandardLibrary.qll b/javascript/ql/lib/semmle/javascript/StandardLibrary.qll index b40f10d9369..0b84e9a734b 100644 --- a/javascript/ql/lib/semmle/javascript/StandardLibrary.qll +++ b/javascript/ql/lib/semmle/javascript/StandardLibrary.qll @@ -117,6 +117,12 @@ class StringReplaceCall extends DataFlow::MethodCallNode { */ predicate isGlobal() { this.getRegExp().isGlobal() or this.getMethodName() = "replaceAll" } + /** + * Holds if this is a global replacement, that is, the first argument is a regular expression + * with the `g` flag or unknown flags, or this is a call to `.replaceAll()`. + */ + predicate maybeGlobal() { this.getRegExp().maybeGlobal() or this.getMethodName() = "replaceAll" } + /** * Holds if this call to `replace` replaces `old` with `new`. */ diff --git a/javascript/ql/lib/semmle/javascript/dataflow/Nodes.qll b/javascript/ql/lib/semmle/javascript/dataflow/Nodes.qll index d88dab4d431..8a7d2d11b91 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/Nodes.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/Nodes.qll @@ -1685,6 +1685,9 @@ class RegExpCreationNode extends DataFlow::SourceNode { /** Holds if the constructed predicate has the `g` flag. */ predicate isGlobal() { RegExp::isGlobal(this.getFlags()) } + /** Holds if the constructed predicate has the `g` flag or unknown flags. */ + predicate maybeGlobal() { RegExp::maybeGlobal(this.tryGetFlags()) } + /** Gets a data flow node referring to this regular expression. */ private DataFlow::SourceNode getAReference(DataFlow::TypeTracker t) { t.start() and diff --git a/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll index a19691e9448..6b6fc9c4b07 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll @@ -612,7 +612,7 @@ module TaintTracking { "italics", "link", "padEnd", "padStart", "repeat", "replace", "replaceAll", "slice", "small", "split", "strike", "sub", "substr", "substring", "sup", "toLocaleLowerCase", "toLocaleUpperCase", "toLowerCase", "toUpperCase", "trim", - "trimLeft", "trimRight" + "trimLeft", "trimRight", "toWellFormed" ] or // sorted, interesting, properties of Object.prototype diff --git a/javascript/ql/lib/semmle/javascript/security/IncompleteBlacklistSanitizer.qll b/javascript/ql/lib/semmle/javascript/security/IncompleteBlacklistSanitizer.qll index 6b05e2c754d..13d5033458a 100644 --- a/javascript/ql/lib/semmle/javascript/security/IncompleteBlacklistSanitizer.qll +++ b/javascript/ql/lib/semmle/javascript/security/IncompleteBlacklistSanitizer.qll @@ -74,7 +74,7 @@ private StringReplaceCall getAStringReplaceMethodCall(StringReplaceCall n) { module HtmlSanitization { private predicate fixedGlobalReplacement(StringReplaceCallSequence chain) { forall(StringReplaceCall member | member = chain.getAMember() | - member.isGlobal() and member.getArgument(0) instanceof DataFlow::RegExpLiteralNode + member.maybeGlobal() and member.getArgument(0) instanceof DataFlow::RegExpCreationNode ) } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll index c783a9c3cfc..b302a025b2c 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll @@ -36,9 +36,12 @@ module CleartextLogging { */ class MaskingReplacer extends Barrier, StringReplaceCall { MaskingReplacer() { - this.isGlobal() and + this.maybeGlobal() and exists(this.getRawReplacement().getStringValue()) and - any(RegExpDot term).getLiteral() = this.getRegExp().asExpr() + exists(DataFlow::RegExpCreationNode regexpObj | + this.(StringReplaceCall).getRegExp() = regexpObj and + regexpObj.getRoot() = any(RegExpDot term).getRootTerm() + ) } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/PrototypePollutingAssignmentQuery.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/PrototypePollutingAssignmentQuery.qll index 0ba2f26b24c..197b8594244 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/PrototypePollutingAssignmentQuery.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/PrototypePollutingAssignmentQuery.qll @@ -46,7 +46,7 @@ class Configuration extends TaintTracking::Configuration { // Replacing with "_" is likely to be exploitable not replace.getRawReplacement().getStringValue() = "_" and ( - replace.isGlobal() + replace.maybeGlobal() or // Non-global replace with a non-empty string can also prevent __proto__ by // inserting a chunk of text that doesn't fit anywhere in __proto__ diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/RegExpInjectionCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/RegExpInjectionCustomizations.qll index 291d6eebc1c..03cbd01b630 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/RegExpInjectionCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/RegExpInjectionCustomizations.qll @@ -76,7 +76,7 @@ module RegExpInjection { */ class MetacharEscapeSanitizer extends Sanitizer, StringReplaceCall { MetacharEscapeSanitizer() { - this.isGlobal() and + this.maybeGlobal() and ( RegExp::alwaysMatchesMetaCharacter(this.getRegExp().getRoot(), ["{", "[", "+"]) or diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll index c24ea7f6110..8798c926086 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll @@ -221,10 +221,10 @@ module TaintedPath { this instanceof StringReplaceCall and input = this.getReceiver() and output = this and - not exists(RegExpLiteral literal, RegExpTerm term | - this.(StringReplaceCall).getRegExp().asExpr() = literal and - this.(StringReplaceCall).isGlobal() and - literal.getRoot() = term + not exists(DataFlow::RegExpCreationNode regexp, RegExpTerm term | + this.(StringReplaceCall).getRegExp() = regexp and + this.(StringReplaceCall).maybeGlobal() and + regexp.getRoot() = term | term.getAMatchedString() = "/" or term.getAMatchedString() = "." or @@ -305,9 +305,9 @@ module TaintedPath { input = this.getReceiver() and output = this and this.isGlobal() and - exists(RegExpLiteral literal, RegExpTerm term | - this.getRegExp().asExpr() = literal and - literal.getRoot() = term and + exists(DataFlow::RegExpCreationNode regexp, RegExpTerm term | + this.getRegExp() = regexp and + regexp.getRoot() = term and not term.getAMatchedString() = "/" | term.getAMatchedString() = "." or diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll index 77625874df9..8e753a5ef63 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll @@ -245,7 +245,7 @@ module UnsafeShellCommandConstruction { class ReplaceQuotesSanitizer extends Sanitizer, StringReplaceCall { ReplaceQuotesSanitizer() { this.getAReplacedString() = "'" and - this.isGlobal() and + this.maybeGlobal() and this.getRawReplacement().mayHaveStringValue(["'\\''", ""]) } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/Xss.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/Xss.qll index fc2db8e9f87..a0def5b7b74 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/Xss.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/Xss.qll @@ -36,7 +36,7 @@ module Shared { */ class MetacharEscapeSanitizer extends Sanitizer, StringReplaceCall { MetacharEscapeSanitizer() { - this.isGlobal() and + this.maybeGlobal() and ( RegExp::alwaysMatchesMetaCharacter(this.getRegExp().getRoot(), ["<", "'", "\""]) or diff --git a/javascript/ql/src/Security/CWE-116/IncompleteSanitization.ql b/javascript/ql/src/Security/CWE-116/IncompleteSanitization.ql index dc92b24abef..7d0dc71a2a8 100644 --- a/javascript/ql/src/Security/CWE-116/IncompleteSanitization.ql +++ b/javascript/ql/src/Security/CWE-116/IncompleteSanitization.ql @@ -23,7 +23,7 @@ string metachar() { result = "'\"\\&<>\n\r\t*|{}[]%$".charAt(_) } /** Gets a string matched by `e` in a `replace` call. */ string getAMatchedString(DataFlow::Node e) { - result = e.(DataFlow::RegExpLiteralNode).getRoot().getAMatchedString() + result = e.(DataFlow::RegExpCreationNode).getRoot().getAMatchedString() or result = e.getStringValue() } @@ -52,8 +52,8 @@ predicate isSimpleAlt(RegExpAlt t) { forall(RegExpTerm ch | ch = t.getAChild() | * Holds if `mce` is of the form `x.replace(re, new)`, where `re` is a global * regular expression and `new` prefixes the matched string with a backslash. */ -predicate isBackslashEscape(StringReplaceCall mce, DataFlow::RegExpLiteralNode re) { - mce.isGlobal() and +predicate isBackslashEscape(StringReplaceCall mce, DataFlow::RegExpCreationNode re) { + mce.maybeGlobal() and re = mce.getRegExp() and ( // replacement with `\$&`, `\$1` or similar @@ -72,7 +72,7 @@ predicate allBackslashesEscaped(DataFlow::Node nd) { nd instanceof JsonStringifyCall or // check whether `nd` itself escapes backslashes - exists(DataFlow::RegExpLiteralNode rel | isBackslashEscape(nd, rel) | + exists(DataFlow::RegExpCreationNode rel | isBackslashEscape(nd, rel) | // if it's a complex regexp, we conservatively assume that it probably escapes backslashes not isSimple(rel.getRoot()) or getAMatchedString(rel) = "\\" @@ -143,12 +143,21 @@ predicate whitelistedRemoval(StringReplaceCall repl) { ) } +/** + * Gets a nice string representation of the pattern or value of the node. + */ +string getPatternOrValueString(DataFlow::Node node) { + if node instanceof DataFlow::RegExpConstructorInvokeNode + then result = "/" + node.(DataFlow::RegExpConstructorInvokeNode).getRoot() + "/" + else result = node.toString() +} + from StringReplaceCall repl, DataFlow::Node old, string msg where (old = repl.getArgument(0) or old = repl.getRegExp()) and ( - not repl.isGlobal() and - msg = "This replaces only the first occurrence of " + old + "." and + not repl.maybeGlobal() and + msg = "This replaces only the first occurrence of " + getPatternOrValueString(old) + "." and // only flag if this is likely to be a sanitizer or URL encoder or decoder exists(string m | m = getAMatchedString(old) | // sanitizer diff --git a/javascript/ql/src/Security/CWE-178/CaseSensitiveMiddlewarePath.ql b/javascript/ql/src/Security/CWE-178/CaseSensitiveMiddlewarePath.ql index d16f72d4172..997ee8971a5 100644 --- a/javascript/ql/src/Security/CWE-178/CaseSensitiveMiddlewarePath.ql +++ b/javascript/ql/src/Security/CWE-178/CaseSensitiveMiddlewarePath.ql @@ -65,8 +65,8 @@ predicate isCaseSensitiveMiddleware( arg = call.getArgument(0) and regexp.getAReference().flowsTo(arg) and exists(string flags | - flags = regexp.getFlags() and - not RegExp::isIgnoreCase(flags) + flags = regexp.tryGetFlags() and + not RegExp::maybeIgnoreCase(flags) ) ) } diff --git a/javascript/ql/src/Statements/UseOfReturnlessFunction.ql b/javascript/ql/src/Statements/UseOfReturnlessFunction.ql index ea5f2fb9755..818f0d922d4 100644 --- a/javascript/ql/src/Statements/UseOfReturnlessFunction.ql +++ b/javascript/ql/src/Statements/UseOfReturnlessFunction.ql @@ -114,7 +114,7 @@ predicate hasNonVoidCallbackMethod(string name) { name = [ "every", "filter", "find", "findIndex", "flatMap", "map", "reduce", "reduceRight", "some", - "sort" + "sort", "findLastIndex", "findLast" ] } diff --git a/javascript/ql/test/library-tests/Arrays/DataFlow.expected b/javascript/ql/test/library-tests/Arrays/DataFlow.expected index 4332f14c45e..07fabfb7270 100644 --- a/javascript/ql/test/library-tests/Arrays/DataFlow.expected +++ b/javascript/ql/test/library-tests/Arrays/DataFlow.expected @@ -14,6 +14,7 @@ | arrays.js:2:16:2:23 | "source" | arrays.js:90:10:90:10 | x | | arrays.js:2:16:2:23 | "source" | arrays.js:93:8:93:17 | arr.at(-1) | | arrays.js:2:16:2:23 | "source" | arrays.js:109:8:109:24 | arr8_spread.pop() | +| arrays.js:2:16:2:23 | "source" | arrays.js:111:8:111:33 | arr.fin ... llback) | | arrays.js:18:22:18:29 | "source" | arrays.js:18:50:18:50 | e | | arrays.js:22:15:22:22 | "source" | arrays.js:23:8:23:17 | arr2.pop() | | arrays.js:25:15:25:22 | "source" | arrays.js:26:8:26:17 | arr3.pop() | @@ -25,3 +26,8 @@ | arrays.js:53:4:53:11 | "source" | arrays.js:54:10:54:18 | ary.pop() | | arrays.js:99:31:99:38 | "source" | arrays.js:100:8:100:17 | arr8.pop() | | arrays.js:103:55:103:62 | "source" | arrays.js:105:8:105:25 | arr8_variant.pop() | +| arrays.js:114:19:114:26 | "source" | arrays.js:115:50:115:53 | item | +| arrays.js:114:19:114:26 | "source" | arrays.js:116:10:116:16 | element | +| arrays.js:120:19:120:26 | "source" | arrays.js:121:46:121:49 | item | +| arrays.js:120:19:120:26 | "source" | arrays.js:122:10:122:16 | element | +| arrays.js:126:19:126:26 | "source" | arrays.js:127:55:127:58 | item | diff --git a/javascript/ql/test/library-tests/Arrays/DataFlow.ql b/javascript/ql/test/library-tests/Arrays/DataFlow.ql index 80c9f068a10..5c5f4a0d10e 100644 --- a/javascript/ql/test/library-tests/Arrays/DataFlow.ql +++ b/javascript/ql/test/library-tests/Arrays/DataFlow.ql @@ -3,7 +3,10 @@ import javascript class ArrayFlowConfig extends DataFlow::Configuration { ArrayFlowConfig() { this = "ArrayFlowConfig" } - override predicate isSource(DataFlow::Node source) { source.asExpr().getStringValue() = "source" } + override predicate isSource(DataFlow::Node source) { + source.asExpr().getStringValue() = "source" or + source.(DataFlow::CallNode).getCalleeName() = "source" + } override predicate isSink(DataFlow::Node sink) { sink = any(DataFlow::CallNode call | call.getCalleeName() = "sink").getAnArgument() diff --git a/javascript/ql/test/library-tests/Arrays/TaintFlow.expected b/javascript/ql/test/library-tests/Arrays/TaintFlow.expected index a531715bfb6..246a52e803b 100644 --- a/javascript/ql/test/library-tests/Arrays/TaintFlow.expected +++ b/javascript/ql/test/library-tests/Arrays/TaintFlow.expected @@ -15,6 +15,7 @@ | arrays.js:2:16:2:23 | "source" | arrays.js:90:10:90:10 | x | | arrays.js:2:16:2:23 | "source" | arrays.js:93:8:93:17 | arr.at(-1) | | arrays.js:2:16:2:23 | "source" | arrays.js:109:8:109:24 | arr8_spread.pop() | +| arrays.js:2:16:2:23 | "source" | arrays.js:111:8:111:33 | arr.fin ... llback) | | arrays.js:18:22:18:29 | "source" | arrays.js:18:50:18:50 | e | | arrays.js:22:15:22:22 | "source" | arrays.js:23:8:23:17 | arr2.pop() | | arrays.js:25:15:25:22 | "source" | arrays.js:26:8:26:17 | arr3.pop() | @@ -29,3 +30,13 @@ | arrays.js:96:9:96:16 | "source" | arrays.js:96:8:96:36 | ["sourc ... => !!x) | | arrays.js:99:31:99:38 | "source" | arrays.js:100:8:100:17 | arr8.pop() | | arrays.js:103:55:103:62 | "source" | arrays.js:105:8:105:25 | arr8_variant.pop() | +| arrays.js:114:19:114:26 | "source" | arrays.js:115:50:115:53 | item | +| arrays.js:114:19:114:26 | "source" | arrays.js:116:10:116:16 | element | +| arrays.js:120:19:120:26 | "source" | arrays.js:121:46:121:49 | item | +| arrays.js:120:19:120:26 | "source" | arrays.js:122:10:122:16 | element | +| arrays.js:126:19:126:26 | "source" | arrays.js:127:55:127:58 | item | +| arrays.js:131:17:131:24 | source() | arrays.js:132:46:132:49 | item | +| arrays.js:131:17:131:24 | source() | arrays.js:133:10:133:17 | element1 | +| arrays.js:137:17:137:24 | source() | arrays.js:138:50:138:53 | item | +| arrays.js:137:17:137:24 | source() | arrays.js:139:10:139:17 | element1 | +| arrays.js:143:17:143:24 | source() | arrays.js:144:55:144:58 | item | diff --git a/javascript/ql/test/library-tests/Arrays/TaintFlow.ql b/javascript/ql/test/library-tests/Arrays/TaintFlow.ql index cee2f294a34..d8f18759162 100644 --- a/javascript/ql/test/library-tests/Arrays/TaintFlow.ql +++ b/javascript/ql/test/library-tests/Arrays/TaintFlow.ql @@ -3,7 +3,10 @@ import javascript class ArrayTaintFlowConfig extends TaintTracking::Configuration { ArrayTaintFlowConfig() { this = "ArrayTaintFlowConfig" } - override predicate isSource(DataFlow::Node source) { source.asExpr().getStringValue() = "source" } + override predicate isSource(DataFlow::Node source) { + source.asExpr().getStringValue() = "source" or + source.(DataFlow::CallNode).getCalleeName() = "source" + } override predicate isSink(DataFlow::Node sink) { sink = any(DataFlow::CallNode call | call.getCalleeName() = "sink").getAnArgument() diff --git a/javascript/ql/test/library-tests/Arrays/arrays.js b/javascript/ql/test/library-tests/Arrays/arrays.js index 579741fa3aa..deedf29f6f6 100644 --- a/javascript/ql/test/library-tests/Arrays/arrays.js +++ b/javascript/ql/test/library-tests/Arrays/arrays.js @@ -107,4 +107,41 @@ var arr8_spread = []; arr8_spread = arr8_spread.toSpliced(0, 0, ...arr); sink(arr8_spread.pop()); // NOT OK + + sink(arr.findLast(someCallback)); // NOT OK + + { // Test for findLast function + const list = ["source"]; + const element = list.findLast((item) => sink(item)); // NOT OK + sink(element); // NOT OK + } + + { // Test for find function + const list = ["source"]; + const element = list.find((item) => sink(item)); // NOT OK + sink(element); // NOT OK + } + + { // Test for findLastIndex function + const list = ["source"]; + const element = list.findLastIndex((item) => sink(item)); // NOT OK + sink(element); // OK + } + { + const arr = source(); + const element1 = arr.find((item) => sink(item)); // NOT OK + sink(element1); // NOT OK + } + + { + const arr = source(); + const element1 = arr.findLast((item) => sink(item)); // NOT OK + sink(element1); // NOT OK + } + + { + const arr = source(); + const element1 = arr.findLastIndex((item) => sink(item)); // NOT OK + sink(element1); // OK + } }); diff --git a/javascript/ql/test/library-tests/Arrays/printAst.expected b/javascript/ql/test/library-tests/Arrays/printAst.expected index a7333b29485..a825b12f3fb 100644 --- a/javascript/ql/test/library-tests/Arrays/printAst.expected +++ b/javascript/ql/test/library-tests/Arrays/printAst.expected @@ -1,9 +1,9 @@ nodes -| arrays.js:1:1:110:2 | [ParExpr] (functi ... T OK }) | semmle.label | [ParExpr] (functi ... T OK }) | -| arrays.js:1:1:110:3 | [ExprStmt] (functi ... OK }); | semmle.label | [ExprStmt] (functi ... OK }); | -| arrays.js:1:1:110:3 | [ExprStmt] (functi ... OK }); | semmle.order | 1 | -| arrays.js:1:2:110:1 | [FunctionExpr] functio ... OT OK } | semmle.label | [FunctionExpr] functio ... OT OK } | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | semmle.label | [BlockStmt] { let ... OT OK } | +| arrays.js:1:1:147:2 | [ParExpr] (functi ... } }) | semmle.label | [ParExpr] (functi ... } }) | +| arrays.js:1:1:147:3 | [ExprStmt] (functi ... } }); | semmle.label | [ExprStmt] (functi ... } }); | +| arrays.js:1:1:147:3 | [ExprStmt] (functi ... } }); | semmle.order | 1 | +| arrays.js:1:2:147:1 | [FunctionExpr] functio ... K } } | semmle.label | [FunctionExpr] functio ... K } } | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | semmle.label | [BlockStmt] { let ... K } } | | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.label | [DeclStmt] let source = ... | | arrays.js:2:7:2:12 | [VarDecl] source | semmle.label | [VarDecl] source | | arrays.js:2:7:2:23 | [VariableDeclarator] source = "source" | semmle.label | [VariableDeclarator] source = "source" | @@ -487,6 +487,146 @@ nodes | arrays.js:109:8:109:22 | [DotExpr] arr8_spread.pop | semmle.label | [DotExpr] arr8_spread.pop | | arrays.js:109:8:109:24 | [MethodCallExpr] arr8_spread.pop() | semmle.label | [MethodCallExpr] arr8_spread.pop() | | arrays.js:109:20:109:22 | [Label] pop | semmle.label | [Label] pop | +| arrays.js:111:3:111:6 | [VarRef] sink | semmle.label | [VarRef] sink | +| arrays.js:111:3:111:34 | [CallExpr] sink(ar ... lback)) | semmle.label | [CallExpr] sink(ar ... lback)) | +| arrays.js:111:3:111:35 | [ExprStmt] sink(ar ... back)); | semmle.label | [ExprStmt] sink(ar ... back)); | +| arrays.js:111:8:111:10 | [VarRef] arr | semmle.label | [VarRef] arr | +| arrays.js:111:8:111:19 | [DotExpr] arr.findLast | semmle.label | [DotExpr] arr.findLast | +| arrays.js:111:8:111:33 | [MethodCallExpr] arr.fin ... llback) | semmle.label | [MethodCallExpr] arr.fin ... llback) | +| arrays.js:111:12:111:19 | [Label] findLast | semmle.label | [Label] findLast | +| arrays.js:111:21:111:32 | [VarRef] someCallback | semmle.label | [VarRef] someCallback | +| arrays.js:113:3:117:3 | [BlockStmt] { // T ... OK } | semmle.label | [BlockStmt] { // T ... OK } | +| arrays.js:114:5:114:28 | [DeclStmt] const list = ... | semmle.label | [DeclStmt] const list = ... | +| arrays.js:114:11:114:14 | [VarDecl] list | semmle.label | [VarDecl] list | +| arrays.js:114:11:114:27 | [VariableDeclarator] list = ["source"] | semmle.label | [VariableDeclarator] list = ["source"] | +| arrays.js:114:18:114:27 | [ArrayExpr] ["source"] | semmle.label | [ArrayExpr] ["source"] | +| arrays.js:114:19:114:26 | [Literal] "source" | semmle.label | [Literal] "source" | +| arrays.js:115:5:115:56 | [DeclStmt] const element = ... | semmle.label | [DeclStmt] const element = ... | +| arrays.js:115:11:115:17 | [VarDecl] element | semmle.label | [VarDecl] element | +| arrays.js:115:11:115:55 | [VariableDeclarator] element ... (item)) | semmle.label | [VariableDeclarator] element ... (item)) | +| arrays.js:115:21:115:24 | [VarRef] list | semmle.label | [VarRef] list | +| arrays.js:115:21:115:33 | [DotExpr] list.findLast | semmle.label | [DotExpr] list.findLast | +| arrays.js:115:21:115:55 | [MethodCallExpr] list.fi ... (item)) | semmle.label | [MethodCallExpr] list.fi ... (item)) | +| arrays.js:115:26:115:33 | [Label] findLast | semmle.label | [Label] findLast | +| arrays.js:115:35:115:54 | [ArrowFunctionExpr] (item) => sink(item) | semmle.label | [ArrowFunctionExpr] (item) => sink(item) | +| arrays.js:115:36:115:39 | [SimpleParameter] item | semmle.label | [SimpleParameter] item | +| arrays.js:115:45:115:48 | [VarRef] sink | semmle.label | [VarRef] sink | +| arrays.js:115:45:115:54 | [CallExpr] sink(item) | semmle.label | [CallExpr] sink(item) | +| arrays.js:115:50:115:53 | [VarRef] item | semmle.label | [VarRef] item | +| arrays.js:116:5:116:8 | [VarRef] sink | semmle.label | [VarRef] sink | +| arrays.js:116:5:116:17 | [CallExpr] sink(element) | semmle.label | [CallExpr] sink(element) | +| arrays.js:116:5:116:18 | [ExprStmt] sink(element); | semmle.label | [ExprStmt] sink(element); | +| arrays.js:116:10:116:16 | [VarRef] element | semmle.label | [VarRef] element | +| arrays.js:119:3:123:3 | [BlockStmt] { // T ... OK } | semmle.label | [BlockStmt] { // T ... OK } | +| arrays.js:120:5:120:28 | [DeclStmt] const list = ... | semmle.label | [DeclStmt] const list = ... | +| arrays.js:120:11:120:14 | [VarDecl] list | semmle.label | [VarDecl] list | +| arrays.js:120:11:120:27 | [VariableDeclarator] list = ["source"] | semmle.label | [VariableDeclarator] list = ["source"] | +| arrays.js:120:18:120:27 | [ArrayExpr] ["source"] | semmle.label | [ArrayExpr] ["source"] | +| arrays.js:120:19:120:26 | [Literal] "source" | semmle.label | [Literal] "source" | +| arrays.js:121:5:121:52 | [DeclStmt] const element = ... | semmle.label | [DeclStmt] const element = ... | +| arrays.js:121:11:121:17 | [VarDecl] element | semmle.label | [VarDecl] element | +| arrays.js:121:11:121:51 | [VariableDeclarator] element ... (item)) | semmle.label | [VariableDeclarator] element ... (item)) | +| arrays.js:121:21:121:24 | [VarRef] list | semmle.label | [VarRef] list | +| arrays.js:121:21:121:29 | [DotExpr] list.find | semmle.label | [DotExpr] list.find | +| arrays.js:121:21:121:51 | [MethodCallExpr] list.fi ... (item)) | semmle.label | [MethodCallExpr] list.fi ... (item)) | +| arrays.js:121:26:121:29 | [Label] find | semmle.label | [Label] find | +| arrays.js:121:31:121:50 | [ArrowFunctionExpr] (item) => sink(item) | semmle.label | [ArrowFunctionExpr] (item) => sink(item) | +| arrays.js:121:32:121:35 | [SimpleParameter] item | semmle.label | [SimpleParameter] item | +| arrays.js:121:41:121:44 | [VarRef] sink | semmle.label | [VarRef] sink | +| arrays.js:121:41:121:50 | [CallExpr] sink(item) | semmle.label | [CallExpr] sink(item) | +| arrays.js:121:46:121:49 | [VarRef] item | semmle.label | [VarRef] item | +| arrays.js:122:5:122:8 | [VarRef] sink | semmle.label | [VarRef] sink | +| arrays.js:122:5:122:17 | [CallExpr] sink(element) | semmle.label | [CallExpr] sink(element) | +| arrays.js:122:5:122:18 | [ExprStmt] sink(element); | semmle.label | [ExprStmt] sink(element); | +| arrays.js:122:10:122:16 | [VarRef] element | semmle.label | [VarRef] element | +| arrays.js:125:3:129:3 | [BlockStmt] { // T ... OK } | semmle.label | [BlockStmt] { // T ... OK } | +| arrays.js:126:5:126:28 | [DeclStmt] const list = ... | semmle.label | [DeclStmt] const list = ... | +| arrays.js:126:11:126:14 | [VarDecl] list | semmle.label | [VarDecl] list | +| arrays.js:126:11:126:27 | [VariableDeclarator] list = ["source"] | semmle.label | [VariableDeclarator] list = ["source"] | +| arrays.js:126:18:126:27 | [ArrayExpr] ["source"] | semmle.label | [ArrayExpr] ["source"] | +| arrays.js:126:19:126:26 | [Literal] "source" | semmle.label | [Literal] "source" | +| arrays.js:127:5:127:61 | [DeclStmt] const element = ... | semmle.label | [DeclStmt] const element = ... | +| arrays.js:127:11:127:17 | [VarDecl] element | semmle.label | [VarDecl] element | +| arrays.js:127:11:127:60 | [VariableDeclarator] element ... (item)) | semmle.label | [VariableDeclarator] element ... (item)) | +| arrays.js:127:21:127:24 | [VarRef] list | semmle.label | [VarRef] list | +| arrays.js:127:21:127:38 | [DotExpr] list.findLastIndex | semmle.label | [DotExpr] list.findLastIndex | +| arrays.js:127:21:127:60 | [MethodCallExpr] list.fi ... (item)) | semmle.label | [MethodCallExpr] list.fi ... (item)) | +| arrays.js:127:26:127:38 | [Label] findLastIndex | semmle.label | [Label] findLastIndex | +| arrays.js:127:40:127:59 | [ArrowFunctionExpr] (item) => sink(item) | semmle.label | [ArrowFunctionExpr] (item) => sink(item) | +| arrays.js:127:41:127:44 | [SimpleParameter] item | semmle.label | [SimpleParameter] item | +| arrays.js:127:50:127:53 | [VarRef] sink | semmle.label | [VarRef] sink | +| arrays.js:127:50:127:59 | [CallExpr] sink(item) | semmle.label | [CallExpr] sink(item) | +| arrays.js:127:55:127:58 | [VarRef] item | semmle.label | [VarRef] item | +| arrays.js:128:5:128:8 | [VarRef] sink | semmle.label | [VarRef] sink | +| arrays.js:128:5:128:17 | [CallExpr] sink(element) | semmle.label | [CallExpr] sink(element) | +| arrays.js:128:5:128:18 | [ExprStmt] sink(element); | semmle.label | [ExprStmt] sink(element); | +| arrays.js:128:10:128:16 | [VarRef] element | semmle.label | [VarRef] element | +| arrays.js:130:3:134:3 | [BlockStmt] { c ... OK } | semmle.label | [BlockStmt] { c ... OK } | +| arrays.js:131:5:131:25 | [DeclStmt] const arr = ... | semmle.label | [DeclStmt] const arr = ... | +| arrays.js:131:11:131:13 | [VarDecl] arr | semmle.label | [VarDecl] arr | +| arrays.js:131:11:131:24 | [VariableDeclarator] arr = source() | semmle.label | [VariableDeclarator] arr = source() | +| arrays.js:131:17:131:22 | [VarRef] source | semmle.label | [VarRef] source | +| arrays.js:131:17:131:24 | [CallExpr] source() | semmle.label | [CallExpr] source() | +| arrays.js:132:5:132:52 | [DeclStmt] const element1 = ... | semmle.label | [DeclStmt] const element1 = ... | +| arrays.js:132:11:132:18 | [VarDecl] element1 | semmle.label | [VarDecl] element1 | +| arrays.js:132:11:132:51 | [VariableDeclarator] element ... (item)) | semmle.label | [VariableDeclarator] element ... (item)) | +| arrays.js:132:22:132:24 | [VarRef] arr | semmle.label | [VarRef] arr | +| arrays.js:132:22:132:29 | [DotExpr] arr.find | semmle.label | [DotExpr] arr.find | +| arrays.js:132:22:132:51 | [MethodCallExpr] arr.fin ... (item)) | semmle.label | [MethodCallExpr] arr.fin ... (item)) | +| arrays.js:132:26:132:29 | [Label] find | semmle.label | [Label] find | +| arrays.js:132:31:132:50 | [ArrowFunctionExpr] (item) => sink(item) | semmle.label | [ArrowFunctionExpr] (item) => sink(item) | +| arrays.js:132:32:132:35 | [SimpleParameter] item | semmle.label | [SimpleParameter] item | +| arrays.js:132:41:132:44 | [VarRef] sink | semmle.label | [VarRef] sink | +| arrays.js:132:41:132:50 | [CallExpr] sink(item) | semmle.label | [CallExpr] sink(item) | +| arrays.js:132:46:132:49 | [VarRef] item | semmle.label | [VarRef] item | +| arrays.js:133:5:133:8 | [VarRef] sink | semmle.label | [VarRef] sink | +| arrays.js:133:5:133:18 | [CallExpr] sink(element1) | semmle.label | [CallExpr] sink(element1) | +| arrays.js:133:5:133:19 | [ExprStmt] sink(element1); | semmle.label | [ExprStmt] sink(element1); | +| arrays.js:133:10:133:17 | [VarRef] element1 | semmle.label | [VarRef] element1 | +| arrays.js:136:3:140:3 | [BlockStmt] { c ... OK } | semmle.label | [BlockStmt] { c ... OK } | +| arrays.js:137:5:137:25 | [DeclStmt] const arr = ... | semmle.label | [DeclStmt] const arr = ... | +| arrays.js:137:11:137:13 | [VarDecl] arr | semmle.label | [VarDecl] arr | +| arrays.js:137:11:137:24 | [VariableDeclarator] arr = source() | semmle.label | [VariableDeclarator] arr = source() | +| arrays.js:137:17:137:22 | [VarRef] source | semmle.label | [VarRef] source | +| arrays.js:137:17:137:24 | [CallExpr] source() | semmle.label | [CallExpr] source() | +| arrays.js:138:5:138:56 | [DeclStmt] const element1 = ... | semmle.label | [DeclStmt] const element1 = ... | +| arrays.js:138:11:138:18 | [VarDecl] element1 | semmle.label | [VarDecl] element1 | +| arrays.js:138:11:138:55 | [VariableDeclarator] element ... (item)) | semmle.label | [VariableDeclarator] element ... (item)) | +| arrays.js:138:22:138:24 | [VarRef] arr | semmle.label | [VarRef] arr | +| arrays.js:138:22:138:33 | [DotExpr] arr.findLast | semmle.label | [DotExpr] arr.findLast | +| arrays.js:138:22:138:55 | [MethodCallExpr] arr.fin ... (item)) | semmle.label | [MethodCallExpr] arr.fin ... (item)) | +| arrays.js:138:26:138:33 | [Label] findLast | semmle.label | [Label] findLast | +| arrays.js:138:35:138:54 | [ArrowFunctionExpr] (item) => sink(item) | semmle.label | [ArrowFunctionExpr] (item) => sink(item) | +| arrays.js:138:36:138:39 | [SimpleParameter] item | semmle.label | [SimpleParameter] item | +| arrays.js:138:45:138:48 | [VarRef] sink | semmle.label | [VarRef] sink | +| arrays.js:138:45:138:54 | [CallExpr] sink(item) | semmle.label | [CallExpr] sink(item) | +| arrays.js:138:50:138:53 | [VarRef] item | semmle.label | [VarRef] item | +| arrays.js:139:5:139:8 | [VarRef] sink | semmle.label | [VarRef] sink | +| arrays.js:139:5:139:18 | [CallExpr] sink(element1) | semmle.label | [CallExpr] sink(element1) | +| arrays.js:139:5:139:19 | [ExprStmt] sink(element1); | semmle.label | [ExprStmt] sink(element1); | +| arrays.js:139:10:139:17 | [VarRef] element1 | semmle.label | [VarRef] element1 | +| arrays.js:142:3:146:3 | [BlockStmt] { c ... OK } | semmle.label | [BlockStmt] { c ... OK } | +| arrays.js:143:5:143:25 | [DeclStmt] const arr = ... | semmle.label | [DeclStmt] const arr = ... | +| arrays.js:143:11:143:13 | [VarDecl] arr | semmle.label | [VarDecl] arr | +| arrays.js:143:11:143:24 | [VariableDeclarator] arr = source() | semmle.label | [VariableDeclarator] arr = source() | +| arrays.js:143:17:143:22 | [VarRef] source | semmle.label | [VarRef] source | +| arrays.js:143:17:143:24 | [CallExpr] source() | semmle.label | [CallExpr] source() | +| arrays.js:144:5:144:61 | [DeclStmt] const element1 = ... | semmle.label | [DeclStmt] const element1 = ... | +| arrays.js:144:11:144:18 | [VarDecl] element1 | semmle.label | [VarDecl] element1 | +| arrays.js:144:11:144:60 | [VariableDeclarator] element ... (item)) | semmle.label | [VariableDeclarator] element ... (item)) | +| arrays.js:144:22:144:24 | [VarRef] arr | semmle.label | [VarRef] arr | +| arrays.js:144:22:144:38 | [DotExpr] arr.findLastIndex | semmle.label | [DotExpr] arr.findLastIndex | +| arrays.js:144:22:144:60 | [MethodCallExpr] arr.fin ... (item)) | semmle.label | [MethodCallExpr] arr.fin ... (item)) | +| arrays.js:144:26:144:38 | [Label] findLastIndex | semmle.label | [Label] findLastIndex | +| arrays.js:144:40:144:59 | [ArrowFunctionExpr] (item) => sink(item) | semmle.label | [ArrowFunctionExpr] (item) => sink(item) | +| arrays.js:144:41:144:44 | [SimpleParameter] item | semmle.label | [SimpleParameter] item | +| arrays.js:144:50:144:53 | [VarRef] sink | semmle.label | [VarRef] sink | +| arrays.js:144:50:144:59 | [CallExpr] sink(item) | semmle.label | [CallExpr] sink(item) | +| arrays.js:144:55:144:58 | [VarRef] item | semmle.label | [VarRef] item | +| arrays.js:145:5:145:8 | [VarRef] sink | semmle.label | [VarRef] sink | +| arrays.js:145:5:145:18 | [CallExpr] sink(element1) | semmle.label | [CallExpr] sink(element1) | +| arrays.js:145:5:145:19 | [ExprStmt] sink(element1); | semmle.label | [ExprStmt] sink(element1); | +| arrays.js:145:10:145:17 | [VarRef] element1 | semmle.label | [VarRef] element1 | | file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | | file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | | file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | @@ -544,6 +684,32 @@ nodes | file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | | file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | | file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | +| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | +| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | +| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | +| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | +| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | | file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | | file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | | file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | @@ -552,128 +718,142 @@ nodes | file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | | file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | edges -| arrays.js:1:1:110:2 | [ParExpr] (functi ... T OK }) | arrays.js:1:2:110:1 | [FunctionExpr] functio ... OT OK } | semmle.label | 1 | -| arrays.js:1:1:110:2 | [ParExpr] (functi ... T OK }) | arrays.js:1:2:110:1 | [FunctionExpr] functio ... OT OK } | semmle.order | 1 | -| arrays.js:1:1:110:3 | [ExprStmt] (functi ... OK }); | arrays.js:1:1:110:2 | [ParExpr] (functi ... T OK }) | semmle.label | 1 | -| arrays.js:1:1:110:3 | [ExprStmt] (functi ... OK }); | arrays.js:1:1:110:2 | [ParExpr] (functi ... T OK }) | semmle.order | 1 | -| arrays.js:1:2:110:1 | [FunctionExpr] functio ... OT OK } | arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | semmle.label | 5 | -| arrays.js:1:2:110:1 | [FunctionExpr] functio ... OT OK } | arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | semmle.order | 5 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.label | 1 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.order | 1 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:4:3:4:28 | [DeclStmt] var obj = ... | semmle.label | 2 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:4:3:4:28 | [DeclStmt] var obj = ... | semmle.order | 2 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:5:3:5:16 | [ExprStmt] sink(obj.foo); | semmle.label | 3 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:5:3:5:16 | [ExprStmt] sink(obj.foo); | semmle.order | 3 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:7:3:7:15 | [DeclStmt] var arr = ... | semmle.label | 4 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:7:3:7:15 | [DeclStmt] var arr = ... | semmle.order | 4 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:8:3:8:19 | [ExprStmt] arr.push(source); | semmle.label | 5 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:8:3:8:19 | [ExprStmt] arr.push(source); | semmle.order | 5 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:10:3:12:3 | [ForStmt] for (va ... OK } | semmle.label | 6 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:10:3:12:3 | [ForStmt] for (va ... OK } | semmle.order | 6 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:15:3:15:30 | [ExprStmt] arr.for ... nk(e)); | semmle.label | 7 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:15:3:15:30 | [ExprStmt] arr.for ... nk(e)); | semmle.order | 7 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:16:3:16:26 | [ExprStmt] arr.map ... nk(e)); | semmle.label | 8 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:16:3:16:26 | [ExprStmt] arr.map ... nk(e)); | semmle.order | 8 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:18:3:18:53 | [ExprStmt] [1, 2, ... nk(e)); | semmle.label | 9 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:18:3:18:53 | [ExprStmt] [1, 2, ... nk(e)); | semmle.order | 9 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:20:3:20:18 | [ExprStmt] sink(arr.pop()); | semmle.label | 10 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:20:3:20:18 | [ExprStmt] sink(arr.pop()); | semmle.order | 10 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:22:3:22:24 | [DeclStmt] var arr2 = ... | semmle.label | 11 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:22:3:22:24 | [DeclStmt] var arr2 = ... | semmle.order | 11 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:23:3:23:19 | [ExprStmt] sink(arr2.pop()); | semmle.label | 12 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:23:3:23:19 | [ExprStmt] sink(arr2.pop()); | semmle.order | 12 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:25:3:25:24 | [DeclStmt] var arr3 = ... | semmle.label | 13 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:25:3:25:24 | [DeclStmt] var arr3 = ... | semmle.order | 13 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:26:3:26:19 | [ExprStmt] sink(arr3.pop()); | semmle.label | 14 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:26:3:26:19 | [ExprStmt] sink(arr3.pop()); | semmle.order | 14 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:28:3:28:16 | [DeclStmt] var arr4 = ... | semmle.label | 15 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:28:3:28:16 | [DeclStmt] var arr4 = ... | semmle.order | 15 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:29:3:29:30 | [ExprStmt] arr4.sp ... urce"); | semmle.label | 16 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:29:3:29:30 | [ExprStmt] arr4.sp ... urce"); | semmle.order | 16 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:30:3:30:19 | [ExprStmt] sink(arr4.pop()); | semmle.label | 17 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:30:3:30:19 | [ExprStmt] sink(arr4.pop()); | semmle.order | 17 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:32:3:32:24 | [DeclStmt] var arr4_variant = ... | semmle.label | 18 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:32:3:32:24 | [DeclStmt] var arr4_variant = ... | semmle.order | 18 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:33:3:33:46 | [ExprStmt] arr4_va ... urce"); | semmle.label | 19 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:33:3:33:46 | [ExprStmt] arr4_va ... urce"); | semmle.order | 19 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:34:3:34:21 | [ExprStmt] arr4_variant.pop(); | semmle.label | 20 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:34:3:34:21 | [ExprStmt] arr4_variant.pop(); | semmle.order | 20 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:35:3:35:27 | [ExprStmt] sink(ar ... pop()); | semmle.label | 21 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:35:3:35:27 | [ExprStmt] sink(ar ... pop()); | semmle.order | 21 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:37:3:37:23 | [DeclStmt] var arr4_spread = ... | semmle.label | 22 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:37:3:37:23 | [DeclStmt] var arr4_spread = ... | semmle.order | 22 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:38:3:38:35 | [ExprStmt] arr4_sp ... ..arr); | semmle.label | 23 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:38:3:38:35 | [ExprStmt] arr4_sp ... ..arr); | semmle.order | 23 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:39:3:39:26 | [ExprStmt] sink(ar ... pop()); | semmle.label | 24 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:39:3:39:26 | [ExprStmt] sink(ar ... pop()); | semmle.order | 24 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:41:3:41:29 | [DeclStmt] var arr5 = ... | semmle.label | 25 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:41:3:41:29 | [DeclStmt] var arr5 = ... | semmle.order | 25 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:42:3:42:19 | [ExprStmt] sink(arr5.pop()); | semmle.label | 26 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:42:3:42:19 | [ExprStmt] sink(arr5.pop()); | semmle.order | 26 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:44:3:44:28 | [ExprStmt] sink(ar ... pop()); | semmle.label | 27 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:44:3:44:28 | [ExprStmt] sink(ar ... pop()); | semmle.order | 27 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:46:3:46:16 | [DeclStmt] var arr6 = ... | semmle.label | 28 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:46:3:46:16 | [DeclStmt] var arr6 = ... | semmle.order | 28 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:47:3:49:3 | [ForStmt] for (va ... i]; } | semmle.label | 29 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:47:3:49:3 | [ForStmt] for (va ... i]; } | semmle.order | 29 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:50:3:50:19 | [ExprStmt] sink(arr6.pop()); | semmle.label | 30 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:50:3:50:19 | [ExprStmt] sink(arr6.pop()); | semmle.order | 30 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:53:3:56:5 | [ExprStmt] ["sourc ... . }); | semmle.label | 31 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:53:3:56:5 | [ExprStmt] ["sourc ... . }); | semmle.order | 31 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:58:3:58:15 | [ExprStmt] sink(arr[0]); | semmle.label | 32 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:58:3:58:15 | [ExprStmt] sink(arr[0]); | semmle.order | 32 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:60:3:62:3 | [ForOfStmt] for (co ... OK } | semmle.label | 33 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:60:3:62:3 | [ForOfStmt] for (co ... OK } | semmle.order | 33 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:64:3:66:3 | [ForOfStmt] for (co ... OK } | semmle.label | 34 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:64:3:66:3 | [ForOfStmt] for (co ... OK } | semmle.order | 34 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:68:3:70:3 | [ForOfStmt] for (co ... OK } | semmle.label | 35 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:68:3:70:3 | [ForOfStmt] for (co ... OK } | semmle.order | 35 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:72:3:72:16 | [DeclStmt] var arr7 = ... | semmle.label | 36 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:72:3:72:16 | [DeclStmt] var arr7 = ... | semmle.order | 36 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:73:3:73:20 | [ExprStmt] arr7.push(...arr); | semmle.label | 37 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:73:3:73:20 | [ExprStmt] arr7.push(...arr); | semmle.order | 37 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:74:3:76:3 | [ForOfStmt] for (co ... OK } | semmle.label | 38 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:74:3:76:3 | [ForOfStmt] for (co ... OK } | semmle.order | 38 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:78:3:78:42 | [DeclStmt] const arrayFrom = ... | semmle.label | 39 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:78:3:78:42 | [DeclStmt] const arrayFrom = ... | semmle.order | 39 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:79:3:81:3 | [ForOfStmt] for (co ... OK } | semmle.label | 40 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:79:3:81:3 | [ForOfStmt] for (co ... OK } | semmle.order | 40 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:83:3:83:31 | [ExprStmt] sink(ar ... back)); | semmle.label | 41 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:83:3:83:31 | [ExprStmt] sink(ar ... back)); | semmle.order | 41 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:85:3:85:42 | [DeclStmt] const arrayFind = ... | semmle.label | 42 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:85:3:85:42 | [DeclStmt] const arrayFind = ... | semmle.order | 42 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:86:3:86:37 | [ExprStmt] sink(ar ... back)); | semmle.label | 43 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:86:3:86:37 | [ExprStmt] sink(ar ... back)); | semmle.order | 43 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:88:3:88:31 | [DeclStmt] const uniq = ... | semmle.label | 44 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:88:3:88:31 | [DeclStmt] const uniq = ... | semmle.order | 44 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:89:3:91:3 | [ForOfStmt] for (co ... OK } | semmle.label | 45 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:89:3:91:3 | [ForOfStmt] for (co ... OK } | semmle.order | 45 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:93:3:93:19 | [ExprStmt] sink(arr.at(-1)); | semmle.label | 46 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:93:3:93:19 | [ExprStmt] sink(arr.at(-1)); | semmle.order | 46 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:95:3:95:36 | [ExprStmt] sink([" ... => x)); | semmle.label | 47 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:95:3:95:36 | [ExprStmt] sink([" ... => x)); | semmle.order | 47 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:96:3:96:38 | [ExprStmt] sink([" ... !!x)); | semmle.label | 48 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:96:3:96:38 | [ExprStmt] sink([" ... !!x)); | semmle.order | 48 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:98:3:98:16 | [DeclStmt] var arr8 = ... | semmle.label | 49 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:98:3:98:16 | [DeclStmt] var arr8 = ... | semmle.order | 49 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:99:3:99:40 | [ExprStmt] arr8 = ... urce"); | semmle.label | 50 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:99:3:99:40 | [ExprStmt] arr8 = ... urce"); | semmle.order | 50 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:100:3:100:19 | [ExprStmt] sink(arr8.pop()); | semmle.label | 51 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:100:3:100:19 | [ExprStmt] sink(arr8.pop()); | semmle.order | 51 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:102:3:102:24 | [DeclStmt] var arr8_variant = ... | semmle.label | 52 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:102:3:102:24 | [DeclStmt] var arr8_variant = ... | semmle.order | 52 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:103:3:103:64 | [ExprStmt] arr8_va ... urce"); | semmle.label | 53 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:103:3:103:64 | [ExprStmt] arr8_va ... urce"); | semmle.order | 53 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:104:3:104:21 | [ExprStmt] arr8_variant.pop(); | semmle.label | 54 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:104:3:104:21 | [ExprStmt] arr8_variant.pop(); | semmle.order | 54 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:105:3:105:27 | [ExprStmt] sink(ar ... pop()); | semmle.label | 55 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:105:3:105:27 | [ExprStmt] sink(ar ... pop()); | semmle.order | 55 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:107:3:107:23 | [DeclStmt] var arr8_spread = ... | semmle.label | 56 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:107:3:107:23 | [DeclStmt] var arr8_spread = ... | semmle.order | 56 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:108:3:108:52 | [ExprStmt] arr8_sp ... ..arr); | semmle.label | 57 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:108:3:108:52 | [ExprStmt] arr8_sp ... ..arr); | semmle.order | 57 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:109:3:109:26 | [ExprStmt] sink(ar ... pop()); | semmle.label | 58 | -| arrays.js:1:14:110:1 | [BlockStmt] { let ... OT OK } | arrays.js:109:3:109:26 | [ExprStmt] sink(ar ... pop()); | semmle.order | 58 | +| arrays.js:1:1:147:2 | [ParExpr] (functi ... } }) | arrays.js:1:2:147:1 | [FunctionExpr] functio ... K } } | semmle.label | 1 | +| arrays.js:1:1:147:2 | [ParExpr] (functi ... } }) | arrays.js:1:2:147:1 | [FunctionExpr] functio ... K } } | semmle.order | 1 | +| arrays.js:1:1:147:3 | [ExprStmt] (functi ... } }); | arrays.js:1:1:147:2 | [ParExpr] (functi ... } }) | semmle.label | 1 | +| arrays.js:1:1:147:3 | [ExprStmt] (functi ... } }); | arrays.js:1:1:147:2 | [ParExpr] (functi ... } }) | semmle.order | 1 | +| arrays.js:1:2:147:1 | [FunctionExpr] functio ... K } } | arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | semmle.label | 5 | +| arrays.js:1:2:147:1 | [FunctionExpr] functio ... K } } | arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | semmle.order | 5 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.label | 1 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.order | 1 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:4:3:4:28 | [DeclStmt] var obj = ... | semmle.label | 2 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:4:3:4:28 | [DeclStmt] var obj = ... | semmle.order | 2 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:5:3:5:16 | [ExprStmt] sink(obj.foo); | semmle.label | 3 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:5:3:5:16 | [ExprStmt] sink(obj.foo); | semmle.order | 3 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:7:3:7:15 | [DeclStmt] var arr = ... | semmle.label | 4 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:7:3:7:15 | [DeclStmt] var arr = ... | semmle.order | 4 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:8:3:8:19 | [ExprStmt] arr.push(source); | semmle.label | 5 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:8:3:8:19 | [ExprStmt] arr.push(source); | semmle.order | 5 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:10:3:12:3 | [ForStmt] for (va ... OK } | semmle.label | 6 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:10:3:12:3 | [ForStmt] for (va ... OK } | semmle.order | 6 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:15:3:15:30 | [ExprStmt] arr.for ... nk(e)); | semmle.label | 7 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:15:3:15:30 | [ExprStmt] arr.for ... nk(e)); | semmle.order | 7 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:16:3:16:26 | [ExprStmt] arr.map ... nk(e)); | semmle.label | 8 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:16:3:16:26 | [ExprStmt] arr.map ... nk(e)); | semmle.order | 8 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:18:3:18:53 | [ExprStmt] [1, 2, ... nk(e)); | semmle.label | 9 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:18:3:18:53 | [ExprStmt] [1, 2, ... nk(e)); | semmle.order | 9 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:20:3:20:18 | [ExprStmt] sink(arr.pop()); | semmle.label | 10 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:20:3:20:18 | [ExprStmt] sink(arr.pop()); | semmle.order | 10 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:22:3:22:24 | [DeclStmt] var arr2 = ... | semmle.label | 11 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:22:3:22:24 | [DeclStmt] var arr2 = ... | semmle.order | 11 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:23:3:23:19 | [ExprStmt] sink(arr2.pop()); | semmle.label | 12 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:23:3:23:19 | [ExprStmt] sink(arr2.pop()); | semmle.order | 12 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:25:3:25:24 | [DeclStmt] var arr3 = ... | semmle.label | 13 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:25:3:25:24 | [DeclStmt] var arr3 = ... | semmle.order | 13 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:26:3:26:19 | [ExprStmt] sink(arr3.pop()); | semmle.label | 14 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:26:3:26:19 | [ExprStmt] sink(arr3.pop()); | semmle.order | 14 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:28:3:28:16 | [DeclStmt] var arr4 = ... | semmle.label | 15 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:28:3:28:16 | [DeclStmt] var arr4 = ... | semmle.order | 15 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:29:3:29:30 | [ExprStmt] arr4.sp ... urce"); | semmle.label | 16 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:29:3:29:30 | [ExprStmt] arr4.sp ... urce"); | semmle.order | 16 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:30:3:30:19 | [ExprStmt] sink(arr4.pop()); | semmle.label | 17 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:30:3:30:19 | [ExprStmt] sink(arr4.pop()); | semmle.order | 17 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:32:3:32:24 | [DeclStmt] var arr4_variant = ... | semmle.label | 18 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:32:3:32:24 | [DeclStmt] var arr4_variant = ... | semmle.order | 18 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:33:3:33:46 | [ExprStmt] arr4_va ... urce"); | semmle.label | 19 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:33:3:33:46 | [ExprStmt] arr4_va ... urce"); | semmle.order | 19 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:34:3:34:21 | [ExprStmt] arr4_variant.pop(); | semmle.label | 20 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:34:3:34:21 | [ExprStmt] arr4_variant.pop(); | semmle.order | 20 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:35:3:35:27 | [ExprStmt] sink(ar ... pop()); | semmle.label | 21 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:35:3:35:27 | [ExprStmt] sink(ar ... pop()); | semmle.order | 21 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:37:3:37:23 | [DeclStmt] var arr4_spread = ... | semmle.label | 22 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:37:3:37:23 | [DeclStmt] var arr4_spread = ... | semmle.order | 22 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:38:3:38:35 | [ExprStmt] arr4_sp ... ..arr); | semmle.label | 23 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:38:3:38:35 | [ExprStmt] arr4_sp ... ..arr); | semmle.order | 23 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:39:3:39:26 | [ExprStmt] sink(ar ... pop()); | semmle.label | 24 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:39:3:39:26 | [ExprStmt] sink(ar ... pop()); | semmle.order | 24 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:41:3:41:29 | [DeclStmt] var arr5 = ... | semmle.label | 25 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:41:3:41:29 | [DeclStmt] var arr5 = ... | semmle.order | 25 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:42:3:42:19 | [ExprStmt] sink(arr5.pop()); | semmle.label | 26 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:42:3:42:19 | [ExprStmt] sink(arr5.pop()); | semmle.order | 26 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:44:3:44:28 | [ExprStmt] sink(ar ... pop()); | semmle.label | 27 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:44:3:44:28 | [ExprStmt] sink(ar ... pop()); | semmle.order | 27 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:46:3:46:16 | [DeclStmt] var arr6 = ... | semmle.label | 28 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:46:3:46:16 | [DeclStmt] var arr6 = ... | semmle.order | 28 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:47:3:49:3 | [ForStmt] for (va ... i]; } | semmle.label | 29 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:47:3:49:3 | [ForStmt] for (va ... i]; } | semmle.order | 29 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:50:3:50:19 | [ExprStmt] sink(arr6.pop()); | semmle.label | 30 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:50:3:50:19 | [ExprStmt] sink(arr6.pop()); | semmle.order | 30 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:53:3:56:5 | [ExprStmt] ["sourc ... . }); | semmle.label | 31 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:53:3:56:5 | [ExprStmt] ["sourc ... . }); | semmle.order | 31 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:58:3:58:15 | [ExprStmt] sink(arr[0]); | semmle.label | 32 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:58:3:58:15 | [ExprStmt] sink(arr[0]); | semmle.order | 32 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:60:3:62:3 | [ForOfStmt] for (co ... OK } | semmle.label | 33 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:60:3:62:3 | [ForOfStmt] for (co ... OK } | semmle.order | 33 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:64:3:66:3 | [ForOfStmt] for (co ... OK } | semmle.label | 34 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:64:3:66:3 | [ForOfStmt] for (co ... OK } | semmle.order | 34 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:68:3:70:3 | [ForOfStmt] for (co ... OK } | semmle.label | 35 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:68:3:70:3 | [ForOfStmt] for (co ... OK } | semmle.order | 35 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:72:3:72:16 | [DeclStmt] var arr7 = ... | semmle.label | 36 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:72:3:72:16 | [DeclStmt] var arr7 = ... | semmle.order | 36 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:73:3:73:20 | [ExprStmt] arr7.push(...arr); | semmle.label | 37 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:73:3:73:20 | [ExprStmt] arr7.push(...arr); | semmle.order | 37 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:74:3:76:3 | [ForOfStmt] for (co ... OK } | semmle.label | 38 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:74:3:76:3 | [ForOfStmt] for (co ... OK } | semmle.order | 38 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:78:3:78:42 | [DeclStmt] const arrayFrom = ... | semmle.label | 39 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:78:3:78:42 | [DeclStmt] const arrayFrom = ... | semmle.order | 39 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:79:3:81:3 | [ForOfStmt] for (co ... OK } | semmle.label | 40 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:79:3:81:3 | [ForOfStmt] for (co ... OK } | semmle.order | 40 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:83:3:83:31 | [ExprStmt] sink(ar ... back)); | semmle.label | 41 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:83:3:83:31 | [ExprStmt] sink(ar ... back)); | semmle.order | 41 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:85:3:85:42 | [DeclStmt] const arrayFind = ... | semmle.label | 42 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:85:3:85:42 | [DeclStmt] const arrayFind = ... | semmle.order | 42 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:86:3:86:37 | [ExprStmt] sink(ar ... back)); | semmle.label | 43 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:86:3:86:37 | [ExprStmt] sink(ar ... back)); | semmle.order | 43 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:88:3:88:31 | [DeclStmt] const uniq = ... | semmle.label | 44 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:88:3:88:31 | [DeclStmt] const uniq = ... | semmle.order | 44 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:89:3:91:3 | [ForOfStmt] for (co ... OK } | semmle.label | 45 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:89:3:91:3 | [ForOfStmt] for (co ... OK } | semmle.order | 45 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:93:3:93:19 | [ExprStmt] sink(arr.at(-1)); | semmle.label | 46 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:93:3:93:19 | [ExprStmt] sink(arr.at(-1)); | semmle.order | 46 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:95:3:95:36 | [ExprStmt] sink([" ... => x)); | semmle.label | 47 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:95:3:95:36 | [ExprStmt] sink([" ... => x)); | semmle.order | 47 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:96:3:96:38 | [ExprStmt] sink([" ... !!x)); | semmle.label | 48 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:96:3:96:38 | [ExprStmt] sink([" ... !!x)); | semmle.order | 48 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:98:3:98:16 | [DeclStmt] var arr8 = ... | semmle.label | 49 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:98:3:98:16 | [DeclStmt] var arr8 = ... | semmle.order | 49 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:99:3:99:40 | [ExprStmt] arr8 = ... urce"); | semmle.label | 50 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:99:3:99:40 | [ExprStmt] arr8 = ... urce"); | semmle.order | 50 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:100:3:100:19 | [ExprStmt] sink(arr8.pop()); | semmle.label | 51 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:100:3:100:19 | [ExprStmt] sink(arr8.pop()); | semmle.order | 51 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:102:3:102:24 | [DeclStmt] var arr8_variant = ... | semmle.label | 52 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:102:3:102:24 | [DeclStmt] var arr8_variant = ... | semmle.order | 52 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:103:3:103:64 | [ExprStmt] arr8_va ... urce"); | semmle.label | 53 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:103:3:103:64 | [ExprStmt] arr8_va ... urce"); | semmle.order | 53 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:104:3:104:21 | [ExprStmt] arr8_variant.pop(); | semmle.label | 54 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:104:3:104:21 | [ExprStmt] arr8_variant.pop(); | semmle.order | 54 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:105:3:105:27 | [ExprStmt] sink(ar ... pop()); | semmle.label | 55 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:105:3:105:27 | [ExprStmt] sink(ar ... pop()); | semmle.order | 55 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:107:3:107:23 | [DeclStmt] var arr8_spread = ... | semmle.label | 56 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:107:3:107:23 | [DeclStmt] var arr8_spread = ... | semmle.order | 56 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:108:3:108:52 | [ExprStmt] arr8_sp ... ..arr); | semmle.label | 57 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:108:3:108:52 | [ExprStmt] arr8_sp ... ..arr); | semmle.order | 57 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:109:3:109:26 | [ExprStmt] sink(ar ... pop()); | semmle.label | 58 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:109:3:109:26 | [ExprStmt] sink(ar ... pop()); | semmle.order | 58 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:111:3:111:35 | [ExprStmt] sink(ar ... back)); | semmle.label | 59 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:111:3:111:35 | [ExprStmt] sink(ar ... back)); | semmle.order | 59 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:113:3:117:3 | [BlockStmt] { // T ... OK } | semmle.label | 60 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:113:3:117:3 | [BlockStmt] { // T ... OK } | semmle.order | 60 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:119:3:123:3 | [BlockStmt] { // T ... OK } | semmle.label | 61 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:119:3:123:3 | [BlockStmt] { // T ... OK } | semmle.order | 61 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:125:3:129:3 | [BlockStmt] { // T ... OK } | semmle.label | 62 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:125:3:129:3 | [BlockStmt] { // T ... OK } | semmle.order | 62 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:130:3:134:3 | [BlockStmt] { c ... OK } | semmle.label | 63 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:130:3:134:3 | [BlockStmt] { c ... OK } | semmle.order | 63 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:136:3:140:3 | [BlockStmt] { c ... OK } | semmle.label | 64 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:136:3:140:3 | [BlockStmt] { c ... OK } | semmle.order | 64 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:142:3:146:3 | [BlockStmt] { c ... OK } | semmle.label | 65 | +| arrays.js:1:14:147:1 | [BlockStmt] { let ... K } } | arrays.js:142:3:146:3 | [BlockStmt] { c ... OK } | semmle.order | 65 | | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | arrays.js:2:7:2:23 | [VariableDeclarator] source = "source" | semmle.label | 1 | | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | arrays.js:2:7:2:23 | [VariableDeclarator] source = "source" | semmle.order | 1 | | arrays.js:2:7:2:23 | [VariableDeclarator] source = "source" | arrays.js:2:7:2:12 | [VarDecl] source | semmle.label | 1 | @@ -1490,6 +1670,272 @@ edges | arrays.js:109:8:109:22 | [DotExpr] arr8_spread.pop | arrays.js:109:20:109:22 | [Label] pop | semmle.order | 2 | | arrays.js:109:8:109:24 | [MethodCallExpr] arr8_spread.pop() | arrays.js:109:8:109:22 | [DotExpr] arr8_spread.pop | semmle.label | 0 | | arrays.js:109:8:109:24 | [MethodCallExpr] arr8_spread.pop() | arrays.js:109:8:109:22 | [DotExpr] arr8_spread.pop | semmle.order | 0 | +| arrays.js:111:3:111:34 | [CallExpr] sink(ar ... lback)) | arrays.js:111:3:111:6 | [VarRef] sink | semmle.label | 0 | +| arrays.js:111:3:111:34 | [CallExpr] sink(ar ... lback)) | arrays.js:111:3:111:6 | [VarRef] sink | semmle.order | 0 | +| arrays.js:111:3:111:34 | [CallExpr] sink(ar ... lback)) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| arrays.js:111:3:111:34 | [CallExpr] sink(ar ... lback)) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| arrays.js:111:3:111:35 | [ExprStmt] sink(ar ... back)); | arrays.js:111:3:111:34 | [CallExpr] sink(ar ... lback)) | semmle.label | 1 | +| arrays.js:111:3:111:35 | [ExprStmt] sink(ar ... back)); | arrays.js:111:3:111:34 | [CallExpr] sink(ar ... lback)) | semmle.order | 1 | +| arrays.js:111:8:111:19 | [DotExpr] arr.findLast | arrays.js:111:8:111:10 | [VarRef] arr | semmle.label | 1 | +| arrays.js:111:8:111:19 | [DotExpr] arr.findLast | arrays.js:111:8:111:10 | [VarRef] arr | semmle.order | 1 | +| arrays.js:111:8:111:19 | [DotExpr] arr.findLast | arrays.js:111:12:111:19 | [Label] findLast | semmle.label | 2 | +| arrays.js:111:8:111:19 | [DotExpr] arr.findLast | arrays.js:111:12:111:19 | [Label] findLast | semmle.order | 2 | +| arrays.js:111:8:111:33 | [MethodCallExpr] arr.fin ... llback) | arrays.js:111:8:111:19 | [DotExpr] arr.findLast | semmle.label | 0 | +| arrays.js:111:8:111:33 | [MethodCallExpr] arr.fin ... llback) | arrays.js:111:8:111:19 | [DotExpr] arr.findLast | semmle.order | 0 | +| arrays.js:111:8:111:33 | [MethodCallExpr] arr.fin ... llback) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| arrays.js:111:8:111:33 | [MethodCallExpr] arr.fin ... llback) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| arrays.js:113:3:117:3 | [BlockStmt] { // T ... OK } | arrays.js:114:5:114:28 | [DeclStmt] const list = ... | semmle.label | 1 | +| arrays.js:113:3:117:3 | [BlockStmt] { // T ... OK } | arrays.js:114:5:114:28 | [DeclStmt] const list = ... | semmle.order | 1 | +| arrays.js:113:3:117:3 | [BlockStmt] { // T ... OK } | arrays.js:115:5:115:56 | [DeclStmt] const element = ... | semmle.label | 2 | +| arrays.js:113:3:117:3 | [BlockStmt] { // T ... OK } | arrays.js:115:5:115:56 | [DeclStmt] const element = ... | semmle.order | 2 | +| arrays.js:113:3:117:3 | [BlockStmt] { // T ... OK } | arrays.js:116:5:116:18 | [ExprStmt] sink(element); | semmle.label | 3 | +| arrays.js:113:3:117:3 | [BlockStmt] { // T ... OK } | arrays.js:116:5:116:18 | [ExprStmt] sink(element); | semmle.order | 3 | +| arrays.js:114:5:114:28 | [DeclStmt] const list = ... | arrays.js:114:11:114:27 | [VariableDeclarator] list = ["source"] | semmle.label | 1 | +| arrays.js:114:5:114:28 | [DeclStmt] const list = ... | arrays.js:114:11:114:27 | [VariableDeclarator] list = ["source"] | semmle.order | 1 | +| arrays.js:114:11:114:27 | [VariableDeclarator] list = ["source"] | arrays.js:114:11:114:14 | [VarDecl] list | semmle.label | 1 | +| arrays.js:114:11:114:27 | [VariableDeclarator] list = ["source"] | arrays.js:114:11:114:14 | [VarDecl] list | semmle.order | 1 | +| arrays.js:114:11:114:27 | [VariableDeclarator] list = ["source"] | arrays.js:114:18:114:27 | [ArrayExpr] ["source"] | semmle.label | 2 | +| arrays.js:114:11:114:27 | [VariableDeclarator] list = ["source"] | arrays.js:114:18:114:27 | [ArrayExpr] ["source"] | semmle.order | 2 | +| arrays.js:114:18:114:27 | [ArrayExpr] ["source"] | arrays.js:114:19:114:26 | [Literal] "source" | semmle.label | 1 | +| arrays.js:114:18:114:27 | [ArrayExpr] ["source"] | arrays.js:114:19:114:26 | [Literal] "source" | semmle.order | 1 | +| arrays.js:115:5:115:56 | [DeclStmt] const element = ... | arrays.js:115:11:115:55 | [VariableDeclarator] element ... (item)) | semmle.label | 1 | +| arrays.js:115:5:115:56 | [DeclStmt] const element = ... | arrays.js:115:11:115:55 | [VariableDeclarator] element ... (item)) | semmle.order | 1 | +| arrays.js:115:11:115:55 | [VariableDeclarator] element ... (item)) | arrays.js:115:11:115:17 | [VarDecl] element | semmle.label | 1 | +| arrays.js:115:11:115:55 | [VariableDeclarator] element ... (item)) | arrays.js:115:11:115:17 | [VarDecl] element | semmle.order | 1 | +| arrays.js:115:11:115:55 | [VariableDeclarator] element ... (item)) | arrays.js:115:21:115:55 | [MethodCallExpr] list.fi ... (item)) | semmle.label | 2 | +| arrays.js:115:11:115:55 | [VariableDeclarator] element ... (item)) | arrays.js:115:21:115:55 | [MethodCallExpr] list.fi ... (item)) | semmle.order | 2 | +| arrays.js:115:21:115:33 | [DotExpr] list.findLast | arrays.js:115:21:115:24 | [VarRef] list | semmle.label | 1 | +| arrays.js:115:21:115:33 | [DotExpr] list.findLast | arrays.js:115:21:115:24 | [VarRef] list | semmle.order | 1 | +| arrays.js:115:21:115:33 | [DotExpr] list.findLast | arrays.js:115:26:115:33 | [Label] findLast | semmle.label | 2 | +| arrays.js:115:21:115:33 | [DotExpr] list.findLast | arrays.js:115:26:115:33 | [Label] findLast | semmle.order | 2 | +| arrays.js:115:21:115:55 | [MethodCallExpr] list.fi ... (item)) | arrays.js:115:21:115:33 | [DotExpr] list.findLast | semmle.label | 0 | +| arrays.js:115:21:115:55 | [MethodCallExpr] list.fi ... (item)) | arrays.js:115:21:115:33 | [DotExpr] list.findLast | semmle.order | 0 | +| arrays.js:115:21:115:55 | [MethodCallExpr] list.fi ... (item)) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| arrays.js:115:21:115:55 | [MethodCallExpr] list.fi ... (item)) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| arrays.js:115:35:115:54 | [ArrowFunctionExpr] (item) => sink(item) | arrays.js:115:45:115:54 | [CallExpr] sink(item) | semmle.label | 5 | +| arrays.js:115:35:115:54 | [ArrowFunctionExpr] (item) => sink(item) | arrays.js:115:45:115:54 | [CallExpr] sink(item) | semmle.order | 5 | +| arrays.js:115:35:115:54 | [ArrowFunctionExpr] (item) => sink(item) | file://:0:0:0:0 | (Parameters) | semmle.label | 1 | +| arrays.js:115:35:115:54 | [ArrowFunctionExpr] (item) => sink(item) | file://:0:0:0:0 | (Parameters) | semmle.order | 1 | +| arrays.js:115:45:115:54 | [CallExpr] sink(item) | arrays.js:115:45:115:48 | [VarRef] sink | semmle.label | 0 | +| arrays.js:115:45:115:54 | [CallExpr] sink(item) | arrays.js:115:45:115:48 | [VarRef] sink | semmle.order | 0 | +| arrays.js:115:45:115:54 | [CallExpr] sink(item) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| arrays.js:115:45:115:54 | [CallExpr] sink(item) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| arrays.js:116:5:116:17 | [CallExpr] sink(element) | arrays.js:116:5:116:8 | [VarRef] sink | semmle.label | 0 | +| arrays.js:116:5:116:17 | [CallExpr] sink(element) | arrays.js:116:5:116:8 | [VarRef] sink | semmle.order | 0 | +| arrays.js:116:5:116:17 | [CallExpr] sink(element) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| arrays.js:116:5:116:17 | [CallExpr] sink(element) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| arrays.js:116:5:116:18 | [ExprStmt] sink(element); | arrays.js:116:5:116:17 | [CallExpr] sink(element) | semmle.label | 1 | +| arrays.js:116:5:116:18 | [ExprStmt] sink(element); | arrays.js:116:5:116:17 | [CallExpr] sink(element) | semmle.order | 1 | +| arrays.js:119:3:123:3 | [BlockStmt] { // T ... OK } | arrays.js:120:5:120:28 | [DeclStmt] const list = ... | semmle.label | 1 | +| arrays.js:119:3:123:3 | [BlockStmt] { // T ... OK } | arrays.js:120:5:120:28 | [DeclStmt] const list = ... | semmle.order | 1 | +| arrays.js:119:3:123:3 | [BlockStmt] { // T ... OK } | arrays.js:121:5:121:52 | [DeclStmt] const element = ... | semmle.label | 2 | +| arrays.js:119:3:123:3 | [BlockStmt] { // T ... OK } | arrays.js:121:5:121:52 | [DeclStmt] const element = ... | semmle.order | 2 | +| arrays.js:119:3:123:3 | [BlockStmt] { // T ... OK } | arrays.js:122:5:122:18 | [ExprStmt] sink(element); | semmle.label | 3 | +| arrays.js:119:3:123:3 | [BlockStmt] { // T ... OK } | arrays.js:122:5:122:18 | [ExprStmt] sink(element); | semmle.order | 3 | +| arrays.js:120:5:120:28 | [DeclStmt] const list = ... | arrays.js:120:11:120:27 | [VariableDeclarator] list = ["source"] | semmle.label | 1 | +| arrays.js:120:5:120:28 | [DeclStmt] const list = ... | arrays.js:120:11:120:27 | [VariableDeclarator] list = ["source"] | semmle.order | 1 | +| arrays.js:120:11:120:27 | [VariableDeclarator] list = ["source"] | arrays.js:120:11:120:14 | [VarDecl] list | semmle.label | 1 | +| arrays.js:120:11:120:27 | [VariableDeclarator] list = ["source"] | arrays.js:120:11:120:14 | [VarDecl] list | semmle.order | 1 | +| arrays.js:120:11:120:27 | [VariableDeclarator] list = ["source"] | arrays.js:120:18:120:27 | [ArrayExpr] ["source"] | semmle.label | 2 | +| arrays.js:120:11:120:27 | [VariableDeclarator] list = ["source"] | arrays.js:120:18:120:27 | [ArrayExpr] ["source"] | semmle.order | 2 | +| arrays.js:120:18:120:27 | [ArrayExpr] ["source"] | arrays.js:120:19:120:26 | [Literal] "source" | semmle.label | 1 | +| arrays.js:120:18:120:27 | [ArrayExpr] ["source"] | arrays.js:120:19:120:26 | [Literal] "source" | semmle.order | 1 | +| arrays.js:121:5:121:52 | [DeclStmt] const element = ... | arrays.js:121:11:121:51 | [VariableDeclarator] element ... (item)) | semmle.label | 1 | +| arrays.js:121:5:121:52 | [DeclStmt] const element = ... | arrays.js:121:11:121:51 | [VariableDeclarator] element ... (item)) | semmle.order | 1 | +| arrays.js:121:11:121:51 | [VariableDeclarator] element ... (item)) | arrays.js:121:11:121:17 | [VarDecl] element | semmle.label | 1 | +| arrays.js:121:11:121:51 | [VariableDeclarator] element ... (item)) | arrays.js:121:11:121:17 | [VarDecl] element | semmle.order | 1 | +| arrays.js:121:11:121:51 | [VariableDeclarator] element ... (item)) | arrays.js:121:21:121:51 | [MethodCallExpr] list.fi ... (item)) | semmle.label | 2 | +| arrays.js:121:11:121:51 | [VariableDeclarator] element ... (item)) | arrays.js:121:21:121:51 | [MethodCallExpr] list.fi ... (item)) | semmle.order | 2 | +| arrays.js:121:21:121:29 | [DotExpr] list.find | arrays.js:121:21:121:24 | [VarRef] list | semmle.label | 1 | +| arrays.js:121:21:121:29 | [DotExpr] list.find | arrays.js:121:21:121:24 | [VarRef] list | semmle.order | 1 | +| arrays.js:121:21:121:29 | [DotExpr] list.find | arrays.js:121:26:121:29 | [Label] find | semmle.label | 2 | +| arrays.js:121:21:121:29 | [DotExpr] list.find | arrays.js:121:26:121:29 | [Label] find | semmle.order | 2 | +| arrays.js:121:21:121:51 | [MethodCallExpr] list.fi ... (item)) | arrays.js:121:21:121:29 | [DotExpr] list.find | semmle.label | 0 | +| arrays.js:121:21:121:51 | [MethodCallExpr] list.fi ... (item)) | arrays.js:121:21:121:29 | [DotExpr] list.find | semmle.order | 0 | +| arrays.js:121:21:121:51 | [MethodCallExpr] list.fi ... (item)) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| arrays.js:121:21:121:51 | [MethodCallExpr] list.fi ... (item)) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| arrays.js:121:31:121:50 | [ArrowFunctionExpr] (item) => sink(item) | arrays.js:121:41:121:50 | [CallExpr] sink(item) | semmle.label | 5 | +| arrays.js:121:31:121:50 | [ArrowFunctionExpr] (item) => sink(item) | arrays.js:121:41:121:50 | [CallExpr] sink(item) | semmle.order | 5 | +| arrays.js:121:31:121:50 | [ArrowFunctionExpr] (item) => sink(item) | file://:0:0:0:0 | (Parameters) | semmle.label | 1 | +| arrays.js:121:31:121:50 | [ArrowFunctionExpr] (item) => sink(item) | file://:0:0:0:0 | (Parameters) | semmle.order | 1 | +| arrays.js:121:41:121:50 | [CallExpr] sink(item) | arrays.js:121:41:121:44 | [VarRef] sink | semmle.label | 0 | +| arrays.js:121:41:121:50 | [CallExpr] sink(item) | arrays.js:121:41:121:44 | [VarRef] sink | semmle.order | 0 | +| arrays.js:121:41:121:50 | [CallExpr] sink(item) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| arrays.js:121:41:121:50 | [CallExpr] sink(item) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| arrays.js:122:5:122:17 | [CallExpr] sink(element) | arrays.js:122:5:122:8 | [VarRef] sink | semmle.label | 0 | +| arrays.js:122:5:122:17 | [CallExpr] sink(element) | arrays.js:122:5:122:8 | [VarRef] sink | semmle.order | 0 | +| arrays.js:122:5:122:17 | [CallExpr] sink(element) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| arrays.js:122:5:122:17 | [CallExpr] sink(element) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| arrays.js:122:5:122:18 | [ExprStmt] sink(element); | arrays.js:122:5:122:17 | [CallExpr] sink(element) | semmle.label | 1 | +| arrays.js:122:5:122:18 | [ExprStmt] sink(element); | arrays.js:122:5:122:17 | [CallExpr] sink(element) | semmle.order | 1 | +| arrays.js:125:3:129:3 | [BlockStmt] { // T ... OK } | arrays.js:126:5:126:28 | [DeclStmt] const list = ... | semmle.label | 1 | +| arrays.js:125:3:129:3 | [BlockStmt] { // T ... OK } | arrays.js:126:5:126:28 | [DeclStmt] const list = ... | semmle.order | 1 | +| arrays.js:125:3:129:3 | [BlockStmt] { // T ... OK } | arrays.js:127:5:127:61 | [DeclStmt] const element = ... | semmle.label | 2 | +| arrays.js:125:3:129:3 | [BlockStmt] { // T ... OK } | arrays.js:127:5:127:61 | [DeclStmt] const element = ... | semmle.order | 2 | +| arrays.js:125:3:129:3 | [BlockStmt] { // T ... OK } | arrays.js:128:5:128:18 | [ExprStmt] sink(element); | semmle.label | 3 | +| arrays.js:125:3:129:3 | [BlockStmt] { // T ... OK } | arrays.js:128:5:128:18 | [ExprStmt] sink(element); | semmle.order | 3 | +| arrays.js:126:5:126:28 | [DeclStmt] const list = ... | arrays.js:126:11:126:27 | [VariableDeclarator] list = ["source"] | semmle.label | 1 | +| arrays.js:126:5:126:28 | [DeclStmt] const list = ... | arrays.js:126:11:126:27 | [VariableDeclarator] list = ["source"] | semmle.order | 1 | +| arrays.js:126:11:126:27 | [VariableDeclarator] list = ["source"] | arrays.js:126:11:126:14 | [VarDecl] list | semmle.label | 1 | +| arrays.js:126:11:126:27 | [VariableDeclarator] list = ["source"] | arrays.js:126:11:126:14 | [VarDecl] list | semmle.order | 1 | +| arrays.js:126:11:126:27 | [VariableDeclarator] list = ["source"] | arrays.js:126:18:126:27 | [ArrayExpr] ["source"] | semmle.label | 2 | +| arrays.js:126:11:126:27 | [VariableDeclarator] list = ["source"] | arrays.js:126:18:126:27 | [ArrayExpr] ["source"] | semmle.order | 2 | +| arrays.js:126:18:126:27 | [ArrayExpr] ["source"] | arrays.js:126:19:126:26 | [Literal] "source" | semmle.label | 1 | +| arrays.js:126:18:126:27 | [ArrayExpr] ["source"] | arrays.js:126:19:126:26 | [Literal] "source" | semmle.order | 1 | +| arrays.js:127:5:127:61 | [DeclStmt] const element = ... | arrays.js:127:11:127:60 | [VariableDeclarator] element ... (item)) | semmle.label | 1 | +| arrays.js:127:5:127:61 | [DeclStmt] const element = ... | arrays.js:127:11:127:60 | [VariableDeclarator] element ... (item)) | semmle.order | 1 | +| arrays.js:127:11:127:60 | [VariableDeclarator] element ... (item)) | arrays.js:127:11:127:17 | [VarDecl] element | semmle.label | 1 | +| arrays.js:127:11:127:60 | [VariableDeclarator] element ... (item)) | arrays.js:127:11:127:17 | [VarDecl] element | semmle.order | 1 | +| arrays.js:127:11:127:60 | [VariableDeclarator] element ... (item)) | arrays.js:127:21:127:60 | [MethodCallExpr] list.fi ... (item)) | semmle.label | 2 | +| arrays.js:127:11:127:60 | [VariableDeclarator] element ... (item)) | arrays.js:127:21:127:60 | [MethodCallExpr] list.fi ... (item)) | semmle.order | 2 | +| arrays.js:127:21:127:38 | [DotExpr] list.findLastIndex | arrays.js:127:21:127:24 | [VarRef] list | semmle.label | 1 | +| arrays.js:127:21:127:38 | [DotExpr] list.findLastIndex | arrays.js:127:21:127:24 | [VarRef] list | semmle.order | 1 | +| arrays.js:127:21:127:38 | [DotExpr] list.findLastIndex | arrays.js:127:26:127:38 | [Label] findLastIndex | semmle.label | 2 | +| arrays.js:127:21:127:38 | [DotExpr] list.findLastIndex | arrays.js:127:26:127:38 | [Label] findLastIndex | semmle.order | 2 | +| arrays.js:127:21:127:60 | [MethodCallExpr] list.fi ... (item)) | arrays.js:127:21:127:38 | [DotExpr] list.findLastIndex | semmle.label | 0 | +| arrays.js:127:21:127:60 | [MethodCallExpr] list.fi ... (item)) | arrays.js:127:21:127:38 | [DotExpr] list.findLastIndex | semmle.order | 0 | +| arrays.js:127:21:127:60 | [MethodCallExpr] list.fi ... (item)) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| arrays.js:127:21:127:60 | [MethodCallExpr] list.fi ... (item)) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| arrays.js:127:40:127:59 | [ArrowFunctionExpr] (item) => sink(item) | arrays.js:127:50:127:59 | [CallExpr] sink(item) | semmle.label | 5 | +| arrays.js:127:40:127:59 | [ArrowFunctionExpr] (item) => sink(item) | arrays.js:127:50:127:59 | [CallExpr] sink(item) | semmle.order | 5 | +| arrays.js:127:40:127:59 | [ArrowFunctionExpr] (item) => sink(item) | file://:0:0:0:0 | (Parameters) | semmle.label | 1 | +| arrays.js:127:40:127:59 | [ArrowFunctionExpr] (item) => sink(item) | file://:0:0:0:0 | (Parameters) | semmle.order | 1 | +| arrays.js:127:50:127:59 | [CallExpr] sink(item) | arrays.js:127:50:127:53 | [VarRef] sink | semmle.label | 0 | +| arrays.js:127:50:127:59 | [CallExpr] sink(item) | arrays.js:127:50:127:53 | [VarRef] sink | semmle.order | 0 | +| arrays.js:127:50:127:59 | [CallExpr] sink(item) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| arrays.js:127:50:127:59 | [CallExpr] sink(item) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| arrays.js:128:5:128:17 | [CallExpr] sink(element) | arrays.js:128:5:128:8 | [VarRef] sink | semmle.label | 0 | +| arrays.js:128:5:128:17 | [CallExpr] sink(element) | arrays.js:128:5:128:8 | [VarRef] sink | semmle.order | 0 | +| arrays.js:128:5:128:17 | [CallExpr] sink(element) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| arrays.js:128:5:128:17 | [CallExpr] sink(element) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| arrays.js:128:5:128:18 | [ExprStmt] sink(element); | arrays.js:128:5:128:17 | [CallExpr] sink(element) | semmle.label | 1 | +| arrays.js:128:5:128:18 | [ExprStmt] sink(element); | arrays.js:128:5:128:17 | [CallExpr] sink(element) | semmle.order | 1 | +| arrays.js:130:3:134:3 | [BlockStmt] { c ... OK } | arrays.js:131:5:131:25 | [DeclStmt] const arr = ... | semmle.label | 1 | +| arrays.js:130:3:134:3 | [BlockStmt] { c ... OK } | arrays.js:131:5:131:25 | [DeclStmt] const arr = ... | semmle.order | 1 | +| arrays.js:130:3:134:3 | [BlockStmt] { c ... OK } | arrays.js:132:5:132:52 | [DeclStmt] const element1 = ... | semmle.label | 2 | +| arrays.js:130:3:134:3 | [BlockStmt] { c ... OK } | arrays.js:132:5:132:52 | [DeclStmt] const element1 = ... | semmle.order | 2 | +| arrays.js:130:3:134:3 | [BlockStmt] { c ... OK } | arrays.js:133:5:133:19 | [ExprStmt] sink(element1); | semmle.label | 3 | +| arrays.js:130:3:134:3 | [BlockStmt] { c ... OK } | arrays.js:133:5:133:19 | [ExprStmt] sink(element1); | semmle.order | 3 | +| arrays.js:131:5:131:25 | [DeclStmt] const arr = ... | arrays.js:131:11:131:24 | [VariableDeclarator] arr = source() | semmle.label | 1 | +| arrays.js:131:5:131:25 | [DeclStmt] const arr = ... | arrays.js:131:11:131:24 | [VariableDeclarator] arr = source() | semmle.order | 1 | +| arrays.js:131:11:131:24 | [VariableDeclarator] arr = source() | arrays.js:131:11:131:13 | [VarDecl] arr | semmle.label | 1 | +| arrays.js:131:11:131:24 | [VariableDeclarator] arr = source() | arrays.js:131:11:131:13 | [VarDecl] arr | semmle.order | 1 | +| arrays.js:131:11:131:24 | [VariableDeclarator] arr = source() | arrays.js:131:17:131:24 | [CallExpr] source() | semmle.label | 2 | +| arrays.js:131:11:131:24 | [VariableDeclarator] arr = source() | arrays.js:131:17:131:24 | [CallExpr] source() | semmle.order | 2 | +| arrays.js:131:17:131:24 | [CallExpr] source() | arrays.js:131:17:131:22 | [VarRef] source | semmle.label | 0 | +| arrays.js:131:17:131:24 | [CallExpr] source() | arrays.js:131:17:131:22 | [VarRef] source | semmle.order | 0 | +| arrays.js:132:5:132:52 | [DeclStmt] const element1 = ... | arrays.js:132:11:132:51 | [VariableDeclarator] element ... (item)) | semmle.label | 1 | +| arrays.js:132:5:132:52 | [DeclStmt] const element1 = ... | arrays.js:132:11:132:51 | [VariableDeclarator] element ... (item)) | semmle.order | 1 | +| arrays.js:132:11:132:51 | [VariableDeclarator] element ... (item)) | arrays.js:132:11:132:18 | [VarDecl] element1 | semmle.label | 1 | +| arrays.js:132:11:132:51 | [VariableDeclarator] element ... (item)) | arrays.js:132:11:132:18 | [VarDecl] element1 | semmle.order | 1 | +| arrays.js:132:11:132:51 | [VariableDeclarator] element ... (item)) | arrays.js:132:22:132:51 | [MethodCallExpr] arr.fin ... (item)) | semmle.label | 2 | +| arrays.js:132:11:132:51 | [VariableDeclarator] element ... (item)) | arrays.js:132:22:132:51 | [MethodCallExpr] arr.fin ... (item)) | semmle.order | 2 | +| arrays.js:132:22:132:29 | [DotExpr] arr.find | arrays.js:132:22:132:24 | [VarRef] arr | semmle.label | 1 | +| arrays.js:132:22:132:29 | [DotExpr] arr.find | arrays.js:132:22:132:24 | [VarRef] arr | semmle.order | 1 | +| arrays.js:132:22:132:29 | [DotExpr] arr.find | arrays.js:132:26:132:29 | [Label] find | semmle.label | 2 | +| arrays.js:132:22:132:29 | [DotExpr] arr.find | arrays.js:132:26:132:29 | [Label] find | semmle.order | 2 | +| arrays.js:132:22:132:51 | [MethodCallExpr] arr.fin ... (item)) | arrays.js:132:22:132:29 | [DotExpr] arr.find | semmle.label | 0 | +| arrays.js:132:22:132:51 | [MethodCallExpr] arr.fin ... (item)) | arrays.js:132:22:132:29 | [DotExpr] arr.find | semmle.order | 0 | +| arrays.js:132:22:132:51 | [MethodCallExpr] arr.fin ... (item)) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| arrays.js:132:22:132:51 | [MethodCallExpr] arr.fin ... (item)) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| arrays.js:132:31:132:50 | [ArrowFunctionExpr] (item) => sink(item) | arrays.js:132:41:132:50 | [CallExpr] sink(item) | semmle.label | 5 | +| arrays.js:132:31:132:50 | [ArrowFunctionExpr] (item) => sink(item) | arrays.js:132:41:132:50 | [CallExpr] sink(item) | semmle.order | 5 | +| arrays.js:132:31:132:50 | [ArrowFunctionExpr] (item) => sink(item) | file://:0:0:0:0 | (Parameters) | semmle.label | 1 | +| arrays.js:132:31:132:50 | [ArrowFunctionExpr] (item) => sink(item) | file://:0:0:0:0 | (Parameters) | semmle.order | 1 | +| arrays.js:132:41:132:50 | [CallExpr] sink(item) | arrays.js:132:41:132:44 | [VarRef] sink | semmle.label | 0 | +| arrays.js:132:41:132:50 | [CallExpr] sink(item) | arrays.js:132:41:132:44 | [VarRef] sink | semmle.order | 0 | +| arrays.js:132:41:132:50 | [CallExpr] sink(item) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| arrays.js:132:41:132:50 | [CallExpr] sink(item) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| arrays.js:133:5:133:18 | [CallExpr] sink(element1) | arrays.js:133:5:133:8 | [VarRef] sink | semmle.label | 0 | +| arrays.js:133:5:133:18 | [CallExpr] sink(element1) | arrays.js:133:5:133:8 | [VarRef] sink | semmle.order | 0 | +| arrays.js:133:5:133:18 | [CallExpr] sink(element1) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| arrays.js:133:5:133:18 | [CallExpr] sink(element1) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| arrays.js:133:5:133:19 | [ExprStmt] sink(element1); | arrays.js:133:5:133:18 | [CallExpr] sink(element1) | semmle.label | 1 | +| arrays.js:133:5:133:19 | [ExprStmt] sink(element1); | arrays.js:133:5:133:18 | [CallExpr] sink(element1) | semmle.order | 1 | +| arrays.js:136:3:140:3 | [BlockStmt] { c ... OK } | arrays.js:137:5:137:25 | [DeclStmt] const arr = ... | semmle.label | 1 | +| arrays.js:136:3:140:3 | [BlockStmt] { c ... OK } | arrays.js:137:5:137:25 | [DeclStmt] const arr = ... | semmle.order | 1 | +| arrays.js:136:3:140:3 | [BlockStmt] { c ... OK } | arrays.js:138:5:138:56 | [DeclStmt] const element1 = ... | semmle.label | 2 | +| arrays.js:136:3:140:3 | [BlockStmt] { c ... OK } | arrays.js:138:5:138:56 | [DeclStmt] const element1 = ... | semmle.order | 2 | +| arrays.js:136:3:140:3 | [BlockStmt] { c ... OK } | arrays.js:139:5:139:19 | [ExprStmt] sink(element1); | semmle.label | 3 | +| arrays.js:136:3:140:3 | [BlockStmt] { c ... OK } | arrays.js:139:5:139:19 | [ExprStmt] sink(element1); | semmle.order | 3 | +| arrays.js:137:5:137:25 | [DeclStmt] const arr = ... | arrays.js:137:11:137:24 | [VariableDeclarator] arr = source() | semmle.label | 1 | +| arrays.js:137:5:137:25 | [DeclStmt] const arr = ... | arrays.js:137:11:137:24 | [VariableDeclarator] arr = source() | semmle.order | 1 | +| arrays.js:137:11:137:24 | [VariableDeclarator] arr = source() | arrays.js:137:11:137:13 | [VarDecl] arr | semmle.label | 1 | +| arrays.js:137:11:137:24 | [VariableDeclarator] arr = source() | arrays.js:137:11:137:13 | [VarDecl] arr | semmle.order | 1 | +| arrays.js:137:11:137:24 | [VariableDeclarator] arr = source() | arrays.js:137:17:137:24 | [CallExpr] source() | semmle.label | 2 | +| arrays.js:137:11:137:24 | [VariableDeclarator] arr = source() | arrays.js:137:17:137:24 | [CallExpr] source() | semmle.order | 2 | +| arrays.js:137:17:137:24 | [CallExpr] source() | arrays.js:137:17:137:22 | [VarRef] source | semmle.label | 0 | +| arrays.js:137:17:137:24 | [CallExpr] source() | arrays.js:137:17:137:22 | [VarRef] source | semmle.order | 0 | +| arrays.js:138:5:138:56 | [DeclStmt] const element1 = ... | arrays.js:138:11:138:55 | [VariableDeclarator] element ... (item)) | semmle.label | 1 | +| arrays.js:138:5:138:56 | [DeclStmt] const element1 = ... | arrays.js:138:11:138:55 | [VariableDeclarator] element ... (item)) | semmle.order | 1 | +| arrays.js:138:11:138:55 | [VariableDeclarator] element ... (item)) | arrays.js:138:11:138:18 | [VarDecl] element1 | semmle.label | 1 | +| arrays.js:138:11:138:55 | [VariableDeclarator] element ... (item)) | arrays.js:138:11:138:18 | [VarDecl] element1 | semmle.order | 1 | +| arrays.js:138:11:138:55 | [VariableDeclarator] element ... (item)) | arrays.js:138:22:138:55 | [MethodCallExpr] arr.fin ... (item)) | semmle.label | 2 | +| arrays.js:138:11:138:55 | [VariableDeclarator] element ... (item)) | arrays.js:138:22:138:55 | [MethodCallExpr] arr.fin ... (item)) | semmle.order | 2 | +| arrays.js:138:22:138:33 | [DotExpr] arr.findLast | arrays.js:138:22:138:24 | [VarRef] arr | semmle.label | 1 | +| arrays.js:138:22:138:33 | [DotExpr] arr.findLast | arrays.js:138:22:138:24 | [VarRef] arr | semmle.order | 1 | +| arrays.js:138:22:138:33 | [DotExpr] arr.findLast | arrays.js:138:26:138:33 | [Label] findLast | semmle.label | 2 | +| arrays.js:138:22:138:33 | [DotExpr] arr.findLast | arrays.js:138:26:138:33 | [Label] findLast | semmle.order | 2 | +| arrays.js:138:22:138:55 | [MethodCallExpr] arr.fin ... (item)) | arrays.js:138:22:138:33 | [DotExpr] arr.findLast | semmle.label | 0 | +| arrays.js:138:22:138:55 | [MethodCallExpr] arr.fin ... (item)) | arrays.js:138:22:138:33 | [DotExpr] arr.findLast | semmle.order | 0 | +| arrays.js:138:22:138:55 | [MethodCallExpr] arr.fin ... (item)) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| arrays.js:138:22:138:55 | [MethodCallExpr] arr.fin ... (item)) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| arrays.js:138:35:138:54 | [ArrowFunctionExpr] (item) => sink(item) | arrays.js:138:45:138:54 | [CallExpr] sink(item) | semmle.label | 5 | +| arrays.js:138:35:138:54 | [ArrowFunctionExpr] (item) => sink(item) | arrays.js:138:45:138:54 | [CallExpr] sink(item) | semmle.order | 5 | +| arrays.js:138:35:138:54 | [ArrowFunctionExpr] (item) => sink(item) | file://:0:0:0:0 | (Parameters) | semmle.label | 1 | +| arrays.js:138:35:138:54 | [ArrowFunctionExpr] (item) => sink(item) | file://:0:0:0:0 | (Parameters) | semmle.order | 1 | +| arrays.js:138:45:138:54 | [CallExpr] sink(item) | arrays.js:138:45:138:48 | [VarRef] sink | semmle.label | 0 | +| arrays.js:138:45:138:54 | [CallExpr] sink(item) | arrays.js:138:45:138:48 | [VarRef] sink | semmle.order | 0 | +| arrays.js:138:45:138:54 | [CallExpr] sink(item) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| arrays.js:138:45:138:54 | [CallExpr] sink(item) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| arrays.js:139:5:139:18 | [CallExpr] sink(element1) | arrays.js:139:5:139:8 | [VarRef] sink | semmle.label | 0 | +| arrays.js:139:5:139:18 | [CallExpr] sink(element1) | arrays.js:139:5:139:8 | [VarRef] sink | semmle.order | 0 | +| arrays.js:139:5:139:18 | [CallExpr] sink(element1) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| arrays.js:139:5:139:18 | [CallExpr] sink(element1) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| arrays.js:139:5:139:19 | [ExprStmt] sink(element1); | arrays.js:139:5:139:18 | [CallExpr] sink(element1) | semmle.label | 1 | +| arrays.js:139:5:139:19 | [ExprStmt] sink(element1); | arrays.js:139:5:139:18 | [CallExpr] sink(element1) | semmle.order | 1 | +| arrays.js:142:3:146:3 | [BlockStmt] { c ... OK } | arrays.js:143:5:143:25 | [DeclStmt] const arr = ... | semmle.label | 1 | +| arrays.js:142:3:146:3 | [BlockStmt] { c ... OK } | arrays.js:143:5:143:25 | [DeclStmt] const arr = ... | semmle.order | 1 | +| arrays.js:142:3:146:3 | [BlockStmt] { c ... OK } | arrays.js:144:5:144:61 | [DeclStmt] const element1 = ... | semmle.label | 2 | +| arrays.js:142:3:146:3 | [BlockStmt] { c ... OK } | arrays.js:144:5:144:61 | [DeclStmt] const element1 = ... | semmle.order | 2 | +| arrays.js:142:3:146:3 | [BlockStmt] { c ... OK } | arrays.js:145:5:145:19 | [ExprStmt] sink(element1); | semmle.label | 3 | +| arrays.js:142:3:146:3 | [BlockStmt] { c ... OK } | arrays.js:145:5:145:19 | [ExprStmt] sink(element1); | semmle.order | 3 | +| arrays.js:143:5:143:25 | [DeclStmt] const arr = ... | arrays.js:143:11:143:24 | [VariableDeclarator] arr = source() | semmle.label | 1 | +| arrays.js:143:5:143:25 | [DeclStmt] const arr = ... | arrays.js:143:11:143:24 | [VariableDeclarator] arr = source() | semmle.order | 1 | +| arrays.js:143:11:143:24 | [VariableDeclarator] arr = source() | arrays.js:143:11:143:13 | [VarDecl] arr | semmle.label | 1 | +| arrays.js:143:11:143:24 | [VariableDeclarator] arr = source() | arrays.js:143:11:143:13 | [VarDecl] arr | semmle.order | 1 | +| arrays.js:143:11:143:24 | [VariableDeclarator] arr = source() | arrays.js:143:17:143:24 | [CallExpr] source() | semmle.label | 2 | +| arrays.js:143:11:143:24 | [VariableDeclarator] arr = source() | arrays.js:143:17:143:24 | [CallExpr] source() | semmle.order | 2 | +| arrays.js:143:17:143:24 | [CallExpr] source() | arrays.js:143:17:143:22 | [VarRef] source | semmle.label | 0 | +| arrays.js:143:17:143:24 | [CallExpr] source() | arrays.js:143:17:143:22 | [VarRef] source | semmle.order | 0 | +| arrays.js:144:5:144:61 | [DeclStmt] const element1 = ... | arrays.js:144:11:144:60 | [VariableDeclarator] element ... (item)) | semmle.label | 1 | +| arrays.js:144:5:144:61 | [DeclStmt] const element1 = ... | arrays.js:144:11:144:60 | [VariableDeclarator] element ... (item)) | semmle.order | 1 | +| arrays.js:144:11:144:60 | [VariableDeclarator] element ... (item)) | arrays.js:144:11:144:18 | [VarDecl] element1 | semmle.label | 1 | +| arrays.js:144:11:144:60 | [VariableDeclarator] element ... (item)) | arrays.js:144:11:144:18 | [VarDecl] element1 | semmle.order | 1 | +| arrays.js:144:11:144:60 | [VariableDeclarator] element ... (item)) | arrays.js:144:22:144:60 | [MethodCallExpr] arr.fin ... (item)) | semmle.label | 2 | +| arrays.js:144:11:144:60 | [VariableDeclarator] element ... (item)) | arrays.js:144:22:144:60 | [MethodCallExpr] arr.fin ... (item)) | semmle.order | 2 | +| arrays.js:144:22:144:38 | [DotExpr] arr.findLastIndex | arrays.js:144:22:144:24 | [VarRef] arr | semmle.label | 1 | +| arrays.js:144:22:144:38 | [DotExpr] arr.findLastIndex | arrays.js:144:22:144:24 | [VarRef] arr | semmle.order | 1 | +| arrays.js:144:22:144:38 | [DotExpr] arr.findLastIndex | arrays.js:144:26:144:38 | [Label] findLastIndex | semmle.label | 2 | +| arrays.js:144:22:144:38 | [DotExpr] arr.findLastIndex | arrays.js:144:26:144:38 | [Label] findLastIndex | semmle.order | 2 | +| arrays.js:144:22:144:60 | [MethodCallExpr] arr.fin ... (item)) | arrays.js:144:22:144:38 | [DotExpr] arr.findLastIndex | semmle.label | 0 | +| arrays.js:144:22:144:60 | [MethodCallExpr] arr.fin ... (item)) | arrays.js:144:22:144:38 | [DotExpr] arr.findLastIndex | semmle.order | 0 | +| arrays.js:144:22:144:60 | [MethodCallExpr] arr.fin ... (item)) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| arrays.js:144:22:144:60 | [MethodCallExpr] arr.fin ... (item)) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| arrays.js:144:40:144:59 | [ArrowFunctionExpr] (item) => sink(item) | arrays.js:144:50:144:59 | [CallExpr] sink(item) | semmle.label | 5 | +| arrays.js:144:40:144:59 | [ArrowFunctionExpr] (item) => sink(item) | arrays.js:144:50:144:59 | [CallExpr] sink(item) | semmle.order | 5 | +| arrays.js:144:40:144:59 | [ArrowFunctionExpr] (item) => sink(item) | file://:0:0:0:0 | (Parameters) | semmle.label | 1 | +| arrays.js:144:40:144:59 | [ArrowFunctionExpr] (item) => sink(item) | file://:0:0:0:0 | (Parameters) | semmle.order | 1 | +| arrays.js:144:50:144:59 | [CallExpr] sink(item) | arrays.js:144:50:144:53 | [VarRef] sink | semmle.label | 0 | +| arrays.js:144:50:144:59 | [CallExpr] sink(item) | arrays.js:144:50:144:53 | [VarRef] sink | semmle.order | 0 | +| arrays.js:144:50:144:59 | [CallExpr] sink(item) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| arrays.js:144:50:144:59 | [CallExpr] sink(item) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| arrays.js:145:5:145:18 | [CallExpr] sink(element1) | arrays.js:145:5:145:8 | [VarRef] sink | semmle.label | 0 | +| arrays.js:145:5:145:18 | [CallExpr] sink(element1) | arrays.js:145:5:145:8 | [VarRef] sink | semmle.order | 0 | +| arrays.js:145:5:145:18 | [CallExpr] sink(element1) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| arrays.js:145:5:145:18 | [CallExpr] sink(element1) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| arrays.js:145:5:145:19 | [ExprStmt] sink(element1); | arrays.js:145:5:145:18 | [CallExpr] sink(element1) | semmle.label | 1 | +| arrays.js:145:5:145:19 | [ExprStmt] sink(element1); | arrays.js:145:5:145:18 | [CallExpr] sink(element1) | semmle.order | 1 | | file://:0:0:0:0 | (Arguments) | arrays.js:5:8:5:14 | [DotExpr] obj.foo | semmle.label | 0 | | file://:0:0:0:0 | (Arguments) | arrays.js:5:8:5:14 | [DotExpr] obj.foo | semmle.order | 0 | | file://:0:0:0:0 | (Arguments) | arrays.js:8:12:8:17 | [VarRef] source | semmle.label | 0 | @@ -1634,6 +2080,46 @@ edges | file://:0:0:0:0 | (Arguments) | arrays.js:108:45:108:50 | [SpreadElement] ...arr | semmle.order | 2 | | file://:0:0:0:0 | (Arguments) | arrays.js:109:8:109:24 | [MethodCallExpr] arr8_spread.pop() | semmle.label | 0 | | file://:0:0:0:0 | (Arguments) | arrays.js:109:8:109:24 | [MethodCallExpr] arr8_spread.pop() | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:111:8:111:33 | [MethodCallExpr] arr.fin ... llback) | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:111:8:111:33 | [MethodCallExpr] arr.fin ... llback) | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:111:21:111:32 | [VarRef] someCallback | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:111:21:111:32 | [VarRef] someCallback | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:115:35:115:54 | [ArrowFunctionExpr] (item) => sink(item) | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:115:35:115:54 | [ArrowFunctionExpr] (item) => sink(item) | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:115:50:115:53 | [VarRef] item | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:115:50:115:53 | [VarRef] item | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:116:10:116:16 | [VarRef] element | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:116:10:116:16 | [VarRef] element | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:121:31:121:50 | [ArrowFunctionExpr] (item) => sink(item) | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:121:31:121:50 | [ArrowFunctionExpr] (item) => sink(item) | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:121:46:121:49 | [VarRef] item | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:121:46:121:49 | [VarRef] item | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:122:10:122:16 | [VarRef] element | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:122:10:122:16 | [VarRef] element | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:127:40:127:59 | [ArrowFunctionExpr] (item) => sink(item) | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:127:40:127:59 | [ArrowFunctionExpr] (item) => sink(item) | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:127:55:127:58 | [VarRef] item | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:127:55:127:58 | [VarRef] item | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:128:10:128:16 | [VarRef] element | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:128:10:128:16 | [VarRef] element | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:132:31:132:50 | [ArrowFunctionExpr] (item) => sink(item) | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:132:31:132:50 | [ArrowFunctionExpr] (item) => sink(item) | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:132:46:132:49 | [VarRef] item | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:132:46:132:49 | [VarRef] item | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:133:10:133:17 | [VarRef] element1 | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:133:10:133:17 | [VarRef] element1 | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:138:35:138:54 | [ArrowFunctionExpr] (item) => sink(item) | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:138:35:138:54 | [ArrowFunctionExpr] (item) => sink(item) | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:138:50:138:53 | [VarRef] item | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:138:50:138:53 | [VarRef] item | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:139:10:139:17 | [VarRef] element1 | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:139:10:139:17 | [VarRef] element1 | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:144:40:144:59 | [ArrowFunctionExpr] (item) => sink(item) | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:144:40:144:59 | [ArrowFunctionExpr] (item) => sink(item) | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:144:55:144:58 | [VarRef] item | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:144:55:144:58 | [VarRef] item | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:145:10:145:17 | [VarRef] element1 | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:145:10:145:17 | [VarRef] element1 | semmle.order | 0 | | file://:0:0:0:0 | (Parameters) | arrays.js:15:16:15:16 | [SimpleParameter] e | semmle.label | 0 | | file://:0:0:0:0 | (Parameters) | arrays.js:15:16:15:16 | [SimpleParameter] e | semmle.order | 0 | | file://:0:0:0:0 | (Parameters) | arrays.js:16:12:16:12 | [SimpleParameter] e | semmle.label | 0 | @@ -1652,5 +2138,17 @@ edges | file://:0:0:0:0 | (Parameters) | arrays.js:95:27:95:27 | [SimpleParameter] x | semmle.order | 0 | | file://:0:0:0:0 | (Parameters) | arrays.js:96:27:96:27 | [SimpleParameter] x | semmle.label | 0 | | file://:0:0:0:0 | (Parameters) | arrays.js:96:27:96:27 | [SimpleParameter] x | semmle.order | 0 | +| file://:0:0:0:0 | (Parameters) | arrays.js:115:36:115:39 | [SimpleParameter] item | semmle.label | 0 | +| file://:0:0:0:0 | (Parameters) | arrays.js:115:36:115:39 | [SimpleParameter] item | semmle.order | 0 | +| file://:0:0:0:0 | (Parameters) | arrays.js:121:32:121:35 | [SimpleParameter] item | semmle.label | 0 | +| file://:0:0:0:0 | (Parameters) | arrays.js:121:32:121:35 | [SimpleParameter] item | semmle.order | 0 | +| file://:0:0:0:0 | (Parameters) | arrays.js:127:41:127:44 | [SimpleParameter] item | semmle.label | 0 | +| file://:0:0:0:0 | (Parameters) | arrays.js:127:41:127:44 | [SimpleParameter] item | semmle.order | 0 | +| file://:0:0:0:0 | (Parameters) | arrays.js:132:32:132:35 | [SimpleParameter] item | semmle.label | 0 | +| file://:0:0:0:0 | (Parameters) | arrays.js:132:32:132:35 | [SimpleParameter] item | semmle.order | 0 | +| file://:0:0:0:0 | (Parameters) | arrays.js:138:36:138:39 | [SimpleParameter] item | semmle.label | 0 | +| file://:0:0:0:0 | (Parameters) | arrays.js:138:36:138:39 | [SimpleParameter] item | semmle.order | 0 | +| file://:0:0:0:0 | (Parameters) | arrays.js:144:41:144:44 | [SimpleParameter] item | semmle.label | 0 | +| file://:0:0:0:0 | (Parameters) | arrays.js:144:41:144:44 | [SimpleParameter] item | semmle.order | 0 | graphProperties | semmle.graphKind | tree | diff --git a/javascript/ql/test/library-tests/EndpointNaming/EndpointNaming.expected b/javascript/ql/test/library-tests/EndpointNaming/EndpointNaming.expected index af5e8d62bb3..d2c34c887cc 100644 --- a/javascript/ql/test/library-tests/EndpointNaming/EndpointNaming.expected +++ b/javascript/ql/test/library-tests/EndpointNaming/EndpointNaming.expected @@ -5,4 +5,3 @@ ambiguousPreferredPredecessor | pack2/main.js:1:1:3:1 | def moduleImport("pack2").getMember("exports").getMember("MainClass").getInstance() | ambiguousSinkName ambiguousFunctionName -failures diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected index f81405a32a2..b6d5ab1e435 100644 --- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected @@ -209,6 +209,10 @@ typeInferenceMismatch | static-capture-groups.js:2:17:2:24 | source() | static-capture-groups.js:27:14:27:22 | RegExp.$1 | | static-capture-groups.js:32:17:32:24 | source() | static-capture-groups.js:38:10:38:18 | RegExp.$1 | | static-capture-groups.js:42:12:42:19 | source() | static-capture-groups.js:43:14:43:22 | RegExp.$1 | +| string-immutable-operations.js:2:13:2:20 | source() | string-immutable-operations.js:3:10:3:25 | x.toWellFormed() | +| string-immutable-operations.js:2:13:2:20 | source() | string-immutable-operations.js:6:10:6:20 | wellFormedX | +| string-immutable-operations.js:2:13:2:20 | source() | string-immutable-operations.js:9:10:9:26 | concatWellFormedX | +| string-immutable-operations.js:11:10:11:17 | source() | string-immutable-operations.js:11:10:11:32 | source( ... ormed() | | string-replace.js:3:13:3:20 | source() | string-replace.js:14:10:14:13 | data | | string-replace.js:3:13:3:20 | source() | string-replace.js:18:10:18:13 | data | | string-replace.js:3:13:3:20 | source() | string-replace.js:21:6:21:41 | safe(). ... taint) | @@ -244,8 +248,19 @@ typeInferenceMismatch | tst.js:2:13:2:20 | source() | tst.js:66:10:66:16 | xSorted | | tst.js:2:13:2:20 | source() | tst.js:68:10:68:23 | x.toReversed() | | tst.js:2:13:2:20 | source() | tst.js:70:10:70:18 | xReversed | -| tst.js:2:13:2:20 | source() | tst.js:72:10:72:17 | x.with() | -| tst.js:2:13:2:20 | source() | tst.js:74:10:74:14 | xWith | +| tst.js:2:13:2:20 | source() | tst.js:72:10:72:31 | Map.gro ... z => z) | +| tst.js:2:13:2:20 | source() | tst.js:74:10:74:34 | Object. ... z => z) | +| tst.js:2:13:2:20 | source() | tst.js:78:55:78:58 | item | +| tst.js:2:13:2:20 | source() | tst.js:79:14:79:20 | grouped | +| tst.js:2:13:2:20 | source() | tst.js:100:10:100:17 | x.with() | +| tst.js:2:13:2:20 | source() | tst.js:102:10:102:14 | xWith | +| tst.js:75:22:75:29 | source() | tst.js:75:10:75:52 | Map.gro ... (item)) | +| tst.js:75:22:75:29 | source() | tst.js:75:47:75:50 | item | +| tst.js:82:23:82:30 | source() | tst.js:83:58:83:61 | item | +| tst.js:82:23:82:30 | source() | tst.js:84:14:84:20 | grouped | +| tst.js:87:22:87:29 | source() | tst.js:90:14:90:25 | taintedValue | +| tst.js:93:22:93:29 | source() | tst.js:96:14:96:25 | taintedValue | +| tst.js:93:22:93:29 | source() | tst.js:97:14:97:26 | map.get(true) | | xml.js:5:18:5:25 | source() | xml.js:8:14:8:17 | text | | xml.js:12:17:12:24 | source() | xml.js:13:14:13:19 | result | | xml.js:23:18:23:25 | source() | xml.js:20:14:20:17 | attr | diff --git a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected index 33a27661ecd..3b89229b2d7 100644 --- a/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected @@ -112,3 +112,5 @@ | thisAssignments.js:7:19:7:26 | source() | thisAssignments.js:8:10:8:20 | this.field2 | | tst.js:2:13:2:20 | source() | tst.js:4:10:4:10 | x | | tst.js:2:13:2:20 | source() | tst.js:54:14:54:19 | unsafe | +| tst.js:93:22:93:29 | source() | tst.js:96:14:96:25 | taintedValue | +| tst.js:93:22:93:29 | source() | tst.js:97:14:97:26 | map.get(true) | diff --git a/javascript/ql/test/library-tests/TaintTracking/string-immutable-operations.js b/javascript/ql/test/library-tests/TaintTracking/string-immutable-operations.js new file mode 100644 index 00000000000..79e93fab002 --- /dev/null +++ b/javascript/ql/test/library-tests/TaintTracking/string-immutable-operations.js @@ -0,0 +1,12 @@ +function test() { + let x = source(); + sink(x.toWellFormed()); // NOT OK + + const wellFormedX = x.toWellFormed(); + sink(wellFormedX); // NOT OK + + const concatWellFormedX = "/" + wellFormedX + "!"; + sink(concatWellFormedX); // NOT OK + + sink(source().toWellFormed()); // NOT OK +} diff --git a/javascript/ql/test/library-tests/TaintTracking/tst.js b/javascript/ql/test/library-tests/TaintTracking/tst.js index 13b4ea48d8d..8fbc5e525bd 100644 --- a/javascript/ql/test/library-tests/TaintTracking/tst.js +++ b/javascript/ql/test/library-tests/TaintTracking/tst.js @@ -69,6 +69,34 @@ function test() { const xReversed = x.toReversed(); sink(xReversed) // NOT OK + sink(Map.groupBy(x, z => z)); // NOT OK + sink(Custom.groupBy(x, z => z)); // OK + sink(Object.groupBy(x, z => z)); // NOT OK + sink(Map.groupBy(source(), (item) => sink(item))); // NOT OK + + { + const grouped = Map.groupBy(x, (item) => sink(item)); // NOT OK + sink(grouped); // NOT OK + } + { + const list = [source()]; + const grouped = Map.groupBy(list, (item) => sink(item)); // NOT OK + sink(grouped); // NOT OK + } + { + const data = source(); + const result = Object.groupBy(data, item => item); + const taintedValue = result[notDefined()]; + sink(taintedValue); // NOT OK + } + { + const data = source(); + const map = Map.groupBy(data, item => item); + const taintedValue = map.get(true); + sink(taintedValue); // NOT OK + sink(map.get(true)); // NOT OK + } + sink(x.with()) // NOT OK const xWith = x.with(); sink(xWith) // NOT OK diff --git a/javascript/ql/test/library-tests/TypeScript/Types/printAst.expected b/javascript/ql/test/library-tests/TypeScript/Types/printAst.expected index 3061a6ba1f0..df304b899bb 100644 --- a/javascript/ql/test/library-tests/TypeScript/Types/printAst.expected +++ b/javascript/ql/test/library-tests/TypeScript/Types/printAst.expected @@ -1877,8 +1877,35 @@ nodes | tst.ts:508:17:508:38 | [MethodCallExpr] obj[key ... rCase() | semmle.label | [MethodCallExpr] obj[key ... rCase() | | tst.ts:508:21:508:23 | [VarRef] key | semmle.label | [VarRef] key | | tst.ts:508:26:508:36 | [Label] toUpperCase | semmle.label | [Label] toUpperCase | +| tst.ts:513:1:520:1 | [NamespaceDeclaration] namespa ... type. } | semmle.label | [NamespaceDeclaration] namespa ... type. } | +| tst.ts:513:1:520:1 | [NamespaceDeclaration] namespa ... type. } | semmle.order | 92 | +| tst.ts:513:11:513:14 | [VarDecl] TS57 | semmle.label | [VarDecl] TS57 | +| tst.ts:514:3:514:26 | [DeclStmt] const a = ... | semmle.label | [DeclStmt] const a = ... | +| tst.ts:514:17:514:17 | [VarDecl] a | semmle.label | [VarDecl] a | +| tst.ts:514:17:514:25 | [VariableDeclarator] a: symbol | semmle.label | [VariableDeclarator] a: symbol | +| tst.ts:514:20:514:25 | [KeywordTypeExpr] symbol | semmle.label | [KeywordTypeExpr] symbol | +| tst.ts:515:3:517:3 | [ExportDeclaration] export ... }; } | semmle.label | [ExportDeclaration] export ... }; } | +| tst.ts:515:10:517:3 | [ClassDefinition,TypeDefinition] class A ... }; } | semmle.label | [ClassDefinition,TypeDefinition] class A ... }; } | +| tst.ts:515:16:515:16 | [VarDecl] A | semmle.label | [VarDecl] A | +| tst.ts:515:18:515:17 | [BlockStmt] {} | semmle.label | [BlockStmt] {} | +| tst.ts:515:18:515:17 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | semmle.label | [ClassInitializedMember,ConstructorDefinition] constructor() {} | +| tst.ts:515:18:515:17 | [FunctionExpr] () {} | semmle.label | [FunctionExpr] () {} | +| tst.ts:515:18:515:17 | [Label] constructor | semmle.label | [Label] constructor | +| tst.ts:516:7:516:24 | [ClassInitializedMember,MethodDefinition] [a]() { return 1 } | semmle.label | [ClassInitializedMember,MethodDefinition] [a]() { return 1 } | +| tst.ts:516:7:516:24 | [FunctionExpr] [a]() { return 1 } | semmle.label | [FunctionExpr] [a]() { return 1 } | +| tst.ts:516:8:516:8 | [VarRef] a | semmle.label | [VarRef] a | +| tst.ts:516:13:516:24 | [BlockStmt] { return 1 } | semmle.label | [BlockStmt] { return 1 } | +| tst.ts:516:15:516:22 | [ReturnStmt] return 1 | semmle.label | [ReturnStmt] return 1 | +| tst.ts:516:22:516:22 | [Literal] 1 | semmle.label | [Literal] 1 | +| tst.ts:519:3:519:32 | [DeclStmt] const e1 = ... | semmle.label | [DeclStmt] const e1 = ... | +| tst.ts:519:17:519:18 | [VarDecl] e1 | semmle.label | [VarDecl] e1 | +| tst.ts:519:17:519:31 | [VariableDeclarator] e1: A[typeof a] | semmle.label | [VariableDeclarator] e1: A[typeof a] | +| tst.ts:519:21:519:21 | [LocalTypeAccess] A | semmle.label | [LocalTypeAccess] A | +| tst.ts:519:21:519:31 | [IndexedAccessTypeExpr] A[typeof a] | semmle.label | [IndexedAccessTypeExpr] A[typeof a] | +| tst.ts:519:23:519:30 | [TypeofTypeExpr] typeof a | semmle.label | [TypeofTypeExpr] typeof a | +| tst.ts:519:30:519:30 | [LocalVarTypeAccess] a | semmle.label | [LocalVarTypeAccess] a | | tstModuleCJS.cts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | semmle.label | [ExportDeclaration] export ... 'b'; } | -| tstModuleCJS.cts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | semmle.order | 92 | +| tstModuleCJS.cts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | semmle.order | 93 | | tstModuleCJS.cts:1:8:3:1 | [FunctionDeclStmt] functio ... 'b'; } | semmle.label | [FunctionDeclStmt] functio ... 'b'; } | | tstModuleCJS.cts:1:17:1:28 | [VarDecl] tstModuleCJS | semmle.label | [VarDecl] tstModuleCJS | | tstModuleCJS.cts:1:33:1:35 | [LiteralTypeExpr] 'a' | semmle.label | [LiteralTypeExpr] 'a' | @@ -1896,7 +1923,7 @@ nodes | tstModuleCJS.cts:2:34:2:36 | [Literal] 'a' | semmle.label | [Literal] 'a' | | tstModuleCJS.cts:2:40:2:42 | [Literal] 'b' | semmle.label | [Literal] 'b' | | tstModuleES.mts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | semmle.label | [ExportDeclaration] export ... 'b'; } | -| tstModuleES.mts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | semmle.order | 93 | +| tstModuleES.mts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | semmle.order | 94 | | tstModuleES.mts:1:16:3:1 | [FunctionDeclStmt] functio ... 'b'; } | semmle.label | [FunctionDeclStmt] functio ... 'b'; } | | tstModuleES.mts:1:25:1:35 | [VarDecl] tstModuleES | semmle.label | [VarDecl] tstModuleES | | tstModuleES.mts:1:40:1:42 | [LiteralTypeExpr] 'a' | semmle.label | [LiteralTypeExpr] 'a' | @@ -1914,7 +1941,7 @@ nodes | tstModuleES.mts:2:34:2:36 | [Literal] 'a' | semmle.label | [Literal] 'a' | | tstModuleES.mts:2:40:2:42 | [Literal] 'b' | semmle.label | [Literal] 'b' | | tstSuffixA.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.label | [ExportDeclaration] export ... .ts'; } | -| tstSuffixA.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.order | 94 | +| tstSuffixA.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.order | 95 | | tstSuffixA.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | semmle.label | [FunctionDeclStmt] functio ... .ts'; } | | tstSuffixA.ts:1:17:1:28 | [VarDecl] resolvedFile | semmle.label | [VarDecl] resolvedFile | | tstSuffixA.ts:1:33:1:47 | [LiteralTypeExpr] 'tstSuffixA.ts' | semmle.label | [LiteralTypeExpr] 'tstSuffixA.ts' | @@ -1922,7 +1949,7 @@ nodes | tstSuffixA.ts:2:5:2:27 | [ReturnStmt] return ... xA.ts'; | semmle.label | [ReturnStmt] return ... xA.ts'; | | tstSuffixA.ts:2:12:2:26 | [Literal] 'tstSuffixA.ts' | semmle.label | [Literal] 'tstSuffixA.ts' | | tstSuffixB.ios.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.label | [ExportDeclaration] export ... .ts'; } | -| tstSuffixB.ios.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.order | 95 | +| tstSuffixB.ios.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.order | 96 | | tstSuffixB.ios.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | semmle.label | [FunctionDeclStmt] functio ... .ts'; } | | tstSuffixB.ios.ts:1:17:1:28 | [VarDecl] resolvedFile | semmle.label | [VarDecl] resolvedFile | | tstSuffixB.ios.ts:1:33:1:51 | [LiteralTypeExpr] 'tstSuffixB.ios.ts' | semmle.label | [LiteralTypeExpr] 'tstSuffixB.ios.ts' | @@ -1930,7 +1957,7 @@ nodes | tstSuffixB.ios.ts:2:5:2:31 | [ReturnStmt] return ... os.ts'; | semmle.label | [ReturnStmt] return ... os.ts'; | | tstSuffixB.ios.ts:2:12:2:30 | [Literal] 'tstSuffixB.ios.ts' | semmle.label | [Literal] 'tstSuffixB.ios.ts' | | tstSuffixB.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.label | [ExportDeclaration] export ... .ts'; } | -| tstSuffixB.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.order | 96 | +| tstSuffixB.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.order | 97 | | tstSuffixB.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | semmle.label | [FunctionDeclStmt] functio ... .ts'; } | | tstSuffixB.ts:1:17:1:28 | [VarDecl] resolvedFile | semmle.label | [VarDecl] resolvedFile | | tstSuffixB.ts:1:33:1:47 | [LiteralTypeExpr] 'tstSuffixB.ts' | semmle.label | [LiteralTypeExpr] 'tstSuffixB.ts' | @@ -1938,16 +1965,16 @@ nodes | tstSuffixB.ts:2:5:2:27 | [ReturnStmt] return ... xB.ts'; | semmle.label | [ReturnStmt] return ... xB.ts'; | | tstSuffixB.ts:2:12:2:26 | [Literal] 'tstSuffixB.ts' | semmle.label | [Literal] 'tstSuffixB.ts' | | type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | -| type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | semmle.order | 97 | +| type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | semmle.order | 98 | | type_alias.ts:1:6:1:6 | [Identifier] B | semmle.label | [Identifier] B | | type_alias.ts:1:10:1:16 | [KeywordTypeExpr] boolean | semmle.label | [KeywordTypeExpr] boolean | | type_alias.ts:3:1:3:9 | [DeclStmt] var b = ... | semmle.label | [DeclStmt] var b = ... | -| type_alias.ts:3:1:3:9 | [DeclStmt] var b = ... | semmle.order | 98 | +| type_alias.ts:3:1:3:9 | [DeclStmt] var b = ... | semmle.order | 99 | | type_alias.ts:3:5:3:5 | [VarDecl] b | semmle.label | [VarDecl] b | | type_alias.ts:3:5:3:8 | [VariableDeclarator] b: B | semmle.label | [VariableDeclarator] b: B | | type_alias.ts:3:8:3:8 | [LocalTypeAccess] B | semmle.label | [LocalTypeAccess] B | | type_alias.ts:5:1:5:50 | [TypeAliasDeclaration,TypeDefinition] type Va ... ay>; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Va ... ay>; | -| type_alias.ts:5:1:5:50 | [TypeAliasDeclaration,TypeDefinition] type Va ... ay>; | semmle.order | 99 | +| type_alias.ts:5:1:5:50 | [TypeAliasDeclaration,TypeDefinition] type Va ... ay>; | semmle.order | 100 | | type_alias.ts:5:6:5:17 | [Identifier] ValueOrArray | semmle.label | [Identifier] ValueOrArray | | type_alias.ts:5:19:5:19 | [Identifier] T | semmle.label | [Identifier] T | | type_alias.ts:5:19:5:19 | [TypeParameter] T | semmle.label | [TypeParameter] T | @@ -1959,14 +1986,14 @@ nodes | type_alias.ts:5:34:5:48 | [GenericTypeExpr] ValueOrArray | semmle.label | [GenericTypeExpr] ValueOrArray | | type_alias.ts:5:47:5:47 | [LocalTypeAccess] T | semmle.label | [LocalTypeAccess] T | | type_alias.ts:7:1:7:28 | [DeclStmt] var c = ... | semmle.label | [DeclStmt] var c = ... | -| type_alias.ts:7:1:7:28 | [DeclStmt] var c = ... | semmle.order | 100 | +| type_alias.ts:7:1:7:28 | [DeclStmt] var c = ... | semmle.order | 101 | | type_alias.ts:7:5:7:5 | [VarDecl] c | semmle.label | [VarDecl] c | | type_alias.ts:7:5:7:27 | [VariableDeclarator] c: Valu ... number> | semmle.label | [VariableDeclarator] c: Valu ... number> | | type_alias.ts:7:8:7:19 | [LocalTypeAccess] ValueOrArray | semmle.label | [LocalTypeAccess] ValueOrArray | | type_alias.ts:7:8:7:27 | [GenericTypeExpr] ValueOrArray | semmle.label | [GenericTypeExpr] ValueOrArray | | type_alias.ts:7:21:7:26 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | | type_alias.ts:9:1:15:13 | [TypeAliasDeclaration,TypeDefinition] type Js ... Json[]; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Js ... Json[]; | -| type_alias.ts:9:1:15:13 | [TypeAliasDeclaration,TypeDefinition] type Js ... Json[]; | semmle.order | 101 | +| type_alias.ts:9:1:15:13 | [TypeAliasDeclaration,TypeDefinition] type Js ... Json[]; | semmle.order | 102 | | type_alias.ts:9:6:9:9 | [Identifier] Json | semmle.label | [Identifier] Json | | type_alias.ts:10:5:15:12 | [UnionTypeExpr] \| strin ... Json[] | semmle.label | [UnionTypeExpr] \| strin ... Json[] | | type_alias.ts:10:7:10:12 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string | @@ -1982,12 +2009,12 @@ nodes | type_alias.ts:15:7:15:10 | [LocalTypeAccess] Json | semmle.label | [LocalTypeAccess] Json | | type_alias.ts:15:7:15:12 | [ArrayTypeExpr] Json[] | semmle.label | [ArrayTypeExpr] Json[] | | type_alias.ts:17:1:17:15 | [DeclStmt] var json = ... | semmle.label | [DeclStmt] var json = ... | -| type_alias.ts:17:1:17:15 | [DeclStmt] var json = ... | semmle.order | 102 | +| type_alias.ts:17:1:17:15 | [DeclStmt] var json = ... | semmle.order | 103 | | type_alias.ts:17:5:17:8 | [VarDecl] json | semmle.label | [VarDecl] json | | type_alias.ts:17:5:17:14 | [VariableDeclarator] json: Json | semmle.label | [VariableDeclarator] json: Json | | type_alias.ts:17:11:17:14 | [LocalTypeAccess] Json | semmle.label | [LocalTypeAccess] Json | | type_alias.ts:19:1:21:57 | [TypeAliasDeclaration,TypeDefinition] type Vi ... ode[]]; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Vi ... ode[]]; | -| type_alias.ts:19:1:21:57 | [TypeAliasDeclaration,TypeDefinition] type Vi ... ode[]]; | semmle.order | 103 | +| type_alias.ts:19:1:21:57 | [TypeAliasDeclaration,TypeDefinition] type Vi ... ode[]]; | semmle.order | 104 | | type_alias.ts:19:6:19:16 | [Identifier] VirtualNode | semmle.label | [Identifier] VirtualNode | | type_alias.ts:20:5:21:56 | [UnionTypeExpr] \| strin ... Node[]] | semmle.label | [UnionTypeExpr] \| strin ... Node[]] | | type_alias.ts:20:7:20:12 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string | @@ -2003,7 +2030,7 @@ nodes | type_alias.ts:21:43:21:53 | [LocalTypeAccess] VirtualNode | semmle.label | [LocalTypeAccess] VirtualNode | | type_alias.ts:21:43:21:55 | [ArrayTypeExpr] VirtualNode[] | semmle.label | [ArrayTypeExpr] VirtualNode[] | | type_alias.ts:23:1:27:6 | [DeclStmt] const myNode = ... | semmle.label | [DeclStmt] const myNode = ... | -| type_alias.ts:23:1:27:6 | [DeclStmt] const myNode = ... | semmle.order | 104 | +| type_alias.ts:23:1:27:6 | [DeclStmt] const myNode = ... | semmle.order | 105 | | type_alias.ts:23:7:23:12 | [VarDecl] myNode | semmle.label | [VarDecl] myNode | | type_alias.ts:23:7:27:5 | [VariableDeclarator] myNode: ... ] ] | semmle.label | [VariableDeclarator] myNode: ... ] ] | | type_alias.ts:23:15:23:25 | [LocalTypeAccess] VirtualNode | semmle.label | [LocalTypeAccess] VirtualNode | @@ -2028,12 +2055,12 @@ nodes | type_alias.ts:26:23:26:36 | [Literal] "second-child" | semmle.label | [Literal] "second-child" | | type_alias.ts:26:41:26:62 | [Literal] "I'm the second child" | semmle.label | [Literal] "I'm the second child" | | type_definition_objects.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.label | [ImportDeclaration] import ... dummy"; | -| type_definition_objects.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 105 | +| type_definition_objects.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 106 | | type_definition_objects.ts:1:8:1:17 | [ImportSpecifier] * as dummy | semmle.label | [ImportSpecifier] * as dummy | | type_definition_objects.ts:1:13:1:17 | [VarDecl] dummy | semmle.label | [VarDecl] dummy | | type_definition_objects.ts:1:24:1:32 | [Literal] "./dummy" | semmle.label | [Literal] "./dummy" | | type_definition_objects.ts:3:1:3:17 | [ExportDeclaration] export class C {} | semmle.label | [ExportDeclaration] export class C {} | -| type_definition_objects.ts:3:1:3:17 | [ExportDeclaration] export class C {} | semmle.order | 106 | +| type_definition_objects.ts:3:1:3:17 | [ExportDeclaration] export class C {} | semmle.order | 107 | | type_definition_objects.ts:3:8:3:17 | [ClassDefinition,TypeDefinition] class C {} | semmle.label | [ClassDefinition,TypeDefinition] class C {} | | type_definition_objects.ts:3:14:3:14 | [VarDecl] C | semmle.label | [VarDecl] C | | type_definition_objects.ts:3:16:3:15 | [BlockStmt] {} | semmle.label | [BlockStmt] {} | @@ -2041,36 +2068,36 @@ nodes | type_definition_objects.ts:3:16:3:15 | [FunctionExpr] () {} | semmle.label | [FunctionExpr] () {} | | type_definition_objects.ts:3:16:3:15 | [Label] constructor | semmle.label | [Label] constructor | | type_definition_objects.ts:4:1:4:17 | [DeclStmt] let classObj = ... | semmle.label | [DeclStmt] let classObj = ... | -| type_definition_objects.ts:4:1:4:17 | [DeclStmt] let classObj = ... | semmle.order | 107 | +| type_definition_objects.ts:4:1:4:17 | [DeclStmt] let classObj = ... | semmle.order | 108 | | type_definition_objects.ts:4:5:4:12 | [VarDecl] classObj | semmle.label | [VarDecl] classObj | | type_definition_objects.ts:4:5:4:16 | [VariableDeclarator] classObj = C | semmle.label | [VariableDeclarator] classObj = C | | type_definition_objects.ts:4:16:4:16 | [VarRef] C | semmle.label | [VarRef] C | | type_definition_objects.ts:6:1:6:16 | [ExportDeclaration] export enum E {} | semmle.label | [ExportDeclaration] export enum E {} | -| type_definition_objects.ts:6:1:6:16 | [ExportDeclaration] export enum E {} | semmle.order | 108 | +| type_definition_objects.ts:6:1:6:16 | [ExportDeclaration] export enum E {} | semmle.order | 109 | | type_definition_objects.ts:6:8:6:16 | [EnumDeclaration,TypeDefinition] enum E {} | semmle.label | [EnumDeclaration,TypeDefinition] enum E {} | | type_definition_objects.ts:6:13:6:13 | [VarDecl] E | semmle.label | [VarDecl] E | | type_definition_objects.ts:7:1:7:16 | [DeclStmt] let enumObj = ... | semmle.label | [DeclStmt] let enumObj = ... | -| type_definition_objects.ts:7:1:7:16 | [DeclStmt] let enumObj = ... | semmle.order | 109 | +| type_definition_objects.ts:7:1:7:16 | [DeclStmt] let enumObj = ... | semmle.order | 110 | | type_definition_objects.ts:7:5:7:11 | [VarDecl] enumObj | semmle.label | [VarDecl] enumObj | | type_definition_objects.ts:7:5:7:15 | [VariableDeclarator] enumObj = E | semmle.label | [VariableDeclarator] enumObj = E | | type_definition_objects.ts:7:15:7:15 | [VarRef] E | semmle.label | [VarRef] E | | type_definition_objects.ts:9:1:9:22 | [ExportDeclaration] export ... e N {;} | semmle.label | [ExportDeclaration] export ... e N {;} | -| type_definition_objects.ts:9:1:9:22 | [ExportDeclaration] export ... e N {;} | semmle.order | 110 | +| type_definition_objects.ts:9:1:9:22 | [ExportDeclaration] export ... e N {;} | semmle.order | 111 | | type_definition_objects.ts:9:8:9:22 | [NamespaceDeclaration] namespace N {;} | semmle.label | [NamespaceDeclaration] namespace N {;} | | type_definition_objects.ts:9:18:9:18 | [VarDecl] N | semmle.label | [VarDecl] N | | type_definition_objects.ts:9:21:9:21 | [EmptyStmt] ; | semmle.label | [EmptyStmt] ; | | type_definition_objects.ts:10:1:10:21 | [DeclStmt] let namespaceObj = ... | semmle.label | [DeclStmt] let namespaceObj = ... | -| type_definition_objects.ts:10:1:10:21 | [DeclStmt] let namespaceObj = ... | semmle.order | 111 | +| type_definition_objects.ts:10:1:10:21 | [DeclStmt] let namespaceObj = ... | semmle.order | 112 | | type_definition_objects.ts:10:5:10:16 | [VarDecl] namespaceObj | semmle.label | [VarDecl] namespaceObj | | type_definition_objects.ts:10:5:10:20 | [VariableDeclarator] namespaceObj = N | semmle.label | [VariableDeclarator] namespaceObj = N | | type_definition_objects.ts:10:20:10:20 | [VarRef] N | semmle.label | [VarRef] N | | type_definitions.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.label | [ImportDeclaration] import ... dummy"; | -| type_definitions.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 112 | +| type_definitions.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 113 | | type_definitions.ts:1:8:1:17 | [ImportSpecifier] * as dummy | semmle.label | [ImportSpecifier] * as dummy | | type_definitions.ts:1:13:1:17 | [VarDecl] dummy | semmle.label | [VarDecl] dummy | | type_definitions.ts:1:24:1:32 | [Literal] "./dummy" | semmle.label | [Literal] "./dummy" | | type_definitions.ts:3:1:5:1 | [InterfaceDeclaration,TypeDefinition] interfa ... x: S; } | semmle.label | [InterfaceDeclaration,TypeDefinition] interfa ... x: S; } | -| type_definitions.ts:3:1:5:1 | [InterfaceDeclaration,TypeDefinition] interfa ... x: S; } | semmle.order | 113 | +| type_definitions.ts:3:1:5:1 | [InterfaceDeclaration,TypeDefinition] interfa ... x: S; } | semmle.order | 114 | | type_definitions.ts:3:11:3:11 | [Identifier] I | semmle.label | [Identifier] I | | type_definitions.ts:3:13:3:13 | [Identifier] S | semmle.label | [Identifier] S | | type_definitions.ts:3:13:3:13 | [TypeParameter] S | semmle.label | [TypeParameter] S | @@ -2078,14 +2105,14 @@ nodes | type_definitions.ts:4:3:4:7 | [FieldDeclaration] x: S; | semmle.label | [FieldDeclaration] x: S; | | type_definitions.ts:4:6:4:6 | [LocalTypeAccess] S | semmle.label | [LocalTypeAccess] S | | type_definitions.ts:6:1:6:16 | [DeclStmt] let i = ... | semmle.label | [DeclStmt] let i = ... | -| type_definitions.ts:6:1:6:16 | [DeclStmt] let i = ... | semmle.order | 114 | +| type_definitions.ts:6:1:6:16 | [DeclStmt] let i = ... | semmle.order | 115 | | type_definitions.ts:6:5:6:5 | [VarDecl] i | semmle.label | [VarDecl] i | | type_definitions.ts:6:5:6:16 | [VariableDeclarator] i: I | semmle.label | [VariableDeclarator] i: I | | type_definitions.ts:6:8:6:8 | [LocalTypeAccess] I | semmle.label | [LocalTypeAccess] I | | type_definitions.ts:6:8:6:16 | [GenericTypeExpr] I | semmle.label | [GenericTypeExpr] I | | type_definitions.ts:6:10:6:15 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | | type_definitions.ts:8:1:10:1 | [ClassDefinition,TypeDefinition] class C ... x: T } | semmle.label | [ClassDefinition,TypeDefinition] class C ... x: T } | -| type_definitions.ts:8:1:10:1 | [ClassDefinition,TypeDefinition] class C ... x: T } | semmle.order | 115 | +| type_definitions.ts:8:1:10:1 | [ClassDefinition,TypeDefinition] class C ... x: T } | semmle.order | 116 | | type_definitions.ts:8:7:8:7 | [VarDecl] C | semmle.label | [VarDecl] C | | type_definitions.ts:8:8:8:7 | [BlockStmt] {} | semmle.label | [BlockStmt] {} | | type_definitions.ts:8:8:8:7 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | semmle.label | [ClassInitializedMember,ConstructorDefinition] constructor() {} | @@ -2097,14 +2124,14 @@ nodes | type_definitions.ts:9:3:9:6 | [FieldDeclaration] x: T | semmle.label | [FieldDeclaration] x: T | | type_definitions.ts:9:6:9:6 | [LocalTypeAccess] T | semmle.label | [LocalTypeAccess] T | | type_definitions.ts:11:1:11:17 | [DeclStmt] let c = ... | semmle.label | [DeclStmt] let c = ... | -| type_definitions.ts:11:1:11:17 | [DeclStmt] let c = ... | semmle.order | 116 | +| type_definitions.ts:11:1:11:17 | [DeclStmt] let c = ... | semmle.order | 117 | | type_definitions.ts:11:5:11:5 | [VarDecl] c | semmle.label | [VarDecl] c | | type_definitions.ts:11:5:11:16 | [VariableDeclarator] c: C | semmle.label | [VariableDeclarator] c: C | | type_definitions.ts:11:8:11:8 | [LocalTypeAccess] C | semmle.label | [LocalTypeAccess] C | | type_definitions.ts:11:8:11:16 | [GenericTypeExpr] C | semmle.label | [GenericTypeExpr] C | | type_definitions.ts:11:10:11:15 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | | type_definitions.ts:13:1:15:1 | [EnumDeclaration,TypeDefinition] enum Co ... blue } | semmle.label | [EnumDeclaration,TypeDefinition] enum Co ... blue } | -| type_definitions.ts:13:1:15:1 | [EnumDeclaration,TypeDefinition] enum Co ... blue } | semmle.order | 117 | +| type_definitions.ts:13:1:15:1 | [EnumDeclaration,TypeDefinition] enum Co ... blue } | semmle.order | 118 | | type_definitions.ts:13:6:13:10 | [VarDecl] Color | semmle.label | [VarDecl] Color | | type_definitions.ts:14:3:14:5 | [EnumMember,TypeDefinition] red | semmle.label | [EnumMember,TypeDefinition] red | | type_definitions.ts:14:3:14:5 | [VarDecl] red | semmle.label | [VarDecl] red | @@ -2113,29 +2140,29 @@ nodes | type_definitions.ts:14:15:14:18 | [EnumMember,TypeDefinition] blue | semmle.label | [EnumMember,TypeDefinition] blue | | type_definitions.ts:14:15:14:18 | [VarDecl] blue | semmle.label | [VarDecl] blue | | type_definitions.ts:16:1:16:17 | [DeclStmt] let color = ... | semmle.label | [DeclStmt] let color = ... | -| type_definitions.ts:16:1:16:17 | [DeclStmt] let color = ... | semmle.order | 118 | +| type_definitions.ts:16:1:16:17 | [DeclStmt] let color = ... | semmle.order | 119 | | type_definitions.ts:16:5:16:9 | [VarDecl] color | semmle.label | [VarDecl] color | | type_definitions.ts:16:5:16:16 | [VariableDeclarator] color: Color | semmle.label | [VariableDeclarator] color: Color | | type_definitions.ts:16:12:16:16 | [LocalTypeAccess] Color | semmle.label | [LocalTypeAccess] Color | | type_definitions.ts:18:1:18:33 | [EnumDeclaration,TypeDefinition] enum En ... ember } | semmle.label | [EnumDeclaration,TypeDefinition] enum En ... ember } | -| type_definitions.ts:18:1:18:33 | [EnumDeclaration,TypeDefinition] enum En ... ember } | semmle.order | 119 | +| type_definitions.ts:18:1:18:33 | [EnumDeclaration,TypeDefinition] enum En ... ember } | semmle.order | 120 | | type_definitions.ts:18:6:18:22 | [VarDecl] EnumWithOneMember | semmle.label | [VarDecl] EnumWithOneMember | | type_definitions.ts:18:26:18:31 | [EnumMember,TypeDefinition] member | semmle.label | [EnumMember,TypeDefinition] member | | type_definitions.ts:18:26:18:31 | [VarDecl] member | semmle.label | [VarDecl] member | | type_definitions.ts:19:1:19:25 | [DeclStmt] let e = ... | semmle.label | [DeclStmt] let e = ... | -| type_definitions.ts:19:1:19:25 | [DeclStmt] let e = ... | semmle.order | 120 | +| type_definitions.ts:19:1:19:25 | [DeclStmt] let e = ... | semmle.order | 121 | | type_definitions.ts:19:5:19:5 | [VarDecl] e | semmle.label | [VarDecl] e | | type_definitions.ts:19:5:19:24 | [VariableDeclarator] e: EnumWithOneMember | semmle.label | [VariableDeclarator] e: EnumWithOneMember | | type_definitions.ts:19:8:19:24 | [LocalTypeAccess] EnumWithOneMember | semmle.label | [LocalTypeAccess] EnumWithOneMember | | type_definitions.ts:21:1:21:20 | [TypeAliasDeclaration,TypeDefinition] type Alias = T[]; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Alias = T[]; | -| type_definitions.ts:21:1:21:20 | [TypeAliasDeclaration,TypeDefinition] type Alias = T[]; | semmle.order | 121 | +| type_definitions.ts:21:1:21:20 | [TypeAliasDeclaration,TypeDefinition] type Alias = T[]; | semmle.order | 122 | | type_definitions.ts:21:6:21:10 | [Identifier] Alias | semmle.label | [Identifier] Alias | | type_definitions.ts:21:12:21:12 | [Identifier] T | semmle.label | [Identifier] T | | type_definitions.ts:21:12:21:12 | [TypeParameter] T | semmle.label | [TypeParameter] T | | type_definitions.ts:21:17:21:17 | [LocalTypeAccess] T | semmle.label | [LocalTypeAccess] T | | type_definitions.ts:21:17:21:19 | [ArrayTypeExpr] T[] | semmle.label | [ArrayTypeExpr] T[] | | type_definitions.ts:22:1:22:39 | [DeclStmt] let aliasForNumberArray = ... | semmle.label | [DeclStmt] let aliasForNumberArray = ... | -| type_definitions.ts:22:1:22:39 | [DeclStmt] let aliasForNumberArray = ... | semmle.order | 122 | +| type_definitions.ts:22:1:22:39 | [DeclStmt] let aliasForNumberArray = ... | semmle.order | 123 | | type_definitions.ts:22:5:22:23 | [VarDecl] aliasForNumberArray | semmle.label | [VarDecl] aliasForNumberArray | | type_definitions.ts:22:5:22:38 | [VariableDeclarator] aliasFo ... number> | semmle.label | [VariableDeclarator] aliasFo ... number> | | type_definitions.ts:22:26:22:30 | [LocalTypeAccess] Alias | semmle.label | [LocalTypeAccess] Alias | @@ -5534,6 +5561,56 @@ edges | tst.ts:508:17:508:36 | [DotExpr] obj[key].toUpperCase | tst.ts:508:26:508:36 | [Label] toUpperCase | semmle.order | 2 | | tst.ts:508:17:508:38 | [MethodCallExpr] obj[key ... rCase() | tst.ts:508:17:508:36 | [DotExpr] obj[key].toUpperCase | semmle.label | 0 | | tst.ts:508:17:508:38 | [MethodCallExpr] obj[key ... rCase() | tst.ts:508:17:508:36 | [DotExpr] obj[key].toUpperCase | semmle.order | 0 | +| tst.ts:513:1:520:1 | [NamespaceDeclaration] namespa ... type. } | tst.ts:513:11:513:14 | [VarDecl] TS57 | semmle.label | 1 | +| tst.ts:513:1:520:1 | [NamespaceDeclaration] namespa ... type. } | tst.ts:513:11:513:14 | [VarDecl] TS57 | semmle.order | 1 | +| tst.ts:513:1:520:1 | [NamespaceDeclaration] namespa ... type. } | tst.ts:514:3:514:26 | [DeclStmt] const a = ... | semmle.label | 2 | +| tst.ts:513:1:520:1 | [NamespaceDeclaration] namespa ... type. } | tst.ts:514:3:514:26 | [DeclStmt] const a = ... | semmle.order | 2 | +| tst.ts:513:1:520:1 | [NamespaceDeclaration] namespa ... type. } | tst.ts:515:3:517:3 | [ExportDeclaration] export ... }; } | semmle.label | 3 | +| tst.ts:513:1:520:1 | [NamespaceDeclaration] namespa ... type. } | tst.ts:515:3:517:3 | [ExportDeclaration] export ... }; } | semmle.order | 3 | +| tst.ts:513:1:520:1 | [NamespaceDeclaration] namespa ... type. } | tst.ts:519:3:519:32 | [DeclStmt] const e1 = ... | semmle.label | 4 | +| tst.ts:513:1:520:1 | [NamespaceDeclaration] namespa ... type. } | tst.ts:519:3:519:32 | [DeclStmt] const e1 = ... | semmle.order | 4 | +| tst.ts:514:3:514:26 | [DeclStmt] const a = ... | tst.ts:514:17:514:25 | [VariableDeclarator] a: symbol | semmle.label | 1 | +| tst.ts:514:3:514:26 | [DeclStmt] const a = ... | tst.ts:514:17:514:25 | [VariableDeclarator] a: symbol | semmle.order | 1 | +| tst.ts:514:17:514:25 | [VariableDeclarator] a: symbol | tst.ts:514:17:514:17 | [VarDecl] a | semmle.label | 1 | +| tst.ts:514:17:514:25 | [VariableDeclarator] a: symbol | tst.ts:514:17:514:17 | [VarDecl] a | semmle.order | 1 | +| tst.ts:514:17:514:25 | [VariableDeclarator] a: symbol | tst.ts:514:20:514:25 | [KeywordTypeExpr] symbol | semmle.label | 2 | +| tst.ts:514:17:514:25 | [VariableDeclarator] a: symbol | tst.ts:514:20:514:25 | [KeywordTypeExpr] symbol | semmle.order | 2 | +| tst.ts:515:3:517:3 | [ExportDeclaration] export ... }; } | tst.ts:515:10:517:3 | [ClassDefinition,TypeDefinition] class A ... }; } | semmle.label | 1 | +| tst.ts:515:3:517:3 | [ExportDeclaration] export ... }; } | tst.ts:515:10:517:3 | [ClassDefinition,TypeDefinition] class A ... }; } | semmle.order | 1 | +| tst.ts:515:10:517:3 | [ClassDefinition,TypeDefinition] class A ... }; } | tst.ts:515:16:515:16 | [VarDecl] A | semmle.label | 1 | +| tst.ts:515:10:517:3 | [ClassDefinition,TypeDefinition] class A ... }; } | tst.ts:515:16:515:16 | [VarDecl] A | semmle.order | 1 | +| tst.ts:515:10:517:3 | [ClassDefinition,TypeDefinition] class A ... }; } | tst.ts:515:18:515:17 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | semmle.label | 2 | +| tst.ts:515:10:517:3 | [ClassDefinition,TypeDefinition] class A ... }; } | tst.ts:515:18:515:17 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | semmle.order | 2 | +| tst.ts:515:10:517:3 | [ClassDefinition,TypeDefinition] class A ... }; } | tst.ts:516:7:516:24 | [ClassInitializedMember,MethodDefinition] [a]() { return 1 } | semmle.label | 3 | +| tst.ts:515:10:517:3 | [ClassDefinition,TypeDefinition] class A ... }; } | tst.ts:516:7:516:24 | [ClassInitializedMember,MethodDefinition] [a]() { return 1 } | semmle.order | 3 | +| tst.ts:515:18:515:17 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | tst.ts:515:18:515:17 | [FunctionExpr] () {} | semmle.label | 2 | +| tst.ts:515:18:515:17 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | tst.ts:515:18:515:17 | [FunctionExpr] () {} | semmle.order | 2 | +| tst.ts:515:18:515:17 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | tst.ts:515:18:515:17 | [Label] constructor | semmle.label | 1 | +| tst.ts:515:18:515:17 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | tst.ts:515:18:515:17 | [Label] constructor | semmle.order | 1 | +| tst.ts:515:18:515:17 | [FunctionExpr] () {} | tst.ts:515:18:515:17 | [BlockStmt] {} | semmle.label | 5 | +| tst.ts:515:18:515:17 | [FunctionExpr] () {} | tst.ts:515:18:515:17 | [BlockStmt] {} | semmle.order | 5 | +| tst.ts:516:7:516:24 | [ClassInitializedMember,MethodDefinition] [a]() { return 1 } | tst.ts:516:7:516:24 | [FunctionExpr] [a]() { return 1 } | semmle.label | 1 | +| tst.ts:516:7:516:24 | [ClassInitializedMember,MethodDefinition] [a]() { return 1 } | tst.ts:516:7:516:24 | [FunctionExpr] [a]() { return 1 } | semmle.order | 1 | +| tst.ts:516:7:516:24 | [ClassInitializedMember,MethodDefinition] [a]() { return 1 } | tst.ts:516:8:516:8 | [VarRef] a | semmle.label | 2 | +| tst.ts:516:7:516:24 | [ClassInitializedMember,MethodDefinition] [a]() { return 1 } | tst.ts:516:8:516:8 | [VarRef] a | semmle.order | 2 | +| tst.ts:516:7:516:24 | [FunctionExpr] [a]() { return 1 } | tst.ts:516:13:516:24 | [BlockStmt] { return 1 } | semmle.label | 5 | +| tst.ts:516:7:516:24 | [FunctionExpr] [a]() { return 1 } | tst.ts:516:13:516:24 | [BlockStmt] { return 1 } | semmle.order | 5 | +| tst.ts:516:13:516:24 | [BlockStmt] { return 1 } | tst.ts:516:15:516:22 | [ReturnStmt] return 1 | semmle.label | 1 | +| tst.ts:516:13:516:24 | [BlockStmt] { return 1 } | tst.ts:516:15:516:22 | [ReturnStmt] return 1 | semmle.order | 1 | +| tst.ts:516:15:516:22 | [ReturnStmt] return 1 | tst.ts:516:22:516:22 | [Literal] 1 | semmle.label | 1 | +| tst.ts:516:15:516:22 | [ReturnStmt] return 1 | tst.ts:516:22:516:22 | [Literal] 1 | semmle.order | 1 | +| tst.ts:519:3:519:32 | [DeclStmt] const e1 = ... | tst.ts:519:17:519:31 | [VariableDeclarator] e1: A[typeof a] | semmle.label | 1 | +| tst.ts:519:3:519:32 | [DeclStmt] const e1 = ... | tst.ts:519:17:519:31 | [VariableDeclarator] e1: A[typeof a] | semmle.order | 1 | +| tst.ts:519:17:519:31 | [VariableDeclarator] e1: A[typeof a] | tst.ts:519:17:519:18 | [VarDecl] e1 | semmle.label | 1 | +| tst.ts:519:17:519:31 | [VariableDeclarator] e1: A[typeof a] | tst.ts:519:17:519:18 | [VarDecl] e1 | semmle.order | 1 | +| tst.ts:519:17:519:31 | [VariableDeclarator] e1: A[typeof a] | tst.ts:519:21:519:31 | [IndexedAccessTypeExpr] A[typeof a] | semmle.label | 2 | +| tst.ts:519:17:519:31 | [VariableDeclarator] e1: A[typeof a] | tst.ts:519:21:519:31 | [IndexedAccessTypeExpr] A[typeof a] | semmle.order | 2 | +| tst.ts:519:21:519:31 | [IndexedAccessTypeExpr] A[typeof a] | tst.ts:519:21:519:21 | [LocalTypeAccess] A | semmle.label | 1 | +| tst.ts:519:21:519:31 | [IndexedAccessTypeExpr] A[typeof a] | tst.ts:519:21:519:21 | [LocalTypeAccess] A | semmle.order | 1 | +| tst.ts:519:21:519:31 | [IndexedAccessTypeExpr] A[typeof a] | tst.ts:519:23:519:30 | [TypeofTypeExpr] typeof a | semmle.label | 2 | +| tst.ts:519:21:519:31 | [IndexedAccessTypeExpr] A[typeof a] | tst.ts:519:23:519:30 | [TypeofTypeExpr] typeof a | semmle.order | 2 | +| tst.ts:519:23:519:30 | [TypeofTypeExpr] typeof a | tst.ts:519:30:519:30 | [LocalVarTypeAccess] a | semmle.label | 1 | +| tst.ts:519:23:519:30 | [TypeofTypeExpr] typeof a | tst.ts:519:30:519:30 | [LocalVarTypeAccess] a | semmle.order | 1 | | tstModuleCJS.cts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | tstModuleCJS.cts:1:8:3:1 | [FunctionDeclStmt] functio ... 'b'; } | semmle.label | 1 | | tstModuleCJS.cts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | tstModuleCJS.cts:1:8:3:1 | [FunctionDeclStmt] functio ... 'b'; } | semmle.order | 1 | | tstModuleCJS.cts:1:8:3:1 | [FunctionDeclStmt] functio ... 'b'; } | tstModuleCJS.cts:1:17:1:28 | [VarDecl] tstModuleCJS | semmle.label | 0 | diff --git a/javascript/ql/test/library-tests/TypeScript/Types/tests.expected b/javascript/ql/test/library-tests/TypeScript/Types/tests.expected index b786fae3713..150ce186724 100644 --- a/javascript/ql/test/library-tests/TypeScript/Types/tests.expected +++ b/javascript/ql/test/library-tests/TypeScript/Types/tests.expected @@ -728,6 +728,13 @@ getExprType | tst.ts:508:17:508:38 | obj[key ... rCase() | string | | tst.ts:508:21:508:23 | key | string | | tst.ts:508:26:508:36 | toUpperCase | () => string | +| tst.ts:513:11:513:14 | TS57 | typeof TS57 in tst.ts | +| tst.ts:514:17:514:17 | a | symbol | +| tst.ts:515:16:515:16 | A | A | +| tst.ts:516:7:516:24 | [a]() { return 1 } | () => number | +| tst.ts:516:8:516:8 | a | symbol | +| tst.ts:516:22:516:22 | 1 | 1 | +| tst.ts:519:17:519:18 | e1 | () => number | | tstModuleCJS.cts:1:17:1:28 | tstModuleCJS | () => "a" \| "b" | | tstModuleCJS.cts:2:12:2:15 | Math | Math | | tstModuleCJS.cts:2:12:2:22 | Math.random | () => number | @@ -843,6 +850,7 @@ getTypeDefinitionType | tst.ts:447:5:458:5 | class P ... }\\n } | Person | | tst.ts:473:5:476:5 | class S ... ;\\n } | SomeClass | | tst.ts:481:5:481:34 | type Pa ... T, T]; | Pair3 | +| tst.ts:515:10:517:3 | class A ... };\\n } | A | | type_alias.ts:1:1:1:17 | type B = boolean; | boolean | | type_alias.ts:5:1:5:50 | type Va ... ay>; | ValueOrArray | | type_alias.ts:9:1:15:13 | type Js ... Json[]; | Json | @@ -1219,6 +1227,11 @@ getTypeExprType | tst.ts:506:27:506:32 | string | string | | tst.ts:506:35:506:41 | unknown | unknown | | tst.ts:506:50:506:55 | string | string | +| tst.ts:514:20:514:25 | symbol | symbol | +| tst.ts:519:21:519:21 | A | A | +| tst.ts:519:21:519:31 | A[typeof a] | () => number | +| tst.ts:519:23:519:30 | typeof a | symbol | +| tst.ts:519:30:519:30 | a | symbol | | tstModuleCJS.cts:1:33:1:35 | 'a' | "a" | | tstModuleCJS.cts:1:33:1:41 | 'a' \| 'b' | "a" \| "b" | | tstModuleCJS.cts:1:39:1:41 | 'b' | "b" | @@ -1290,6 +1303,7 @@ getTypeExprType missingToString referenceDefinition | A | badTypes.ts:5:1:5:29 | interfa ... is.B {} | +| A | tst.ts:515:10:517:3 | class A ... };\\n } | | Action | tst.ts:252:3:254:50 | type Ac ... ring }; | | Alias | type_definitions.ts:21:1:21:20 | type Alias = T[]; | | Alias | type_definitions.ts:21:1:21:20 | type Alias = T[]; | diff --git a/javascript/ql/test/library-tests/TypeScript/Types/tst.ts b/javascript/ql/test/library-tests/TypeScript/Types/tst.ts index 4c29465b564..87f876be9d0 100644 --- a/javascript/ql/test/library-tests/TypeScript/Types/tst.ts +++ b/javascript/ql/test/library-tests/TypeScript/Types/tst.ts @@ -508,4 +508,13 @@ module TS55 { var str = obj[key].toUpperCase(); // Now okay, previously was error } } -} \ No newline at end of file +} + +namespace TS57{ + declare const a: symbol; + export class A { + [a]() { return 1 }; + } + + declare const e1: A[typeof a]; // Now okay, previously was compilation error TS2538: Type 'symbol' cannot be used as an index type. +} diff --git a/javascript/ql/test/library-tests/threat-models/sources/TestSources.expected b/javascript/ql/test/library-tests/threat-models/sources/TestSources.expected index 8ec8033d086..e69de29bb2d 100644 --- a/javascript/ql/test/library-tests/threat-models/sources/TestSources.expected +++ b/javascript/ql/test/library-tests/threat-models/sources/TestSources.expected @@ -1,2 +0,0 @@ -testFailures -failures diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected index 0022ca69c6b..6a45147a4e2 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected @@ -1517,6 +1517,207 @@ nodes | TaintedPath.js:198:35:198:38 | path | | TaintedPath.js:198:35:198:38 | path | | TaintedPath.js:198:35:198:38 | path | +| TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:24:202:30 | req.url | +| TaintedPath.js:202:24:202:30 | req.url | +| TaintedPath.js:202:24:202:30 | req.url | +| TaintedPath.js:202:24:202:30 | req.url | +| TaintedPath.js:202:24:202:30 | req.url | +| TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:24:211:30 | req.url | +| TaintedPath.js:211:24:211:30 | req.url | +| TaintedPath.js:211:24:211:30 | req.url | +| TaintedPath.js:211:24:211:30 | req.url | +| TaintedPath.js:211:24:211:30 | req.url | +| TaintedPath.js:213:29:213:32 | path | +| TaintedPath.js:213:29:213:32 | path | +| TaintedPath.js:213:29:213:32 | path | +| TaintedPath.js:213:29:213:32 | path | +| TaintedPath.js:213:29:213:32 | path | +| TaintedPath.js:213:29:213:32 | path | +| TaintedPath.js:213:29:213:32 | path | +| TaintedPath.js:213:29:213:32 | path | +| TaintedPath.js:213:29:213:68 | path.re ... '), '') | +| TaintedPath.js:213:29:213:68 | path.re ... '), '') | +| TaintedPath.js:213:29:213:68 | path.re ... '), '') | +| TaintedPath.js:213:29:213:68 | path.re ... '), '') | +| TaintedPath.js:213:29:213:68 | path.re ... '), '') | +| TaintedPath.js:216:31:216:34 | path | +| TaintedPath.js:216:31:216:34 | path | +| TaintedPath.js:216:31:216:34 | path | +| TaintedPath.js:216:31:216:34 | path | +| TaintedPath.js:216:31:216:34 | path | +| TaintedPath.js:216:31:216:34 | path | +| TaintedPath.js:216:31:216:34 | path | +| TaintedPath.js:216:31:216:34 | path | +| TaintedPath.js:216:31:216:69 | path.re ... '), '') | +| TaintedPath.js:216:31:216:69 | path.re ... '), '') | +| TaintedPath.js:216:31:216:69 | path.re ... '), '') | +| TaintedPath.js:216:31:216:69 | path.re ... '), '') | +| TaintedPath.js:216:31:216:69 | path.re ... '), '') | +| TaintedPath.js:216:31:216:69 | path.re ... '), '') | +| TaintedPath.js:216:31:216:69 | path.re ... '), '') | +| TaintedPath.js:216:31:216:69 | path.re ... '), '') | +| TaintedPath.js:216:31:216:69 | path.re ... '), '') | | examples/TaintedPath.js:8:7:8:52 | filePath | | examples/TaintedPath.js:8:7:8:52 | filePath | | examples/TaintedPath.js:8:7:8:52 | filePath | @@ -6680,6 +6881,262 @@ edges | TaintedPath.js:195:24:195:30 | req.url | TaintedPath.js:195:14:195:37 | url.par ... , true) | | TaintedPath.js:195:24:195:30 | req.url | TaintedPath.js:195:14:195:37 | url.par ... , true) | | TaintedPath.js:195:24:195:30 | req.url | TaintedPath.js:195:14:195:37 | url.par ... , true) | +| TaintedPath.js:202:7:202:48 | path | TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:202:7:202:48 | path | TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:202:7:202:48 | path | TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:202:7:202:48 | path | TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:202:7:202:48 | path | TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:202:7:202:48 | path | TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:202:7:202:48 | path | TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:202:7:202:48 | path | TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:202:7:202:48 | path | TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:202:7:202:48 | path | TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:202:7:202:48 | path | TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:202:7:202:48 | path | TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:202:7:202:48 | path | TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:202:7:202:48 | path | TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:202:7:202:48 | path | TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:202:7:202:48 | path | TaintedPath.js:206:29:206:32 | path | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:37 | url.par ... , true) | TaintedPath.js:202:14:202:43 | url.par ... ).query | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:43 | url.par ... ).query | TaintedPath.js:202:14:202:48 | url.par ... ry.path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:14:202:48 | url.par ... ry.path | TaintedPath.js:202:7:202:48 | path | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:202:14:202:37 | url.par ... , true) | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:206:29:206:32 | path | TaintedPath.js:206:29:206:85 | path.re ... '), '') | +| TaintedPath.js:211:7:211:48 | path | TaintedPath.js:213:29:213:32 | path | +| TaintedPath.js:211:7:211:48 | path | TaintedPath.js:213:29:213:32 | path | +| TaintedPath.js:211:7:211:48 | path | TaintedPath.js:213:29:213:32 | path | +| TaintedPath.js:211:7:211:48 | path | TaintedPath.js:213:29:213:32 | path | +| TaintedPath.js:211:7:211:48 | path | TaintedPath.js:213:29:213:32 | path | +| TaintedPath.js:211:7:211:48 | path | TaintedPath.js:213:29:213:32 | path | +| TaintedPath.js:211:7:211:48 | path | TaintedPath.js:213:29:213:32 | path | +| TaintedPath.js:211:7:211:48 | path | TaintedPath.js:213:29:213:32 | path | +| TaintedPath.js:211:7:211:48 | path | TaintedPath.js:216:31:216:34 | path | +| TaintedPath.js:211:7:211:48 | path | TaintedPath.js:216:31:216:34 | path | +| TaintedPath.js:211:7:211:48 | path | TaintedPath.js:216:31:216:34 | path | +| TaintedPath.js:211:7:211:48 | path | TaintedPath.js:216:31:216:34 | path | +| TaintedPath.js:211:7:211:48 | path | TaintedPath.js:216:31:216:34 | path | +| TaintedPath.js:211:7:211:48 | path | TaintedPath.js:216:31:216:34 | path | +| TaintedPath.js:211:7:211:48 | path | TaintedPath.js:216:31:216:34 | path | +| TaintedPath.js:211:7:211:48 | path | TaintedPath.js:216:31:216:34 | path | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:37 | url.par ... , true) | TaintedPath.js:211:14:211:43 | url.par ... ).query | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:43 | url.par ... ).query | TaintedPath.js:211:14:211:48 | url.par ... ry.path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:14:211:48 | url.par ... ry.path | TaintedPath.js:211:7:211:48 | path | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:211:14:211:37 | url.par ... , true) | +| TaintedPath.js:213:29:213:32 | path | TaintedPath.js:213:29:213:68 | path.re ... '), '') | +| TaintedPath.js:213:29:213:32 | path | TaintedPath.js:213:29:213:68 | path.re ... '), '') | +| TaintedPath.js:213:29:213:32 | path | TaintedPath.js:213:29:213:68 | path.re ... '), '') | +| TaintedPath.js:213:29:213:32 | path | TaintedPath.js:213:29:213:68 | path.re ... '), '') | +| TaintedPath.js:213:29:213:32 | path | TaintedPath.js:213:29:213:68 | path.re ... '), '') | +| TaintedPath.js:213:29:213:32 | path | TaintedPath.js:213:29:213:68 | path.re ... '), '') | +| TaintedPath.js:213:29:213:32 | path | TaintedPath.js:213:29:213:68 | path.re ... '), '') | +| TaintedPath.js:213:29:213:32 | path | TaintedPath.js:213:29:213:68 | path.re ... '), '') | +| TaintedPath.js:213:29:213:32 | path | TaintedPath.js:213:29:213:68 | path.re ... '), '') | +| TaintedPath.js:213:29:213:32 | path | TaintedPath.js:213:29:213:68 | path.re ... '), '') | +| TaintedPath.js:213:29:213:32 | path | TaintedPath.js:213:29:213:68 | path.re ... '), '') | +| TaintedPath.js:213:29:213:32 | path | TaintedPath.js:213:29:213:68 | path.re ... '), '') | +| TaintedPath.js:213:29:213:32 | path | TaintedPath.js:213:29:213:68 | path.re ... '), '') | +| TaintedPath.js:213:29:213:32 | path | TaintedPath.js:213:29:213:68 | path.re ... '), '') | +| TaintedPath.js:213:29:213:32 | path | TaintedPath.js:213:29:213:68 | path.re ... '), '') | +| TaintedPath.js:213:29:213:32 | path | TaintedPath.js:213:29:213:68 | path.re ... '), '') | +| TaintedPath.js:216:31:216:34 | path | TaintedPath.js:216:31:216:69 | path.re ... '), '') | +| TaintedPath.js:216:31:216:34 | path | TaintedPath.js:216:31:216:69 | path.re ... '), '') | +| TaintedPath.js:216:31:216:34 | path | TaintedPath.js:216:31:216:69 | path.re ... '), '') | +| TaintedPath.js:216:31:216:34 | path | TaintedPath.js:216:31:216:69 | path.re ... '), '') | +| TaintedPath.js:216:31:216:34 | path | TaintedPath.js:216:31:216:69 | path.re ... '), '') | +| TaintedPath.js:216:31:216:34 | path | TaintedPath.js:216:31:216:69 | path.re ... '), '') | +| TaintedPath.js:216:31:216:34 | path | TaintedPath.js:216:31:216:69 | path.re ... '), '') | +| TaintedPath.js:216:31:216:34 | path | TaintedPath.js:216:31:216:69 | path.re ... '), '') | +| TaintedPath.js:216:31:216:34 | path | TaintedPath.js:216:31:216:69 | path.re ... '), '') | +| TaintedPath.js:216:31:216:34 | path | TaintedPath.js:216:31:216:69 | path.re ... '), '') | +| TaintedPath.js:216:31:216:34 | path | TaintedPath.js:216:31:216:69 | path.re ... '), '') | +| TaintedPath.js:216:31:216:34 | path | TaintedPath.js:216:31:216:69 | path.re ... '), '') | +| TaintedPath.js:216:31:216:34 | path | TaintedPath.js:216:31:216:69 | path.re ... '), '') | +| TaintedPath.js:216:31:216:34 | path | TaintedPath.js:216:31:216:69 | path.re ... '), '') | +| TaintedPath.js:216:31:216:34 | path | TaintedPath.js:216:31:216:69 | path.re ... '), '') | +| TaintedPath.js:216:31:216:34 | path | TaintedPath.js:216:31:216:69 | path.re ... '), '') | | examples/TaintedPath.js:8:7:8:52 | filePath | examples/TaintedPath.js:11:36:11:43 | filePath | | examples/TaintedPath.js:8:7:8:52 | filePath | examples/TaintedPath.js:11:36:11:43 | filePath | | examples/TaintedPath.js:8:7:8:52 | filePath | examples/TaintedPath.js:11:36:11:43 | filePath | @@ -10499,6 +10956,9 @@ edges | TaintedPath.js:196:31:196:34 | path | TaintedPath.js:195:24:195:30 | req.url | TaintedPath.js:196:31:196:34 | path | This path depends on a $@. | TaintedPath.js:195:24:195:30 | req.url | user-provided value | | TaintedPath.js:197:45:197:48 | path | TaintedPath.js:195:24:195:30 | req.url | TaintedPath.js:197:45:197:48 | path | This path depends on a $@. | TaintedPath.js:195:24:195:30 | req.url | user-provided value | | TaintedPath.js:198:35:198:38 | path | TaintedPath.js:195:24:195:30 | req.url | TaintedPath.js:198:35:198:38 | path | This path depends on a $@. | TaintedPath.js:195:24:195:30 | req.url | user-provided value | +| TaintedPath.js:206:29:206:85 | path.re ... '), '') | TaintedPath.js:202:24:202:30 | req.url | TaintedPath.js:206:29:206:85 | path.re ... '), '') | This path depends on a $@. | TaintedPath.js:202:24:202:30 | req.url | user-provided value | +| TaintedPath.js:213:29:213:68 | path.re ... '), '') | TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:213:29:213:68 | path.re ... '), '') | This path depends on a $@. | TaintedPath.js:211:24:211:30 | req.url | user-provided value | +| TaintedPath.js:216:31:216:69 | path.re ... '), '') | TaintedPath.js:211:24:211:30 | req.url | TaintedPath.js:216:31:216:69 | path.re ... '), '') | This path depends on a $@. | TaintedPath.js:211:24:211:30 | req.url | user-provided value | | examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | examples/TaintedPath.js:8:28:8:34 | req.url | examples/TaintedPath.js:11:29:11:43 | ROOT + filePath | This path depends on a $@. | examples/TaintedPath.js:8:28:8:34 | req.url | user-provided value | | express.js:8:20:8:32 | req.query.bar | express.js:8:20:8:32 | req.query.bar | express.js:8:20:8:32 | req.query.bar | This path depends on a $@. | express.js:8:20:8:32 | req.query.bar | user-provided value | | handlebars.js:11:32:11:39 | filePath | handlebars.js:29:46:29:60 | req.params.path | handlebars.js:11:32:11:39 | filePath | This path depends on a $@. | handlebars.js:29:46:29:60 | req.params.path | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.js b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.js index d28549da0ec..fd768fecfff 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.js +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.js @@ -197,3 +197,25 @@ var server = http.createServer(function(req, res) { cp.execFileSync("foobar", ["args"], {cwd: path}); // NOT OK cp.execFileSync("foobar", {cwd: path}); // NOT OK }); + +var server = http.createServer(function(req, res) { + let path = url.parse(req.url, true).query.path; + + // Removal of forward-slash or dots. + res.write(fs.readFileSync(path.replace(new RegExp("[\\]\\[*,;'\"`<>\\?/]", 'g'), ''))); // OK + res.write(fs.readFileSync(path.replace(new RegExp("[\\]\\[*,;'\"`<>\\?/]", ''), ''))); // NOT OK. + res.write(fs.readFileSync(path.replace(new RegExp("[\\]\\[*,;'\"`<>\\?/]", unknownFlags()), ''))); // OK -- Might be okay depending on what unknownFlags evaluates to. +}); + +var server = http.createServer(function(req, res) { + let path = url.parse(req.url, true).query.path; + + res.write(fs.readFileSync(path.replace(new RegExp("[.]", 'g'), ''))); // NOT OK (can be absolute) + + if (!pathModule.isAbsolute(path)) { + res.write(fs.readFileSync(path.replace(new RegExp("[.]", ''), ''))); // NOT OK + res.write(fs.readFileSync(path.replace(new RegExp("[.]", 'g'), ''))); // OK + res.write(fs.readFileSync(path.replace(new RegExp("[.]", unknownFlags()), ''))); // OK + } +}); + diff --git a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected index b4022c8550c..f2fa354a305 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected @@ -319,6 +319,15 @@ nodes | lib/lib.js:626:29:626:32 | name | | lib/lib.js:629:25:629:28 | name | | lib/lib.js:629:25:629:28 | name | +| lib/lib.js:632:38:632:41 | name | +| lib/lib.js:632:38:632:41 | name | +| lib/lib.js:633:6:633:68 | sanitized | +| lib/lib.js:633:18:633:68 | "'" + n ... ) + "'" | +| lib/lib.js:633:24:633:27 | name | +| lib/lib.js:633:24:633:62 | name.re ... '\\\\''") | +| lib/lib.js:633:24:633:62 | name.re ... '\\\\''") | +| lib/lib.js:634:22:634:30 | sanitized | +| lib/lib.js:634:22:634:30 | sanitized | | lib/subLib2/compiled-file.ts:3:26:3:29 | name | | lib/subLib2/compiled-file.ts:3:26:3:29 | name | | lib/subLib2/compiled-file.ts:4:25:4:28 | name | @@ -749,6 +758,14 @@ edges | lib/lib.js:608:42:608:45 | name | lib/lib.js:629:25:629:28 | name | | lib/lib.js:608:42:608:45 | name | lib/lib.js:629:25:629:28 | name | | lib/lib.js:608:42:608:45 | name | lib/lib.js:629:25:629:28 | name | +| lib/lib.js:632:38:632:41 | name | lib/lib.js:633:24:633:27 | name | +| lib/lib.js:632:38:632:41 | name | lib/lib.js:633:24:633:27 | name | +| lib/lib.js:633:6:633:68 | sanitized | lib/lib.js:634:22:634:30 | sanitized | +| lib/lib.js:633:6:633:68 | sanitized | lib/lib.js:634:22:634:30 | sanitized | +| lib/lib.js:633:18:633:68 | "'" + n ... ) + "'" | lib/lib.js:633:6:633:68 | sanitized | +| lib/lib.js:633:24:633:27 | name | lib/lib.js:633:24:633:62 | name.re ... '\\\\''") | +| lib/lib.js:633:24:633:27 | name | lib/lib.js:633:24:633:62 | name.re ... '\\\\''") | +| lib/lib.js:633:24:633:62 | name.re ... '\\\\''") | lib/lib.js:633:18:633:68 | "'" + n ... ) + "'" | | lib/subLib2/compiled-file.ts:3:26:3:29 | name | lib/subLib2/compiled-file.ts:4:25:4:28 | name | | lib/subLib2/compiled-file.ts:3:26:3:29 | name | lib/subLib2/compiled-file.ts:4:25:4:28 | name | | lib/subLib2/compiled-file.ts:3:26:3:29 | name | lib/subLib2/compiled-file.ts:4:25:4:28 | name | @@ -879,6 +896,8 @@ edges | lib/lib.js:609:10:609:25 | "rm -rf " + name | lib/lib.js:608:42:608:45 | name | lib/lib.js:609:22:609:25 | name | This string concatenation which depends on $@ is later used in a $@. | lib/lib.js:608:42:608:45 | name | library input | lib/lib.js:609:2:609:26 | cp.exec ... + name) | shell command | | lib/lib.js:626:17:626:32 | "rm -rf " + name | lib/lib.js:608:42:608:45 | name | lib/lib.js:626:29:626:32 | name | This string concatenation which depends on $@ is later used in a $@. | lib/lib.js:608:42:608:45 | name | library input | lib/lib.js:626:9:626:33 | cp.exec ... + name) | shell command | | lib/lib.js:629:13:629:28 | "rm -rf " + name | lib/lib.js:608:42:608:45 | name | lib/lib.js:629:25:629:28 | name | This string concatenation which depends on $@ is later used in a $@. | lib/lib.js:608:42:608:45 | name | library input | lib/lib.js:629:5:629:29 | cp.exec ... + name) | shell command | +| lib/lib.js:633:18:633:68 | "'" + n ... ) + "'" | lib/lib.js:632:38:632:41 | name | lib/lib.js:633:24:633:62 | name.re ... '\\\\''") | This string concatenation which depends on $@ is later used in a $@. | lib/lib.js:632:38:632:41 | name | library input | lib/lib.js:634:2:634:31 | cp.exec ... itized) | shell command | +| lib/lib.js:634:10:634:30 | "rm -rf ... nitized | lib/lib.js:632:38:632:41 | name | lib/lib.js:634:22:634:30 | sanitized | This string concatenation which depends on $@ is later used in a $@. | lib/lib.js:632:38:632:41 | name | library input | lib/lib.js:634:2:634:31 | cp.exec ... itized) | shell command | | lib/subLib2/compiled-file.ts:4:13:4:28 | "rm -rf " + name | lib/subLib2/compiled-file.ts:3:26:3:29 | name | lib/subLib2/compiled-file.ts:4:25:4:28 | name | This string concatenation which depends on $@ is later used in a $@. | lib/subLib2/compiled-file.ts:3:26:3:29 | name | library input | lib/subLib2/compiled-file.ts:4:5:4:29 | cp.exec ... + name) | shell command | | lib/subLib2/special-file.js:4:10:4:25 | "rm -rf " + name | lib/subLib2/special-file.js:3:28:3:31 | name | lib/subLib2/special-file.js:4:22:4:25 | name | This string concatenation which depends on $@ is later used in a $@. | lib/subLib2/special-file.js:3:28:3:31 | name | library input | lib/subLib2/special-file.js:4:2:4:26 | cp.exec ... + name) | shell command | | lib/subLib3/my-file.ts:4:10:4:25 | "rm -rf " + name | lib/subLib3/my-file.ts:3:28:3:31 | name | lib/subLib3/my-file.ts:4:22:4:25 | name | This string concatenation which depends on $@ is later used in a $@. | lib/subLib3/my-file.ts:3:28:3:31 | name | library input | lib/subLib3/my-file.ts:4:2:4:26 | cp.exec ... + name) | shell command | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction/lib/lib.js b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction/lib/lib.js index 504de998c1c..09488f0a887 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction/lib/lib.js +++ b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction/lib/lib.js @@ -628,3 +628,14 @@ module.exports.veryIndeirect = function (name) { cp.exec("rm -rf " + name); // NOT OK } + +module.exports.sanitizer = function (name) { + var sanitized = "'" + name.replace(new RegExp("\'"), "'\\''") + "'" + cp.exec("rm -rf " + sanitized); // NOT OK + + var sanitized = "'" + name.replace(new RegExp("\'", 'g'), "'\\''") + "'" + cp.exec("rm -rf " + sanitized); // OK + + var sanitized = "'" + name.replace(new RegExp("\'", unknownFlags()), "'\\''") + "'" + cp.exec("rm -rf " + sanitized); // OK -- Most likely should be okay and not flagged to reduce false positives. +} diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected index feec74921aa..9b764729c99 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/Xss.expected @@ -1148,6 +1148,12 @@ nodes | tst.js:501:33:501:63 | decodeU ... n.hash) | | tst.js:501:43:501:62 | window.location.hash | | tst.js:501:43:501:62 | window.location.hash | +| tst.js:508:7:508:39 | target | +| tst.js:508:16:508:39 | documen ... .search | +| tst.js:508:16:508:39 | documen ... .search | +| tst.js:509:18:509:23 | target | +| tst.js:509:18:509:54 | target. ... "), '') | +| tst.js:509:18:509:54 | target. ... "), '') | | typeahead.js:20:13:20:45 | target | | typeahead.js:20:22:20:45 | documen ... .search | | typeahead.js:20:22:20:45 | documen ... .search | @@ -2331,6 +2337,11 @@ edges | tst.js:501:43:501:62 | window.location.hash | tst.js:501:33:501:63 | decodeU ... n.hash) | | tst.js:501:43:501:62 | window.location.hash | tst.js:501:33:501:63 | decodeU ... n.hash) | | tst.js:501:43:501:62 | window.location.hash | tst.js:501:33:501:63 | decodeU ... n.hash) | +| tst.js:508:7:508:39 | target | tst.js:509:18:509:23 | target | +| tst.js:508:16:508:39 | documen ... .search | tst.js:508:7:508:39 | target | +| tst.js:508:16:508:39 | documen ... .search | tst.js:508:7:508:39 | target | +| tst.js:509:18:509:23 | target | tst.js:509:18:509:54 | target. ... "), '') | +| tst.js:509:18:509:23 | target | tst.js:509:18:509:54 | target. ... "), '') | | typeahead.js:20:13:20:45 | target | typeahead.js:21:12:21:17 | target | | typeahead.js:20:22:20:45 | documen ... .search | typeahead.js:20:13:20:45 | target | | typeahead.js:20:22:20:45 | documen ... .search | typeahead.js:20:13:20:45 | target | @@ -2623,6 +2634,7 @@ edges | tst.js:491:23:491:45 | locatio ... bstr(1) | tst.js:491:23:491:35 | location.hash | tst.js:491:23:491:45 | locatio ... bstr(1) | Cross-site scripting vulnerability due to $@. | tst.js:491:23:491:35 | location.hash | user-provided value | | tst.js:494:18:494:40 | locatio ... bstr(1) | tst.js:494:18:494:30 | location.hash | tst.js:494:18:494:40 | locatio ... bstr(1) | Cross-site scripting vulnerability due to $@. | tst.js:494:18:494:30 | location.hash | user-provided value | | tst.js:501:33:501:63 | decodeU ... n.hash) | tst.js:501:43:501:62 | window.location.hash | tst.js:501:33:501:63 | decodeU ... n.hash) | Cross-site scripting vulnerability due to $@. | tst.js:501:43:501:62 | window.location.hash | user-provided value | +| tst.js:509:18:509:54 | target. ... "), '') | tst.js:508:16:508:39 | documen ... .search | tst.js:509:18:509:54 | target. ... "), '') | Cross-site scripting vulnerability due to $@. | tst.js:508:16:508:39 | documen ... .search | user-provided value | | typeahead.js:25:18:25:20 | val | typeahead.js:20:22:20:45 | documen ... .search | typeahead.js:25:18:25:20 | val | Cross-site scripting vulnerability due to $@. | typeahead.js:20:22:20:45 | documen ... .search | user-provided value | | v-html.vue:2:8:2:23 | v-html=tainted | v-html.vue:6:42:6:58 | document.location | v-html.vue:2:8:2:23 | v-html=tainted | Cross-site scripting vulnerability due to $@. | v-html.vue:6:42:6:58 | document.location | user-provided value | | various-concat-obfuscations.js:4:4:4:31 | "
    " ...
    " | various-concat-obfuscations.js:2:16:2:39 | documen ... .search | various-concat-obfuscations.js:4:4:4:31 | "
    " ...
    " | Cross-site scripting vulnerability due to $@. | various-concat-obfuscations.js:2:16:2:39 | documen ... .search | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected index 3b1d10d5162..185cae0d2d3 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/XssWithAdditionalSources.expected @@ -1160,6 +1160,12 @@ nodes | tst.js:501:33:501:63 | decodeU ... n.hash) | | tst.js:501:43:501:62 | window.location.hash | | tst.js:501:43:501:62 | window.location.hash | +| tst.js:508:7:508:39 | target | +| tst.js:508:16:508:39 | documen ... .search | +| tst.js:508:16:508:39 | documen ... .search | +| tst.js:509:18:509:23 | target | +| tst.js:509:18:509:54 | target. ... "), '') | +| tst.js:509:18:509:54 | target. ... "), '') | | typeahead.js:9:28:9:30 | loc | | typeahead.js:9:28:9:30 | loc | | typeahead.js:9:28:9:30 | loc | @@ -2393,6 +2399,11 @@ edges | tst.js:501:43:501:62 | window.location.hash | tst.js:501:33:501:63 | decodeU ... n.hash) | | tst.js:501:43:501:62 | window.location.hash | tst.js:501:33:501:63 | decodeU ... n.hash) | | tst.js:501:43:501:62 | window.location.hash | tst.js:501:33:501:63 | decodeU ... n.hash) | +| tst.js:508:7:508:39 | target | tst.js:509:18:509:23 | target | +| tst.js:508:16:508:39 | documen ... .search | tst.js:508:7:508:39 | target | +| tst.js:508:16:508:39 | documen ... .search | tst.js:508:7:508:39 | target | +| tst.js:509:18:509:23 | target | tst.js:509:18:509:54 | target. ... "), '') | +| tst.js:509:18:509:23 | target | tst.js:509:18:509:54 | target. ... "), '') | | typeahead.js:9:28:9:30 | loc | typeahead.js:10:16:10:18 | loc | | typeahead.js:9:28:9:30 | loc | typeahead.js:10:16:10:18 | loc | | typeahead.js:9:28:9:30 | loc | typeahead.js:10:16:10:18 | loc | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/tst.js b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/tst.js index 3a8c5992645..9a110d0bb72 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/tst.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/tst.js @@ -503,3 +503,10 @@ function Foo() { }; Object.assign(this, obj); } + +function nonGlobalSanitizer() { + var target = document.location.search + $("#foo").html(target.replace(new RegExp("<|>"), '')); // NOT OK + $("#foo").html(target.replace(new RegExp("<|>", unknownFlags()), '')); // OK -- most likely good. We don't know what the flags are. + $("#foo").html(target.replace(new RegExp("<|>", "g"), '')); // OK +} diff --git a/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/DoubleEscaping.expected b/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/DoubleEscaping.expected index 651e9443b3a..9ec4549b7f6 100644 --- a/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/DoubleEscaping.expected +++ b/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/DoubleEscaping.expected @@ -6,3 +6,4 @@ | tst.js:60:7:60:28 | s.repla ... '%25') | This replacement may double-escape '%' characters from $@. | tst.js:59:7:59:28 | s.repla ... '%26') | here | | tst.js:68:10:70:38 | s.repla ... &") | This replacement may double-escape '&' characters from $@. | tst.js:68:10:69:39 | s.repla ... apos;") | here | | tst.js:79:10:79:66 | s.repla ... &") | This replacement may double-escape '&' characters from $@. | tst.js:79:10:79:43 | s.repla ... epl[c]) | here | +| tst.js:99:10:101:49 | s.repla ... &") | This replacement may double-escape '&' characters from $@. | tst.js:99:10:100:51 | s.repla ... apos;") | here | diff --git a/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js b/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js index 76cfe80b238..4fe8c9d6f22 100644 --- a/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js +++ b/javascript/ql/test/query-tests/Security/CWE-116/DoubleEscaping/tst.js @@ -94,3 +94,21 @@ function testWithCapturedVar(x) { function encodeDecodeEncode(s) { return goodEncode(goodDecode(goodEncode(s))); } + +function badEncode(s) { + return s.replace(new RegExp("\"", "g"), """) + .replace(new RegExp("\'", "g"), "'") + .replace(new RegExp("&", "g"), "&"); // NOT OK +} + +function goodEncode(s) { + return s.replace(new RegExp("\"", ""), """) + .replace(new RegExp("\'", ""), "'") + .replace(new RegExp("&", ""), "&"); // OK +} + +function goodEncode(s) { + return s.replace(new RegExp("\"", unknownFlags()), """) + .replace(new RegExp("\'", unknownFlags()), "'") + .replace(new RegExp("&", unknownFlags()), "&"); // OK +} diff --git a/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteBlacklistSanitizer.expected b/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteBlacklistSanitizer.expected index 4223a4224d3..379ffbdc9c3 100644 --- a/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteBlacklistSanitizer.expected +++ b/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteBlacklistSanitizer.expected @@ -65,3 +65,9 @@ | tst.js:305:10:305:34 | s().rep ... ]/g,'') | This HTML sanitizer does not sanitize double quotes | | tst.js:309:10:318:3 | s().rep ... ;";\\n\\t}) | This HTML sanitizer does not sanitize single quotes | | tst.js:320:9:329:3 | s().rep ... ;";\\n\\t}) | This HTML sanitizer does not sanitize single quotes | +| tst.js:333:2:333:40 | s().rep ... g"),'') | This HTML sanitizer does not sanitize ampersands | +| tst.js:333:2:333:40 | s().rep ... g"),'') | This HTML sanitizer does not sanitize double quotes | +| tst.js:333:2:333:40 | s().rep ... g"),'') | This HTML sanitizer does not sanitize single quotes | +| tst.js:337:2:337:46 | s().rep ... ()),'') | This HTML sanitizer does not sanitize ampersands | +| tst.js:337:2:337:46 | s().rep ... ()),'') | This HTML sanitizer does not sanitize double quotes | +| tst.js:337:2:337:46 | s().rep ... ()),'') | This HTML sanitizer does not sanitize single quotes | diff --git a/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteMultiCharacterSanitization.expected b/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteMultiCharacterSanitization.expected index 32400608814..96a48fec6cb 100644 --- a/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteMultiCharacterSanitization.expected +++ b/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteMultiCharacterSanitization.expected @@ -39,3 +39,4 @@ | tst-multi-character-sanitization.js:145:13:145:90 | content ... /g, '') | This string may still contain $@, which may cause an HTML element injection vulnerability. | tst-multi-character-sanitization.js:145:30:145:30 | < |