Compare commits

...

84 Commits

Author SHA1 Message Date
Óscar San José
7a4b88fadc Merge pull request #21586 from github/oscarsj/hotfix-2.25.1-base
Release 2.25.1 preparations
2026-03-26 16:36:02 +01:00
Óscar San José
fe565baf06 Apply suggestions from code review
Co-authored-by: Óscar San José <oscarsj@github.com>
2026-03-26 15:54:35 +01:00
Óscar San José
a5be35170b Missing file 2026-03-26 15:26:16 +01:00
Óscar San José
805c2c3c3c Merge remote-tracking branch 'origin/codeql-cli-2.25.1' into oscarsj/hotfix-2.25.1-base 2026-03-26 14:29:44 +01:00
Florin Coada
8382a352d4 Merge pull request #21558 from github/codeql-spark-run-23458057791
Update changelog documentation site for codeql-cli-2.25.0
2026-03-26 13:45:50 +01:00
Óscar San José
b2d9a600e5 Merge pull request #21486 from github/post-release-prep/codeql-cli-2.25.0
Post-release preparation for codeql-cli-2.25.0
2026-03-26 13:45:15 +01:00
Óscar San José
970b57cbe7 Merge pull request #21578 from github/release-prep/2.25.1
Release preparation for version 2.25.1
2026-03-26 00:51:30 +01:00
github-actions[bot]
fb011842c9 Release preparation for version 2.25.1 2026-03-25 23:43:06 +00:00
Óscar San José
851315fb93 Merge pull request #21573 from github/release-prep/2.25.1
Release preparation for version 2.25.1
2026-03-25 10:55:04 +01:00
github-actions[bot]
8cf0954796 Release preparation for version 2.25.1 2026-03-25 08:28:30 +00:00
Óscar San José
72534e882b Merge pull request #21483 from github/release-prep/2.25.0
Release preparation for version 2.25.0
2026-03-16 15:45:36 +01:00
github-actions[bot]
d6055754b6 Release preparation for version 2.25.0 2026-03-16 12:15:34 +00:00
Anders Schack-Mulligen
c24b43d01e Merge pull request #21482 from aschackmull/csharp/rangeanalysis-no-split
C#: Remove splitting-awareness from Range Analysis.
2026-03-16 10:54:49 +01:00
Jeroen Ketema
179a4cd41a Merge pull request #21474 from jketema/jketema/swift-linux-2
Swift: Ignore some DB-CHECK results on Linux
2026-03-16 10:50:05 +01:00
Anders Schack-Mulligen
a929c0bf24 C#: Remove splitting-awareness from Range Analysis. 2026-03-16 09:58:14 +01:00
Anders Schack-Mulligen
427ccee3b9 Merge pull request #21473 from aschackmull/csharp/dataflow-no-split
C#: Remove splitting-awareness from data flow.
2026-03-16 09:33:31 +01:00
Asger F
22f16dda85 Merge pull request #21368 from asgerf/browser-sources
JS: Add 'browser' source kinds
2026-03-16 09:24:54 +01:00
Anders Schack-Mulligen
db0a3e38e2 C#: Accept a few irrelevant taint steps. 2026-03-16 09:09:54 +01:00
Anders Schack-Mulligen
e7edf15031 C#: Clean up. 2026-03-16 08:51:51 +01:00
Anders Schack-Mulligen
4c77e0f315 C#: Remove splitting-awareness for local expression steps. 2026-03-16 08:51:51 +01:00
Anders Schack-Mulligen
7124cd4e6e C#: Remove splitting-awareness for source-to-def steps. 2026-03-16 08:51:50 +01:00
Anders Schack-Mulligen
c076992b83 C#: Remove splitting-awareness in ObjectInitializerNode. 2026-03-16 08:51:49 +01:00
Anders Schack-Mulligen
659d8e7c90 C#: Remove splitting-awareness in argumentOf. 2026-03-16 08:51:49 +01:00
Anders Schack-Mulligen
1e8de0511b C#: Remove splitting-awareness in lambda flow. 2026-03-16 08:51:48 +01:00
Anders Schack-Mulligen
bce0a4d2a7 C#: Remove splitting-awareness for store steps. 2026-03-16 08:51:48 +01:00
Anders Schack-Mulligen
2160910d56 C#: Remove splitting-awareness for read steps. 2026-03-16 08:51:47 +01:00
Anders Schack-Mulligen
a5c8a5b5f8 C#: Remove splitting-awareness for taint steps. 2026-03-16 08:51:47 +01:00
Jeroen Ketema
f9f1d9eecc Swift: Ignore some DB-CHECK results on Linux 2026-03-13 20:06:57 +01:00
Owen Mansel-Chan
d52e9bc18c Merge pull request #21370 from github/owen-mc/go/overlay-annotations
Go: Add overlay annotations from script
2026-03-13 16:46:01 +00:00
Owen Mansel-Chan
b8b841cfba Add overlay[loca] in 4 more tests 2026-03-13 16:19:00 +00:00
Owen Mansel-Chan
df9f8ee386 Merge branch 'main' into owen-mc/go/overlay-annotations 2026-03-13 15:55:17 +00:00
Owen Mansel-Chan
99f4930e24 Explicitly mark DataFlowNodes.qll as overlay[local] 2026-03-13 15:23:39 +00:00
Owen Mansel-Chan
e9df9147ad Add overlay annotations in 4 PrintAst tests 2026-03-13 15:03:05 +00:00
Owen Mansel-Chan
f32f85399a Mark various files as overlay[local] 2026-03-13 15:03:02 +00:00
Jonas Jensen
c56feb7644 Go: annotate the standard library with for overlay
This commit is auto-generated with:

    python3 config/add-overlay-annotations.py go
2026-03-13 15:03:01 +00:00
Jonas Jensen
7ef60a8649 Update the overlay annotation script for go
The Go libraries follow their own naming convention for "query
libraries". These need to be exempted from automatic `overlay[local?]`
annotations since otherwise it appears that too many predicates are
evaluated, possibly because of inadequate use of sentinels.
2026-03-13 15:02:58 +00:00
Asger F
7d6e08ecf1 Merge pull request #21461 from github/asger/js-shebang-bun-tsx
JS: Recognise bun and tsx in shebang lines
2026-03-13 15:07:12 +01:00
Asger F
dfa6d20072 JS: Replace broken link with plain text 2026-03-13 15:05:07 +01:00
Asger F
821cc0e875 JS: Address PR review comments
- Fix misplaced semicolons in test files (was inside comment, moved before it)
- Update QLdoc comments to reference new browser source kind names
- Update docs to list browser source kinds and fix outdated 'only remote' note

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-13 14:58:04 +01:00
Anders Schack-Mulligen
f11815c633 Merge pull request #21471 from aschackmull/csharp/rm-prebasicblock
C#: Delete PreBasicBlocks.
2026-03-13 08:54:06 +01:00
Owen Mansel-Chan
52cfd49087 Merge pull request #21469 from github/dependabot/go_modules/go/extractor/extractor-dependencies-7af763c229
Bump the extractor-dependencies group across 1 directory with 2 updates
2026-03-13 07:06:44 +00:00
Anders Schack-Mulligen
8c1c039edf C#: Delete PreBasicBlocks. 2026-03-13 08:00:08 +01:00
dependabot[bot]
c9e0927992 Bump the extractor-dependencies group across 1 directory with 2 updates
Bumps the extractor-dependencies group with 2 updates in the /go/extractor directory: [golang.org/x/mod](https://github.com/golang/mod) and [golang.org/x/tools](https://github.com/golang/tools).


Updates `golang.org/x/mod` from 0.33.0 to 0.34.0
- [Commits](https://github.com/golang/mod/compare/v0.33.0...v0.34.0)

Updates `golang.org/x/tools` from 0.42.0 to 0.43.0
- [Release notes](https://github.com/golang/tools/releases)
- [Commits](https://github.com/golang/tools/compare/v0.42.0...v0.43.0)

---
updated-dependencies:
- dependency-name: golang.org/x/mod
  dependency-version: 0.34.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: extractor-dependencies
- dependency-name: golang.org/x/tools
  dependency-version: 0.43.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: extractor-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-13 03:04:44 +00:00
Jeroen Ketema
d5f667e585 Merge pull request #21467 from jketema/jketema/swift-linux
Swift: Disable stack protector pass
2026-03-12 22:42:51 +01:00
Jeroen Ketema
b758732a28 Merge pull request #21468 from jketema/jketema/swift-lines
Swift: Limit successfully extracted lines
2026-03-12 17:24:28 +01:00
Jeroen Ketema
ba3fadbf20 Swift: Rename function 2026-03-12 16:37:13 +01:00
Owen Mansel-Chan
d7d1554461 Merge pull request #21465 from owen-mc/go/small-tweaks
Go: improve detection of type expressions when database is missing some type information
2026-03-12 14:58:16 +00:00
Jeroen Ketema
12e0f3f359 Swift: Limit successfully extracted lines 2026-03-12 15:46:23 +01:00
Owen Mansel-Chan
0bb6ff58cc Merge pull request #21466 from owen-mc/go/add-nil-helper-predicate
Go: Add and use `exprRefersToNil` predicate
2026-03-12 14:36:03 +00:00
Jeroen Ketema
b9c0aca11a Swift: Fix formatting 2026-03-12 15:00:18 +01:00
Jeroen Ketema
ee3674cb80 Swift: Disable stack protector pass 2026-03-12 14:43:05 +01:00
Owen Mansel-Chan
c271755985 Add and use exprRefersToNil predicate 2026-03-12 13:28:57 +00:00
Owen Mansel-Chan
a16c43881b Use "database" instead of "snapshot" in QLDocs 2026-03-12 13:28:06 +00:00
Owen Mansel-Chan
39e0382089 Improve QLDoc for isTypeExprTopDown 2026-03-12 13:28:05 +00:00
Owen Mansel-Chan
22e012c6f4 Expand isTypeExprTopDown
We should be using all subtypes of `FieldBase`. This allows us to find
more type expressions, and is also simpler to evaluate.
2026-03-12 13:28:03 +00:00
Asger F
b8c44be599 Add QL test for bun/tsx shebang recognition in TypeScript files
Add test files with #!/usr/bin/env bun, #!/usr/bin/env tsx, and
#!/usr/bin/env node shebangs. The query lists extracted .ts files,
verifying that all three shebangs are recognized and the files are
not skipped by the extractor.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-12 10:09:56 +01:00
Asger F
84d1828a9c JavaScript extractor: recognise bun and tsx in shebang lines
Update the shebang regexp (renamed NODE_INVOCATION -> JS_INVOCATION) to
also match 'bun' and 'tsx' so that scripts using these runtimes are
correctly identified as JavaScript files.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-12 09:35:36 +01:00
Mario Campos
f2e7dca65c Merge pull request #21454 from github/mario-campos-patch-1
Correct comment about AES crypto algorithm strength
2026-03-11 22:43:21 -05:00
Mario Campos
b9b3b3a0b5 Empty commit for missed Green Check 2026-03-11 22:37:20 -05:00
Asger F
5db30c9947 JS: Add change note 2026-03-11 15:40:07 +01:00
Mario Campos
6fb10555ff Correct comment about AES crypto algorithm strength 2026-03-11 09:27:03 -05:00
Ian Lynagh
bbd02b855b Merge pull request #21424 from github/idrissrio/cpp/overlay/discard
C/C++ overlay: update discard mechanism
2026-03-11 13:45:52 +00:00
Idriss Riouak
48a03e2a04 Apply suggestions from code review
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-11 14:25:53 +01:00
idrissrio
a92d97744f C/C++ overlay: address review comment 2026-03-11 14:25:52 +01:00
idrissrio
ef6c1a9968 C/C++ overlay: fix failing header_dependency test 2026-03-11 14:25:50 +01:00
idrissrio
72142b51f7 C/C++ overlay: switch to updated discard strategy 2026-03-11 14:25:49 +01:00
Tom Hvitved
c06d4d2647 Merge pull request #21422 from hvitved/rust/type-mention-refactor
Rust: Small refactor in `TypeMention.qll`
2026-03-11 14:01:03 +01:00
Asger F
4a001f960f JS: Add tests in request forgery queries 2026-03-11 13:53:25 +01:00
Asger F
1253553aec JS: Add browser source kinds 2026-03-11 13:50:07 +01:00
Ian Lynagh
68dfa5c83b Merge pull request #21451 from igfoo/igfoo/fix-build
Revert "Bump rules_android from 0.6.4 to 0.7.1"
2026-03-11 12:27:20 +00:00
Ian Lynagh
25a20f74f0 Revert "Bump rules_android from 0.6.4 to 0.7.1"
This reverts commit c7349740f0.

It was making the build fail
2026-03-11 11:54:18 +00:00
Taus
5a65282241 Merge pull request #21429 from github/tausbn/fix-bad-join-in-method-call-order
Python: Fix bad join in method call order computation
2026-03-10 18:17:35 +01:00
Paolo Tranquilli
79499c240a Merge pull request #21444 from github/dependabot/bazel/googletest-1.17.0.bcr.2
Bump googletest from 1.14.0.bcr.1 to 1.17.0.bcr.2
2026-03-10 16:41:38 +01:00
Paolo Tranquilli
267a46d01b Merge pull request #21445 from github/dependabot/bazel/rules_shell-0.6.1
Bump rules_shell from 0.5.0 to 0.6.1
2026-03-10 16:41:24 +01:00
Ian Lynagh
341059d2d0 Merge pull request #21437 from igfoo/igfoo/onemk
C++: Small simplification
2026-03-10 15:36:38 +00:00
Paolo Tranquilli
3c3c58b0a9 Merge pull request #21443 from github/dependabot/bazel/rules_android-0.7.1
Bump rules_android from 0.6.4 to 0.7.1
2026-03-10 16:06:40 +01:00
Paolo Tranquilli
9bf1072a01 Merge pull request #21447 from github/revert-21414-redsun82/rerun-slash-command
Revert "Add `/rerun` slash command for failed internal checks"
2026-03-10 15:55:45 +01:00
Paolo Tranquilli
a5f23ade8c Revert "Add /rerun slash command for failed internal checks" 2026-03-10 14:43:59 +01:00
dependabot[bot]
b631138b63 Bump rules_shell from 0.5.0 to 0.6.1
Bumps [rules_shell](https://github.com/bazelbuild/rules_shell) from 0.5.0 to 0.6.1.
- [Release notes](https://github.com/bazelbuild/rules_shell/releases)
- [Commits](https://github.com/bazelbuild/rules_shell/compare/v0.5.0...v0.6.1)

---
updated-dependencies:
- dependency-name: rules_shell
  dependency-version: 0.6.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-10 11:21:40 +00:00
dependabot[bot]
093d36ebe6 Bump googletest from 1.14.0.bcr.1 to 1.17.0.bcr.2
Bumps [googletest](https://github.com/google/googletest) from 1.14.0.bcr.1 to 1.17.0.bcr.2.
- [Release notes](https://github.com/google/googletest/releases)
- [Commits](https://github.com/google/googletest/commits)

---
updated-dependencies:
- dependency-name: googletest
  dependency-version: 1.17.0.bcr.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-10 11:21:37 +00:00
dependabot[bot]
c7349740f0 Bump rules_android from 0.6.4 to 0.7.1
Bumps [rules_android](https://github.com/bazelbuild/rules_android) from 0.6.4 to 0.7.1.
- [Release notes](https://github.com/bazelbuild/rules_android/releases)
- [Commits](https://github.com/bazelbuild/rules_android/compare/v0.6.4...v0.7.1)

---
updated-dependencies:
- dependency-name: rules_android
  dependency-version: 0.7.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-10 11:21:34 +00:00
Ian Lynagh
dbb8bb86ba C++: Small simplification 2026-03-09 17:45:38 +00:00
Taus
c5360ba46c Python: Fix bad join in method call order computation
This join had badness 1127 on the project FiacreT/M-moire, producing ~31
million tuples in order to end up with only ~27k tuples later in the
pipeline. With the fix, we reduce this by roughly the full 31 million
(the new materialised helper predicate accounting for roughly 130k
tuples on its own).

Co-authored-by: Mathias Vorreiter Pedersen <mathiasvp@github.com>
2026-03-09 13:09:29 +00:00
Tom Hvitved
4dca9aa958 Rust: Small refactor in TypeMention.qll 2026-03-06 15:33:11 +01:00
453 changed files with 2046 additions and 1615 deletions

View File

@@ -1,14 +0,0 @@
---
trigger: rerun
title: Rerun failed internal checks
surfaces:
- pull_request
description: >
Finds all failed internal CI checks for this PR and reruns their failed jobs.
steps:
- type: repository_dispatch
eventType: rerun-workflow
- type: fill
submit_form: true
template: "Rerun has been triggered."

View File

@@ -21,7 +21,7 @@ bazel_dep(name = "rules_java", version = "9.0.3")
bazel_dep(name = "rules_pkg", version = "1.0.1")
bazel_dep(name = "rules_nodejs", version = "6.7.3")
bazel_dep(name = "rules_python", version = "1.9.0")
bazel_dep(name = "rules_shell", version = "0.5.0")
bazel_dep(name = "rules_shell", version = "0.6.1")
bazel_dep(name = "bazel_skylib", version = "1.8.1")
bazel_dep(name = "abseil-cpp", version = "20260107.1", repo_name = "absl")
bazel_dep(name = "nlohmann_json", version = "3.11.3", repo_name = "json")
@@ -29,7 +29,7 @@ bazel_dep(name = "fmt", version = "12.1.0-codeql.1")
bazel_dep(name = "rules_kotlin", version = "2.2.2-codeql.1")
bazel_dep(name = "gazelle", version = "0.47.0")
bazel_dep(name = "rules_dotnet", version = "0.21.5-codeql.1")
bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
bazel_dep(name = "googletest", version = "1.17.0.bcr.2")
bazel_dep(name = "rules_rust", version = "0.68.1.codeql.1")
bazel_dep(name = "zstd", version = "1.5.7.bcr.1")

View File

@@ -1,3 +1,15 @@
## 0.4.32
No user-facing changes.
## 0.4.31
No user-facing changes.
## 0.4.30
No user-facing changes.
## 0.4.29
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 0.4.30
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 0.4.31
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 0.4.32
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.4.29
lastReleaseVersion: 0.4.32

View File

@@ -1,5 +1,5 @@
name: codeql/actions-all
version: 0.4.30-dev
version: 0.4.32
library: true
warnOnImplicitThis: true
dependencies:

View File

@@ -1,3 +1,15 @@
## 0.6.24
No user-facing changes.
## 0.6.23
No user-facing changes.
## 0.6.22
No user-facing changes.
## 0.6.21
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 0.6.22
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 0.6.23
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 0.6.24
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.6.21
lastReleaseVersion: 0.6.24

View File

@@ -1,5 +1,5 @@
name: codeql/actions-queries
version: 0.6.22-dev
version: 0.6.24
library: false
warnOnImplicitThis: true
groups: [actions, queries]

View File

@@ -199,6 +199,7 @@ def annotate_as_appropriate(filename, lines):
# as overlay[local?]. It is not clear that these heuristics are exactly what we want,
# but they seem to work well enough for now (as determined by speed and accuracy numbers).
if (filename.endswith("Test.qll") or
re.search(r"go/ql/lib/semmle/go/security/[^/]+[.]qll$", filename.replace(os.sep, "/")) or
((filename.endswith("Query.qll") or filename.endswith("Config.qll")) and
any("implements DataFlow::ConfigSig" in line for line in lines))):
return None

View File

@@ -172,10 +172,6 @@
"cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/reachability/PrintDominance.qll",
"cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll"
],
"C# ControlFlowReachability": [
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ControlFlowReachability.qll"
],
"C++ ExternalAPIs": [
"cpp/ql/src/Security/CWE/CWE-020/ExternalAPIs.qll",
"cpp/ql/src/Security/CWE/CWE-020/ir/ExternalAPIs.qll"

View File

@@ -1,3 +1,17 @@
## 8.0.3
No user-facing changes.
## 8.0.2
No user-facing changes.
## 8.0.1
### Minor Analysis Improvements
* Inline expectations test comments, which are of the form `// $ tag` or `// $ tag=value`, are now parsed more strictly and will not be recognized if there isn't a space after the `$` symbol.
## 8.0.0
### Breaking Changes

View File

@@ -1,4 +1,5 @@
---
category: minorAnalysis
---
## 8.0.1
### Minor Analysis Improvements
* Inline expectations test comments, which are of the form `// $ tag` or `// $ tag=value`, are now parsed more strictly and will not be recognized if there isn't a space after the `$` symbol.

View File

@@ -0,0 +1,3 @@
## 8.0.2
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 8.0.3
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 8.0.0
lastReleaseVersion: 8.0.3

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-all
version: 8.0.1-dev
version: 8.0.3
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp

View File

@@ -1663,7 +1663,7 @@ private module Cached {
private predicate compares_ge(
ValueNumber test, Operand left, Operand right, int k, boolean isGe, GuardValue value
) {
exists(int onemk | k = 1 - onemk | compares_lt(test, right, left, onemk, isGe, value))
compares_lt(test, right, left, 1 - k, isGe, value)
}
/** Rearrange various simple comparisons into `left < right + k` form. */

View File

@@ -6,117 +6,67 @@ private import OverlayXml
/**
* Holds always for the overlay variant and never for the base variant.
* This local predicate is used to define local predicates that behave
* differently for the base and overlay variant.
*/
overlay[local]
predicate isOverlay() { databaseMetadata("isOverlay", "true") }
overlay[local]
private string getLocationFilePath(@location_default loc) {
exists(@file file | locations_default(loc, file, _, _, _, _) | files(file, result))
}
/**
* Gets the file path for an element with a single location.
* Holds if the TRAP file or tag `t` is reachable from source file `sourceFile`
* in the base (isOverlayVariant=false) or overlay (isOverlayVariant=true) variant.
*/
overlay[local]
private string getSingleLocationFilePath(@element e) {
exists(@location_default loc |
var_decls(e, _, _, _, loc)
or
fun_decls(e, _, _, _, loc)
or
type_decls(e, _, loc)
or
namespace_decls(e, _, loc, _)
or
macroinvocations(e, _, loc, _)
or
preprocdirects(e, _, loc)
or
diagnostics(e, _, _, _, _, loc)
or
usings(e, _, loc, _)
or
static_asserts(e, _, _, loc, _)
or
derivations(e, _, _, _, loc)
or
frienddecls(e, _, _, loc)
or
comments(e, _, loc)
or
exprs(e, _, loc)
or
stmts(e, _, loc)
or
initialisers(e, _, _, loc)
or
attributes(e, _, _, _, loc)
or
attribute_args(e, _, _, _, loc)
or
namequalifiers(e, _, _, loc)
or
enumconstants(e, _, _, _, _, loc)
or
type_mentions(e, _, loc, _)
or
lambda_capture(e, _, _, _, _, _, loc)
or
concept_templates(e, _, loc)
|
result = getLocationFilePath(loc)
private predicate locallyReachableTrapOrTag(
boolean isOverlayVariant, string sourceFile, @trap_or_tag t
) {
exists(@source_file sf, @trap trap |
(if isOverlay() then isOverlayVariant = true else isOverlayVariant = false) and
source_file_uses_trap(sf, trap) and
source_file_name(sf, sourceFile) and
(t = trap or trap_uses_tag(trap, t))
)
}
/**
* Gets the file path for an element with potentially multiple locations.
* Holds if element `e` is in TRAP file or tag `t`
* in the base (isOverlayVariant=false) or overlay (isOverlayVariant=true) variant.
*/
overlay[local]
private string getMultiLocationFilePath(@element e) {
exists(@location_default loc |
var_decls(_, e, _, _, loc)
or
fun_decls(_, e, _, _, loc)
or
type_decls(_, e, loc)
or
namespace_decls(_, e, loc, _)
|
result = getLocationFilePath(loc)
)
}
/**
* A local helper predicate that holds in the base variant and never in the
* overlay variant.
*/
overlay[local]
private predicate isBase() { not isOverlay() }
/**
* Holds if `path` was extracted in the overlay database.
*/
overlay[local]
private predicate overlayHasFile(string path) {
isOverlay() and
files(_, path) and
path != ""
private predicate locallyInTrapOrTag(boolean isOverlayVariant, @element e, @trap_or_tag t) {
(if isOverlay() then isOverlayVariant = true else isOverlayVariant = false) and
in_trap_or_tag(e, t)
}
/**
* Discards an element from the base variant if:
* - It has a single location in a file extracted in the overlay, or
* - All of its locations are in files extracted in the overlay.
* - We have knowledge about what TRAP file or tag it is in (in the base).
* - It is not in any overlay TRAP file or tag that is reachable from an overlay source file.
* - For every base TRAP file or tag that contains it and is reachable from a base source file,
* either the source file has changed, or the overlay has redefined the TRAP file or tag,
* or the overlay runner has re-extracted the same source file.
*/
overlay[discard_entity]
private predicate discardElement(@element e) {
isBase() and
(
overlayHasFile(getSingleLocationFilePath(e))
or
forex(string path | path = getMultiLocationFilePath(e) | overlayHasFile(path))
// If we don't have any knowledge about what TRAP file something
// is in, then we don't want to discard it, so we only consider
// entities that are known to be in a base TRAP file or tag.
locallyInTrapOrTag(false, e, _) and
// Anything that is reachable from an overlay source file should
// not be discarded.
not exists(@trap_or_tag t | locallyInTrapOrTag(true, e, t) |
locallyReachableTrapOrTag(true, _, t)
) and
// Finally, we have to make sure the base variant does not retain it.
// If it is reachable from a base source file, then that is
// sufficient unless either the base source file has changed (in
// particular, been deleted), or the overlay has redefined the TRAP
// file or tag it is in, or the overlay runner has re-extracted the same
// source file (e.g. because a header it includes has changed).
forall(@trap_or_tag t, string sourceFile |
locallyInTrapOrTag(false, e, t) and
locallyReachableTrapOrTag(false, sourceFile, t)
|
overlayChangedFiles(sourceFile) or
locallyReachableTrapOrTag(true, _, t) or
locallyReachableTrapOrTag(true, sourceFile, _)
)
}

View File

@@ -1,3 +1,15 @@
## 1.5.15
No user-facing changes.
## 1.5.14
No user-facing changes.
## 1.5.13
No user-facing changes.
## 1.5.12
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.5.13
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.5.14
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.5.15
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.5.12
lastReleaseVersion: 1.5.15

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries
version: 1.5.13-dev
version: 1.5.15
groups:
- cpp
- queries

View File

@@ -1,3 +1,15 @@
## 1.7.63
No user-facing changes.
## 1.7.62
No user-facing changes.
## 1.7.61
No user-facing changes.
## 1.7.60
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.7.61
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.7.62
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.7.63
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.7.60
lastReleaseVersion: 1.7.63

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-all
version: 1.7.61-dev
version: 1.7.63
groups:
- csharp
- solorigate

View File

@@ -1,3 +1,15 @@
## 1.7.63
No user-facing changes.
## 1.7.62
No user-facing changes.
## 1.7.61
No user-facing changes.
## 1.7.60
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.7.61
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.7.62
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.7.63
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.7.60
lastReleaseVersion: 1.7.63

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-solorigate-queries
version: 1.7.61-dev
version: 1.7.63
groups:
- csharp
- solorigate

View File

@@ -1,63 +1,5 @@
import csharp
import semmle.code.csharp.controlflow.internal.Completion
import semmle.code.csharp.controlflow.internal.PreBasicBlocks
import ControlFlow
import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl::Consistency
import semmle.code.csharp.controlflow.internal.Splitting
private predicate splitBB(ControlFlow::BasicBlock bb) {
exists(ControlFlow::Node first |
first = bb.getFirstNode() and
first.isJoin() and
strictcount(first.getAPredecessor().getAstNode()) = 1
)
}
private class RelevantBasicBlock extends ControlFlow::BasicBlock {
RelevantBasicBlock() { not splitBB(this) }
}
predicate bbStartInconsistency(ControlFlowElement cfe) {
exists(RelevantBasicBlock bb | bb.getFirstNode() = cfe.getAControlFlowNode()) and
not cfe = any(PreBasicBlock bb).getFirstElement()
}
predicate bbSuccInconsistency(ControlFlowElement pred, ControlFlowElement succ) {
exists(RelevantBasicBlock predBB, RelevantBasicBlock succBB |
predBB.getLastNode() = pred.getAControlFlowNode() and
succBB = predBB.getASuccessor() and
succBB.getFirstNode() = succ.getAControlFlowNode()
) and
not exists(PreBasicBlock predBB, PreBasicBlock succBB |
predBB.getLastNode() = pred and
succBB = predBB.getASuccessor() and
succBB.getFirstElement() = succ
)
}
predicate bbIntraSuccInconsistency(ControlFlowElement pred, ControlFlowElement succ) {
exists(ControlFlow::BasicBlock bb, int i |
pred.getAControlFlowNode() = bb.getNode(i) and
succ.getAControlFlowNode() = bb.getNode(i + 1)
) and
not exists(PreBasicBlock bb |
bb.getLastNode() = pred and
bb.getASuccessor().getFirstElement() = succ
) and
not exists(PreBasicBlock bb, int i |
bb.getNode(i) = pred and
bb.getNode(i + 1) = succ
)
}
query predicate preBasicBlockConsistency(ControlFlowElement cfe1, ControlFlowElement cfe2, string s) {
bbStartInconsistency(cfe1) and
cfe2 = cfe1 and
s = "start inconsistency"
or
bbSuccInconsistency(cfe1, cfe2) and
s = "succ inconsistency"
or
bbIntraSuccInconsistency(cfe1, cfe2) and
s = "intra succ inconsistency"
}

View File

@@ -35,9 +35,7 @@ private module Input implements InputSig<Location, CsharpDataFlow> {
or
n.asExpr().(ObjectCreation).hasInitializer()
or
exists(
n.(PostUpdateNode).getPreUpdateNode().asExprAtNode(LocalFlow::getPostUpdateReverseStep(_))
)
n.(PostUpdateNode).getPreUpdateNode().asExpr() = LocalFlow::getPostUpdateReverseStep(_)
}
predicate argHasPostUpdateExclude(ArgumentNode n) {

View File

@@ -1,3 +1,21 @@
## 5.4.11
No user-facing changes.
## 5.4.10
No user-facing changes.
## 5.4.9
### Minor Analysis Improvements
* Inline expectations test comments, which are of the form `// $ tag` or `// $ tag=value`, are now parsed more strictly and will not be recognized if there isn't a space after the `$` symbol.
* Added `System.Net.WebSockets::ReceiveAsync` as a remote flow source.
* Added reverse taint flow from implicit conversion operator calls to their arguments.
* Added post-update nodes for struct-type arguments, allowing data flow out of method calls via those arguments.
* C# 14: Added support for partial constructors.
## 5.4.8
### Minor Analysis Improvements

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* C# 14: Added support for partial constructors.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Added post-update nodes for struct-type arguments, allowing data flow out of method calls via those arguments.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Added reverse taint flow from implicit conversion operator calls to their arguments.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Added `System.Net.WebSockets::ReceiveAsync` as a remote flow source.

View File

@@ -0,0 +1,3 @@
## 5.4.10
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 5.4.11
No user-facing changes.

View File

@@ -0,0 +1,9 @@
## 5.4.9
### Minor Analysis Improvements
* Inline expectations test comments, which are of the form `// $ tag` or `// $ tag=value`, are now parsed more strictly and will not be recognized if there isn't a space after the `$` symbol.
* Added `System.Net.WebSockets::ReceiveAsync` as a remote flow source.
* Added reverse taint flow from implicit conversion operator calls to their arguments.
* Added post-update nodes for struct-type arguments, allowing data flow out of method calls via those arguments.
* C# 14: Added support for partial constructors.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 5.4.8
lastReleaseVersion: 5.4.11

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-all
version: 5.4.9-dev
version: 5.4.11
groups: csharp
dbscheme: semmlecode.csharp.dbscheme
extractor: csharp

View File

@@ -1,175 +0,0 @@
/**
* INTERNAL: Do not use.
*
* Provides a basic block implementation on control flow elements. That is,
* a "pre-CFG" where the nodes are (unsplit) control flow elements and the
* successor relation is `succ = succ(pred, _)`.
*
* The logic is duplicated from the implementation in `BasicBlocks.qll`, and
* being an internal class, all predicate documentation has been removed.
*/
import csharp
private import Completion
private import ControlFlowGraphImpl
private import semmle.code.csharp.controlflow.ControlFlowGraph::ControlFlow as Cfg
private import codeql.controlflow.BasicBlock as BB
private predicate startsBB(ControlFlowElement cfe) {
not succ(_, cfe, _) and
(
succ(cfe, _, _)
or
scopeLast(_, cfe, _)
)
or
strictcount(ControlFlowElement pred, Completion c | succ(pred, cfe, c)) > 1
or
succ(_, cfe, any(ConditionalCompletion c))
or
exists(ControlFlowElement pred, int i |
succ(pred, cfe, _) and
i = count(ControlFlowElement succ, Completion c | succ(pred, succ, c))
|
i > 1
or
i = 1 and
scopeLast(_, pred, _)
)
}
private predicate intraBBSucc(ControlFlowElement pred, ControlFlowElement succ) {
succ(pred, succ, _) and
not startsBB(succ)
}
private predicate bbIndex(ControlFlowElement bbStart, ControlFlowElement cfe, int i) =
shortestDistances(startsBB/1, intraBBSucc/2)(bbStart, cfe, i)
private predicate succBB(PreBasicBlock pred, PreBasicBlock succ) { succ = pred.getASuccessor() }
private predicate entryBB(PreBasicBlock bb) { scopeFirst(_, bb) }
private predicate bbIDominates(PreBasicBlock dom, PreBasicBlock bb) =
idominance(entryBB/1, succBB/2)(_, dom, bb)
class PreBasicBlock extends ControlFlowElement {
PreBasicBlock() { startsBB(this) }
PreBasicBlock getASuccessor(Cfg::SuccessorType t) {
succ(this.getLastNode(), result, any(Completion c | t = c.getAMatchingSuccessorType()))
}
deprecated PreBasicBlock getASuccessorByType(Cfg::SuccessorType t) {
result = this.getASuccessor(t)
}
PreBasicBlock getASuccessor() { result = this.getASuccessor(_) }
PreBasicBlock getAPredecessor() { result.getASuccessor() = this }
ControlFlowElement getNode(int pos) { bbIndex(this, result, pos) }
deprecated ControlFlowElement getElement(int pos) { result = this.getNode(pos) }
ControlFlowElement getAnElement() { result = this.getNode(_) }
ControlFlowElement getFirstElement() { result = this }
ControlFlowElement getLastNode() { result = this.getNode(this.length() - 1) }
deprecated ControlFlowElement getLastElement() { result = this.getLastNode() }
int length() { result = strictcount(this.getAnElement()) }
PreBasicBlock getImmediateDominator() { bbIDominates(result, this) }
predicate immediatelyDominates(PreBasicBlock bb) { bbIDominates(this, bb) }
pragma[inline]
predicate strictlyDominates(PreBasicBlock bb) { this.immediatelyDominates+(bb) }
pragma[inline]
predicate dominates(PreBasicBlock bb) {
bb = this
or
this.strictlyDominates(bb)
}
predicate inDominanceFrontier(PreBasicBlock df) {
this = df.getAPredecessor() and not bbIDominates(this, df)
or
exists(PreBasicBlock prev | prev.inDominanceFrontier(df) |
bbIDominates(this, prev) and
not bbIDominates(this, df)
)
}
/** Unsupported. Do not use. */
predicate strictlyPostDominates(PreBasicBlock bb) { none() }
/** Unsupported. Do not use. */
predicate postDominates(PreBasicBlock bb) {
this.strictlyPostDominates(bb) or
this = bb
}
}
private Completion getConditionalCompletion(ConditionalCompletion cc) {
result.getInnerCompletion() = cc
}
pragma[nomagic]
private predicate conditionBlockImmediatelyControls(
ConditionBlock cond, PreBasicBlock succ, ConditionalCompletion cc
) {
exists(ControlFlowElement last, Completion c |
last = cond.getLastNode() and
c = getConditionalCompletion(cc) and
succ(last, succ, c) and
// In the pre-CFG, we need to account for case where one predecessor node has
// two edges to the same successor node. Assertion expressions are examples of
// such nodes.
not exists(Completion other |
succ(last, succ, other) and
other != c
) and
forall(PreBasicBlock pred | pred = succ.getAPredecessor() and pred != cond |
succ.dominates(pred)
)
)
}
class ConditionBlock extends PreBasicBlock {
ConditionBlock() {
exists(Completion c | c = getConditionalCompletion(_) |
succ(this.getLastNode(), _, c)
or
scopeLast(_, this.getLastNode(), c)
)
}
pragma[nomagic]
predicate controls(PreBasicBlock controlled, Cfg::ConditionalSuccessor s) {
exists(PreBasicBlock succ, ConditionalCompletion c |
conditionBlockImmediatelyControls(this, succ, c)
|
succ.dominates(controlled) and
s = c.getAMatchingSuccessorType()
)
}
}
module PreCfg implements BB::CfgSig<Location> {
class ControlFlowNode = ControlFlowElement;
class BasicBlock = PreBasicBlock;
class EntryBasicBlock extends BasicBlock {
EntryBasicBlock() { entryBB(this) }
}
predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) {
conditionBlockImmediatelyControls(bb1, bb2, _)
}
}

View File

@@ -1,246 +0,0 @@
import csharp
private class ControlFlowScope extends ControlFlowElement {
private boolean exactScope;
ControlFlowScope() {
exists(ControlFlowReachabilityConfiguration c |
c.candidate(_, _, this, exactScope, _) or
c.candidateDef(_, _, this, exactScope, _)
)
}
predicate isExact() { exactScope = true }
predicate isNonExact() { exactScope = false }
}
private newtype TControlFlowElementOrBasicBlock =
TControlFlowElement(ControlFlowElement cfe) or
TBasicBlock(ControlFlow::BasicBlock bb)
class ControlFlowElementOrBasicBlock extends TControlFlowElementOrBasicBlock {
ControlFlowElement asControlFlowElement() { this = TControlFlowElement(result) }
ControlFlow::BasicBlock asBasicBlock() { this = TBasicBlock(result) }
string toString() {
result = this.asControlFlowElement().toString()
or
result = this.asBasicBlock().toString()
}
Location getLocation() {
result = this.asControlFlowElement().getLocation()
or
result = this.asBasicBlock().getLocation()
}
}
private predicate isBasicBlock(ControlFlowElementOrBasicBlock c) { c instanceof TBasicBlock }
private predicate isNonExactScope(ControlFlowElementOrBasicBlock c) {
c.asControlFlowElement().(ControlFlowScope).isNonExact()
}
private predicate step(ControlFlowElementOrBasicBlock pred, ControlFlowElementOrBasicBlock succ) {
pred.asBasicBlock().getANode().getAstNode() = succ.asControlFlowElement()
or
pred.asControlFlowElement() = succ.asControlFlowElement().getAChild()
}
private predicate basicBlockInNonExactScope(
ControlFlowElementOrBasicBlock bb, ControlFlowElementOrBasicBlock scope
) = doublyBoundedFastTC(step/2, isBasicBlock/1, isNonExactScope/1)(bb, scope)
pragma[noinline]
private ControlFlow::BasicBlock getABasicBlockInScope(ControlFlowScope scope, boolean exactScope) {
basicBlockInNonExactScope(TBasicBlock(result), TControlFlowElement(scope)) and
exactScope = false
or
scope.isExact() and
result.getANode().getAstNode() = scope and
exactScope = true
}
/**
* A helper class for determining control-flow reachability for pairs of
* elements.
*
* This is useful when defining for example expression-based data-flow steps in
* the presence of control-flow splitting, where a data-flow step should make
* sure to stay in the same split.
*
* For example, in
*
* ```csharp
* if (b)
* ....
* var x = "foo";
* if (b)
* ....
* ```
*
* there should only be steps from `[b = true] "foo"` to `[b = true] SSA def(x)`
* and `[b = false] "foo"` to `[b = false] SSA def(x)`, and for example not from
* `[b = true] "foo"` to `[b = false] SSA def(x)`
*/
abstract class ControlFlowReachabilityConfiguration extends string {
bindingset[this]
ControlFlowReachabilityConfiguration() { any() }
/**
* Holds if `e1` and `e2` are expressions for which we want to find a
* control-flow path that follows control flow successors (resp.
* predecessors, as specified by `isSuccessor`) inside the syntactic scope
* `scope`. The Boolean `exactScope` indicates whether a transitive child
* of `scope` is allowed (`exactScope = false`).
*/
predicate candidate(
Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor
) {
none()
}
/**
* Holds if `e` and `def` are elements for which we want to find a
* control-flow path that follows control flow successors (resp.
* predecessors, as specified by `isSuccessor`) inside the syntactic scope
* `scope`. The Boolean `exactScope` indicates whether a transitive child
* of `scope` is allowed (`exactScope = false`).
*/
predicate candidateDef(
Expr e, AssignableDefinition def, ControlFlowElement scope, boolean exactScope,
boolean isSuccessor
) {
none()
}
pragma[nomagic]
private predicate reachesBasicBlockExprBase(
Expr e1, Expr e2, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn1, int i,
ControlFlow::BasicBlock bb
) {
this.candidate(e1, e2, _, _, isSuccessor) and
cfn1 = e1.getAControlFlowNode() and
bb.getNode(i) = cfn1
}
pragma[nomagic]
private predicate reachesBasicBlockExprRec(
Expr e1, Expr e2, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn1,
ControlFlow::BasicBlock bb
) {
exists(ControlFlow::BasicBlock mid |
this.reachesBasicBlockExpr(e1, e2, isSuccessor, cfn1, mid)
|
isSuccessor = true and
bb = mid.getASuccessor()
or
isSuccessor = false and
bb = mid.getAPredecessor()
)
}
pragma[nomagic]
private predicate reachesBasicBlockExpr(
Expr e1, Expr e2, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn1,
ControlFlow::BasicBlock bb
) {
this.reachesBasicBlockExprBase(e1, e2, isSuccessor, cfn1, _, bb)
or
exists(ControlFlowElement scope, boolean exactScope |
this.candidate(e1, e2, scope, exactScope, isSuccessor) and
this.reachesBasicBlockExprRec(e1, e2, isSuccessor, cfn1, bb) and
bb = getABasicBlockInScope(scope, exactScope)
)
}
pragma[nomagic]
private predicate reachesBasicBlockDefinitionBase(
Expr e, AssignableDefinition def, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn,
int i, ControlFlow::BasicBlock bb
) {
this.candidateDef(e, def, _, _, isSuccessor) and
cfn = e.getAControlFlowNode() and
bb.getNode(i) = cfn
}
pragma[nomagic]
private predicate reachesBasicBlockDefinitionRec(
Expr e, AssignableDefinition def, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn,
ControlFlow::BasicBlock bb
) {
exists(ControlFlow::BasicBlock mid |
this.reachesBasicBlockDefinition(e, def, isSuccessor, cfn, mid)
|
isSuccessor = true and
bb = mid.getASuccessor()
or
isSuccessor = false and
bb = mid.getAPredecessor()
)
}
pragma[nomagic]
private predicate reachesBasicBlockDefinition(
Expr e, AssignableDefinition def, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn,
ControlFlow::BasicBlock bb
) {
this.reachesBasicBlockDefinitionBase(e, def, isSuccessor, cfn, _, bb)
or
exists(ControlFlowElement scope, boolean exactScope |
this.candidateDef(e, def, scope, exactScope, isSuccessor) and
this.reachesBasicBlockDefinitionRec(e, def, isSuccessor, cfn, bb) and
bb = getABasicBlockInScope(scope, exactScope)
)
}
/**
* Holds if there is a control-flow path from `cfn1` to `cfn2`, where `cfn1` is a
* control-flow node for `e1` and `cfn2` is a control-flow node for `e2`.
*/
pragma[nomagic]
predicate hasExprPath(Expr e1, ControlFlow::Node cfn1, Expr e2, ControlFlow::Node cfn2) {
exists(ControlFlow::BasicBlock bb, boolean isSuccessor, int i, int j |
this.reachesBasicBlockExprBase(e1, e2, isSuccessor, cfn1, i, bb) and
cfn2 = bb.getNode(j) and
cfn2 = e2.getAControlFlowNode()
|
isSuccessor = true and j >= i
or
isSuccessor = false and i >= j
)
or
exists(ControlFlow::BasicBlock bb |
this.reachesBasicBlockExprRec(e1, e2, _, cfn1, bb) and
cfn2 = bb.getANode() and
cfn2 = e2.getAControlFlowNode()
)
}
/**
* Holds if there is a control-flow path from `cfn` to `cfnDef`, where `cfn` is a
* control-flow node for `e` and `cfnDef` is a control-flow node for `def`.
*/
pragma[nomagic]
predicate hasDefPath(
Expr e, ControlFlow::Node cfn, AssignableDefinition def, ControlFlow::Node cfnDef
) {
exists(ControlFlow::BasicBlock bb, boolean isSuccessor, int i, int j |
this.reachesBasicBlockDefinitionBase(e, def, isSuccessor, cfn, i, bb) and
cfnDef = bb.getNode(j) and
def.getExpr().getAControlFlowNode() = cfnDef
|
isSuccessor = true and j >= i
or
isSuccessor = false and i >= j
)
or
exists(ControlFlow::BasicBlock bb |
this.reachesBasicBlockDefinitionRec(e, def, _, cfn, bb) and
def.getExpr().getAControlFlowNode() = cfnDef and
cfnDef = bb.getANode()
)
}
}

View File

@@ -2,7 +2,6 @@ private import csharp
private import DataFlowPublic
private import DataFlowDispatch
private import DataFlowImplCommon
private import ControlFlowReachability
private import FlowSummaryImpl as FlowSummaryImpl
private import semmle.code.csharp.dataflow.FlowSummary as FlowSummary
private import semmle.code.csharp.dataflow.internal.ExternalFlow
@@ -259,34 +258,16 @@ private module ThisFlow {
}
}
/**
* Holds if there is a control-flow path from `n1` to `n2`. `n2` is either an
* expression node or an SSA definition node.
*/
pragma[nomagic]
predicate hasNodePath(ControlFlowReachabilityConfiguration conf, ExprNode n1, Node n2) {
exists(ControlFlow::Node cfn1, ControlFlow::Node cfn2 | conf.hasExprPath(_, cfn1, _, cfn2) |
cfn1 = n1.getControlFlowNode() and
cfn2 = n2.(ExprNode).getControlFlowNode()
)
or
exists(ControlFlow::Node cfn, AssignableDefinition def, ControlFlow::Node cfnDef |
conf.hasDefPath(_, cfn, def, cfnDef) and
cfn = n1.getControlFlowNode() and
n2 = TAssignableDefinitionNode(def, cfnDef)
)
}
/** Provides logic related to captured variables. */
module VariableCapture {
private import codeql.dataflow.VariableCapture as Shared
private import semmle.code.csharp.controlflow.BasicBlocks as BasicBlocks
private predicate closureFlowStep(ControlFlow::Nodes::ExprNode e1, ControlFlow::Nodes::ExprNode e2) {
e1 = LocalFlow::getALastEvalNode(e2)
e1.getExpr() = LocalFlow::getALastEvalNode(e2.getExpr())
or
exists(Ssa::Definition def, AssignableDefinition adef |
LocalFlow::defAssigns(adef, _, e1) and
LocalFlow::defAssigns(adef, _, _, e1) and
def.getAnUltimateDefinition().(Ssa::ExplicitDefinition).getADefinition() = adef and
exists(def.getAReadAtNode(e2))
)
@@ -379,7 +360,7 @@ module VariableCapture {
this = def.getExpr().getAControlFlowNode()
}
ControlFlow::Node getRhs() { LocalFlow::defAssigns(def, this, result) }
ControlFlow::Node getRhs() { LocalFlow::defAssigns(def, this, _, result) }
CapturedVariable getVariable() { result = v }
}
@@ -528,127 +509,74 @@ module SsaFlow {
/** Provides predicates related to local data flow. */
module LocalFlow {
class LocalExprStepConfiguration extends ControlFlowReachabilityConfiguration {
LocalExprStepConfiguration() { this = "LocalExprStepConfiguration" }
override predicate candidate(
Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor
) {
exactScope = false and
(
e1 = e2.(ParenthesizedExpr).getExpr() and
scope = e2 and
isSuccessor = true
or
e1 = e2.(NullCoalescingExpr).getAnOperand() and
scope = e2 and
isSuccessor = true
or
e1 = e2.(SuppressNullableWarningExpr).getExpr() and
scope = e2 and
isSuccessor = true
or
e2 =
any(ConditionalExpr ce |
e1 = ce.getThen() or
e1 = ce.getElse()
) and
scope = e2 and
isSuccessor = true
or
e1 = e2.(Cast).getExpr() and
scope = e2 and
isSuccessor = true
or
// An `=` expression, where the result of the expression is used
e2 =
any(AssignExpr ae |
ae.getParent() = any(ControlFlowElement cfe | not cfe instanceof ExprStmt) and
e1 = ae.getRValue()
) and
scope = e2 and
isSuccessor = true
or
e1 = e2.(ObjectCreation).getInitializer() and
scope = e2 and
isSuccessor = false
or
e1 = e2.(ArrayCreation).getInitializer() and
scope = e2 and
isSuccessor = false
or
e1 = e2.(SwitchExpr).getACase().getBody() and
scope = e2 and
isSuccessor = true
or
e1 = e2.(CheckedExpr).getExpr() and
scope = e2 and
isSuccessor = true
or
e1 = e2.(UncheckedExpr).getExpr() and
scope = e2 and
isSuccessor = true
or
e1 = e2.(CollectionExpression).getAnElement() and
e1 instanceof SpreadElementExpr and
scope = e2 and
isSuccessor = true
or
e1 = e2.(SpreadElementExpr).getExpr() and
scope = e2 and
isSuccessor = true
or
exists(WithExpr we |
scope = we and
isSuccessor = true
|
e1 = we.getExpr() and
e2 = we.getInitializer()
or
e1 = we.getInitializer() and
e2 = we
)
or
scope = any(AssignExpr ae | ae.getLValue().(TupleExpr) = e2 and ae.getRValue() = e1) and
isSuccessor = false
or
isSuccessor = true and
exists(ControlFlowElement cfe | cfe = e2.(TupleExpr).(PatternExpr).getPatternMatch() |
cfe.(IsExpr).getExpr() = e1 and scope = cfe
or
exists(Switch sw | sw.getACase() = cfe and sw.getExpr() = e1 and scope = sw)
)
predicate localExprStep(Expr e1, Expr e2) {
e1 = e2.(ParenthesizedExpr).getExpr()
or
e1 = e2.(NullCoalescingExpr).getAnOperand()
or
e1 = e2.(SuppressNullableWarningExpr).getExpr()
or
e2 =
any(ConditionalExpr ce |
e1 = ce.getThen() or
e1 = ce.getElse()
)
}
override predicate candidateDef(
Expr e, AssignableDefinition def, ControlFlowElement scope, boolean exactScope,
boolean isSuccessor
) {
// Flow from source to definition
exactScope = false and
def.getSource() = e and
(
scope = def.getExpr() and
isSuccessor = true
or
scope = def.(AssignableDefinitions::PatternDefinition).getMatch().(IsExpr) and
isSuccessor = false
or
exists(Switch s |
s.getACase() = def.(AssignableDefinitions::PatternDefinition).getMatch() and
isSuccessor = true
|
scope = s.getExpr()
or
scope = s.getACase()
)
or
e1 = e2.(Cast).getExpr()
or
// An `=` expression, where the result of the expression is used
e2 =
any(AssignExpr ae |
ae.getParent() = any(ControlFlowElement cfe | not cfe instanceof ExprStmt) and
e1 = ae.getRValue()
)
}
or
e1 = e2.(ObjectCreation).getInitializer()
or
e1 = e2.(ArrayCreation).getInitializer()
or
e1 = e2.(SwitchExpr).getACase().getBody()
or
e1 = e2.(CheckedExpr).getExpr()
or
e1 = e2.(UncheckedExpr).getExpr()
or
e1 = e2.(CollectionExpression).getAnElement() and
e1 instanceof SpreadElementExpr
or
e1 = e2.(SpreadElementExpr).getExpr()
or
exists(WithExpr we |
e1 = we.getExpr() and
e2 = we.getInitializer()
or
e1 = we.getInitializer() and
e2 = we
)
or
exists(AssignExpr ae | ae.getLValue().(TupleExpr) = e2 and ae.getRValue() = e1)
or
exists(ControlFlowElement cfe | cfe = e2.(TupleExpr).(PatternExpr).getPatternMatch() |
cfe.(IsExpr).getExpr() = e1
or
exists(Switch sw | sw.getACase() = cfe and sw.getExpr() = e1)
)
}
predicate defAssigns(AssignableDefinition def, ControlFlow::Node cfnDef, ControlFlow::Node value) {
any(LocalExprStepConfiguration x).hasDefPath(_, value, def, cfnDef)
predicate defAssigns(
AssignableDefinition def, ControlFlow::Node cfnDef, Expr value, ControlFlow::Node valueCfn
) {
def.getSource() = value and
valueCfn = value.getControlFlowNode() and
cfnDef = def.getExpr().getAControlFlowNode()
}
private predicate defAssigns(ExprNode value, AssignableDefinitionNode defNode) {
exists(ControlFlow::Node cfn, AssignableDefinition def, ControlFlow::Node cfnDef |
defAssigns(def, cfnDef, value.getExpr(), _) and
cfn = value.getControlFlowNode() and
defNode = TAssignableDefinitionNode(def, cfnDef)
)
}
/**
@@ -659,7 +587,9 @@ module LocalFlow {
}
predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) {
hasNodePath(any(LocalExprStepConfiguration x), nodeFrom, nodeTo)
localExprStep(nodeFrom.asExpr(), nodeTo.asExpr())
or
defAssigns(nodeFrom, nodeTo)
or
ThisFlow::adjacentThisRefs(nodeFrom, nodeTo) and
nodeFrom != nodeTo
@@ -685,11 +615,12 @@ module LocalFlow {
}
/**
* Gets a node that may execute last in `n`, and which, when it executes last,
* will be the value of `n`.
* Gets a node that may execute last in `e`, and which, when it executes last,
* will be the value of `e`.
*/
ControlFlow::Nodes::ExprNode getALastEvalNode(ControlFlow::Nodes::ExprNode cfn) {
exists(Expr e | any(LocalExprStepConfiguration x).hasExprPath(_, result, e, cfn) |
Expr getALastEvalNode(Expr e) {
localExprStep(result, e) and
(
e instanceof ConditionalExpr or
e instanceof Cast or
e instanceof NullCoalescingExpr or
@@ -713,9 +644,7 @@ module LocalFlow {
* we add a reverse flow step from `[post] b ? x : y` to `[post] x` and to
* `[post] y`, in order for the side-effect of `m` to reach both `x` and `y`.
*/
ControlFlow::Nodes::ExprNode getPostUpdateReverseStep(ControlFlow::Nodes::ExprNode e) {
result = getALastEvalNode(e)
}
Expr getPostUpdateReverseStep(Expr e) { result = getALastEvalNode(e) }
/**
* Holds if the value of `node2` is given by `node1`.
@@ -729,9 +658,10 @@ module LocalFlow {
e instanceof ThisAccess or e instanceof BaseAccess
)
or
hasNodePath(any(LocalExprStepConfiguration x), node1, node2) and
defAssigns(node1, node2)
or
localExprStep(node1.asExpr(), node2.asExpr()) and
(
node2 instanceof AssignableDefinitionNode or
node2.asExpr() instanceof Cast or
node2.asExpr() instanceof AssignExpr
)
@@ -775,12 +705,8 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) {
or
nodeTo = nodeFrom.(LocalFunctionCreationNode).getAnAccess(true)
or
nodeTo.(PostUpdateNode).getPreUpdateNode().(ExprNode).getControlFlowNode() =
LocalFlow::getPostUpdateReverseStep(nodeFrom
.(PostUpdateNode)
.getPreUpdateNode()
.(ExprNode)
.getControlFlowNode())
nodeTo.(PostUpdateNode).getPreUpdateNode().asExpr() =
LocalFlow::getPostUpdateReverseStep(nodeFrom.(PostUpdateNode).getPreUpdateNode().asExpr())
) and
model = ""
or
@@ -834,11 +760,11 @@ private class Argument extends Expr {
}
/**
* Holds if `e` is an assignment of `src` to field or property `c` of `q`.
* Holds if there is an assignment of `src` to field or property `c` of `q`.
*
* `postUpdate` indicates whether the store targets a post-update node.
*/
private predicate fieldOrPropertyStore(Expr e, ContentSet c, Expr src, Expr q, boolean postUpdate) {
private predicate fieldOrPropertyStore(ContentSet c, Expr src, Expr q, boolean postUpdate) {
exists(FieldOrProperty f |
c = f.getContentSet() and
(
@@ -861,25 +787,20 @@ private predicate fieldOrPropertyStore(Expr e, ContentSet c, Expr src, Expr q, b
f = fa.getTarget() and
src = def.getSource() and
q = fa.getQualifier() and
e = def.getExpr() and
postUpdate = true
)
or
// `with` expression initializer, `x with { f = src }`
e =
any(WithExpr we |
exists(MemberInitializer mi |
q = we and
mi = we.getInitializer().getAMemberInitializer() and
f = mi.getInitializedMember() and
src = mi.getRValue() and
postUpdate = false
)
)
exists(WithExpr we, MemberInitializer mi |
q = we and
mi = we.getInitializer().getAMemberInitializer() and
f = mi.getInitializedMember() and
src = mi.getRValue() and
postUpdate = false
)
or
// Object initializer, `new C() { f = src }`
exists(MemberInitializer mi |
e = q and
mi = q.(ObjectInitializer).getAMemberInitializer() and
q.getParent() instanceof ObjectCreation and
f = mi.getInitializedMember() and
@@ -888,16 +809,13 @@ private predicate fieldOrPropertyStore(Expr e, ContentSet c, Expr src, Expr q, b
)
or
// Tuple element, `(..., src, ...)` `f` is `ItemX` of tuple `q`
e =
any(TupleExpr te |
exists(int i |
e = q and
src = te.getArgument(i) and
te.isConstruction() and
f = q.getType().(TupleType).getElement(i) and
postUpdate = false
)
)
exists(TupleExpr te, int i |
te = q and
src = te.getArgument(i) and
te.isConstruction() and
f = q.getType().(TupleType).getElement(i) and
postUpdate = false
)
)
or
// A write to a dynamic property
@@ -907,7 +825,6 @@ private predicate fieldOrPropertyStore(Expr e, ContentSet c, Expr src, Expr q, b
c.isDynamicProperty(dp) and
src = def.getSource() and
q = dma.getQualifier() and
e = def.getExpr() and
postUpdate = true
)
}
@@ -943,22 +860,20 @@ private predicate collectionStore(Expr src, CollectionExpression ce) {
}
/**
* Holds if `e` is an expression that adds `src` to array `a`.
* Holds if there is an expression that adds `src` to array `a`.
*
* `postUpdate` indicates whether the store targets a post-update node.
*/
private predicate arrayStore(Expr e, Expr src, Expr a, boolean postUpdate) {
private predicate arrayStore(Expr src, Expr a, boolean postUpdate) {
// Direct assignment, `a[i] = src`
exists(AssignableDefinition def |
a = def.getTargetAccess().(ArrayWrite).getQualifier() and
src = def.getSource() and
e = def.getExpr() and
postUpdate = true
)
or
// Array initializer, `new [] { src }`
src = a.(ArrayInitializer).getAnElement() and
e = a and
postUpdate = false
or
// Member initializer, `new C { Array = { [i] = src } }`
@@ -966,7 +881,6 @@ private predicate arrayStore(Expr e, Expr src, Expr a, boolean postUpdate) {
mi = a.(ObjectInitializer).getAMemberInitializer() and
mi.getLValue() instanceof ArrayAccess and
mi.getRValue() = src and
e = a and
postUpdate = false
)
}
@@ -1141,17 +1055,17 @@ private module Cached {
(
cfn.getExpr() instanceof Argument
or
cfn =
LocalFlow::getPostUpdateReverseStep(any(ControlFlow::Nodes::ExprNode e |
exists(any(SourcePostUpdateNode p).getPreUpdateNode().asExprAtNode(e))
))
cfn.getExpr() =
LocalFlow::getPostUpdateReverseStep(any(SourcePostUpdateNode p)
.getPreUpdateNode()
.asExpr())
) and
exprMayHavePostUpdateNode(cfn.getExpr())
or
exists(Expr e | e = cfn.getExpr() |
fieldOrPropertyStore(_, _, _, e, true)
fieldOrPropertyStore(_, _, e, true)
or
arrayStore(_, _, e, true)
arrayStore(_, e, true)
or
// needed for reverse stores; e.g. `x.f1.f2 = y` induces
// a store step of `f1` into `x`
@@ -1166,7 +1080,7 @@ private module Cached {
)
)
or
lambdaCallExpr(_, cfn)
lambdaCallExpr(_, _, cfn)
} or
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) {
sn.getSummarizedCallable() instanceof CallableUsedInSource
@@ -1563,35 +1477,15 @@ abstract private class ArgumentNodeImpl extends Node {
}
private module ArgumentNodes {
private class ArgumentConfiguration extends ControlFlowReachabilityConfiguration {
ArgumentConfiguration() { this = "ArgumentConfiguration" }
override predicate candidate(
Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor
) {
e1.(Argument).isArgumentOf(e2, _) and
exactScope = false and
isSuccessor = true and
if e2 instanceof PropertyWrite
then
exists(AssignableDefinition def |
def.getTargetAccess() = e2 and
scope = def.getExpr()
)
else scope = e2
}
}
/** A data-flow node that represents an explicit call argument. */
class ExplicitArgumentNode extends ArgumentNodeImpl {
ExplicitArgumentNode() { this.asExpr() instanceof Argument }
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
exists(ArgumentConfiguration x, Expr c, Argument arg |
exists(Expr c, Argument arg |
arg = this.asExpr() and
c = call.getExpr() and
arg.isArgumentOf(c, pos) and
x.hasExprPath(_, this.getControlFlowNode(), _, call.getControlFlowNode())
arg.isArgumentOf(c, pos)
)
}
}
@@ -1600,7 +1494,7 @@ private module ArgumentNodes {
class DelegateSelfArgumentNode extends ArgumentNodeImpl, ExprNode {
private DataFlowCall call_;
DelegateSelfArgumentNode() { lambdaCallExpr(call_, this.getControlFlowNode()) }
DelegateSelfArgumentNode() { lambdaCallExpr(call_, this.getExpr(), _) }
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
call = call_ and
@@ -1857,27 +1751,6 @@ private module OutNodes {
}
}
class ObjectOrCollectionInitializerConfiguration extends ControlFlowReachabilityConfiguration {
ObjectOrCollectionInitializerConfiguration() {
this = "ObjectOrCollectionInitializerConfiguration"
}
override predicate candidate(
Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor
) {
exactScope = false and
scope = e1 and
isSuccessor = true and
exists(ObjectOrCollectionInitializer init | init = e1.(ObjectCreation).getInitializer() |
// E.g. `new Dictionary<int, string>{ {0, "a"}, {1, "b"} }`
e2 = init.(CollectionInitializer).getAnElementInitializer()
or
// E.g. `new Dictionary<int, string>() { [0] = "a", [1] = "b" }`
e2 = init.(ObjectInitializer).getAMemberInitializer().getLValue()
)
}
}
/**
* A data-flow node that reads a value returned by a callable using an
* `out` or `ref` parameter.
@@ -2236,30 +2109,6 @@ predicate jumpStep(Node pred, Node succ) {
succ = pred.(LocalFunctionCreationNode).getAnAccess(false)
}
private class StoreStepConfiguration extends ControlFlowReachabilityConfiguration {
StoreStepConfiguration() { this = "StoreStepConfiguration" }
override predicate candidate(
Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor
) {
exactScope = false and
fieldOrPropertyStore(scope, _, e1, e2, isSuccessor.booleanNot())
or
exactScope = false and
arrayStore(scope, e1, e2, isSuccessor.booleanNot())
or
exactScope = false and
isSuccessor = true and
collectionStore(e1, e2) and
scope = e2
or
exactScope = false and
isSuccessor = true and
isParamsArg(e2, e1, _) and
scope = e2
}
}
pragma[nomagic]
private ContentSet getResultContent() {
result.isProperty(any(SystemThreadingTasksTaskTClass c_).getResultProperty())
@@ -2282,21 +2131,17 @@ private predicate recordParameter(RecordType t, Parameter p, string name) {
}
private predicate storeContentStep(Node node1, Content c, Node node2) {
exists(StoreStepConfiguration x, ExprNode node, boolean postUpdate |
hasNodePath(x, node1, node) and
exists(ExprNode node, boolean postUpdate |
if postUpdate = true then node = node2.(PostUpdateNode).getPreUpdateNode() else node = node2
|
arrayStore(_, node1.asExpr(), node.getExpr(), postUpdate) and c instanceof ElementContent
arrayStore(node1.asExpr(), node.getExpr(), postUpdate) and c instanceof ElementContent
)
or
exists(StoreStepConfiguration x | hasNodePath(x, node1, node2) |
collectionStore(node1.asExpr(), node2.asExpr()) and c instanceof ElementContent
)
collectionStore(node1.asExpr(), node2.asExpr()) and c instanceof ElementContent
or
exists(StoreStepConfiguration x, Expr arg, ControlFlow::Node callCfn |
x.hasExprPath(arg, node1.(ExprNode).getControlFlowNode(), _, callCfn) and
node2 = TParamsArgumentNode(callCfn) and
isParamsArg(_, arg, _) and
exists(Call call |
node2 = TParamsArgumentNode(call.getControlFlowNode()) and
isParamsArg(call, node1.asExpr(), _) and
c instanceof ElementContent
)
or
@@ -2352,11 +2197,10 @@ predicate storeStep(Node node1, ContentSet c, Node node2) {
c.isSingleton(cont)
)
or
exists(StoreStepConfiguration x, ExprNode node, boolean postUpdate |
hasNodePath(x, node1, node) and
exists(ExprNode node, boolean postUpdate |
if postUpdate = true then node = node2.(PostUpdateNode).getPreUpdateNode() else node = node2
|
fieldOrPropertyStore(_, c, node1.asExpr(), node.getExpr(), postUpdate)
fieldOrPropertyStore(c, node1.asExpr(), node.getExpr(), postUpdate)
)
or
exists(Expr e |
@@ -2378,133 +2222,51 @@ predicate storeStep(Node node1, ContentSet c, Node node2) {
storeStepDelegateCall(node1, c, node2)
}
pragma[nomagic]
private predicate isAssignExprLValueDescendant(Expr e) {
e = any(AssignExpr ae).getLValue()
or
exists(Expr parent |
isAssignExprLValueDescendant(parent) and
e = parent.getAChildExpr()
)
}
private class ReadStepConfiguration extends ControlFlowReachabilityConfiguration {
ReadStepConfiguration() { this = "ReadStepConfiguration" }
override predicate candidate(
Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor
) {
exactScope = false and
isSuccessor = true and
fieldOrPropertyRead(e1, _, e2) and
scope = e2
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
exactScope = false and
e1 = e2.(AwaitExpr).getExpr() and
scope = e2 and
isSuccessor = true
or
exactScope = false and
e2 = e1.(TupleExpr).getAnArgument() and
scope = e1 and
isSuccessor = false
}
override predicate candidateDef(
Expr e, AssignableDefinition defTo, ControlFlowElement scope, boolean exactScope,
boolean isSuccessor
) {
exists(ForeachStmt fs |
e = fs.getIterableExpr() and
defTo.(AssignableDefinitions::LocalVariableDefinition).getDeclaration() =
fs.getVariableDeclExpr() and
isSuccessor = true
|
scope = fs and
exactScope = true
or
scope = fs.getIterableExpr() and
exactScope = false
or
scope = fs.getVariableDeclExpr() and
exactScope = false
)
or
scope =
any(AssignExpr ae |
ae = defTo.(AssignableDefinitions::TupleAssignmentDefinition).getAssignment() and
isAssignExprLValueDescendant(e.(TupleExpr)) and
exactScope = false and
isSuccessor = true
)
or
scope =
any(TupleExpr te |
te.getAnArgument() = defTo.(AssignableDefinitions::LocalVariableDefinition).getDeclaration() and
e = te and
exactScope = false and
isSuccessor = false
)
}
}
private predicate readContentStep(Node node1, Content c, Node node2) {
exists(ReadStepConfiguration x |
hasNodePath(x, node1, node2) and
arrayRead(node1.asExpr(), node2.asExpr()) and
arrayRead(node1.asExpr(), node2.asExpr()) and
c instanceof ElementContent
or
exists(
ForeachStmt fs, Ssa::ExplicitDefinition def,
AssignableDefinitions::LocalVariableDefinition defTo
|
node1.asExpr() = fs.getIterableExpr() and
defTo.getDeclaration() = fs.getVariableDeclExpr() and
def.getADefinition() = defTo and
node2.(SsaDefinitionNode).getDefinition() = def and
c instanceof ElementContent
)
or
node1 =
any(InstanceParameterAccessPreNode n |
n.getUnderlyingControlFlowNode() = node2.(ExprNode).getControlFlowNode() and
n.getParameter() = c.(PrimaryConstructorParameterContent).getParameter()
) and
node2.asExpr() instanceof ParameterRead
or
// node1 = (..., node2, ...)
// node1.ItemX flows to node2
exists(TupleExpr te, int i, Expr item |
te = node1.asExpr() and
not te.isConstruction() and
c.(FieldContent).getField() = te.getType().(TupleType).getElement(i).getUnboundDeclaration() and
// node1 = (..., item, ...)
te.getArgument(i) = item
|
// item = (..., ..., ...) in node1 = (..., (..., ..., ...), ...)
node2.asExpr().(TupleExpr) = item
or
exists(ForeachStmt fs, Ssa::ExplicitDefinition def |
x.hasDefPath(fs.getIterableExpr(), node1.getControlFlowNode(), def.getADefinition(),
def.getControlFlowNode()) and
node2.(SsaDefinitionNode).getDefinition() = def and
c instanceof ElementContent
// item = variable in node1 = (..., variable, ...)
exists(AssignableDefinitions::TupleAssignmentDefinition tad |
node2.(AssignableDefinitionNode).getDefinition() = tad and
tad.getLeaf() = item
)
or
node1 =
any(InstanceParameterAccessPreNode n |
n.getUnderlyingControlFlowNode() = node2.(ExprNode).getControlFlowNode() and
n.getParameter() = c.(PrimaryConstructorParameterContent).getParameter()
) and
node2.asExpr() instanceof ParameterRead
or
// node1 = (..., node2, ...)
// node1.ItemX flows to node2
exists(TupleExpr te, int i, Expr item |
te = node1.asExpr() and
not te.isConstruction() and
c.(FieldContent).getField() = te.getType().(TupleType).getElement(i).getUnboundDeclaration() and
// node1 = (..., item, ...)
te.getArgument(i) = item
|
// item = (..., ..., ...) in node1 = (..., (..., ..., ...), ...)
node2.asExpr().(TupleExpr) = item and
hasNodePath(x, node1, node2)
or
// item = variable in node1 = (..., variable, ...)
exists(AssignableDefinitions::TupleAssignmentDefinition tad |
node2.(AssignableDefinitionNode).getDefinition() = tad and
tad.getLeaf() = item and
hasNodePath(x, node1, node2)
)
or
// item = variable in node1 = (..., variable, ...) in a case/is var (..., ...)
isPatternExprDescendant(te) and
exists(AssignableDefinitions::LocalVariableDefinition lvd |
node2.(AssignableDefinitionNode).getDefinition() = lvd and
lvd.getDeclaration() = item and
hasNodePath(x, node1, node2)
)
// item = variable in node1 = (..., variable, ...) in a case/is var (..., ...)
isPatternExprDescendant(te) and
exists(AssignableDefinitions::LocalVariableDefinition lvd |
node2.(AssignableDefinitionNode).getDefinition() = lvd and
lvd.getDeclaration() = item
)
)
or
@@ -2535,14 +2297,12 @@ predicate readStep(Node node1, ContentSet c, Node node2) {
c.isSingleton(cont)
)
or
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()
)
fieldOrPropertyRead(node1.asExpr(), c, node2.asExpr())
or
dynamicPropertyRead(node1.asExpr(), c, node2.asExpr())
or
node2.asExpr().(AwaitExpr).getExpr() = node1.asExpr() and
c = getResultContent()
or
FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), c,
node2.(FlowSummaryNode).getSummaryNode())
@@ -2576,9 +2336,9 @@ predicate clearsContent(Node n, ContentSet c) {
c.isSingleton(cont)
)
or
fieldOrPropertyStore(_, c, _, n.asExpr(), true)
fieldOrPropertyStore(c, _, n.asExpr(), true)
or
fieldOrPropertyStore(_, c, _, n.(ObjectInitializerNode).getInitializer(), false)
fieldOrPropertyStore(c, _, n.(ObjectInitializerNode).getInitializer(), false)
or
FlowSummaryImpl::Private::Steps::summaryClearsContent(n.(FlowSummaryNode).getSummaryNode(), c)
or
@@ -2817,8 +2577,13 @@ module PostUpdateNodes {
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
pos.isQualifier() and
any(ObjectOrCollectionInitializerConfiguration x)
.hasExprPath(_, cfn, _, call.getControlFlowNode())
exists(ObjectOrCollectionInitializer init | init = oc.getInitializer() |
// E.g. `new Dictionary<int, string>{ {0, "a"}, {1, "b"} }`
call.getExpr() = init.(CollectionInitializer).getAnElementInitializer()
or
// E.g. `new Dictionary<int, string>() { [0] = "a", [1] = "b" }`
call.getExpr() = init.(ObjectInitializer).getAMemberInitializer().getLValue()
)
}
override DataFlowCallable getEnclosingCallableImpl() {
@@ -2980,45 +2745,26 @@ private predicate isLocalFunctionCallReceiver(
f = receiver.getTarget().getUnboundDeclaration()
}
private class LambdaConfiguration extends ControlFlowReachabilityConfiguration {
LambdaConfiguration() { this = "LambdaConfiguration" }
override predicate candidate(
Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor
) {
e1 = e2.(DelegateLikeCall).getExpr() and
exactScope = false and
scope = e2 and
isSuccessor = true
or
e1 = e2.(DelegateCreation).getArgument() and
exactScope = false and
scope = e2 and
isSuccessor = true
or
isLocalFunctionCallReceiver(e2, e1, _) and
exactScope = false and
scope = e2 and
isSuccessor = true
}
}
private predicate lambdaCallExpr(DataFlowCall call, ControlFlow::Node receiver) {
exists(LambdaConfiguration x, DelegateLikeCall dc |
x.hasExprPath(dc.getExpr(), receiver, dc, call.getControlFlowNode())
private predicate lambdaCallExpr(DataFlowCall call, Expr receiver, ControlFlow::Node receiverCfn) {
exists(DelegateLikeCall dc |
call.(ExplicitDelegateLikeDataFlowCall).getCall() = dc and
receiver = dc.getExpr() and
receiverCfn = receiver.getControlFlowNode()
)
or
// In local function calls, `F()`, we use the local function access `F`
// to represent the receiver. Only needed for flow through captured variables.
exists(LambdaConfiguration x, LocalFunctionCall fc |
x.hasExprPath(fc.getAChild(), receiver, fc, call.getControlFlowNode())
exists(LocalFunctionCall fc |
receiver = fc.getAChild() and
receiverCfn = receiver.getControlFlowNode() and
fc.getControlFlowNode() = call.getControlFlowNode()
)
}
/** Holds if `call` is a lambda call where `receiver` is the lambda expression. */
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
(
lambdaCallExpr(call, receiver.(ExprNode).getControlFlowNode()) and
lambdaCallExpr(call, receiver.asExpr(), _) and
// local function calls can be resolved directly without a flow analysis
not call.getControlFlowNode().getAstNode() instanceof LocalFunctionCall
or
@@ -3028,9 +2774,9 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
}
private predicate delegateCreationStep(Node nodeFrom, Node nodeTo) {
exists(LambdaConfiguration x, DelegateCreation dc |
x.hasExprPath(dc.getArgument(), nodeFrom.(ExprNode).getControlFlowNode(), dc,
nodeTo.(ExprNode).getControlFlowNode())
exists(DelegateCreation dc |
dc.getArgument() = nodeFrom.asExpr() and
dc = nodeTo.asExpr()
)
}

View File

@@ -4,7 +4,6 @@ private import FlowSummaryImpl as FlowSummaryImpl
private import semmle.code.csharp.Caching
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
private import semmle.code.csharp.dataflow.internal.ControlFlowReachability
private import semmle.code.csharp.dispatch.Dispatch
private import semmle.code.csharp.commons.ComparisonTest
// import `TaintedMember` definitions from other files to avoid potential reevaluation
@@ -45,82 +44,58 @@ predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::ContentSet c)
)
}
private class LocalTaintExprStepConfiguration extends ControlFlowReachabilityConfiguration {
LocalTaintExprStepConfiguration() { this = "LocalTaintExprStepConfiguration" }
override predicate candidate(
Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor
) {
exactScope = false and
isSuccessor = true and
(
e1 = e2.(ElementAccess).getQualifier() and
scope = e2
or
e1 = e2.(AddExpr).getAnOperand() and
scope = e2
or
// A comparison expression where taint can flow from one of the
// operands if the other operand is a constant value.
exists(ComparisonTest ct, Expr other |
ct.getExpr() = e2 and
e1 = ct.getAnArgument() and
other = ct.getAnArgument() and
other.stripCasts().hasValue() and
e1 != other and
scope = e2
)
or
e1 = e2.(UnaryLogicalOperation).getAnOperand() and
scope = e2
or
e1 = e2.(BinaryLogicalOperation).getAnOperand() and
scope = e2
or
e1 = e2.(InterpolatedStringExpr).getAChild() and
scope = e2
or
e1 = e2.(InterpolatedStringInsertExpr).getInsert() and
scope = e2
or
e2 =
any(OperatorCall oc |
oc.getTarget().(ConversionOperator).fromLibrary() and
e1 = oc.getAnArgument() and
scope = e2
)
or
e1 = e2.(AwaitExpr).getExpr() and
scope = e2
or
// Taint flows from the operand of a cast to the cast expression if the cast is to an interpolated string handler.
e2 =
any(CastExpr ce |
e1 = ce.getExpr() and
scope = ce and
ce.getTargetType()
.(Attributable)
.getAnAttribute()
.getType()
.hasFullyQualifiedName("System.Runtime.CompilerServices",
"InterpolatedStringHandlerAttribute")
)
)
}
}
private ControlFlow::Nodes::ExprNode getALastEvalNode(ControlFlow::Nodes::ExprNode cfn) {
exists(OperatorCall oc | any(LocalTaintExprStepConfiguration x).hasExprPath(_, result, oc, cfn) |
oc.getTarget() instanceof ImplicitConversionOperator
private predicate localTaintExprStep(Expr e1, Expr e2) {
e1 = e2.(ElementAccess).getQualifier()
or
e1 = e2.(AddExpr).getAnOperand()
or
// A comparison expression where taint can flow from one of the
// operands if the other operand is a constant value.
exists(ComparisonTest ct, Expr other |
ct.getExpr() = e2 and
e1 = ct.getAnArgument() and
other = ct.getAnArgument() and
other.stripCasts().hasValue() and
e1 != other
)
or
e1 = e2.(UnaryLogicalOperation).getAnOperand()
or
e1 = e2.(BinaryLogicalOperation).getAnOperand()
or
e1 = e2.(InterpolatedStringExpr).getAChild()
or
e1 = e2.(InterpolatedStringInsertExpr).getInsert()
or
e2 =
any(OperatorCall oc |
oc.getTarget().(ConversionOperator).fromLibrary() and
e1 = oc.getAnArgument()
)
or
e1 = e2.(AwaitExpr).getExpr()
or
// Taint flows from the operand of a cast to the cast expression if the cast is to an interpolated string handler.
e2 =
any(CastExpr ce |
e1 = ce.getExpr() and
ce.getTargetType()
.(Attributable)
.getAnAttribute()
.getType()
.hasFullyQualifiedName("System.Runtime.CompilerServices",
"InterpolatedStringHandlerAttribute")
)
}
private ControlFlow::Nodes::ExprNode getPostUpdateReverseStep(ControlFlow::Nodes::ExprNode e) {
result = getALastEvalNode(e)
private Expr getALastEvalNode(OperatorCall oc) {
localTaintExprStep(result, oc) and oc.getTarget() instanceof ImplicitConversionOperator
}
private Expr getPostUpdateReverseStep(Expr e) { result = getALastEvalNode(e) }
private predicate localTaintStepCommon(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
hasNodePath(any(LocalTaintExprStepConfiguration x), nodeFrom, nodeTo)
localTaintExprStep(nodeFrom.asExpr(), nodeTo.asExpr())
}
cached
@@ -191,12 +166,8 @@ private module Cached {
// Allow reverse update flow for implicit conversion operator calls.
// This is needed to support flow out of method call arguments, where an implicit conversion is applied
// to a call argument.
nodeTo.(PostUpdateNode).getPreUpdateNode().(DataFlow::ExprNode).getControlFlowNode() =
getPostUpdateReverseStep(nodeFrom
.(PostUpdateNode)
.getPreUpdateNode()
.(DataFlow::ExprNode)
.getControlFlowNode())
nodeTo.(PostUpdateNode).getPreUpdateNode().asExpr() =
getPostUpdateReverseStep(nodeFrom.(PostUpdateNode).getPreUpdateNode().asExpr())
) and
model = ""
or

View File

@@ -1,246 +0,0 @@
import csharp
private class ControlFlowScope extends ControlFlowElement {
private boolean exactScope;
ControlFlowScope() {
exists(ControlFlowReachabilityConfiguration c |
c.candidate(_, _, this, exactScope, _) or
c.candidateDef(_, _, this, exactScope, _)
)
}
predicate isExact() { exactScope = true }
predicate isNonExact() { exactScope = false }
}
private newtype TControlFlowElementOrBasicBlock =
TControlFlowElement(ControlFlowElement cfe) or
TBasicBlock(ControlFlow::BasicBlock bb)
class ControlFlowElementOrBasicBlock extends TControlFlowElementOrBasicBlock {
ControlFlowElement asControlFlowElement() { this = TControlFlowElement(result) }
ControlFlow::BasicBlock asBasicBlock() { this = TBasicBlock(result) }
string toString() {
result = this.asControlFlowElement().toString()
or
result = this.asBasicBlock().toString()
}
Location getLocation() {
result = this.asControlFlowElement().getLocation()
or
result = this.asBasicBlock().getLocation()
}
}
private predicate isBasicBlock(ControlFlowElementOrBasicBlock c) { c instanceof TBasicBlock }
private predicate isNonExactScope(ControlFlowElementOrBasicBlock c) {
c.asControlFlowElement().(ControlFlowScope).isNonExact()
}
private predicate step(ControlFlowElementOrBasicBlock pred, ControlFlowElementOrBasicBlock succ) {
pred.asBasicBlock().getANode().getAstNode() = succ.asControlFlowElement()
or
pred.asControlFlowElement() = succ.asControlFlowElement().getAChild()
}
private predicate basicBlockInNonExactScope(
ControlFlowElementOrBasicBlock bb, ControlFlowElementOrBasicBlock scope
) = doublyBoundedFastTC(step/2, isBasicBlock/1, isNonExactScope/1)(bb, scope)
pragma[noinline]
private ControlFlow::BasicBlock getABasicBlockInScope(ControlFlowScope scope, boolean exactScope) {
basicBlockInNonExactScope(TBasicBlock(result), TControlFlowElement(scope)) and
exactScope = false
or
scope.isExact() and
result.getANode().getAstNode() = scope and
exactScope = true
}
/**
* A helper class for determining control-flow reachability for pairs of
* elements.
*
* This is useful when defining for example expression-based data-flow steps in
* the presence of control-flow splitting, where a data-flow step should make
* sure to stay in the same split.
*
* For example, in
*
* ```csharp
* if (b)
* ....
* var x = "foo";
* if (b)
* ....
* ```
*
* there should only be steps from `[b = true] "foo"` to `[b = true] SSA def(x)`
* and `[b = false] "foo"` to `[b = false] SSA def(x)`, and for example not from
* `[b = true] "foo"` to `[b = false] SSA def(x)`
*/
abstract class ControlFlowReachabilityConfiguration extends string {
bindingset[this]
ControlFlowReachabilityConfiguration() { any() }
/**
* Holds if `e1` and `e2` are expressions for which we want to find a
* control-flow path that follows control flow successors (resp.
* predecessors, as specified by `isSuccessor`) inside the syntactic scope
* `scope`. The Boolean `exactScope` indicates whether a transitive child
* of `scope` is allowed (`exactScope = false`).
*/
predicate candidate(
Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor
) {
none()
}
/**
* Holds if `e` and `def` are elements for which we want to find a
* control-flow path that follows control flow successors (resp.
* predecessors, as specified by `isSuccessor`) inside the syntactic scope
* `scope`. The Boolean `exactScope` indicates whether a transitive child
* of `scope` is allowed (`exactScope = false`).
*/
predicate candidateDef(
Expr e, AssignableDefinition def, ControlFlowElement scope, boolean exactScope,
boolean isSuccessor
) {
none()
}
pragma[nomagic]
private predicate reachesBasicBlockExprBase(
Expr e1, Expr e2, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn1, int i,
ControlFlow::BasicBlock bb
) {
this.candidate(e1, e2, _, _, isSuccessor) and
cfn1 = e1.getAControlFlowNode() and
bb.getNode(i) = cfn1
}
pragma[nomagic]
private predicate reachesBasicBlockExprRec(
Expr e1, Expr e2, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn1,
ControlFlow::BasicBlock bb
) {
exists(ControlFlow::BasicBlock mid |
this.reachesBasicBlockExpr(e1, e2, isSuccessor, cfn1, mid)
|
isSuccessor = true and
bb = mid.getASuccessor()
or
isSuccessor = false and
bb = mid.getAPredecessor()
)
}
pragma[nomagic]
private predicate reachesBasicBlockExpr(
Expr e1, Expr e2, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn1,
ControlFlow::BasicBlock bb
) {
this.reachesBasicBlockExprBase(e1, e2, isSuccessor, cfn1, _, bb)
or
exists(ControlFlowElement scope, boolean exactScope |
this.candidate(e1, e2, scope, exactScope, isSuccessor) and
this.reachesBasicBlockExprRec(e1, e2, isSuccessor, cfn1, bb) and
bb = getABasicBlockInScope(scope, exactScope)
)
}
pragma[nomagic]
private predicate reachesBasicBlockDefinitionBase(
Expr e, AssignableDefinition def, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn,
int i, ControlFlow::BasicBlock bb
) {
this.candidateDef(e, def, _, _, isSuccessor) and
cfn = e.getAControlFlowNode() and
bb.getNode(i) = cfn
}
pragma[nomagic]
private predicate reachesBasicBlockDefinitionRec(
Expr e, AssignableDefinition def, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn,
ControlFlow::BasicBlock bb
) {
exists(ControlFlow::BasicBlock mid |
this.reachesBasicBlockDefinition(e, def, isSuccessor, cfn, mid)
|
isSuccessor = true and
bb = mid.getASuccessor()
or
isSuccessor = false and
bb = mid.getAPredecessor()
)
}
pragma[nomagic]
private predicate reachesBasicBlockDefinition(
Expr e, AssignableDefinition def, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfn,
ControlFlow::BasicBlock bb
) {
this.reachesBasicBlockDefinitionBase(e, def, isSuccessor, cfn, _, bb)
or
exists(ControlFlowElement scope, boolean exactScope |
this.candidateDef(e, def, scope, exactScope, isSuccessor) and
this.reachesBasicBlockDefinitionRec(e, def, isSuccessor, cfn, bb) and
bb = getABasicBlockInScope(scope, exactScope)
)
}
/**
* Holds if there is a control-flow path from `cfn1` to `cfn2`, where `cfn1` is a
* control-flow node for `e1` and `cfn2` is a control-flow node for `e2`.
*/
pragma[nomagic]
predicate hasExprPath(Expr e1, ControlFlow::Node cfn1, Expr e2, ControlFlow::Node cfn2) {
exists(ControlFlow::BasicBlock bb, boolean isSuccessor, int i, int j |
this.reachesBasicBlockExprBase(e1, e2, isSuccessor, cfn1, i, bb) and
cfn2 = bb.getNode(j) and
cfn2 = e2.getAControlFlowNode()
|
isSuccessor = true and j >= i
or
isSuccessor = false and i >= j
)
or
exists(ControlFlow::BasicBlock bb |
this.reachesBasicBlockExprRec(e1, e2, _, cfn1, bb) and
cfn2 = bb.getANode() and
cfn2 = e2.getAControlFlowNode()
)
}
/**
* Holds if there is a control-flow path from `cfn` to `cfnDef`, where `cfn` is a
* control-flow node for `e` and `cfnDef` is a control-flow node for `def`.
*/
pragma[nomagic]
predicate hasDefPath(
Expr e, ControlFlow::Node cfn, AssignableDefinition def, ControlFlow::Node cfnDef
) {
exists(ControlFlow::BasicBlock bb, boolean isSuccessor, int i, int j |
this.reachesBasicBlockDefinitionBase(e, def, isSuccessor, cfn, i, bb) and
cfnDef = bb.getNode(j) and
def.getExpr().getAControlFlowNode() = cfnDef
|
isSuccessor = true and j >= i
or
isSuccessor = false and i >= j
)
or
exists(ControlFlow::BasicBlock bb |
this.reachesBasicBlockDefinitionRec(e, def, _, cfn, bb) and
def.getExpr().getAControlFlowNode() = cfnDef and
cfnDef = bb.getANode()
)
}
}

View File

@@ -8,26 +8,14 @@ private module Impl {
private import ConstantUtils
private import SsaReadPositionCommon
private import semmle.code.csharp.controlflow.Guards as G
private import ControlFlowReachability
private class ExprNode = ControlFlow::Nodes::ExprNode;
private class ExprChildReachability extends ControlFlowReachabilityConfiguration {
ExprChildReachability() { this = "ExprChildReachability" }
override predicate candidate(
Expr e1, Expr e2, ControlFlowElement scope, boolean exactScope, boolean isSuccessor
) {
e2 = e1.getAChild() and
scope = e1 and
exactScope = false and
isSuccessor in [false, true]
}
}
/** Holds if `parent` having child `child` implies `parentNode` having child `childNode`. */
predicate hasChild(Expr parent, Expr child, ExprNode parentNode, ExprNode childNode) {
any(ExprChildReachability x).hasExprPath(parent, parentNode, child, childNode)
parent.getAChild() = child and
parentNode = parent.getControlFlowNode() and
childNode = child.getControlFlowNode()
}
/** Holds if SSA definition `def` equals `e + delta`. */

View File

@@ -1,3 +1,15 @@
## 1.6.6
No user-facing changes.
## 1.6.5
No user-facing changes.
## 1.6.4
No user-facing changes.
## 1.6.3
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.6.4
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.6.5
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.6.6
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.6.3
lastReleaseVersion: 1.6.6

View File

@@ -1,5 +1,5 @@
name: codeql/csharp-queries
version: 1.6.4-dev
version: 1.6.6
groups:
- csharp
- queries

View File

@@ -26,6 +26,7 @@
| CSharp7.cs:31:16:31:16 | access to parameter i | CSharp7.cs:31:16:31:20 | ... > ... |
| CSharp7.cs:31:16:31:16 | access to parameter i | CSharp7.cs:31:24:31:24 | access to parameter i |
| CSharp7.cs:31:24:31:24 | access to parameter i | CSharp7.cs:31:16:31:59 | ... ? ... : ... |
| CSharp7.cs:31:28:31:59 | throw ... | CSharp7.cs:31:16:31:59 | ... ? ... : ... |
| CSharp7.cs:35:7:35:18 | this | CSharp7.cs:35:7:35:18 | this access |
| CSharp7.cs:39:9:39:9 | access to parameter x | CSharp7.cs:39:9:39:21 | SSA def(x) |
| CSharp7.cs:39:13:39:21 | "tainted" | CSharp7.cs:39:9:39:9 | access to parameter x |
@@ -253,6 +254,7 @@
| CSharp7.cs:233:13:233:13 | access to local variable o | CSharp7.cs:235:13:235:42 | [input] SSA phi read(o) |
| CSharp7.cs:233:13:233:13 | access to local variable o | CSharp7.cs:237:18:237:18 | access to local variable o |
| CSharp7.cs:233:13:233:23 | [false] ... is ... | CSharp7.cs:233:13:233:33 | [false] ... && ... |
| CSharp7.cs:233:13:233:23 | [false] ... is ... | CSharp7.cs:233:13:233:33 | [true] ... && ... |
| CSharp7.cs:233:13:233:23 | [true] ... is ... | CSharp7.cs:233:13:233:33 | [false] ... && ... |
| CSharp7.cs:233:13:233:23 | [true] ... is ... | CSharp7.cs:233:13:233:33 | [true] ... && ... |
| CSharp7.cs:233:18:233:23 | Int32 i1 | CSharp7.cs:233:18:233:23 | SSA def(i1) |
@@ -338,6 +340,8 @@
| CSharp7.cs:297:35:297:35 | access to local variable x | CSharp7.cs:297:40:297:44 | Int32 y |
| CSharp7.cs:297:35:297:35 | access to local variable x | CSharp7.cs:297:49:297:49 | access to local variable x |
| CSharp7.cs:297:35:297:44 | [false] ... is ... | CSharp7.cs:297:25:297:44 | [false] ... && ... |
| CSharp7.cs:297:35:297:44 | [false] ... is ... | CSharp7.cs:297:25:297:44 | [true] ... && ... |
| CSharp7.cs:297:35:297:44 | [true] ... is ... | CSharp7.cs:297:25:297:44 | [false] ... && ... |
| CSharp7.cs:297:35:297:44 | [true] ... is ... | CSharp7.cs:297:25:297:44 | [true] ... && ... |
| CSharp7.cs:297:40:297:44 | Int32 y | CSharp7.cs:297:40:297:44 | SSA def(y) |
| CSharp7.cs:297:40:297:44 | SSA def(y) | CSharp7.cs:299:31:299:31 | access to local variable y |

View File

@@ -406,7 +406,7 @@ Adds a new taint source. Most taint-tracking queries will use the new source.
- **type**: Name of a type from which to evaluate **path**.
- **path**: Access path leading to the source.
- **kind**: Kind of source to add. Currently only **remote** is used.
- **kind**: Kind of source to add. See the section on source kinds for a list of supported kinds.
Example:
@@ -553,7 +553,16 @@ Kinds
Source kinds
~~~~~~~~~~~~
See documentation below for :ref:`Threat models <threat-models-javascript>`.
- **remote**: A general source of remote flow.
- **browser**: A source in the browser environment that does not fit a more specific browser kind.
- **browser-url-query**: A source derived from the query parameters of the browser URL, such as ``location.search``.
- **browser-url-fragment**: A source derived from the fragment part of the browser URL, such as ``location.hash``.
- **browser-url-path**: A source derived from the pathname of the browser URL, such as ``location.pathname``.
- **browser-url**: A source derived from the browser URL, where the untrusted part is prefixed by trusted data such as the scheme and hostname.
- **browser-window-name**: A source derived from the window name, such as ``window.name``.
- **browser-message-event**: A source derived from cross-window message passing, such as ``event`` in ``window.onmessage = event => {...}``.
See also :ref:`Threat models <threat-models-javascript>`.
Sink kinds
~~~~~~~~~~

View File

@@ -0,0 +1,121 @@
.. _codeql-cli-2.24.3:
==========================
CodeQL 2.24.3 (2026-03-05)
==========================
.. contents:: Contents
:depth: 2
:local:
:backlinks: none
This is an overview of changes in the CodeQL CLI and relevant CodeQL query and library packs. For additional updates on changes to the CodeQL code scanning experience, check out the `code scanning section on the GitHub blog <https://github.blog/tag/code-scanning/>`__, `relevant GitHub Changelog updates <https://github.blog/changelog/label/application-security/>`__, `changes in the CodeQL extension for Visual Studio Code <https://marketplace.visualstudio.com/items/GitHub.vscode-codeql/changelog>`__, and the `CodeQL Action changelog <https://github.com/github/codeql-action/blob/main/CHANGELOG.md>`__.
Security Coverage
-----------------
CodeQL 2.24.3 runs a total of 491 security queries when configured with the Default suite (covering 166 CWE). The Extended suite enables an additional 135 queries (covering 35 more CWE).
CodeQL CLI
----------
Bug Fixes
~~~~~~~~~
* Fixed a race condition that could cause flaky failures in overlay CodeQL tests. Test extraction now skips :code:`*.testproj` directories by name, preventing interference from concurrently cleaned-up test databases.
* Fixed spurious "OOPS" warnings that could appear in help output for commands using mutually exclusive option groups, such as :code:`codeql query run`.
Query Packs
-----------
Minor Analysis Improvements
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Java/Kotlin
"""""""""""
* The Java extractor and QL libraries now support Java 26.
* Java analysis now selects the Java version to use informed by Maven POM files across all project modules. It also tries to use Java 17 or higher for all Maven projects if possible, for improved build compatibility.
Rust
""""
* The macro resolution metric has been removed from :code:`rust/diagnostic/database-quality`. This metric was found to be an unreliable indicator of database quality in many cases, leading to false alarms on the tool status page.
Language Libraries
------------------
Bug Fixes
~~~~~~~~~
C/C++
"""""
* The :code:`allowInterproceduralFlow` predicate of must-flow data flow configurations now correctly handles direct recursion.
C#
""
* Fixed an issue where the body of a partial member could be extracted twice. When both a *defining* and an *implementing* declaration exist, only the *implementing* declaration is now extracted.
Breaking Changes
~~~~~~~~~~~~~~~~
C/C++
"""""
* CodeQL version 2.24.2 accidentally introduced a syntactical breaking change to :code:`BarrierGuard<...>::getAnIndirectBarrierNode` and :code:`InstructionBarrierGuard<...>::getAnIndirectBarrierNode`. These breaking changes have now been reverted so that the original code compiles again.
* :code:`MustFlow`, the inter-procedural must-flow data flow analysis library, has been re-worked to use parameterized modules. Like in the case of data flow and taint tracking, instead of extending the :code:`MustFlowConfiguration` class, the user should now implement a module with the :code:`MustFlow::ConfigSig` signature, and instantiate the :code:`MustFlow::Global` parameterized module with the implemented module.
Python
""""""
* The :code:`Metrics` library no longer contains code that depends on the points-to analysis. The removed functionality has instead been moved to the :code:`LegacyPointsTo` module, to classes like :code:`ModuleMetricsWithPointsTo` etc. If you depend on any of these classes, you must now remember to import :code:`LegacyPointsTo`, and use the appropriate types in order to use the points-to-based functionality.
Major Analysis Improvements
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Python
""""""
* The CodeQL Python libraries have been updated to be compatible with overlay evaluation. This should result in a significant speedup on analyses for which a base database already exists. Note that it may be necessary to add :code:`overlay[local?] module;` to user-managed libraries that extend classes that are now marked as :code:`overlay[local]`.
Minor Analysis Improvements
~~~~~~~~~~~~~~~~~~~~~~~~~~~
C/C++
"""""
* Refactored the "Year field changed using an arithmetic operation without checking for leap year" query (:code:`cpp/leap-year/unchecked-after-arithmetic-year-modification`) to address large numbers of false positive results.
C#
""
* C# 14: Added support for partial events.
* C# 14: Added support for the :code:`field` keyword in properties.
Java/Kotlin
"""""""""""
* Some modelling which previously only worked for Java EE packages beginning with "javax" will now also work for Java EE packages beginning with "jakarta" as well. This may lead to some alert changes.
JavaScript/TypeScript
"""""""""""""""""""""
* Added support for React components wrapped by :code:`observer` from :code:`mobx-react` and :code:`mobx-react-lite`.
Python
""""""
* Added new full SSRF sanitization barrier from the new AntiSSRF library.
* When a guard such as :code:`isSafe(x)` is defined, we now also automatically handle :code:`isSafe(x) == true` and :code:`isSafe(x) != false`.
Ruby
""""
* We now track taint flow through :code:`Shellwords.escape` and :code:`Shellwords.shellescape` for all queries except command injection, for which they are sanitizers.
Rust
""""
* Added support for neutral models (:code:`extensible: neutralModel`) to control where generated source, sink and flow summary models apply.

View File

@@ -0,0 +1,131 @@
.. _codeql-cli-2.25.0:
==========================
CodeQL 2.25.0 (2026-03-19)
==========================
.. contents:: Contents
:depth: 2
:local:
:backlinks: none
This is an overview of changes in the CodeQL CLI and relevant CodeQL query and library packs. For additional updates on changes to the CodeQL code scanning experience, check out the `code scanning section on the GitHub blog <https://github.blog/tag/code-scanning/>`__, `relevant GitHub Changelog updates <https://github.blog/changelog/label/application-security/>`__, `changes in the CodeQL extension for Visual Studio Code <https://marketplace.visualstudio.com/items/GitHub.vscode-codeql/changelog>`__, and the `CodeQL Action changelog <https://github.com/github/codeql-action/blob/main/CHANGELOG.md>`__.
Security Coverage
-----------------
CodeQL 2.25.0 runs a total of 491 security queries when configured with the Default suite (covering 166 CWE). The Extended suite enables an additional 135 queries (covering 35 more CWE).
CodeQL CLI
----------
Breaking Changes
~~~~~~~~~~~~~~~~
* :code:`codeql database interpret-results` and :code:`codeql database analyze` no longer attempt to reconstruct file baseline information from databases created with CLI versions before 2.11.2.
Bug Fixes
~~~~~~~~~
* Upgraded Jackson library from 2.16.1 to 2.18.6 to address a high-severity denial of service vulnerability (GHSA-72hv-8253-57qq) in jackson-core's async JSON parser.
* Upgraded snakeyaml (which is a dependency of jackson-dataformat-yaml) from 2.2 to 2.3.
Language Libraries
------------------
Breaking Changes
~~~~~~~~~~~~~~~~
Java/Kotlin
"""""""""""
* The Java control flow graph (CFG) implementation has been completely rewritten. The CFG now includes additional nodes to more accurately represent certain constructs. This also means that any existing code that implicitly relies on very specific details about the CFG may need to be updated.
The CFG now only includes the nodes that are reachable from the entry point.
Additionally, the following breaking changes have been made:
* :code:`ControlFlowNode.asCall` has been removed - use :code:`Call.getControlFlowNode` instead.
* :code:`ControlFlowNode.getEnclosingStmt` has been removed.
* :code:`ControlFlow::ExprNode` has been removed.
* :code:`ControlFlow::StmtNode` has been removed.
* :code:`ControlFlow::Node` has been removed - this was merely an alias of
:code:`ControlFlowNode`, which is still available.
* Previously deprecated predicates on :code:`BasicBlock` have been removed.
Major Analysis Improvements
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Swift
"""""
* Upgraded to allow analysis of Swift 6.2.4.
Minor Analysis Improvements
~~~~~~~~~~~~~~~~~~~~~~~~~~~
C/C++
"""""
* Inline expectations test comments, which are of the form :code:`// $ tag` or :code:`// $ tag=value`, are now parsed more strictly and will not be recognized if there isn't a space after the :code:`$` symbol.
C#
""
* Inline expectations test comments, which are of the form :code:`// $ tag` or :code:`// $ tag=value`, are now parsed more strictly and will not be recognized if there isn't a space after the :code:`$` symbol.
* Added :code:`System.Net.WebSockets::ReceiveAsync` as a remote flow source.
* Added reverse taint flow from implicit conversion operator calls to their arguments.
* Added post-update nodes for struct-type arguments, allowing data flow out of method calls via those arguments.
* C# 14: Added support for partial constructors.
Golang
""""""
* Inline expectations test comments, which are of the form :code:`// $ tag` or :code:`// $ tag=value`, are now parsed more strictly and will not be recognized if there isn't a space after the :code:`$` symbol.
Java/Kotlin
"""""""""""
* Inline expectations test comments, which are of the form :code:`// $ tag` or :code:`// $ tag=value`, are now parsed more strictly and will not be recognized if there isn't a space after the :code:`$` symbol.
* The class :code:`Assignment` now extends :code:`BinaryExpr`. Uses of :code:`BinaryExpr` may in some cases need slight adjustment.
JavaScript/TypeScript
"""""""""""""""""""""
* Added support for browser-specific source kinds (:code:`browser`, :code:`browser-url-query`, :code:`browser-url-fragment`, :code:`browser-url-path`, :code:`browser-url`, :code:`browser-window-name`, :code:`browser-message-event`) that can be used in data extensions to model sources in browser environments.
* Inline expectations test comments, which are of the form :code:`// $ tag` or :code:`// $ tag=value`, are now parsed more strictly and will not be recognized if there isn't a space after the :code:`$` symbol.
Python
""""""
* The call graph resolution no longer considers methods marked using |link-code-typing-overload-1|_ as valid targets. This ensures that only the method that contains the actual implementation gets resolved as a target.
* Inline expectations test comments, which are of the form :code:`# $ tag` or :code:`# $ tag=value`, are now parsed more strictly and will not be recognized if there isn't a space after the :code:`$` symbol.
Ruby
""""
* Inline expectations test comments, which are of the form :code:`# $ tag` or :code:`# $ tag=value`, are now parsed more strictly and will not be recognized if there isn't a space after the :code:`$` symbol.
Swift
"""""
* Inline expectations test comments, which are of the form :code:`// $ tag` or :code:`// $ tag=value`, are now parsed more strictly and will not be recognized if there isn't a space after the :code:`$` symbol.
Rust
""""
* Inline expectations test comments, which are of the form :code:`// $ tag` or :code:`// $ tag=value`, are now parsed more strictly and will not be recognized if there isn't a space after the :code:`$` symbol.
* Added neutral models to inhibit spurious generated sink models for :code:`map` and :code:`from`. This fixes some false positive query results.
Shared Libraries
----------------
New Features
~~~~~~~~~~~~
Dataflow Analysis
"""""""""""""""""
* Two new flow features :code:`FeatureEscapesSourceCallContext` and :code:`FeatureEscapesSourceCallContextOrEqualSourceSinkCallContext` have been added. The former implies that the sink must be reached from the source by escaping the source call context, that is, flow must either return from the callable containing the source or use a jump-step before reaching the sink. The latter is the disjunction of the former and the existing :code:`FeatureEqualSourceSinkCallContext` flow feature.
.. |link-code-typing-overload-1| replace:: :code:`@typing.overload`\
.. _link-code-typing-overload-1: https://typing.python.org/en/latest/spec/overload.html#overloads

View File

@@ -11,6 +11,8 @@ A list of queries for each suite and language `is available here <https://docs.g
.. toctree::
:maxdepth: 1
codeql-cli-2.25.0
codeql-cli-2.24.3
codeql-cli-2.24.2
codeql-cli-2.24.1
codeql-cli-2.24.0

View File

@@ -9,8 +9,8 @@ toolchain go1.26.0
// when adding or removing dependencies, run
// bazel mod tidy
require (
golang.org/x/mod v0.33.0
golang.org/x/tools v0.42.0
golang.org/x/mod v0.34.0
golang.org/x/tools v0.43.0
)
require github.com/stretchr/testify v1.11.1
@@ -18,6 +18,6 @@ require github.com/stretchr/testify v1.11.1
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sync v0.20.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@@ -6,12 +6,12 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=
golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s=
golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

View File

@@ -1,3 +1,15 @@
## 1.0.46
No user-facing changes.
## 1.0.45
No user-facing changes.
## 1.0.44
No user-facing changes.
## 1.0.43
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.44
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.45
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 1.0.46
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.0.43
lastReleaseVersion: 1.0.46

View File

@@ -1,5 +1,5 @@
name: codeql-go-consistency-queries
version: 1.0.44-dev
version: 1.0.46
groups:
- go
- queries

View File

@@ -1,3 +1,17 @@
## 7.0.4
No user-facing changes.
## 7.0.3
No user-facing changes.
## 7.0.2
### Minor Analysis Improvements
* Inline expectations test comments, which are of the form `// $ tag` or `// $ tag=value`, are now parsed more strictly and will not be recognized if there isn't a space after the `$` symbol.
## 7.0.1
No user-facing changes.

View File

@@ -8,5 +8,7 @@
* `FileSystemAccess`, or the `Source` and `Sink` classes associated with the security queries
* to model frameworks that are not covered by the standard library.
*/
overlay[local?]
module;
import go

View File

@@ -1,4 +1,5 @@
---
category: minorAnalysis
---
## 7.0.2
### Minor Analysis Improvements
* Inline expectations test comments, which are of the form `// $ tag` or `// $ tag=value`, are now parsed more strictly and will not be recognized if there isn't a space after the `$` symbol.

View File

@@ -0,0 +1,3 @@
## 7.0.3
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 7.0.4
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 7.0.1
lastReleaseVersion: 7.0.4

View File

@@ -1,6 +1,8 @@
/**
* Provides classes for working with Go programs.
*/
overlay[local?]
module;
import Customizations
import semmle.go.Architectures

View File

@@ -2,6 +2,8 @@
* Provides classes and predicates related to contextual queries
* in the code viewer.
*/
overlay[local?]
module;
import go
private import codeql.util.FileSystem

View File

@@ -1,5 +1,5 @@
name: codeql/go-all
version: 7.0.2-dev
version: 7.0.4
groups: go
dbscheme: go.dbscheme
extractor: go

View File

@@ -1,6 +1,8 @@
/**
* Provides classes for working with AST nodes.
*/
overlay[local]
module;
import go

View File

@@ -1,4 +1,6 @@
/** Provides classes for working with architectures. */
overlay[local]
module;
import go

View File

@@ -1,6 +1,8 @@
/**
* Provides classes for working with code comments.
*/
overlay[local]
module;
import go

View File

@@ -3,6 +3,8 @@
* access or system command execution, for which individual framework libraries
* provide concrete subclasses.
*/
overlay[local?]
module;
import go
import semmle.go.dataflow.FunctionInputsAndOutputs

View File

@@ -1,6 +1,8 @@
/**
* Provides classes for working with declarations.
*/
overlay[local]
module;
import go

View File

@@ -1,4 +1,6 @@
/** Provides classes for working with errors and warnings recorded during extraction. */
overlay[local]
module;
import go

View File

@@ -1,4 +1,6 @@
/** Provides classes for working with Go frontend errors recorded during extraction. */
overlay[local]
module;
import go

View File

@@ -1,6 +1,8 @@
/**
* Provides classes for working with expressions.
*/
overlay[local]
module;
import go
@@ -829,7 +831,7 @@ class ConversionExpr extends CallOrConversionExpr {
/**
* A function call expression.
*
* On snapshots with incomplete type information, type conversions may be misclassified
* On databases with incomplete type information, type conversions may be misclassified
* as function call expressions.
*
* Examples:
@@ -2035,6 +2037,9 @@ class ConstantName extends ValueName {
override string getAPrimaryQlClass() { result = "ConstantName" }
}
/** Holds if `e` is an expression that refers to the `nil` constant. */
predicate exprRefersToNil(Expr e) { e.(ConstantName).getTarget() = Builtin::nil() }
/**
* A name referring to a variable.
*
@@ -2093,7 +2098,7 @@ class LabelName extends Name {
* Holds if `e` is a type expression, as determined by a bottom-up syntactic
* analysis starting with `TypeName`s.
*
* On a snapshot with full type information, this predicate covers all type
* On a database with full type information, this predicate covers all type
* expressions. However, if type information is missing then not all type names
* may be identified as such, so not all type expressions can be determined by
* a bottom-up analysis. In such cases, `isTypeExprTopDown` below is useful.
@@ -2131,11 +2136,12 @@ private predicate isTypeExprBottomUp(Expr e) {
* Holds if `e` must be a type expression because it either occurs in a syntactic
* position where a type is expected, or it is part of a larger type expression.
*
* This predicate is only needed on snapshots for which type information is
* incomplete. It is an underapproximation; in cases where it is syntactically ambiguous
* whether an expression refers to a type or a value, we conservatively assume that
* it may be the latter and so this predicate does not consider the expression to be
* a type expression.
* This predicate is only needed on databases for which type information is
* incomplete - for example, when some dependencies could not be reached during
* extraction. It is an underapproximation; in cases where it is syntactically
* ambiguous whether an expression refers to a type or a value, we conservatively
* assume that it may be the latter and so this predicate does not consider the
* expression to be a type expression.
*/
pragma[nomagic]
private predicate isTypeExprTopDown(Expr e) {
@@ -2145,20 +2151,12 @@ private predicate isTypeExprTopDown(Expr e) {
or
e = any(ArrayTypeExpr ae).getElement()
or
e = any(FieldDecl f).getTypeExpr()
or
e = any(ParameterDecl pd).getTypeExpr()
e = any(FieldBase fb).getTypeExpr()
or
e = any(TypeParamDecl tpd).getTypeConstraintExpr()
or
e = any(TypeParamDecl tpd).getNameExpr(_)
or
e = any(ReceiverDecl rd).getTypeExpr()
or
e = any(ResultVariableDecl rvd).getTypeExpr()
or
e = any(MethodSpec md).getTypeExpr()
or
e = any(MapTypeExpr mt).getKeyTypeExpr()
or
e = any(MapTypeExpr mt).getValueTypeExpr()
@@ -2175,7 +2173,7 @@ private predicate isTypeExprTopDown(Expr e) {
or
e = any(TypeSwitchStmt s).getACase().getExpr(_) and
// special case: `nil` is allowed in a type case but isn't a type
not e = Builtin::nil().getAReference()
not exprRefersToNil(e)
or
e = any(SelectorExpr sel | isTypeExprTopDown(sel)).getBase()
or

View File

@@ -1,4 +1,6 @@
/** Provides classes for working with files and folders. */
overlay[local]
module;
import go
private import codeql.util.FileSystem

View File

@@ -1,6 +1,8 @@
/**
* Provides classes for working with go.mod files.
*/
overlay[local]
module;
import go

View File

@@ -1,4 +1,6 @@
/** Provides classes for working with HTML documents. */
overlay[local]
module;
import go

View File

@@ -1,4 +1,6 @@
/** Provides classes for working with locations and program elements that have locations. */
overlay[local]
module;
import go
private import semmle.go.Overlay

Some files were not shown because too many files have changed in this diff Show More