mirror of
https://github.com/github/codeql.git
synced 2026-05-16 04:09:27 +02:00
Compare commits
398 Commits
codeql-cli
...
codeql-cli
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce9c8e6e9f | ||
|
|
02a1b1efcb | ||
|
|
7670a2bd77 | ||
|
|
eac8a79d49 | ||
|
|
97a11de1e3 | ||
|
|
edf79a3730 | ||
|
|
6d9e489e7c | ||
|
|
a2d83274bc | ||
|
|
8fbd720fe5 | ||
|
|
49ccb8ce2b | ||
|
|
429c4eac96 | ||
|
|
ee78b7dc96 | ||
|
|
45eff3dac8 | ||
|
|
78bfdfd931 | ||
|
|
fa36d9f84e | ||
|
|
0ceb2f3f72 | ||
|
|
57e15b9a91 | ||
|
|
107d142b24 | ||
|
|
6264f46970 | ||
|
|
61faeef1d3 | ||
|
|
5c33af32e3 | ||
|
|
65102a073a | ||
|
|
f587273828 | ||
|
|
c375f24598 | ||
|
|
278a1efb4b | ||
|
|
18c96fd7d4 | ||
|
|
9231119b07 | ||
|
|
a4c845c418 | ||
|
|
cc72314219 | ||
|
|
7860857b55 | ||
|
|
b797df6ad5 | ||
|
|
3a75500f54 | ||
|
|
0d23ab07db | ||
|
|
2c6db00cbc | ||
|
|
e002f2088f | ||
|
|
35c75c00ba | ||
|
|
312471e9db | ||
|
|
d37425ae3e | ||
|
|
5cf052dec1 | ||
|
|
22b61852a1 | ||
|
|
d6a14e63ba | ||
|
|
d0091e1b3c | ||
|
|
78389c8897 | ||
|
|
af49301332 | ||
|
|
00f644888c | ||
|
|
acb4d9f681 | ||
|
|
35438294d1 | ||
|
|
be39c4c0cd | ||
|
|
875c7da87c | ||
|
|
b308c5438f | ||
|
|
50bdc658ba | ||
|
|
989081ba4a | ||
|
|
118ac07b71 | ||
|
|
9f83b67a7c | ||
|
|
e2d94127d6 | ||
|
|
5d3ea2f4d3 | ||
|
|
2bb9e2f7be | ||
|
|
e2e6fd0683 | ||
|
|
e302616135 | ||
|
|
f9ffee010f | ||
|
|
2743fc0be1 | ||
|
|
e8f1ec68db | ||
|
|
60d07cf30d | ||
|
|
03321ff910 | ||
|
|
4a8ffea0f6 | ||
|
|
12dcd751d3 | ||
|
|
29ba013580 | ||
|
|
db5c58180e | ||
|
|
f5780ae369 | ||
|
|
4fb133a43d | ||
|
|
d10cdfb7f1 | ||
|
|
69a1c7e1e8 | ||
|
|
452bbf7289 | ||
|
|
924a8eac5c | ||
|
|
1ebdcdfa8c | ||
|
|
db1f399067 | ||
|
|
e8ddac08b7 | ||
|
|
e9fcd985f9 | ||
|
|
d638ee9741 | ||
|
|
7c35835e25 | ||
|
|
a773042c5d | ||
|
|
0f5bd3799e | ||
|
|
3de9356141 | ||
|
|
352610d651 | ||
|
|
fd5b5baa8f | ||
|
|
92124a9033 | ||
|
|
5ac80353d2 | ||
|
|
cb766de37e | ||
|
|
b456a8c4e5 | ||
|
|
d5ee91b1e8 | ||
|
|
aaa67a2da9 | ||
|
|
ffeece1179 | ||
|
|
050a9e155f | ||
|
|
8ce2d3954e | ||
|
|
cc131a09a1 | ||
|
|
0b43203349 | ||
|
|
ae4cf302f2 | ||
|
|
511308746c | ||
|
|
a0e963f769 | ||
|
|
b3f4c68a1d | ||
|
|
0b5745c24b | ||
|
|
f4575d9d03 | ||
|
|
4d0635dc8a | ||
|
|
d87e9ec095 | ||
|
|
f74913aa4d | ||
|
|
671bea58af | ||
|
|
d9e7c89af0 | ||
|
|
84e70e166e | ||
|
|
fa18fd2782 | ||
|
|
cbbf7c2578 | ||
|
|
051da9d407 | ||
|
|
32131cf9ae | ||
|
|
2f9961888a | ||
|
|
7a2391f848 | ||
|
|
8af8c6d95a | ||
|
|
9a96372f53 | ||
|
|
2bc035cfcf | ||
|
|
d224f85b24 | ||
|
|
59fc7aa8e1 | ||
|
|
e7df1b220c | ||
|
|
eea70069e7 | ||
|
|
b996dc3b62 | ||
|
|
a6714809c4 | ||
|
|
a9a0cb928e | ||
|
|
dcc5572767 | ||
|
|
5c19aad012 | ||
|
|
4227dd7d73 | ||
|
|
b5c7bc1b33 | ||
|
|
3815503314 | ||
|
|
065388df91 | ||
|
|
d1a3294f06 | ||
|
|
762d2ef793 | ||
|
|
a20737308a | ||
|
|
c73d081a32 | ||
|
|
50cd200ec5 | ||
|
|
edec76ae10 | ||
|
|
186e42b1fe | ||
|
|
e5da0b90ce | ||
|
|
d39263dcac | ||
|
|
72d7223fd0 | ||
|
|
d097946e1f | ||
|
|
5a9b562f19 | ||
|
|
dacc9e26e9 | ||
|
|
f8bdf924db | ||
|
|
b7bc94b987 | ||
|
|
046d0d4938 | ||
|
|
e5ba1c7a84 | ||
|
|
b89b68dfdb | ||
|
|
166c77d776 | ||
|
|
09edc29979 | ||
|
|
fbc4f0b84f | ||
|
|
d575d3c9e4 | ||
|
|
174f89fbcb | ||
|
|
125cc91ba6 | ||
|
|
e3e1bcd63f | ||
|
|
2e90499df4 | ||
|
|
a1980ee23c | ||
|
|
b34fa7abc0 | ||
|
|
f7c74664fa | ||
|
|
417e79c3c0 | ||
|
|
3aee4a88aa | ||
|
|
fd7d216fe3 | ||
|
|
4b9d102f46 | ||
|
|
a0f8b5829a | ||
|
|
30b93d18b7 | ||
|
|
51052c74bb | ||
|
|
6ea6f30cc5 | ||
|
|
91f9247c2b | ||
|
|
4f9d8271a2 | ||
|
|
387d08a1b3 | ||
|
|
1c922f0f45 | ||
|
|
e1047dc40b | ||
|
|
63a2c9da76 | ||
|
|
c4633c7e23 | ||
|
|
aa9d299230 | ||
|
|
d8e943ea05 | ||
|
|
f104205538 | ||
|
|
0752dbea9b | ||
|
|
b5045b3407 | ||
|
|
d51361cd35 | ||
|
|
2505272af7 | ||
|
|
2d84f8a739 | ||
|
|
702d6d80c4 | ||
|
|
dc247e03e0 | ||
|
|
84df8f91a9 | ||
|
|
40c8c3a526 | ||
|
|
4c1fa58367 | ||
|
|
a81989d2d8 | ||
|
|
9f47996448 | ||
|
|
728a4aff22 | ||
|
|
3aba4d3e1e | ||
|
|
55ff71b760 | ||
|
|
89e080cd99 | ||
|
|
311690cffe | ||
|
|
f52a427295 | ||
|
|
16fbe8d96f | ||
|
|
eea11dbf5f | ||
|
|
666678a582 | ||
|
|
117c41bd55 | ||
|
|
2f4c728bb9 | ||
|
|
a8541b9f76 | ||
|
|
9f1e60ca6d | ||
|
|
0159f5b422 | ||
|
|
29c22e6fcf | ||
|
|
d9787efc10 | ||
|
|
572da264d3 | ||
|
|
3f4b2b7cc8 | ||
|
|
b0ef0f06eb | ||
|
|
ed11a32f42 | ||
|
|
827ea4c769 | ||
|
|
7bf05297cf | ||
|
|
08298f48d0 | ||
|
|
6c9a75eab3 | ||
|
|
b4e6d3009e | ||
|
|
ba5318f63f | ||
|
|
869b7e09d7 | ||
|
|
8c34b7eaea | ||
|
|
66379deadd | ||
|
|
c6adc51220 | ||
|
|
c5cb86ac24 | ||
|
|
ed9ed43923 | ||
|
|
1caf18ede1 | ||
|
|
7d479704e8 | ||
|
|
039b5af2e0 | ||
|
|
c5ee0f3c22 | ||
|
|
61485908b9 | ||
|
|
fe7426740b | ||
|
|
e18b049d10 | ||
|
|
1e77891271 | ||
|
|
fea05331aa | ||
|
|
526990e015 | ||
|
|
e7fbd28505 | ||
|
|
8c13faf3d8 | ||
|
|
a6fb45b9cb | ||
|
|
82476b9efd | ||
|
|
b2feaaceea | ||
|
|
ef114c4a07 | ||
|
|
a08878f419 | ||
|
|
e719dd912d | ||
|
|
bab2a79055 | ||
|
|
215602c963 | ||
|
|
76ca1a576f | ||
|
|
0d03c813d0 | ||
|
|
b2b5199055 | ||
|
|
d8c4d6deb4 | ||
|
|
e6eacca50b | ||
|
|
f1186432c1 | ||
|
|
fc1b9277b3 | ||
|
|
b2ef60c165 | ||
|
|
a6b68ec7de | ||
|
|
c26a56a332 | ||
|
|
3a9a559d25 | ||
|
|
9363bc318a | ||
|
|
81b1e73e18 | ||
|
|
f51ee4c04f | ||
|
|
5d3ec35e29 | ||
|
|
2100dc1288 | ||
|
|
4645bd766a | ||
|
|
a551a55ca0 | ||
|
|
3c35e1e6ee | ||
|
|
76f2c6a9f1 | ||
|
|
1605438333 | ||
|
|
6c773a7473 | ||
|
|
fffb4c03b0 | ||
|
|
6b022edf06 | ||
|
|
de6d9f4d50 | ||
|
|
c5e5b8a585 | ||
|
|
af82da5db3 | ||
|
|
c4c8dbcf7d | ||
|
|
d3d608fa33 | ||
|
|
6c751ce934 | ||
|
|
4dac80a998 | ||
|
|
64d68feab3 | ||
|
|
4926d278a2 | ||
|
|
d8346ef106 | ||
|
|
8009ddebce | ||
|
|
61e8ad264f | ||
|
|
26919a6c6e | ||
|
|
5b0ef40a3e | ||
|
|
dd99a2d3bd | ||
|
|
2a45b28e5f | ||
|
|
7cbaa114a3 | ||
|
|
8fc81f4263 | ||
|
|
e610465ee8 | ||
|
|
a9baf34629 | ||
|
|
f2b8ac127f | ||
|
|
dff5ed7d29 | ||
|
|
cd6a151d9b | ||
|
|
fb1387340f | ||
|
|
83d53baf82 | ||
|
|
462d639627 | ||
|
|
9f31f02c12 | ||
|
|
2dcf3c7c45 | ||
|
|
1ea843f23c | ||
|
|
5d2268fa80 | ||
|
|
ab3ad20a1e | ||
|
|
8de1ed0d85 | ||
|
|
de8e535c3a | ||
|
|
1b683f6359 | ||
|
|
f7201023de | ||
|
|
17d23a9b78 | ||
|
|
31852985e5 | ||
|
|
0bb7fdccf6 | ||
|
|
f833fe0e6e | ||
|
|
d3d737b383 | ||
|
|
9d521e9cb6 | ||
|
|
7490d8ddd2 | ||
|
|
e8a2600a0c | ||
|
|
8a92b2d611 | ||
|
|
6f5da528a4 | ||
|
|
464d8b13a8 | ||
|
|
9431b0c754 | ||
|
|
90caded4fe | ||
|
|
f4df3881f8 | ||
|
|
438cc961da | ||
|
|
8a7553232f | ||
|
|
f68d3477d4 | ||
|
|
f0f66c6d58 | ||
|
|
6a9324fab0 | ||
|
|
ffbc83deeb | ||
|
|
6e8f44da42 | ||
|
|
74f5687660 | ||
|
|
fdab63fd5f | ||
|
|
5bd08e8174 | ||
|
|
dc78330529 | ||
|
|
d9320b3c16 | ||
|
|
60845001dd | ||
|
|
3d4d347150 | ||
|
|
f7097136f1 | ||
|
|
8545c7d36f | ||
|
|
8c9c66c002 | ||
|
|
ba68fe9a0f | ||
|
|
fb0380bfbc | ||
|
|
cc486ddb08 | ||
|
|
72df584e9b | ||
|
|
c9dc54abf8 | ||
|
|
58f2bd4000 | ||
|
|
5992dc3b0a | ||
|
|
e01519f547 | ||
|
|
74a312735c | ||
|
|
37997c0561 | ||
|
|
8b10ad49d7 | ||
|
|
dbd31259b3 | ||
|
|
ba8658491a | ||
|
|
86bb0e8af2 | ||
|
|
daa5525a10 | ||
|
|
b4b20d7d3f | ||
|
|
18b949c0a9 | ||
|
|
9619ae8a2d | ||
|
|
c9932e187a | ||
|
|
9ac95266c7 | ||
|
|
3c74e12b9c | ||
|
|
99a05ed5a4 | ||
|
|
732c818916 | ||
|
|
45b5efad25 | ||
|
|
4f63528844 | ||
|
|
d0daacd17e | ||
|
|
a02016a95f | ||
|
|
38af3ac925 | ||
|
|
bea8502cc5 | ||
|
|
64f9758c29 | ||
|
|
4e70627629 | ||
|
|
0d9b8d0592 | ||
|
|
bbf7995100 | ||
|
|
144e34c669 | ||
|
|
45b8158fe5 | ||
|
|
4685b4f8a9 | ||
|
|
ca393a9afe | ||
|
|
92fcda3cc7 | ||
|
|
1e25b4de4b | ||
|
|
c1662cf05c | ||
|
|
cf9196fb55 | ||
|
|
d8c193df18 | ||
|
|
8b50ac291f | ||
|
|
8434dc3890 | ||
|
|
71bac5eda8 | ||
|
|
67dc01b636 | ||
|
|
57b4534d30 | ||
|
|
e0916c8750 | ||
|
|
32606584ea | ||
|
|
c39c04cb86 | ||
|
|
10c10c7d30 | ||
|
|
9cc6e9c8a9 | ||
|
|
021aa13ee2 | ||
|
|
791a7e242e | ||
|
|
2baca58b27 | ||
|
|
fd4233e30e | ||
|
|
84ffbbec33 | ||
|
|
95743d7109 | ||
|
|
92daa7d42c | ||
|
|
358617f533 | ||
|
|
e2f3c9d1b6 | ||
|
|
b4b848a25c | ||
|
|
f86152d3bd | ||
|
|
504ae0f35a | ||
|
|
575da5c31c | ||
|
|
8c4dbca23c | ||
|
|
26f3b40d35 |
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 9.0.100
|
||||
dotnet-version: 9.0.300
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
|
||||
10
.github/workflows/csharp-qltest.yml
vendored
10
.github/workflows/csharp-qltest.yml
vendored
@@ -43,14 +43,14 @@ jobs:
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 9.0.100
|
||||
dotnet-version: 9.0.300
|
||||
- name: Extractor unit tests
|
||||
run: |
|
||||
dotnet tool restore
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.0 extractor/Semmle.Util.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.0 extractor/Semmle.Extraction.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.0 autobuilder/Semmle.Autobuild.CSharp.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.0 autobuilder/Semmle.Autobuild.Cpp.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.5 extractor/Semmle.Util.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.5 extractor/Semmle.Extraction.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.5 autobuilder/Semmle.Autobuild.CSharp.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.5 autobuilder/Semmle.Autobuild.Cpp.Tests
|
||||
shell: bash
|
||||
stubgentest:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
2
.github/workflows/query-list.yml
vendored
2
.github/workflows/query-list.yml
vendored
@@ -31,7 +31,7 @@ jobs:
|
||||
with:
|
||||
python-version: 3.8
|
||||
- name: Download CodeQL CLI
|
||||
# Look under the `codeql` directory, as this is where we checked out the `github/codeql` repo
|
||||
# Look under the `codeql` directory, as this is where we checked out the `github/codeql` repo
|
||||
uses: ./codeql/.github/actions/fetch-codeql
|
||||
- name: Build code scanning query list
|
||||
run: |
|
||||
|
||||
@@ -26,7 +26,7 @@ bazel_dep(name = "nlohmann_json", version = "3.11.3", repo_name = "json")
|
||||
bazel_dep(name = "fmt", version = "10.0.0")
|
||||
bazel_dep(name = "rules_kotlin", version = "2.1.3-codeql.1")
|
||||
bazel_dep(name = "gazelle", version = "0.40.0")
|
||||
bazel_dep(name = "rules_dotnet", version = "0.17.4")
|
||||
bazel_dep(name = "rules_dotnet", version = "0.19.2-codeql.1")
|
||||
bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
|
||||
bazel_dep(name = "rules_rust", version = "0.63.0")
|
||||
bazel_dep(name = "zstd", version = "1.5.5.bcr.1")
|
||||
@@ -172,7 +172,7 @@ http_archive(
|
||||
)
|
||||
|
||||
dotnet = use_extension("@rules_dotnet//dotnet:extensions.bzl", "dotnet")
|
||||
dotnet.toolchain(dotnet_version = "9.0.100")
|
||||
dotnet.toolchain(dotnet_version = "9.0.300")
|
||||
use_repo(dotnet, "dotnet_toolchains")
|
||||
|
||||
register_toolchains("@dotnet_toolchains//:all")
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
name: "actions"
|
||||
aliases: []
|
||||
display_name: "GitHub Actions"
|
||||
version: 0.0.1
|
||||
column_kind: "utf16"
|
||||
@@ -8,9 +7,11 @@ build_modes:
|
||||
- none
|
||||
default_queries:
|
||||
- codeql/actions-queries
|
||||
file_coverage_languages: []
|
||||
# Actions workflows are not reported separately by the GitHub API, so we can't
|
||||
# associate them with a specific language.
|
||||
github_api_languages: []
|
||||
scc_languages: []
|
||||
scc_languages:
|
||||
- YAML
|
||||
file_types:
|
||||
- name: workflow
|
||||
display_name: GitHub Actions workflow files
|
||||
|
||||
10
actions/extractor/tools/baseline-config.json
Normal file
10
actions/extractor/tools/baseline-config.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"paths": [
|
||||
".github/workflows/*.yml",
|
||||
".github/workflows/*.yaml",
|
||||
".github/reusable_workflows/**/*.yml",
|
||||
".github/reusable_workflows/**/*.yaml",
|
||||
"**/action.yml",
|
||||
"**/action.yaml"
|
||||
]
|
||||
}
|
||||
2
actions/extractor/tools/configure-baseline.cmd
Executable file
2
actions/extractor/tools/configure-baseline.cmd
Executable file
@@ -0,0 +1,2 @@
|
||||
@echo off
|
||||
type "%CODEQL_EXTRACTOR_ACTIONS_ROOT%\tools\baseline-config.json"
|
||||
3
actions/extractor/tools/configure-baseline.sh
Executable file
3
actions/extractor/tools/configure-baseline.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
cat "$CODEQL_EXTRACTOR_ACTIONS_ROOT/tools/baseline-config.json"
|
||||
@@ -1,3 +1,4 @@
|
||||
ql/actions/ql/src/Diagnostics/SuccessfullyExtractedFiles.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvPathInjectionCritical.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvVarInjectionCritical.ql
|
||||
ql/actions/ql/src/Security/CWE-094/CodeInjectionCritical.ql
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
ql/actions/ql/src/Debug/SyntaxError.ql
|
||||
ql/actions/ql/src/Diagnostics/SuccessfullyExtractedFiles.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvPathInjectionCritical.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvPathInjectionMedium.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvVarInjectionCritical.ql
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
ql/actions/ql/src/Diagnostics/SuccessfullyExtractedFiles.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvPathInjectionCritical.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvPathInjectionMedium.ql
|
||||
ql/actions/ql/src/Security/CWE-077/EnvVarInjectionCritical.ql
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 0.4.17
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.16
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
3
actions/ql/lib/change-notes/released/0.4.17.md
Normal file
3
actions/ql/lib/change-notes/released/0.4.17.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.4.17
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.4.16
|
||||
lastReleaseVersion: 0.4.17
|
||||
|
||||
@@ -70,8 +70,8 @@ class Location extends TLocation, TBaseLocation {
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* The location spans column `sc` of line `sl` to
|
||||
* column `ec` of line `el` in file `p`.
|
||||
* For more information, see
|
||||
* [Providing locations in CodeQL queries](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
|
||||
@@ -261,7 +261,7 @@ class If extends AstNode instanceof IfImpl {
|
||||
}
|
||||
|
||||
/**
|
||||
* An Environemnt node representing a deployment environment.
|
||||
* An Environment node representing a deployment environment.
|
||||
*/
|
||||
class Environment extends AstNode instanceof EnvironmentImpl {
|
||||
string getName() { result = super.getName() }
|
||||
|
||||
@@ -125,12 +125,11 @@ abstract class AstNodeImpl extends TAstNode {
|
||||
* Gets the enclosing Step.
|
||||
*/
|
||||
StepImpl getEnclosingStep() {
|
||||
if this instanceof StepImpl
|
||||
then result = this
|
||||
else
|
||||
if this instanceof ScalarValueImpl
|
||||
then result.getAChildNode*() = this.getParentNode()
|
||||
else none()
|
||||
this instanceof StepImpl and
|
||||
result = this
|
||||
or
|
||||
this instanceof ScalarValueImpl and
|
||||
result.getAChildNode*() = this.getParentNode()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1416,9 +1415,8 @@ class ExternalJobImpl extends JobImpl, UsesImpl {
|
||||
override string getVersion() {
|
||||
exists(YamlString name |
|
||||
n.lookup("uses") = name and
|
||||
if not name.getValue().matches("\\.%")
|
||||
then result = name.getValue().regexpCapture(repoUsesParser(), 4)
|
||||
else none()
|
||||
not name.getValue().matches("\\.%") and
|
||||
result = name.getValue().regexpCapture(repoUsesParser(), 4)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,7 +286,7 @@ private module Cached {
|
||||
/**
|
||||
* Holds if `cfn` is the `i`th node in basic block `bb`.
|
||||
*
|
||||
* In other words, `i` is the shortest distance from a node `bb`
|
||||
* In other words, `i` is the shortest distance from a node `bbStart`
|
||||
* that starts a basic block to `cfn` along the `intraBBSucc` relation.
|
||||
*/
|
||||
cached
|
||||
|
||||
@@ -3,6 +3,8 @@ private import codeql.controlflow.Cfg as CfgShared
|
||||
private import codeql.Locations
|
||||
|
||||
module Completion {
|
||||
import codeql.controlflow.SuccessorType
|
||||
|
||||
private newtype TCompletion =
|
||||
TSimpleCompletion() or
|
||||
TBooleanCompletion(boolean b) { b in [false, true] } or
|
||||
@@ -25,7 +27,7 @@ module Completion {
|
||||
|
||||
override predicate isValidFor(AstNode e) { not any(Completion c).isValidForSpecific(e) }
|
||||
|
||||
override NormalSuccessor getAMatchingSuccessorType() { any() }
|
||||
override DirectSuccessor getAMatchingSuccessorType() { any() }
|
||||
}
|
||||
|
||||
class BooleanCompletion extends NormalCompletion, TBooleanCompletion {
|
||||
@@ -49,34 +51,6 @@ module Completion {
|
||||
|
||||
override ReturnSuccessor getAMatchingSuccessorType() { any() }
|
||||
}
|
||||
|
||||
cached
|
||||
private newtype TSuccessorType =
|
||||
TNormalSuccessor() or
|
||||
TBooleanSuccessor(boolean b) { b in [false, true] } or
|
||||
TReturnSuccessor()
|
||||
|
||||
class SuccessorType extends TSuccessorType {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class NormalSuccessor extends SuccessorType, TNormalSuccessor {
|
||||
override string toString() { result = "successor" }
|
||||
}
|
||||
|
||||
class BooleanSuccessor extends SuccessorType, TBooleanSuccessor {
|
||||
boolean value;
|
||||
|
||||
BooleanSuccessor() { this = TBooleanSuccessor(value) }
|
||||
|
||||
override string toString() { result = value.toString() }
|
||||
|
||||
boolean getValue() { result = value }
|
||||
}
|
||||
|
||||
class ReturnSuccessor extends SuccessorType, TReturnSuccessor {
|
||||
override string toString() { result = "return" }
|
||||
}
|
||||
}
|
||||
|
||||
module CfgScope {
|
||||
@@ -127,14 +101,8 @@ private module Implementation implements CfgShared::InputSig<Location> {
|
||||
last(scope.(CompositeAction), e, c)
|
||||
}
|
||||
|
||||
predicate successorTypeIsSimple(SuccessorType t) { t instanceof NormalSuccessor }
|
||||
|
||||
predicate successorTypeIsCondition(SuccessorType t) { t instanceof BooleanSuccessor }
|
||||
|
||||
SuccessorType getAMatchingSuccessorType(Completion c) { result = c.getAMatchingSuccessorType() }
|
||||
|
||||
predicate isAbnormalExitType(SuccessorType t) { none() }
|
||||
|
||||
int idOfAstNode(AstNode node) { none() }
|
||||
|
||||
int idOfCfgScope(CfgScope scope) { none() }
|
||||
|
||||
@@ -63,10 +63,10 @@ predicate madSource(DataFlow::Node source, string kind, string fieldName) {
|
||||
(
|
||||
if fieldName.trim().matches("env.%")
|
||||
then source.asExpr() = uses.getInScopeEnvVarExpr(fieldName.trim().replaceAll("env.", ""))
|
||||
else
|
||||
if fieldName.trim().matches("output.%")
|
||||
then source.asExpr() = uses
|
||||
else none()
|
||||
else (
|
||||
fieldName.trim().matches("output.%") and
|
||||
source.asExpr() = uses
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -31,14 +31,14 @@ abstract class RemoteFlowSource extends SourceNode {
|
||||
class GitHubCtxSource extends RemoteFlowSource {
|
||||
string flag;
|
||||
string event;
|
||||
GitHubExpression e;
|
||||
|
||||
GitHubCtxSource() {
|
||||
this.asExpr() = e and
|
||||
// github.head_ref
|
||||
e.getFieldName() = "head_ref" and
|
||||
flag = "branch" and
|
||||
(
|
||||
exists(GitHubExpression e |
|
||||
this.asExpr() = e and
|
||||
// github.head_ref
|
||||
e.getFieldName() = "head_ref" and
|
||||
flag = "branch"
|
||||
|
|
||||
event = e.getATriggerEvent().getName() and
|
||||
event = "pull_request_target"
|
||||
or
|
||||
@@ -148,7 +148,6 @@ class GhCLICommandSource extends RemoteFlowSource, CommandSource {
|
||||
class GitHubEventPathSource extends RemoteFlowSource, CommandSource {
|
||||
string cmd;
|
||||
string flag;
|
||||
string access_path;
|
||||
Run run;
|
||||
|
||||
// Examples
|
||||
@@ -163,7 +162,7 @@ class GitHubEventPathSource extends RemoteFlowSource, CommandSource {
|
||||
run.getScript().getACommand() = cmd and
|
||||
cmd.matches("jq%") and
|
||||
cmd.matches("%GITHUB_EVENT_PATH%") and
|
||||
exists(string regexp |
|
||||
exists(string regexp, string access_path |
|
||||
untrustedEventPropertiesDataModel(regexp, flag) and
|
||||
not flag = "json" and
|
||||
access_path = "github.event" + cmd.regexpCapture(".*\\s+([^\\s]+)\\s+.*", 1) and
|
||||
|
||||
@@ -19,7 +19,6 @@ abstract class ArgumentInjectionSink extends DataFlow::Node {
|
||||
*/
|
||||
class ArgumentInjectionFromEnvVarSink extends ArgumentInjectionSink {
|
||||
string command;
|
||||
string argument;
|
||||
|
||||
ArgumentInjectionFromEnvVarSink() {
|
||||
exists(Run run, string var |
|
||||
@@ -28,7 +27,7 @@ class ArgumentInjectionFromEnvVarSink extends ArgumentInjectionSink {
|
||||
exists(run.getInScopeEnvVarExpr(var)) or
|
||||
var = "GITHUB_HEAD_REF"
|
||||
) and
|
||||
run.getScript().getAnEnvReachingArgumentInjectionSink(var, command, argument)
|
||||
run.getScript().getAnEnvReachingArgumentInjectionSink(var, command, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -44,13 +43,12 @@ class ArgumentInjectionFromEnvVarSink extends ArgumentInjectionSink {
|
||||
*/
|
||||
class ArgumentInjectionFromCommandSink extends ArgumentInjectionSink {
|
||||
string command;
|
||||
string argument;
|
||||
|
||||
ArgumentInjectionFromCommandSink() {
|
||||
exists(CommandSource source, Run run |
|
||||
run = source.getEnclosingRun() and
|
||||
this.asExpr() = run.getScript() and
|
||||
run.getScript().getACmdReachingArgumentInjectionSink(source.getCommand(), command, argument)
|
||||
run.getScript().getACmdReachingArgumentInjectionSink(source.getCommand(), command, _)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -125,8 +125,6 @@ class LegitLabsDownloadArtifactActionStep extends UntrustedArtifactDownloadStep,
|
||||
}
|
||||
|
||||
class ActionsGitHubScriptDownloadStep extends UntrustedArtifactDownloadStep, UsesStep {
|
||||
string script;
|
||||
|
||||
ActionsGitHubScriptDownloadStep() {
|
||||
// eg:
|
||||
// - uses: actions/github-script@v6
|
||||
@@ -149,12 +147,14 @@ class ActionsGitHubScriptDownloadStep extends UntrustedArtifactDownloadStep, Use
|
||||
// var fs = require('fs');
|
||||
// fs.writeFileSync('${{github.workspace}}/test-results.zip', Buffer.from(download.data));
|
||||
this.getCallee() = "actions/github-script" and
|
||||
this.getArgument("script") = script and
|
||||
script.matches("%listWorkflowRunArtifacts(%") and
|
||||
script.matches("%downloadArtifact(%") and
|
||||
script.matches("%writeFileSync(%") and
|
||||
// Filter out artifacts that were created by pull-request.
|
||||
not script.matches("%exclude_pull_requests: true%")
|
||||
exists(string script |
|
||||
this.getArgument("script") = script and
|
||||
script.matches("%listWorkflowRunArtifacts(%") and
|
||||
script.matches("%downloadArtifact(%") and
|
||||
script.matches("%writeFileSync(%") and
|
||||
// Filter out artifacts that were created by pull-request.
|
||||
not script.matches("%exclude_pull_requests: true%")
|
||||
)
|
||||
}
|
||||
|
||||
override string getPath() {
|
||||
@@ -171,10 +171,10 @@ class ActionsGitHubScriptDownloadStep extends UntrustedArtifactDownloadStep, Use
|
||||
.getScript()
|
||||
.getACommand()
|
||||
.regexpCapture(unzipRegexp() + unzipDirArgRegexp(), 3)))
|
||||
else
|
||||
if this.getAFollowingStep().(Run).getScript().getACommand().regexpMatch(unzipRegexp())
|
||||
then result = "GITHUB_WORKSPACE/"
|
||||
else none()
|
||||
else (
|
||||
this.getAFollowingStep().(Run).getScript().getACommand().regexpMatch(unzipRegexp()) and
|
||||
result = "GITHUB_WORKSPACE/"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,12 +207,13 @@ class GHRunArtifactDownloadStep extends UntrustedArtifactDownloadStep, Run {
|
||||
.getScript()
|
||||
.getACommand()
|
||||
.regexpCapture(unzipRegexp() + unzipDirArgRegexp(), 3)))
|
||||
else
|
||||
if
|
||||
else (
|
||||
(
|
||||
this.getAFollowingStep().(Run).getScript().getACommand().regexpMatch(unzipRegexp()) or
|
||||
this.getScript().getACommand().regexpMatch(unzipRegexp())
|
||||
then result = "GITHUB_WORKSPACE/"
|
||||
else none()
|
||||
) and
|
||||
result = "GITHUB_WORKSPACE/"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,15 +260,15 @@ class DirectArtifactDownloadStep extends UntrustedArtifactDownloadStep, Run {
|
||||
|
||||
class ArtifactPoisoningSink extends DataFlow::Node {
|
||||
UntrustedArtifactDownloadStep download;
|
||||
PoisonableStep poisonable;
|
||||
|
||||
ArtifactPoisoningSink() {
|
||||
download.getAFollowingStep() = poisonable and
|
||||
// excluding artifacts downloaded to the temporary directory
|
||||
not download.getPath().regexpMatch("^/tmp.*") and
|
||||
not download.getPath().regexpMatch("^\\$\\{\\{\\s*runner\\.temp\\s*}}.*") and
|
||||
not download.getPath().regexpMatch("^\\$RUNNER_TEMP.*") and
|
||||
(
|
||||
exists(PoisonableStep poisonable |
|
||||
download.getAFollowingStep() = poisonable and
|
||||
// excluding artifacts downloaded to the temporary directory
|
||||
not download.getPath().regexpMatch("^/tmp.*") and
|
||||
not download.getPath().regexpMatch("^\\$\\{\\{\\s*runner\\.temp\\s*}}.*") and
|
||||
not download.getPath().regexpMatch("^\\$RUNNER_TEMP.*")
|
||||
|
|
||||
poisonable.(Run).getScript() = this.asExpr() and
|
||||
(
|
||||
// Check if the poisonable step is a local script execution step
|
||||
|
||||
@@ -159,11 +159,8 @@ abstract class CommentVsHeadDateCheck extends ControlCheck {
|
||||
|
||||
/* Specific implementations of control checks */
|
||||
class LabelIfCheck extends LabelCheck instanceof If {
|
||||
string condition;
|
||||
|
||||
LabelIfCheck() {
|
||||
condition = normalizeExpr(this.getCondition()) and
|
||||
(
|
||||
exists(string condition | condition = normalizeExpr(this.getCondition()) |
|
||||
// eg: contains(github.event.pull_request.labels.*.name, 'safe to test')
|
||||
condition.regexpMatch(".*(^|[^!])contains\\(\\s*github\\.event\\.pull_request\\.labels\\b.*")
|
||||
or
|
||||
|
||||
@@ -55,12 +55,8 @@ class EnvVarInjectionFromFileReadSink extends EnvVarInjectionSink {
|
||||
* echo "COMMIT_MESSAGE=${COMMIT_MESSAGE}" >> $GITHUB_ENV
|
||||
*/
|
||||
class EnvVarInjectionFromCommandSink extends EnvVarInjectionSink {
|
||||
CommandSource inCommand;
|
||||
string injectedVar;
|
||||
string command;
|
||||
|
||||
EnvVarInjectionFromCommandSink() {
|
||||
exists(Run run |
|
||||
exists(Run run, CommandSource inCommand, string injectedVar, string command |
|
||||
this.asExpr() = inCommand.getEnclosingRun().getScript() and
|
||||
run = inCommand.getEnclosingRun() and
|
||||
run.getScript().getACmdReachingGitHubEnvWrite(inCommand.getCommand(), injectedVar) and
|
||||
@@ -86,12 +82,8 @@ class EnvVarInjectionFromCommandSink extends EnvVarInjectionSink {
|
||||
* echo "FOO=$BODY" >> $GITHUB_ENV
|
||||
*/
|
||||
class EnvVarInjectionFromEnvVarSink extends EnvVarInjectionSink {
|
||||
string inVar;
|
||||
string injectedVar;
|
||||
string command;
|
||||
|
||||
EnvVarInjectionFromEnvVarSink() {
|
||||
exists(Run run |
|
||||
exists(Run run, string inVar, string injectedVar, string command |
|
||||
run.getScript() = this.asExpr() and
|
||||
exists(run.getInScopeEnvVarExpr(inVar)) and
|
||||
run.getScript().getAnEnvReachingGitHubEnvWrite(inVar, injectedVar) and
|
||||
|
||||
@@ -99,18 +99,14 @@ class OutputClobberingFromEnvVarSink extends OutputClobberingSink {
|
||||
* echo $BODY
|
||||
*/
|
||||
class WorkflowCommandClobberingFromEnvVarSink extends OutputClobberingSink {
|
||||
string clobbering_var;
|
||||
string clobbered_value;
|
||||
|
||||
WorkflowCommandClobberingFromEnvVarSink() {
|
||||
exists(Run run, string workflow_cmd_stmt, string clobbering_stmt |
|
||||
exists(Run run, string workflow_cmd_stmt, string clobbering_stmt, string clobbering_var |
|
||||
run.getScript() = this.asExpr() and
|
||||
run.getScript().getAStmt() = clobbering_stmt and
|
||||
clobbering_stmt.regexpMatch("echo\\s+(-e\\s+)?(\"|')?\\$(\\{)?" + clobbering_var + ".*") and
|
||||
exists(run.getInScopeEnvVarExpr(clobbering_var)) and
|
||||
run.getScript().getAStmt() = workflow_cmd_stmt and
|
||||
clobbered_value =
|
||||
trimQuotes(workflow_cmd_stmt.regexpCapture(".*::set-output\\s+name=.*::(.*)", 1))
|
||||
exists(trimQuotes(workflow_cmd_stmt.regexpCapture(".*::set-output\\s+name=.*::(.*)", 1)))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import actions
|
||||
|
||||
class UnversionedImmutableAction extends UsesStep {
|
||||
string immutable_action;
|
||||
|
||||
UnversionedImmutableAction() {
|
||||
isImmutableAction(this, immutable_action) and
|
||||
isImmutableAction(this, _) and
|
||||
not isSemVer(this.getVersion())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/actions-all
|
||||
version: 0.4.16
|
||||
version: 0.4.17
|
||||
library: true
|
||||
warnOnImplicitThis: true
|
||||
dependencies:
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
## 0.6.9
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Actions analysis now reports file coverage information on the CodeQL status page.
|
||||
|
||||
## 0.6.8
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
13
actions/ql/src/Diagnostics/SuccessfullyExtractedFiles.ql
Normal file
13
actions/ql/src/Diagnostics/SuccessfullyExtractedFiles.ql
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* @id actions/diagnostics/successfully-extracted-files
|
||||
* @name Extracted files
|
||||
* @description List all files that were extracted.
|
||||
* @kind diagnostic
|
||||
* @tags successfully-extracted-files
|
||||
*/
|
||||
|
||||
private import codeql.Locations
|
||||
|
||||
from File f
|
||||
where exists(f.getRelativePath())
|
||||
select f, ""
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@v1
|
||||
- run: |
|
||||
npm install # scripts in package.json from PR would be executed here
|
||||
npm install # scripts in package.json from PR would be executed here
|
||||
npm build
|
||||
|
||||
- uses: completely/fakeaction@v2
|
||||
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@v1
|
||||
- run: |
|
||||
npm install # scripts in package.json from PR would be executed here
|
||||
npm install # scripts in package.json from PR would be executed here
|
||||
npm build
|
||||
|
||||
- uses: completely/fakeaction@v2
|
||||
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@v1
|
||||
- run: |
|
||||
npm install # scripts in package.json from PR would be executed here
|
||||
npm install # scripts in package.json from PR would be executed here
|
||||
npm build
|
||||
|
||||
- uses: completely/fakeaction@v2
|
||||
|
||||
5
actions/ql/src/change-notes/released/0.6.9.md
Normal file
5
actions/ql/src/change-notes/released/0.6.9.md
Normal file
@@ -0,0 +1,5 @@
|
||||
## 0.6.9
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Actions analysis now reports file coverage information on the CodeQL status page.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.6.8
|
||||
lastReleaseVersion: 0.6.9
|
||||
|
||||
@@ -37,8 +37,6 @@ where
|
||||
)
|
||||
or
|
||||
// upload artifact is not used in the same workflow
|
||||
not exists(UsesStep upload |
|
||||
download.getEnclosingWorkflow().getAJob().(LocalJob).getAStep() = upload
|
||||
)
|
||||
not download.getEnclosingWorkflow().getAJob().(LocalJob).getAStep() instanceof UsesStep
|
||||
)
|
||||
select download, "Potential artifact poisoning"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/actions-queries
|
||||
version: 0.6.8
|
||||
version: 0.6.9
|
||||
library: false
|
||||
warnOnImplicitThis: true
|
||||
groups: [actions, queries]
|
||||
|
||||
@@ -177,6 +177,12 @@ def insert_overlay_caller_annotations(lines):
|
||||
out_lines.append(line)
|
||||
return out_lines
|
||||
|
||||
explicitly_global = set([
|
||||
"java/ql/lib/semmle/code/java/dispatch/VirtualDispatch.qll",
|
||||
"java/ql/lib/semmle/code/java/dispatch/DispatchFlow.qll",
|
||||
"java/ql/lib/semmle/code/java/dispatch/ObjFlow.qll",
|
||||
"java/ql/lib/semmle/code/java/dispatch/internal/Unification.qll",
|
||||
])
|
||||
|
||||
def annotate_as_appropriate(filename, lines):
|
||||
'''
|
||||
@@ -196,6 +202,9 @@ def annotate_as_appropriate(filename, lines):
|
||||
((filename.endswith("Query.qll") or filename.endswith("Config.qll")) and
|
||||
any("implements DataFlow::ConfigSig" in line for line in lines))):
|
||||
return None
|
||||
elif filename in explicitly_global:
|
||||
# These files are explicitly global and should not be annotated.
|
||||
return None
|
||||
elif not any(line for line in lines if line.strip()):
|
||||
return None
|
||||
|
||||
|
||||
@@ -7,12 +7,10 @@ ql/cpp/ql/src/Diagnostics/ExtractedFiles.ql
|
||||
ql/cpp/ql/src/Diagnostics/ExtractionWarnings.ql
|
||||
ql/cpp/ql/src/Diagnostics/FailedExtractorInvocations.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Arithmetic/BadAdditionOverflowCheck.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Arithmetic/IntMultToLong.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Arithmetic/SignedOverflowCheck.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Conversion/CastArrayPointerArithmetic.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Format/SnprintfOverflow.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Format/WrongNumberOfFormatArguments.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Memory Management/AllocaInLoop.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Memory Management/PointerOverflow.ql
|
||||
ql/cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql
|
||||
@@ -30,7 +28,6 @@ ql/cpp/ql/src/Security/CWE/CWE-120/VeryLikelyOverrunWrite.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-131/NoSpaceForZeroTerminator.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-134/UncontrolledFormatString.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-190/ArithmeticUncontrolled.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-190/ComparisonWithWiderType.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-253/HResultBooleanConversion.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-311/CleartextFileWrite.ql
|
||||
@@ -43,7 +40,6 @@ ql/cpp/ql/src/Security/CWE/CWE-367/TOCTOUFilesystemRace.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-416/IteratorToExpiredContainer.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-416/UseOfStringAfterLifetimeEnds.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-416/UseOfUniquePointerAfterLifetimeEnds.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-468/SuspiciousAddWithSizeof.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-497/ExposedSystemData.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-611/XXE.ql
|
||||
ql/cpp/ql/src/Security/CWE/CWE-676/DangerousFunctionOverflow.ql
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
## 5.6.0
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The predicate `getAContructorCall` in the class `SslContextClass` has been deprecated. Use `getAConstructorCall` instead.
|
||||
|
||||
### New Features
|
||||
|
||||
* Added predicates `getTransitiveNumberOfVlaDimensionStmts`, `getTransitiveVlaDimensionStmt`, and `getParentVlaDecl` to `VlaDeclStmt` for handling `VlaDeclStmt`s whose base type is defined in terms of another `VlaDeclStmt` via a `typedef`.
|
||||
|
||||
## 5.5.0
|
||||
|
||||
### New Features
|
||||
|
||||
@@ -35,7 +35,7 @@ class CustomOptions extends Options {
|
||||
override predicate returnsNull(Call call) { Options.super.returnsNull(call) }
|
||||
|
||||
/**
|
||||
* Holds if a call to this function will never return.
|
||||
* Holds if a call to the function `f` will never return.
|
||||
*
|
||||
* By default, this holds for `exit`, `_exit`, `abort`, `__assert_fail`,
|
||||
* `longjmp`, `error`, `__builtin_unreachable` and any function with a
|
||||
|
||||
9
cpp/ql/lib/change-notes/released/5.6.0.md
Normal file
9
cpp/ql/lib/change-notes/released/5.6.0.md
Normal file
@@ -0,0 +1,9 @@
|
||||
## 5.6.0
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The predicate `getAContructorCall` in the class `SslContextClass` has been deprecated. Use `getAConstructorCall` instead.
|
||||
|
||||
### New Features
|
||||
|
||||
* Added predicates `getTransitiveNumberOfVlaDimensionStmts`, `getTransitiveVlaDimensionStmt`, and `getParentVlaDecl` to `VlaDeclStmt` for handling `VlaDeclStmt`s whose base type is defined in terms of another `VlaDeclStmt` via a `typedef`.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 5.5.0
|
||||
lastReleaseVersion: 5.6.0
|
||||
|
||||
@@ -127,7 +127,7 @@ abstract class CryptographicAlgorithm extends CryptographicArtifact {
|
||||
/**
|
||||
* Normalizes a raw name into a normalized name as found in `CryptoAlgorithmNames.qll`.
|
||||
* Subclassess should override for more api-specific normalization.
|
||||
* By deafult, converts a raw name to upper-case with no hyphen, underscore, hash, or space.
|
||||
* By default, converts a raw name to upper-case with no hyphen, underscore, hash, or space.
|
||||
*/
|
||||
bindingset[s]
|
||||
string normalizeName(string s) {
|
||||
|
||||
@@ -652,14 +652,14 @@ module KeyGeneration {
|
||||
* Trace from EVP_PKEY_CTX* at algorithm sink to keygen,
|
||||
* users can then extrapolatae the matching algorithm from the alg sink to the keygen
|
||||
*/
|
||||
module EVP_PKEY_CTX_Ptr_Source_to_KeyGenOperationWithNoSize implements DataFlow::ConfigSig {
|
||||
module EVP_PKEY_CTX_Ptr_Source_to_KeyGenOperationWithNoSizeConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { isEVP_PKEY_CTX_Source(source, _) }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { isKeyGen_EVP_PKEY_CTX_Sink(sink, _) }
|
||||
}
|
||||
|
||||
module EVP_PKEY_CTX_Ptr_Source_to_KeyGenOperationWithNoSize_Flow =
|
||||
DataFlow::Global<EVP_PKEY_CTX_Ptr_Source_to_KeyGenOperationWithNoSize>;
|
||||
DataFlow::Global<EVP_PKEY_CTX_Ptr_Source_to_KeyGenOperationWithNoSizeConfig>;
|
||||
|
||||
/**
|
||||
* UNKNOWN key sizes to general purpose key generation functions (i.e., that take in no key size and assume
|
||||
|
||||
@@ -59,7 +59,7 @@ private string privateNormalizeFunctionName(Function f, string algType) {
|
||||
*
|
||||
* The predicate attempts to restrict normalization to what looks like an openssl
|
||||
* library by looking for functions only in an openssl path (see `isPossibleOpenSSLFunction`).
|
||||
* This may give false postive functions if a directory erronously appears to be openssl;
|
||||
* This may give false positive functions if a directory erronously appears to be openssl;
|
||||
* however, we take the stance that if a function
|
||||
* exists strongly mapping to a known function name in a directory such as these,
|
||||
* regardless of whether its actually a part of openSSL or not, we will analyze it as though it were.
|
||||
|
||||
@@ -49,7 +49,7 @@ private string privateNormalizeFunctionName(Function f, string algType) {
|
||||
*
|
||||
* The predicate attempts to restrict normalization to what looks like an openssl
|
||||
* library by looking for functions only in an openssl path (see `isPossibleOpenSSLFunction`).
|
||||
* This may give false postive functions if a directory erronously appears to be openssl;
|
||||
* This may give false positive functions if a directory erronously appears to be openssl;
|
||||
* however, we take the stance that if a function
|
||||
* exists strongly mapping to a known function name in a directory such as these,
|
||||
* regardless of whether its actually a part of openSSL or not, we will analyze it as though it were.
|
||||
|
||||
@@ -31,7 +31,7 @@ predicate knownPassthroughFunction(Function f, int inInd, int outInd) {
|
||||
|
||||
/**
|
||||
* `c` is a call to a function that preserves the algorithm but changes its form.
|
||||
* `onExpr` is the input argument passing through to, `outExpr` is the next expression in a dataflow step associated with `c`
|
||||
* `inExpr` is the input argument passing through to, `outExpr` is the next expression in a dataflow step associated with `c`
|
||||
*/
|
||||
predicate knownPassthoughCall(Call c, Expr inExpr, Expr outExpr) {
|
||||
exists(int inInd, int outInd |
|
||||
|
||||
@@ -298,10 +298,11 @@ private predicate boundFlowStep(Instruction i, NonPhiOperand op, int delta, bool
|
||||
else
|
||||
if strictlyNegative(x)
|
||||
then upper = true and delta = -1
|
||||
else
|
||||
if negative(x)
|
||||
then upper = true and delta = 0
|
||||
else none()
|
||||
else (
|
||||
negative(x) and
|
||||
upper = true and
|
||||
delta = 0
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(Operand x |
|
||||
@@ -321,10 +322,11 @@ private predicate boundFlowStep(Instruction i, NonPhiOperand op, int delta, bool
|
||||
else
|
||||
if strictlyNegative(x)
|
||||
then upper = false and delta = 1
|
||||
else
|
||||
if negative(x)
|
||||
then upper = false and delta = 0
|
||||
else none()
|
||||
else (
|
||||
negative(x) and
|
||||
upper = false and
|
||||
delta = 0
|
||||
)
|
||||
)
|
||||
or
|
||||
i.(RemInstruction).getRightOperand() = op and positive(op) and delta = -1 and upper = true
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 5.5.0
|
||||
version: 5.6.0
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -198,7 +198,7 @@ class ConceptIdExpr extends Expr, @concept_id {
|
||||
final Locatable getATemplateArgumentKind() { result = this.getTemplateArgumentKind(_) }
|
||||
|
||||
/**
|
||||
* Gets the `i`th template argument passed to the concept.
|
||||
* Gets template argument at index `index` passed to the concept, if any.
|
||||
*
|
||||
* For example, if:
|
||||
* ```cpp
|
||||
@@ -219,7 +219,7 @@ class ConceptIdExpr extends Expr, @concept_id {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the kind of the `i`th template argument value passed to the concept.
|
||||
* Gets the kind of the template argument value at index `index` passed to the concept, if any.
|
||||
*
|
||||
* For example, if:
|
||||
* ```cpp
|
||||
|
||||
@@ -223,8 +223,8 @@ class Declaration extends Locatable, @declaration {
|
||||
final Locatable getATemplateArgumentKind() { result = this.getTemplateArgumentKind(_) }
|
||||
|
||||
/**
|
||||
* Gets the `i`th template argument used to instantiate this declaration from a
|
||||
* template.
|
||||
* Gets the template argument at index `index` used to instantiate this declaration from a
|
||||
* template, if any.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
@@ -245,9 +245,9 @@ class Declaration extends Locatable, @declaration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `i`th template argument value used to instantiate this declaration
|
||||
* from a template. When called on a template, this will return the `i`th template
|
||||
* parameter value if it exists.
|
||||
* Gets the template argument value at index `index` used to instantiate this declaration
|
||||
* from a template. When called on a template, this will return the template
|
||||
* parameter value at index `index` if it exists.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
|
||||
@@ -877,7 +877,7 @@ class FormatLiteral extends Literal instanceof StringLiteral {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the char type required by the nth conversion specifier.
|
||||
* Gets the char type required by the `n`th conversion specifier.
|
||||
* - in the base case this is the default for the formatting function
|
||||
* (e.g. `char` for `printf`, `char` or `wchar_t` for `wprintf`).
|
||||
* - the `%C` format character reverses wideness.
|
||||
@@ -922,7 +922,7 @@ class FormatLiteral extends Literal instanceof StringLiteral {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string type required by the nth conversion specifier.
|
||||
* Gets the string type required by the `n`th conversion specifier.
|
||||
* - in the base case this is the default for the formatting function
|
||||
* (e.g. `char *` for `printf`, `char *` or `wchar_t *` for `wprintf`).
|
||||
* - the `%S` format character reverses wideness on some platforms.
|
||||
|
||||
@@ -101,7 +101,7 @@ predicate postDominates(ControlFlowNode postDominator, ControlFlowNode node) {
|
||||
*/
|
||||
|
||||
/**
|
||||
* Holds if `dominator` is an immediate dominator of `node` in the control-flow
|
||||
* Holds if `dom` is an immediate dominator of `node` in the control-flow
|
||||
* graph of basic blocks.
|
||||
*/
|
||||
predicate bbIDominates(BasicBlock dom, BasicBlock node) =
|
||||
@@ -117,7 +117,7 @@ private predicate bb_predecessor(BasicBlock succ, BasicBlock pred) { bb_successo
|
||||
private predicate bb_exit(ExitBasicBlock exit) { any() }
|
||||
|
||||
/**
|
||||
* Holds if `postDominator` is an immediate post-dominator of `node` in the control-flow
|
||||
* Holds if `pDom` is an immediate post-dominator of `node` in the control-flow
|
||||
* graph of basic blocks.
|
||||
*/
|
||||
predicate bbIPostDominates(BasicBlock pDom, BasicBlock node) =
|
||||
|
||||
@@ -72,6 +72,20 @@ abstract private class GuardConditionImpl extends Expr {
|
||||
*/
|
||||
abstract predicate valueControls(BasicBlock controlled, AbstractValue v);
|
||||
|
||||
/**
|
||||
* Holds if the control-flow edge `(pred, succ)` may be taken only if
|
||||
* the value of this condition is `v`.
|
||||
*/
|
||||
abstract predicate valueControlsEdge(BasicBlock pred, BasicBlock succ, AbstractValue v);
|
||||
|
||||
/**
|
||||
* Holds if the control-flow edge `(pred, succ)` may be taken only if
|
||||
* this the value of this condition is `testIsTrue`.
|
||||
*/
|
||||
final predicate controlsEdge(BasicBlock pred, BasicBlock succ, boolean testIsTrue) {
|
||||
this.valueControlsEdge(pred, succ, any(BooleanValue bv | bv.getValue() = testIsTrue))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this condition controls `controlled`, meaning that `controlled` is only
|
||||
* entered if the value of this condition is `testIsTrue`.
|
||||
@@ -175,6 +189,58 @@ abstract private class GuardConditionImpl extends Expr {
|
||||
*/
|
||||
pragma[inline]
|
||||
abstract predicate ensuresEq(Expr e, int k, BasicBlock block, boolean areEqual);
|
||||
|
||||
/**
|
||||
* Holds if (determined by this guard) `left == right + k` must be `areEqual` on the edge from
|
||||
* `pred` to `succ`. If `areEqual = false` then this implies `left != right + k`.
|
||||
*/
|
||||
pragma[inline]
|
||||
final predicate ensuresEqEdge(
|
||||
Expr left, Expr right, int k, BasicBlock pred, BasicBlock succ, boolean areEqual
|
||||
) {
|
||||
exists(boolean testIsTrue |
|
||||
this.comparesEq(left, right, k, areEqual, testIsTrue) and
|
||||
this.controlsEdge(pred, succ, testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if (determined by this guard) `e == k` must be `areEqual` on the edge from
|
||||
* `pred` to `succ`. If `areEqual = false` then this implies `e != k`.
|
||||
*/
|
||||
pragma[inline]
|
||||
final predicate ensuresEqEdge(Expr e, int k, BasicBlock pred, BasicBlock succ, boolean areEqual) {
|
||||
exists(AbstractValue v |
|
||||
this.comparesEq(e, k, areEqual, v) and
|
||||
this.valueControlsEdge(pred, succ, v)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if (determined by this guard) `left < right + k` must be `isLessThan` on the edge from
|
||||
* `pred` to `succ`. If `isLessThan = false` then this implies `left >= right + k`.
|
||||
*/
|
||||
pragma[inline]
|
||||
final predicate ensuresLtEdge(
|
||||
Expr left, Expr right, int k, BasicBlock pred, BasicBlock succ, boolean isLessThan
|
||||
) {
|
||||
exists(boolean testIsTrue |
|
||||
this.comparesLt(left, right, k, isLessThan, testIsTrue) and
|
||||
this.controlsEdge(pred, succ, testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if (determined by this guard) `e < k` must be `isLessThan` on the edge from
|
||||
* `pred` to `succ`. If `isLessThan = false` then this implies `e >= k`.
|
||||
*/
|
||||
pragma[inline]
|
||||
final predicate ensuresLtEdge(Expr e, int k, BasicBlock pred, BasicBlock succ, boolean isLessThan) {
|
||||
exists(AbstractValue v |
|
||||
this.comparesLt(e, k, isLessThan, v) and
|
||||
this.valueControlsEdge(pred, succ, v)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
final class GuardCondition = GuardConditionImpl;
|
||||
@@ -187,6 +253,16 @@ private class GuardConditionFromBinaryLogicalOperator extends GuardConditionImpl
|
||||
this.(BinaryLogicalOperation).getAnOperand() instanceof GuardCondition
|
||||
}
|
||||
|
||||
override predicate valueControlsEdge(BasicBlock pred, BasicBlock succ, AbstractValue v) {
|
||||
exists(BinaryLogicalOperation binop, GuardCondition lhs, GuardCondition rhs |
|
||||
this = binop and
|
||||
lhs = binop.getLeftOperand() and
|
||||
rhs = binop.getRightOperand() and
|
||||
lhs.valueControlsEdge(pred, succ, v) and
|
||||
rhs.valueControlsEdge(pred, succ, v)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate valueControls(BasicBlock controlled, AbstractValue v) {
|
||||
exists(BinaryLogicalOperation binop, GuardCondition lhs, GuardCondition rhs |
|
||||
this = binop and
|
||||
@@ -274,6 +350,25 @@ private predicate controlsBlock(IRGuardCondition ir, BasicBlock controlled, Abst
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `ir` controls the `(pred, succ)` edge, meaning that the edge
|
||||
* `(pred, succ)` is only taken if the value of this condition is `v`. This
|
||||
* helper predicate does not necessarily hold for binary logical operations
|
||||
* like `&&` and `||`.
|
||||
* See the detailed explanation on predicate `controlsEdge`.
|
||||
*/
|
||||
private predicate controlsEdge(
|
||||
IRGuardCondition ir, BasicBlock pred, BasicBlock succ, AbstractValue v
|
||||
) {
|
||||
exists(IRBlock irPred, IRBlock irSucc |
|
||||
ir.valueControlsEdge(irPred, irSucc, v) and
|
||||
nonExcludedIRAndBasicBlock(irPred, pred) and
|
||||
nonExcludedIRAndBasicBlock(irSucc, succ) and
|
||||
not isUnreachedBlock(irPred) and
|
||||
not isUnreachedBlock(irSucc)
|
||||
)
|
||||
}
|
||||
|
||||
private class GuardConditionFromNotExpr extends GuardConditionImpl {
|
||||
IRGuardCondition ir;
|
||||
|
||||
@@ -295,6 +390,10 @@ private class GuardConditionFromNotExpr extends GuardConditionImpl {
|
||||
controlsBlock(ir, controlled, v.getDualValue())
|
||||
}
|
||||
|
||||
override predicate valueControlsEdge(BasicBlock pred, BasicBlock succ, AbstractValue v) {
|
||||
controlsEdge(ir, pred, succ, v.getDualValue())
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
override predicate comparesLt(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue) {
|
||||
exists(Instruction li, Instruction ri |
|
||||
@@ -383,6 +482,10 @@ private class GuardConditionFromIR extends GuardConditionImpl {
|
||||
controlsBlock(ir, controlled, v)
|
||||
}
|
||||
|
||||
override predicate valueControlsEdge(BasicBlock pred, BasicBlock succ, AbstractValue v) {
|
||||
controlsEdge(ir, pred, succ, v)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
override predicate comparesLt(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue) {
|
||||
exists(Instruction li, Instruction ri |
|
||||
|
||||
@@ -1042,8 +1042,8 @@ private predicate subEdgeIncludingDestructors(Pos p1, Node n1, Node n2, Pos p2)
|
||||
* - `MicrosoftTryFinallyStmt`: On the edge following the `__finally` block for
|
||||
* the case where an exception was thrown and needs to be propagated.
|
||||
*/
|
||||
DestructorCall getSynthesisedDestructorCallAfterNode(Node n, int i) {
|
||||
synthetic_destructor_call(n, i, result)
|
||||
DestructorCall getSynthesisedDestructorCallAfterNode(Node node, int index) {
|
||||
synthetic_destructor_call(node, index, result)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -834,8 +834,10 @@ class ContentSet instanceof Content {
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
||||
super.hasLocationInfo(path, sl, sc, el, ec)
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2273,8 +2273,10 @@ class ContentSet instanceof Content {
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
||||
super.hasLocationInfo(path, sl, sc, el, ec)
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Provides classes that specify the conditions under which control flows along a given edge.
|
||||
*/
|
||||
|
||||
private import codeql.controlflow.SuccessorType
|
||||
private import internal.EdgeKindInternal
|
||||
|
||||
private newtype TEdgeKind =
|
||||
@@ -28,6 +29,21 @@ abstract private class EdgeKindImpl extends TEdgeKind {
|
||||
|
||||
final class EdgeKind = EdgeKindImpl;
|
||||
|
||||
private SuccessorType getAMatchingSpecificSuccessorType(EdgeKind k) {
|
||||
result.(BooleanSuccessor).getValue() = true and k instanceof TrueEdge
|
||||
or
|
||||
result.(BooleanSuccessor).getValue() = false and k instanceof FalseEdge
|
||||
or
|
||||
result instanceof ExceptionSuccessor and k instanceof ExceptionEdge
|
||||
}
|
||||
|
||||
SuccessorType getAMatchingSuccessorType(EdgeKind k) {
|
||||
result = getAMatchingSpecificSuccessorType(k)
|
||||
or
|
||||
not exists(getAMatchingSpecificSuccessorType(k)) and
|
||||
result instanceof DirectSuccessor
|
||||
}
|
||||
|
||||
/**
|
||||
* A "goto" edge, representing the unconditional successor of an `Instruction`
|
||||
* or `IRBlock`.
|
||||
|
||||
@@ -265,9 +265,9 @@ private predicate isEntryBlock(TIRBlock block) {
|
||||
}
|
||||
|
||||
module IRCfg implements BB::CfgSig<Language::Location> {
|
||||
class ControlFlowNode = Instruction;
|
||||
private import codeql.controlflow.SuccessorType
|
||||
|
||||
class SuccessorType = EdgeKind;
|
||||
class ControlFlowNode = Instruction;
|
||||
|
||||
final private class FinalIRBlock = IRBlock;
|
||||
|
||||
@@ -280,7 +280,12 @@ module IRCfg implements BB::CfgSig<Language::Location> {
|
||||
|
||||
BasicBlock getASuccessor() { result = super.getASuccessor() }
|
||||
|
||||
BasicBlock getASuccessor(SuccessorType t) { result = super.getSuccessor(t) }
|
||||
BasicBlock getASuccessor(SuccessorType t) {
|
||||
exists(EdgeKind k |
|
||||
result = super.getSuccessor(k) and
|
||||
t = getAMatchingSuccessorType(k)
|
||||
)
|
||||
}
|
||||
|
||||
predicate strictlyDominates(BasicBlock bb) { super.strictlyDominates(bb) }
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ newtype TValueNumber =
|
||||
) {
|
||||
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
|
||||
} or
|
||||
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
||||
TUniqueValueNumber(Instruction instr) { uniqueValueNumber(instr) }
|
||||
|
||||
/**
|
||||
* A `ConvertInstruction` which converts data of type `T` to data of type `U`
|
||||
@@ -129,12 +129,14 @@ private predicate filteredNumberableInstruction(Instruction instr) {
|
||||
count(instr.(InheritanceConversionInstruction).getBaseClass()) != 1 or
|
||||
count(instr.(InheritanceConversionInstruction).getDerivedClass()) != 1
|
||||
)
|
||||
or
|
||||
count(instr.getEnclosingIRFunction()) != 1
|
||||
}
|
||||
|
||||
private predicate variableAddressValueNumber(
|
||||
VariableAddressInstruction instr, IRFunction irFunc, Language::AST ast
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
@@ -144,7 +146,7 @@ private predicate variableAddressValueNumber(
|
||||
private predicate initializeParameterValueNumber(
|
||||
InitializeParameterInstruction instr, IRFunction irFunc, Language::AST var
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
@@ -154,7 +156,7 @@ private predicate initializeParameterValueNumber(
|
||||
private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
unique( | | instr.getResultIRType()) = type and
|
||||
instr.getValue() = value
|
||||
}
|
||||
@@ -162,7 +164,7 @@ private predicate constantValueNumber(
|
||||
private predicate stringConstantValueNumber(
|
||||
StringConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue().getValue() = value
|
||||
}
|
||||
@@ -171,7 +173,7 @@ private predicate fieldAddressValueNumber(
|
||||
FieldAddressInstruction instr, IRFunction irFunc, Language::Field field,
|
||||
TValueNumber objectAddress
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
unique( | | instr.getField()) = field and
|
||||
tvalueNumber(instr.getObjectAddress()) = objectAddress
|
||||
}
|
||||
@@ -182,7 +184,7 @@ private predicate binaryValueNumber0(
|
||||
TValueNumber valueNumber
|
||||
) {
|
||||
not instr instanceof PointerArithmeticInstruction and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
(
|
||||
isLeft = true and
|
||||
@@ -206,7 +208,7 @@ private predicate pointerArithmeticValueNumber0(
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize,
|
||||
boolean isLeft, TValueNumber valueNumber
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getElementSize() = elementSize and
|
||||
(
|
||||
@@ -229,7 +231,7 @@ private predicate pointerArithmeticValueNumber(
|
||||
private predicate unaryValueNumber(
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
not instr instanceof FieldAddressInstruction and
|
||||
@@ -242,7 +244,7 @@ private predicate inheritanceConversionValueNumber(
|
||||
InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode,
|
||||
Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
tvalueNumber(instr.getUnary()) = operand and
|
||||
unique( | | instr.getBaseClass()) = baseClass and
|
||||
@@ -254,7 +256,7 @@ private predicate loadTotalOverlapValueNumber0(
|
||||
LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber valueNumber,
|
||||
boolean isAddress
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
(
|
||||
isAddress = true and
|
||||
@@ -277,8 +279,7 @@ private predicate loadTotalOverlapValueNumber(
|
||||
* Holds if `instr` should be assigned a unique value number because this library does not know how
|
||||
* to determine if two instances of that instruction are equivalent.
|
||||
*/
|
||||
private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
private predicate uniqueValueNumber(Instruction instr) {
|
||||
not instr.getResultIRType() instanceof IRVoidType and
|
||||
(
|
||||
not numberableInstruction(instr)
|
||||
@@ -294,10 +295,8 @@ cached
|
||||
TValueNumber tvalueNumber(Instruction instr) {
|
||||
result = nonUniqueValueNumber(instr)
|
||||
or
|
||||
exists(IRFunction irFunc |
|
||||
uniqueValueNumber(instr, irFunc) and
|
||||
result = TUniqueValueNumber(irFunc, instr)
|
||||
)
|
||||
uniqueValueNumber(instr) and
|
||||
result = TUniqueValueNumber(instr)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -311,68 +310,64 @@ TValueNumber tvalueNumberOfOperand(Operand op) { result = tvalueNumber(op.getDef
|
||||
* value number.
|
||||
*/
|
||||
private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
exists(IRFunction irFunc |
|
||||
irFunc = instr.getEnclosingIRFunction() and
|
||||
(
|
||||
exists(Language::AST ast |
|
||||
variableAddressValueNumber(instr, irFunc, ast) and
|
||||
result = TVariableAddressValueNumber(irFunc, ast)
|
||||
)
|
||||
or
|
||||
exists(Language::AST var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Language::Field field, TValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and
|
||||
result =
|
||||
TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
or
|
||||
// The value number of a type-preserving conversion is just the value
|
||||
// number of the unconverted value.
|
||||
result = tvalueNumber(instr.(TypePreservingConvertInstruction).getUnary())
|
||||
exists(IRFunction irFunc | irFunc = instr.getEnclosingIRFunction() |
|
||||
exists(Language::AST ast |
|
||||
variableAddressValueNumber(instr, irFunc, ast) and
|
||||
result = TVariableAddressValueNumber(irFunc, ast)
|
||||
)
|
||||
or
|
||||
exists(Language::AST var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Language::Field field, TValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and
|
||||
result = TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
or
|
||||
// The value number of a type-preserving conversion is just the value
|
||||
// number of the unconverted value.
|
||||
result = tvalueNumber(instr.(TypePreservingConvertInstruction).getUnary())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -265,9 +265,9 @@ private predicate isEntryBlock(TIRBlock block) {
|
||||
}
|
||||
|
||||
module IRCfg implements BB::CfgSig<Language::Location> {
|
||||
class ControlFlowNode = Instruction;
|
||||
private import codeql.controlflow.SuccessorType
|
||||
|
||||
class SuccessorType = EdgeKind;
|
||||
class ControlFlowNode = Instruction;
|
||||
|
||||
final private class FinalIRBlock = IRBlock;
|
||||
|
||||
@@ -280,7 +280,12 @@ module IRCfg implements BB::CfgSig<Language::Location> {
|
||||
|
||||
BasicBlock getASuccessor() { result = super.getASuccessor() }
|
||||
|
||||
BasicBlock getASuccessor(SuccessorType t) { result = super.getSuccessor(t) }
|
||||
BasicBlock getASuccessor(SuccessorType t) {
|
||||
exists(EdgeKind k |
|
||||
result = super.getSuccessor(k) and
|
||||
t = getAMatchingSuccessorType(k)
|
||||
)
|
||||
}
|
||||
|
||||
predicate strictlyDominates(BasicBlock bb) { super.strictlyDominates(bb) }
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ newtype TValueNumber =
|
||||
) {
|
||||
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
|
||||
} or
|
||||
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
||||
TUniqueValueNumber(Instruction instr) { uniqueValueNumber(instr) }
|
||||
|
||||
/**
|
||||
* A `ConvertInstruction` which converts data of type `T` to data of type `U`
|
||||
@@ -129,12 +129,14 @@ private predicate filteredNumberableInstruction(Instruction instr) {
|
||||
count(instr.(InheritanceConversionInstruction).getBaseClass()) != 1 or
|
||||
count(instr.(InheritanceConversionInstruction).getDerivedClass()) != 1
|
||||
)
|
||||
or
|
||||
count(instr.getEnclosingIRFunction()) != 1
|
||||
}
|
||||
|
||||
private predicate variableAddressValueNumber(
|
||||
VariableAddressInstruction instr, IRFunction irFunc, Language::AST ast
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
@@ -144,7 +146,7 @@ private predicate variableAddressValueNumber(
|
||||
private predicate initializeParameterValueNumber(
|
||||
InitializeParameterInstruction instr, IRFunction irFunc, Language::AST var
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
@@ -154,7 +156,7 @@ private predicate initializeParameterValueNumber(
|
||||
private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
unique( | | instr.getResultIRType()) = type and
|
||||
instr.getValue() = value
|
||||
}
|
||||
@@ -162,7 +164,7 @@ private predicate constantValueNumber(
|
||||
private predicate stringConstantValueNumber(
|
||||
StringConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue().getValue() = value
|
||||
}
|
||||
@@ -171,7 +173,7 @@ private predicate fieldAddressValueNumber(
|
||||
FieldAddressInstruction instr, IRFunction irFunc, Language::Field field,
|
||||
TValueNumber objectAddress
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
unique( | | instr.getField()) = field and
|
||||
tvalueNumber(instr.getObjectAddress()) = objectAddress
|
||||
}
|
||||
@@ -182,7 +184,7 @@ private predicate binaryValueNumber0(
|
||||
TValueNumber valueNumber
|
||||
) {
|
||||
not instr instanceof PointerArithmeticInstruction and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
(
|
||||
isLeft = true and
|
||||
@@ -206,7 +208,7 @@ private predicate pointerArithmeticValueNumber0(
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize,
|
||||
boolean isLeft, TValueNumber valueNumber
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getElementSize() = elementSize and
|
||||
(
|
||||
@@ -229,7 +231,7 @@ private predicate pointerArithmeticValueNumber(
|
||||
private predicate unaryValueNumber(
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
not instr instanceof FieldAddressInstruction and
|
||||
@@ -242,7 +244,7 @@ private predicate inheritanceConversionValueNumber(
|
||||
InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode,
|
||||
Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
tvalueNumber(instr.getUnary()) = operand and
|
||||
unique( | | instr.getBaseClass()) = baseClass and
|
||||
@@ -254,7 +256,7 @@ private predicate loadTotalOverlapValueNumber0(
|
||||
LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber valueNumber,
|
||||
boolean isAddress
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
(
|
||||
isAddress = true and
|
||||
@@ -277,8 +279,7 @@ private predicate loadTotalOverlapValueNumber(
|
||||
* Holds if `instr` should be assigned a unique value number because this library does not know how
|
||||
* to determine if two instances of that instruction are equivalent.
|
||||
*/
|
||||
private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
private predicate uniqueValueNumber(Instruction instr) {
|
||||
not instr.getResultIRType() instanceof IRVoidType and
|
||||
(
|
||||
not numberableInstruction(instr)
|
||||
@@ -294,10 +295,8 @@ cached
|
||||
TValueNumber tvalueNumber(Instruction instr) {
|
||||
result = nonUniqueValueNumber(instr)
|
||||
or
|
||||
exists(IRFunction irFunc |
|
||||
uniqueValueNumber(instr, irFunc) and
|
||||
result = TUniqueValueNumber(irFunc, instr)
|
||||
)
|
||||
uniqueValueNumber(instr) and
|
||||
result = TUniqueValueNumber(instr)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -311,68 +310,64 @@ TValueNumber tvalueNumberOfOperand(Operand op) { result = tvalueNumber(op.getDef
|
||||
* value number.
|
||||
*/
|
||||
private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
exists(IRFunction irFunc |
|
||||
irFunc = instr.getEnclosingIRFunction() and
|
||||
(
|
||||
exists(Language::AST ast |
|
||||
variableAddressValueNumber(instr, irFunc, ast) and
|
||||
result = TVariableAddressValueNumber(irFunc, ast)
|
||||
)
|
||||
or
|
||||
exists(Language::AST var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Language::Field field, TValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and
|
||||
result =
|
||||
TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
or
|
||||
// The value number of a type-preserving conversion is just the value
|
||||
// number of the unconverted value.
|
||||
result = tvalueNumber(instr.(TypePreservingConvertInstruction).getUnary())
|
||||
exists(IRFunction irFunc | irFunc = instr.getEnclosingIRFunction() |
|
||||
exists(Language::AST ast |
|
||||
variableAddressValueNumber(instr, irFunc, ast) and
|
||||
result = TVariableAddressValueNumber(irFunc, ast)
|
||||
)
|
||||
or
|
||||
exists(Language::AST var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Language::Field field, TValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and
|
||||
result = TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
or
|
||||
// The value number of a type-preserving conversion is just the value
|
||||
// number of the unconverted value.
|
||||
result = tvalueNumber(instr.(TypePreservingConvertInstruction).getUnary())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -97,7 +97,14 @@ newtype TInstructionTag =
|
||||
exists(Stmt s | exists(s.getImplicitDestructorCall(index)))
|
||||
} or
|
||||
CoAwaitBranchTag() or
|
||||
BoolToIntConversionTag()
|
||||
BoolToIntConversionTag() or
|
||||
SizeofVlaBaseSizeTag() or
|
||||
SizeofVlaConversionTag(int index) {
|
||||
exists(VlaDeclStmt v | exists(v.getTransitiveVlaDimensionStmt(index)))
|
||||
} or
|
||||
SizeofVlaDimensionTag(int index) {
|
||||
exists(VlaDeclStmt v | exists(v.getTransitiveVlaDimensionStmt(index)))
|
||||
}
|
||||
|
||||
class InstructionTag extends TInstructionTag {
|
||||
final string toString() { result = getInstructionTagId(this) }
|
||||
|
||||
@@ -123,13 +123,16 @@ private predicate ignoreExprAndDescendants(Expr expr) {
|
||||
// or
|
||||
ignoreExprAndDescendants(getRealParent(expr)) // recursive case
|
||||
or
|
||||
// va_start doesn't evaluate its argument, so we don't need to translate it.
|
||||
// va_start does not evaluate its argument, so we do not need to translate it.
|
||||
exists(BuiltInVarArgsStart vaStartExpr |
|
||||
vaStartExpr.getLastNamedParameter().getFullyConverted() = expr
|
||||
)
|
||||
or
|
||||
// sizeof does not evaluate its argument, so we do not need to translate it.
|
||||
exists(SizeofExprOperator sizeofExpr | sizeofExpr.getExprOperand().getFullyConverted() = expr)
|
||||
or
|
||||
// The children of C11 _Generic expressions are just surface syntax.
|
||||
exists(C11GenericExpr generic | generic.getAChild() = expr)
|
||||
exists(C11GenericExpr generic | generic.getAChild().getFullyConverted() = expr)
|
||||
or
|
||||
// Do not translate implicit destructor calls for unnamed temporary variables that are
|
||||
// conditionally constructed (until we have a mechanism for calling these only when the
|
||||
|
||||
@@ -187,7 +187,7 @@ Variable getEnclosingVariable(Expr e) {
|
||||
}
|
||||
|
||||
/**
|
||||
* The IR translation of the "core" part of an expression. This is the part of
|
||||
* The IR translation of the "core" part of an expression. This is the part of
|
||||
* the expression that produces the result value of the expression, before any
|
||||
* lvalue-to-rvalue conversion on the result. Every expression has a single
|
||||
* `TranslatedCoreExpr`.
|
||||
@@ -4094,6 +4094,155 @@ class TranslatedStmtExpr extends TranslatedNonConstantExpr {
|
||||
TranslatedStmt getStmt() { result = getTranslatedStmt(expr.getStmt()) }
|
||||
}
|
||||
|
||||
private VlaDeclStmt getVlaDeclStmt(Expr expr, int pointerDerefCount) {
|
||||
expr.(VariableAccess).getTarget() = result.getVariable() and
|
||||
pointerDerefCount = 0
|
||||
or
|
||||
not expr.(PointerDereferenceExpr).getOperand() instanceof AddressOfExpr and
|
||||
result = getVlaDeclStmt(expr.(PointerDereferenceExpr).getOperand(), pointerDerefCount - 1)
|
||||
or
|
||||
// Skip sequences of the form `*&...`
|
||||
result =
|
||||
getVlaDeclStmt(expr.(PointerDereferenceExpr).getOperand().(AddressOfExpr).getOperand(),
|
||||
pointerDerefCount)
|
||||
or
|
||||
result = getVlaDeclStmt(expr.(ArrayExpr).getArrayBase(), pointerDerefCount - 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* The IR translation of `SizeofExprOperator` when its result is non-constant, i.e.,
|
||||
* when the operand expression refers to a variable length array.
|
||||
*/
|
||||
class TranslatedSizeofExpr extends TranslatedNonConstantExpr {
|
||||
override SizeofExprOperator expr;
|
||||
VlaDeclStmt vlaDeclStmt;
|
||||
int vlaDimensions;
|
||||
int pointerDerefCount;
|
||||
|
||||
TranslatedSizeofExpr() {
|
||||
vlaDeclStmt = getVlaDeclStmt(expr.getExprOperand(), pointerDerefCount) and
|
||||
vlaDimensions = vlaDeclStmt.getTransitiveNumberOfVlaDimensionStmts() and
|
||||
pointerDerefCount < vlaDimensions
|
||||
}
|
||||
|
||||
final override Instruction getFirstInstruction(EdgeKind kind) {
|
||||
result = this.getInstruction(SizeofVlaBaseSizeTag()) and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
override Instruction getALastInstructionInternal() {
|
||||
result = this.getInstruction(SizeofVlaDimensionTag(vlaDimensions - 1))
|
||||
}
|
||||
|
||||
final override TranslatedElement getChildInternal(int id) { none() }
|
||||
|
||||
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
opcode instanceof Opcode::Constant and
|
||||
tag = SizeofVlaBaseSizeTag() and
|
||||
resultType = this.getResultType()
|
||||
or
|
||||
exists(int n, Type dimType |
|
||||
pointerDerefCount <= n and
|
||||
n < vlaDimensions and
|
||||
dimType = this.getDimensionExpr(n).getUnderlyingType() and
|
||||
tag = SizeofVlaConversionTag(n)
|
||||
|
|
||||
(
|
||||
expr.getUnderlyingType() = dimType and
|
||||
opcode instanceof Opcode::CopyValue
|
||||
or
|
||||
not expr.getUnderlyingType() = dimType and
|
||||
opcode instanceof Opcode::Convert
|
||||
)
|
||||
) and
|
||||
resultType = this.getResultType()
|
||||
or
|
||||
opcode instanceof Opcode::Mul and
|
||||
exists(int n | pointerDerefCount <= n and n < vlaDimensions | tag = SizeofVlaDimensionTag(n)) and
|
||||
resultType = this.getResultType()
|
||||
}
|
||||
|
||||
final override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
|
||||
tag = SizeofVlaBaseSizeTag() and
|
||||
result = this.getInstruction(SizeofVlaConversionTag(pointerDerefCount)) and
|
||||
kind instanceof GotoEdge
|
||||
or
|
||||
exists(int n | pointerDerefCount <= n and n < vlaDimensions |
|
||||
tag = SizeofVlaConversionTag(n) and
|
||||
result = this.getInstruction(SizeofVlaDimensionTag(n))
|
||||
) and
|
||||
kind instanceof GotoEdge
|
||||
or
|
||||
exists(int n | pointerDerefCount <= n and n < vlaDimensions - 1 |
|
||||
tag = SizeofVlaDimensionTag(n) and
|
||||
result = this.getInstruction(SizeofVlaConversionTag(n + 1))
|
||||
) and
|
||||
kind instanceof GotoEdge
|
||||
or
|
||||
tag = SizeofVlaDimensionTag(vlaDimensions - 1) and
|
||||
result = this.getParent().getChildSuccessor(this, kind)
|
||||
}
|
||||
|
||||
override string getInstructionConstantValue(InstructionTag tag) {
|
||||
tag = SizeofVlaBaseSizeTag() and
|
||||
result = this.getBaseType(vlaDeclStmt).getSize().toString()
|
||||
}
|
||||
|
||||
private Type getBaseType(VlaDeclStmt v) {
|
||||
not exists(v.getParentVlaDecl()) and
|
||||
(
|
||||
result =
|
||||
this.getBaseType(v.getVariable().getUnderlyingType(), v.getNumberOfVlaDimensionStmts())
|
||||
or
|
||||
result = this.getBaseType(v.getType().getUnderlyingType(), v.getNumberOfVlaDimensionStmts())
|
||||
)
|
||||
or
|
||||
result = this.getBaseType(v.getParentVlaDecl())
|
||||
}
|
||||
|
||||
private Type getBaseType(Type type, int n) {
|
||||
n = 0 and
|
||||
result = type
|
||||
or
|
||||
result = this.getBaseType(type.(DerivedType).getBaseType(), n - 1)
|
||||
}
|
||||
|
||||
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
exists(int n | pointerDerefCount <= n and n < vlaDimensions |
|
||||
tag = SizeofVlaConversionTag(n) and
|
||||
(
|
||||
operandTag instanceof UnaryOperandTag and
|
||||
result = getTranslatedExpr(this.getDimensionExpr(n)).getResult()
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(int n | pointerDerefCount <= n and n < vlaDimensions |
|
||||
tag = SizeofVlaDimensionTag(n) and
|
||||
(
|
||||
operandTag instanceof LeftOperandTag and
|
||||
(
|
||||
n - 1 >= pointerDerefCount and
|
||||
result = this.getInstruction(SizeofVlaDimensionTag(n - 1))
|
||||
or
|
||||
n - 1 < pointerDerefCount and
|
||||
result = this.getInstruction(SizeofVlaBaseSizeTag())
|
||||
)
|
||||
or
|
||||
operandTag instanceof RightOperandTag and
|
||||
result = this.getInstruction(SizeofVlaConversionTag(n))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private Expr getDimensionExpr(int n) {
|
||||
result = vlaDeclStmt.getTransitiveVlaDimensionStmt(n).getDimensionExpr().getFullyConverted()
|
||||
}
|
||||
|
||||
final override Instruction getResult() {
|
||||
result = this.getInstruction(SizeofVlaDimensionTag(vlaDimensions - 1))
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedErrorExpr extends TranslatedSingleInstructionExpr {
|
||||
override ErrorExpr expr;
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ CppType getEllipsisVariablePRValueType() {
|
||||
CppType getEllipsisVariableGLValueType() { result = getTypeForGLValue(any(UnknownType t)) }
|
||||
|
||||
/**
|
||||
* Holds if the function returns a value, as opposed to returning `void`.
|
||||
* Holds if the function `func` returns a value, as opposed to returning `void`.
|
||||
*/
|
||||
predicate hasReturnValue(Function func) { not func.getUnspecifiedType() instanceof VoidType }
|
||||
|
||||
|
||||
@@ -601,7 +601,7 @@ class TranslatedReturnVoidStmt extends TranslatedReturnStmt {
|
||||
* The IR translation of an implicit `return` statement generated by the extractor to handle control
|
||||
* flow that reaches the end of a non-`void`-returning function body. Such control flow
|
||||
* produces undefined behavior in C++ but not in C. However even in C using the return value is
|
||||
* undefined behaviour. We make it return uninitialized memory to get as much flow as possible.
|
||||
* undefined behavior. We make it return uninitialized memory to get as much flow as possible.
|
||||
*/
|
||||
class TranslatedNoValueReturnStmt extends TranslatedReturnStmt, TranslatedVariableInitialization {
|
||||
TranslatedNoValueReturnStmt() {
|
||||
|
||||
@@ -265,9 +265,9 @@ private predicate isEntryBlock(TIRBlock block) {
|
||||
}
|
||||
|
||||
module IRCfg implements BB::CfgSig<Language::Location> {
|
||||
class ControlFlowNode = Instruction;
|
||||
private import codeql.controlflow.SuccessorType
|
||||
|
||||
class SuccessorType = EdgeKind;
|
||||
class ControlFlowNode = Instruction;
|
||||
|
||||
final private class FinalIRBlock = IRBlock;
|
||||
|
||||
@@ -280,7 +280,12 @@ module IRCfg implements BB::CfgSig<Language::Location> {
|
||||
|
||||
BasicBlock getASuccessor() { result = super.getASuccessor() }
|
||||
|
||||
BasicBlock getASuccessor(SuccessorType t) { result = super.getSuccessor(t) }
|
||||
BasicBlock getASuccessor(SuccessorType t) {
|
||||
exists(EdgeKind k |
|
||||
result = super.getSuccessor(k) and
|
||||
t = getAMatchingSuccessorType(k)
|
||||
)
|
||||
}
|
||||
|
||||
predicate strictlyDominates(BasicBlock bb) { super.strictlyDominates(bb) }
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ newtype TValueNumber =
|
||||
) {
|
||||
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
|
||||
} or
|
||||
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
||||
TUniqueValueNumber(Instruction instr) { uniqueValueNumber(instr) }
|
||||
|
||||
/**
|
||||
* A `ConvertInstruction` which converts data of type `T` to data of type `U`
|
||||
@@ -129,12 +129,14 @@ private predicate filteredNumberableInstruction(Instruction instr) {
|
||||
count(instr.(InheritanceConversionInstruction).getBaseClass()) != 1 or
|
||||
count(instr.(InheritanceConversionInstruction).getDerivedClass()) != 1
|
||||
)
|
||||
or
|
||||
count(instr.getEnclosingIRFunction()) != 1
|
||||
}
|
||||
|
||||
private predicate variableAddressValueNumber(
|
||||
VariableAddressInstruction instr, IRFunction irFunc, Language::AST ast
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
@@ -144,7 +146,7 @@ private predicate variableAddressValueNumber(
|
||||
private predicate initializeParameterValueNumber(
|
||||
InitializeParameterInstruction instr, IRFunction irFunc, Language::AST var
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
// The underlying AST element is used as value-numbering key instead of the
|
||||
// `IRVariable` to work around a problem where a variable or expression with
|
||||
// multiple types gives rise to multiple `IRVariable`s.
|
||||
@@ -154,7 +156,7 @@ private predicate initializeParameterValueNumber(
|
||||
private predicate constantValueNumber(
|
||||
ConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
unique( | | instr.getResultIRType()) = type and
|
||||
instr.getValue() = value
|
||||
}
|
||||
@@ -162,7 +164,7 @@ private predicate constantValueNumber(
|
||||
private predicate stringConstantValueNumber(
|
||||
StringConstantInstruction instr, IRFunction irFunc, IRType type, string value
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
instr.getValue().getValue() = value
|
||||
}
|
||||
@@ -171,7 +173,7 @@ private predicate fieldAddressValueNumber(
|
||||
FieldAddressInstruction instr, IRFunction irFunc, Language::Field field,
|
||||
TValueNumber objectAddress
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
unique( | | instr.getField()) = field and
|
||||
tvalueNumber(instr.getObjectAddress()) = objectAddress
|
||||
}
|
||||
@@ -182,7 +184,7 @@ private predicate binaryValueNumber0(
|
||||
TValueNumber valueNumber
|
||||
) {
|
||||
not instr instanceof PointerArithmeticInstruction and
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
(
|
||||
isLeft = true and
|
||||
@@ -206,7 +208,7 @@ private predicate pointerArithmeticValueNumber0(
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize,
|
||||
boolean isLeft, TValueNumber valueNumber
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
instr.getElementSize() = elementSize and
|
||||
(
|
||||
@@ -229,7 +231,7 @@ private predicate pointerArithmeticValueNumber(
|
||||
private predicate unaryValueNumber(
|
||||
UnaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
not instr instanceof FieldAddressInstruction and
|
||||
@@ -242,7 +244,7 @@ private predicate inheritanceConversionValueNumber(
|
||||
InheritanceConversionInstruction instr, IRFunction irFunc, Opcode opcode,
|
||||
Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getOpcode() = opcode and
|
||||
tvalueNumber(instr.getUnary()) = operand and
|
||||
unique( | | instr.getBaseClass()) = baseClass and
|
||||
@@ -254,7 +256,7 @@ private predicate loadTotalOverlapValueNumber0(
|
||||
LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber valueNumber,
|
||||
boolean isAddress
|
||||
) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
unique( | | instr.getEnclosingIRFunction()) = irFunc and
|
||||
instr.getResultIRType() = type and
|
||||
(
|
||||
isAddress = true and
|
||||
@@ -277,8 +279,7 @@ private predicate loadTotalOverlapValueNumber(
|
||||
* Holds if `instr` should be assigned a unique value number because this library does not know how
|
||||
* to determine if two instances of that instruction are equivalent.
|
||||
*/
|
||||
private predicate uniqueValueNumber(Instruction instr, IRFunction irFunc) {
|
||||
instr.getEnclosingIRFunction() = irFunc and
|
||||
private predicate uniqueValueNumber(Instruction instr) {
|
||||
not instr.getResultIRType() instanceof IRVoidType and
|
||||
(
|
||||
not numberableInstruction(instr)
|
||||
@@ -294,10 +295,8 @@ cached
|
||||
TValueNumber tvalueNumber(Instruction instr) {
|
||||
result = nonUniqueValueNumber(instr)
|
||||
or
|
||||
exists(IRFunction irFunc |
|
||||
uniqueValueNumber(instr, irFunc) and
|
||||
result = TUniqueValueNumber(irFunc, instr)
|
||||
)
|
||||
uniqueValueNumber(instr) and
|
||||
result = TUniqueValueNumber(instr)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -311,68 +310,64 @@ TValueNumber tvalueNumberOfOperand(Operand op) { result = tvalueNumber(op.getDef
|
||||
* value number.
|
||||
*/
|
||||
private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
exists(IRFunction irFunc |
|
||||
irFunc = instr.getEnclosingIRFunction() and
|
||||
(
|
||||
exists(Language::AST ast |
|
||||
variableAddressValueNumber(instr, irFunc, ast) and
|
||||
result = TVariableAddressValueNumber(irFunc, ast)
|
||||
)
|
||||
or
|
||||
exists(Language::AST var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Language::Field field, TValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and
|
||||
result =
|
||||
TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
or
|
||||
// The value number of a type-preserving conversion is just the value
|
||||
// number of the unconverted value.
|
||||
result = tvalueNumber(instr.(TypePreservingConvertInstruction).getUnary())
|
||||
exists(IRFunction irFunc | irFunc = instr.getEnclosingIRFunction() |
|
||||
exists(Language::AST ast |
|
||||
variableAddressValueNumber(instr, irFunc, ast) and
|
||||
result = TVariableAddressValueNumber(irFunc, ast)
|
||||
)
|
||||
or
|
||||
exists(Language::AST var |
|
||||
initializeParameterValueNumber(instr, irFunc, var) and
|
||||
result = TInitializeParameterValueNumber(irFunc, var)
|
||||
)
|
||||
or
|
||||
exists(string value, IRType type |
|
||||
constantValueNumber(instr, irFunc, type, value) and
|
||||
result = TConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(IRType type, string value |
|
||||
stringConstantValueNumber(instr, irFunc, type, value) and
|
||||
result = TStringConstantValueNumber(irFunc, type, value)
|
||||
)
|
||||
or
|
||||
exists(Language::Field field, TValueNumber objectAddress |
|
||||
fieldAddressValueNumber(instr, irFunc, field, objectAddress) and
|
||||
result = TFieldAddressValueNumber(irFunc, field, objectAddress)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
binaryValueNumber(instr, irFunc, opcode, leftOperand, rightOperand) and
|
||||
result = TBinaryValueNumber(irFunc, opcode, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, TValueNumber operand |
|
||||
unaryValueNumber(instr, irFunc, opcode, operand) and
|
||||
result = TUnaryValueNumber(irFunc, opcode, operand)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
Opcode opcode, Language::Class baseClass, Language::Class derivedClass, TValueNumber operand
|
||||
|
|
||||
inheritanceConversionValueNumber(instr, irFunc, opcode, baseClass, derivedClass, operand) and
|
||||
result = TInheritanceConversionValueNumber(irFunc, opcode, baseClass, derivedClass, operand)
|
||||
)
|
||||
or
|
||||
exists(Opcode opcode, int elementSize, TValueNumber leftOperand, TValueNumber rightOperand |
|
||||
pointerArithmeticValueNumber(instr, irFunc, opcode, elementSize, leftOperand, rightOperand) and
|
||||
result = TPointerArithmeticValueNumber(irFunc, opcode, elementSize, leftOperand, rightOperand)
|
||||
)
|
||||
or
|
||||
exists(IRType type, TValueNumber memOperand, TValueNumber operand |
|
||||
loadTotalOverlapValueNumber(instr, irFunc, type, memOperand, operand) and
|
||||
result = TLoadTotalOverlapValueNumber(irFunc, type, memOperand, operand)
|
||||
)
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
or
|
||||
// The value number of a type-preserving conversion is just the value
|
||||
// number of the unconverted value.
|
||||
result = tvalueNumber(instr.(TypePreservingConvertInstruction).getUnary())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -49,7 +49,8 @@ Type getVariableType(Variable v) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the database contains a `case` label with the specified minimum and maximum value.
|
||||
* Holds if the database contains a `switchCase` label with the specified minimum `minValue`
|
||||
* and maximum `maxValue` value.
|
||||
*/
|
||||
predicate hasCaseEdge(SwitchCase switchCase, string minValue, string maxValue) {
|
||||
minValue = switchCase.getExpr().getFullyConverted().getValue() and
|
||||
|
||||
@@ -371,7 +371,7 @@ class FunctionOutput extends TFunctionOutput {
|
||||
/**
|
||||
* Holds if this is the output value pointed to by a pointer parameter to a function, or the
|
||||
* output value referred to by a reference parameter to a function, where the parameter has
|
||||
* index `index`.
|
||||
* index `i`.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
@@ -389,7 +389,7 @@ class FunctionOutput extends TFunctionOutput {
|
||||
/**
|
||||
* Holds if this is the output value pointed to by a pointer parameter (through `ind` number
|
||||
* of indirections) to a function, or the output value referred to by a reference parameter to
|
||||
* a function, where the parameter has index `index`.
|
||||
* a function, where the parameter has index `i`.
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
|
||||
@@ -307,13 +307,12 @@ class SemStoreExpr extends SemUnaryExpr {
|
||||
}
|
||||
|
||||
class SemConditionalExpr extends SemKnownExpr {
|
||||
SemExpr condition;
|
||||
SemExpr trueResult;
|
||||
SemExpr falseResult;
|
||||
|
||||
SemConditionalExpr() {
|
||||
opcode instanceof Opcode::Conditional and
|
||||
Specific::conditionalExpr(this, type, condition, trueResult, falseResult)
|
||||
Specific::conditionalExpr(this, type, any(SemExpr condition), trueResult, falseResult)
|
||||
}
|
||||
|
||||
final SemExpr getBranchExpr(boolean branch) {
|
||||
|
||||
@@ -21,7 +21,9 @@ class FileWrite extends Expr {
|
||||
Expr getDest() { fileWrite(this, _, result) }
|
||||
|
||||
/**
|
||||
* Gets the conversion character for this write, if it exists and is known. For example in the following code the write of `value1` has conversion character `"s"`, whereas the write of `value2` has no conversion specifier.
|
||||
* Gets the conversion character from `source` for this write, if it exists and is known.
|
||||
* For example in the following code the write of `value1` has conversion character `"s"`, whereas
|
||||
* the write of `value2` has no conversion specifier.
|
||||
* ```
|
||||
* fprintf(file, "%s", value1);
|
||||
* stream << value2;
|
||||
|
||||
@@ -191,11 +191,19 @@ module BoostorgAsio {
|
||||
class SslContextClass extends Class {
|
||||
SslContextClass() { this.getQualifiedName() = "boost::asio::ssl::context" }
|
||||
|
||||
ConstructorCall getAContructorCall() {
|
||||
/**
|
||||
* Gets a constructor call, if any.
|
||||
*/
|
||||
ConstructorCall getAConstructorCall() {
|
||||
this.getAConstructor().getACallToThisFunction() = result and
|
||||
not result.getLocation().getFile().toString().matches("%/boost/asio/%") and
|
||||
result.fromSource()
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getAConstructorCall` instead.
|
||||
*/
|
||||
deprecated ConstructorCall getAContructorCall() { result = this.getAConstructorCall() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -368,7 +376,7 @@ module BoostorgAsio {
|
||||
*/
|
||||
default predicate isSink(DataFlow::Node sink) {
|
||||
exists(ConstructorCall cc, SslContextClass c, Expr e | e = sink.asExpr() |
|
||||
c.getAContructorCall() = cc and
|
||||
c.getAConstructorCall() = cc and
|
||||
cc.getArgument(0) = e
|
||||
)
|
||||
}
|
||||
@@ -468,7 +476,7 @@ module BoostorgAsio {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(SslContextClass c, ConstructorCall cc |
|
||||
cc = source.asExpr() and
|
||||
c.getAContructorCall() = cc
|
||||
c.getAConstructorCall() = cc
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -2355,6 +2355,20 @@ class VlaDeclStmt extends Stmt, @stmt_vla_decl {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of VLA dimension statements in this VLA declaration
|
||||
* statement and transitively of the VLA declaration used to define its
|
||||
* base type. if any.
|
||||
*/
|
||||
int getTransitiveNumberOfVlaDimensionStmts() {
|
||||
not exists(this.getParentVlaDecl()) and
|
||||
result = this.getNumberOfVlaDimensionStmts()
|
||||
or
|
||||
result =
|
||||
this.getNumberOfVlaDimensionStmts() +
|
||||
this.getParentVlaDecl().getTransitiveNumberOfVlaDimensionStmts()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `i`th VLA dimension statement in this VLA
|
||||
* declaration statement.
|
||||
@@ -2367,6 +2381,19 @@ class VlaDeclStmt extends Stmt, @stmt_vla_decl {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `i`th VLA dimension statement in this VLA declaration
|
||||
* statement or transitively of the VLA declaration used to define
|
||||
* its base type.
|
||||
*/
|
||||
VlaDimensionStmt getTransitiveVlaDimensionStmt(int i) {
|
||||
i < this.getNumberOfVlaDimensionStmts() and
|
||||
result = this.getVlaDimensionStmt(i)
|
||||
or
|
||||
result =
|
||||
this.getParentVlaDecl().getTransitiveVlaDimensionStmt(i - this.getNumberOfVlaDimensionStmts())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type that this VLA declaration statement relates to,
|
||||
* if any.
|
||||
@@ -2378,4 +2405,31 @@ class VlaDeclStmt extends Stmt, @stmt_vla_decl {
|
||||
* if any.
|
||||
*/
|
||||
Variable getVariable() { variable_vla(unresolveElement(result), underlyingElement(this)) }
|
||||
|
||||
/**
|
||||
* Get the VLA declaration used to define the base type of
|
||||
* this VLA declaration, if any.
|
||||
*/
|
||||
VlaDeclStmt getParentVlaDecl() {
|
||||
exists(Variable v, Type baseType |
|
||||
v = this.getVariable() and
|
||||
baseType = this.getBaseType(v.getType(), this.getNumberOfVlaDimensionStmts())
|
||||
|
|
||||
result.getType() = baseType
|
||||
)
|
||||
or
|
||||
exists(Type t, Type baseType |
|
||||
t = this.getType().(TypedefType).getBaseType() and
|
||||
baseType = this.getBaseType(t, this.getNumberOfVlaDimensionStmts())
|
||||
|
|
||||
result.getType() = baseType
|
||||
)
|
||||
}
|
||||
|
||||
private Type getBaseType(Type type, int n) {
|
||||
n = 0 and
|
||||
result = type
|
||||
or
|
||||
result = this.getBaseType(type.(DerivedType).getBaseType(), n - 1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,12 +164,17 @@ predicate valueOccurrenceCount(string value, int n) {
|
||||
n > 20
|
||||
}
|
||||
|
||||
predicate occurenceCount(Literal lit, string value, int n) {
|
||||
predicate occurrenceCount(Literal lit, string value, int n) {
|
||||
valueOccurrenceCount(value, n) and
|
||||
value = lit.getValue() and
|
||||
nonTrivialValue(_, lit)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `occurrenceCount` instead.
|
||||
*/
|
||||
deprecated predicate occurenceCount = occurrenceCount/3;
|
||||
|
||||
/*
|
||||
* Literals repeated frequently
|
||||
*/
|
||||
@@ -178,7 +183,7 @@ predicate check(Literal lit, string value, int n, File f) {
|
||||
// Check that the literal is nontrivial
|
||||
not trivial(lit) and
|
||||
// Check that it is repeated a number of times
|
||||
occurenceCount(lit, value, n) and
|
||||
occurrenceCount(lit, value, n) and
|
||||
n > 20 and
|
||||
f = lit.getFile() and
|
||||
// Exclude generated files
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
## 1.5.0
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* The queries `cpp/wrong-type-format-argument`, `cpp/comparison-with-wider-type`, `cpp/integer-multiplication-cast-to-long`, `cpp/implicit-function-declaration` and `cpp/suspicious-add-sizeof` have had their precisions reduced from `high` to `medium`. They will also now give alerts for projects built with `build-mode: none`.
|
||||
* The queries `cpp/wrong-type-format-argument`, `cpp/comparison-with-wider-type`, `cpp/integer-multiplication-cast-to-long` and `cpp/suspicious-add-sizeof` are no longer included in the `code-scanning` suite.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* The predicate `occurenceCount` in the file module `MagicConstants` has been deprecated. Use `occurrenceCount` instead.
|
||||
* The predicate `additionalAdditionOrSubstractionCheckForLeapYear` in the file module `LeapYear` has been deprecated. Use `additionalAdditionOrSubtractionCheckForLeapYear` instead.
|
||||
|
||||
## 1.4.7
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -4,13 +4,9 @@ private import semmle.code.cpp.controlflow.IRGuards
|
||||
private import semmle.code.cpp.ir.ValueNumbering
|
||||
|
||||
private predicate exprInBooleanContext(Expr e) {
|
||||
exists(IRGuardCondition gc |
|
||||
exists(Instruction i |
|
||||
i.getUnconvertedResultExpression() = e and
|
||||
gc.comparesEq(valueNumber(i).getAUse(), 0, _, _)
|
||||
)
|
||||
or
|
||||
gc.getUnconvertedResultExpression() = e
|
||||
exists(IRGuardCondition gc, Instruction i |
|
||||
i.getUnconvertedResultExpression() = e and
|
||||
gc.comparesEq(valueNumber(i).getAUse(), 0, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -36,20 +32,18 @@ private string getEofValue() {
|
||||
* Holds if the value of `call` has been checked to not equal `EOF`.
|
||||
*/
|
||||
private predicate checkedForEof(ScanfFunctionCall call) {
|
||||
exists(IRGuardCondition gc |
|
||||
exists(CallInstruction i | i.getUnconvertedResultExpression() = call |
|
||||
exists(int val | gc.comparesEq(valueNumber(i).getAUse(), val, _, _) |
|
||||
// call == EOF
|
||||
val = getEofValue().toInt()
|
||||
or
|
||||
// call == [any positive number]
|
||||
val > 0
|
||||
)
|
||||
exists(IRGuardCondition gc, CallInstruction i | i.getUnconvertedResultExpression() = call |
|
||||
exists(int val | gc.comparesEq(valueNumber(i).getAUse(), val, _, _) |
|
||||
// call == EOF
|
||||
val = getEofValue().toInt()
|
||||
or
|
||||
exists(int val | gc.comparesLt(valueNumber(i).getAUse(), val, true, _) |
|
||||
// call < [any non-negative number] (EOF is guaranteed to be negative)
|
||||
val >= 0
|
||||
)
|
||||
// call == [any positive number]
|
||||
val > 0
|
||||
)
|
||||
or
|
||||
exists(int val | gc.comparesLt(valueNumber(i).getAUse(), val, true, _) |
|
||||
// call < [any non-negative number] (EOF is guaranteed to be negative)
|
||||
val >= 0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 8.1
|
||||
* @precision high
|
||||
* @precision medium
|
||||
* @id cpp/integer-multiplication-cast-to-long
|
||||
* @tags reliability
|
||||
* security
|
||||
@@ -179,7 +179,6 @@ predicate overflows(MulExpr me, Type t) {
|
||||
|
||||
from MulExpr me, Type t1, Type t2
|
||||
where
|
||||
not any(Compilation c).buildModeNone() and
|
||||
t1 = me.getType().getUnderlyingType() and
|
||||
t2 = me.getConversion().getType().getUnderlyingType() and
|
||||
t1.getSize() < t2.getSize() and
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @security-severity 7.5
|
||||
* @precision high
|
||||
* @precision medium
|
||||
* @id cpp/wrong-type-format-argument
|
||||
* @tags reliability
|
||||
* correctness
|
||||
@@ -154,7 +154,6 @@ int sizeof_IntType() { exists(IntType it | result = it.getSize()) }
|
||||
|
||||
from FormattingFunctionCall ffc, int n, Expr arg, Type expected, Type actual
|
||||
where
|
||||
not any(Compilation c).buildModeNone() and
|
||||
(
|
||||
formattingFunctionCallExpectedType(ffc, n, expected) and
|
||||
formattingFunctionCallActualType(ffc, n, arg, actual) and
|
||||
|
||||
@@ -128,11 +128,18 @@ abstract class LeapYearFieldAccess extends YearFieldAccess {
|
||||
/**
|
||||
* Holds if the top-level binary operation includes an addition or subtraction operator with an operand specified by `valueToCheck`.
|
||||
*/
|
||||
predicate additionalAdditionOrSubstractionCheckForLeapYear(int valueToCheck) {
|
||||
predicate additionalAdditionOrSubtractionCheckForLeapYear(int valueToCheck) {
|
||||
additionalLogicalCheck(this, "+", valueToCheck) or
|
||||
additionalLogicalCheck(this, "-", valueToCheck)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `additionalAdditionOrSubtractionCheckForLeapYear` instead.
|
||||
*/
|
||||
deprecated predicate additionalAdditionOrSubstractionCheckForLeapYear(int valueToCheck) {
|
||||
this.additionalAdditionOrSubtractionCheckForLeapYear(valueToCheck)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this object is used on a modulus 4 operation, which would likely indicate the start of a leap year check.
|
||||
*/
|
||||
@@ -180,13 +187,13 @@ class StructTmLeapYearFieldAccess extends LeapYearFieldAccess {
|
||||
this.additionalModulusCheckForLeapYear(100) and
|
||||
// tm_year represents years since 1900
|
||||
(
|
||||
this.additionalAdditionOrSubstractionCheckForLeapYear(1900)
|
||||
this.additionalAdditionOrSubtractionCheckForLeapYear(1900)
|
||||
or
|
||||
// some systems may use 2000 for 2-digit year conversions
|
||||
this.additionalAdditionOrSubstractionCheckForLeapYear(2000)
|
||||
this.additionalAdditionOrSubtractionCheckForLeapYear(2000)
|
||||
or
|
||||
// converting from/to Unix epoch
|
||||
this.additionalAdditionOrSubstractionCheckForLeapYear(1970)
|
||||
this.additionalAdditionOrSubtractionCheckForLeapYear(1970)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import cpp
|
||||
import semmle.code.cpp.security.boostorg.asio.protocols
|
||||
|
||||
predicate isSourceImpl(DataFlow::Node source, ConstructorCall cc) {
|
||||
exists(BoostorgAsio::SslContextClass c | c.getAContructorCall() = cc and cc = source.asExpr())
|
||||
exists(BoostorgAsio::SslContextClass c | c.getAConstructorCall() = cc and cc = source.asExpr())
|
||||
}
|
||||
|
||||
predicate isSinkImpl(DataFlow::Node sink, FunctionCall fcSetOptions) {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* may lead to unpredictable behavior.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision high
|
||||
* @precision medium
|
||||
* @id cpp/implicit-function-declaration
|
||||
* @tags correctness
|
||||
* maintainability
|
||||
@@ -38,7 +38,6 @@ predicate isCompiledAsC(File f) {
|
||||
|
||||
from FunctionDeclarationEntry fdeIm, FunctionCall fc
|
||||
where
|
||||
not any(Compilation c).buildModeNone() and
|
||||
isCompiledAsC(fdeIm.getFile()) and
|
||||
not isFromMacroDefinition(fc) and
|
||||
fdeIm.isImplicit() and
|
||||
|
||||
@@ -20,12 +20,14 @@ class RangeFunction extends Function {
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
||||
super.getLocation().hasLocationInfo(path, sl, sc, _, _) and
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _) and
|
||||
(
|
||||
this.getBlock().getLocation().hasLocationInfo(path, _, _, el, ec)
|
||||
this.getBlock().getLocation().hasLocationInfo(filepath, _, _, endline, endcolumn)
|
||||
or
|
||||
not exists(this.getBlock()) and el = sl + 1 and ec = 1
|
||||
not exists(this.getBlock()) and endline = startline + 1 and endcolumn = 1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ predicate lessThanOrEqual(IRGuardCondition g, Expr e, boolean branch) {
|
||||
g.comparesEq(left, _, _, true, branch)
|
||||
|
|
||||
interestingLessThanOrEqual(left) and
|
||||
left.getDef().getUnconvertedResultExpression() = e
|
||||
left.getDef().getConvertedResultExpression() = e
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 7.8
|
||||
* @precision high
|
||||
* @precision medium
|
||||
* @tags reliability
|
||||
* security
|
||||
* external/cwe/cwe-190
|
||||
@@ -51,7 +51,6 @@ int getComparisonSizeAdjustment(Expr e) {
|
||||
|
||||
from Loop l, RelationalOperation rel, VariableAccess small, Expr large
|
||||
where
|
||||
not any(Compilation c).buildModeNone() and
|
||||
small = rel.getLesserOperand() and
|
||||
large = rel.getGreaterOperand() and
|
||||
rel = l.getCondition().getAChild*() and
|
||||
|
||||
@@ -25,10 +25,10 @@ import semmle.code.cpp.controlflow.IRGuards as IRGuards
|
||||
predicate outOfBoundsExpr(Expr expr, string kind) {
|
||||
if convertedExprMightOverflowPositively(expr)
|
||||
then kind = "overflow"
|
||||
else
|
||||
if convertedExprMightOverflowNegatively(expr)
|
||||
then kind = "overflow negatively"
|
||||
else none()
|
||||
else (
|
||||
convertedExprMightOverflowNegatively(expr) and
|
||||
kind = "overflow negatively"
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSource(FS::FlowSource source, string sourceType) { sourceType = source.getSourceType() }
|
||||
|
||||
@@ -55,30 +55,9 @@ predicate resultIsChecked(SslGetPeerCertificateCall getCertCall, ControlFlowNode
|
||||
predicate certIsZero(
|
||||
SslGetPeerCertificateCall getCertCall, ControlFlowNode node1, ControlFlowNode node2
|
||||
) {
|
||||
exists(Expr cert | cert = globalValueNumber(getCertCall).getAnExpr() |
|
||||
exists(GuardCondition guard, Expr zero |
|
||||
zero.getValue().toInt() = 0 and
|
||||
node1 = guard and
|
||||
(
|
||||
// if (cert == zero) {
|
||||
guard.comparesEq(cert, zero, 0, true, true) and
|
||||
node2 = guard.getATrueSuccessor()
|
||||
or
|
||||
// if (cert != zero) { }
|
||||
guard.comparesEq(cert, zero, 0, false, true) and
|
||||
node2 = guard.getAFalseSuccessor()
|
||||
)
|
||||
)
|
||||
or
|
||||
(
|
||||
// if (cert) { }
|
||||
node1 = cert
|
||||
or
|
||||
// if (!cert) {
|
||||
node1.(NotExpr).getAChild() = cert
|
||||
) and
|
||||
node2 = node1.getASuccessor() and
|
||||
not cert.(GuardCondition).controls(node2, true) // cert may be false
|
||||
exists(Expr cert |
|
||||
cert = globalValueNumber(getCertCall).getAnExpr() and
|
||||
node1.(GuardCondition).ensuresEqEdge(cert, 0, _, node2.getBasicBlock(), true)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -31,27 +31,28 @@ private predicate hasConditionalInitialization(
|
||||
class ConditionallyInitializedVariable extends LocalVariable {
|
||||
ConditionalInitializationCall call;
|
||||
ConditionalInitializationFunction f;
|
||||
VariableAccess initAccess;
|
||||
Evidence e;
|
||||
|
||||
ConditionallyInitializedVariable() {
|
||||
// Find a call that conditionally initializes this variable
|
||||
hasConditionalInitialization(f, call, this, initAccess, e) and
|
||||
// Ignore cases where the variable is assigned prior to the call
|
||||
not reaches(this.getAnAssignedValue(), initAccess) and
|
||||
// Ignore cases where the variable is assigned field-wise prior to the call.
|
||||
not exists(FieldAccess fa |
|
||||
exists(Assignment a |
|
||||
fa = getAFieldAccess(this) and
|
||||
a.getLValue() = fa
|
||||
exists(VariableAccess initAccess |
|
||||
hasConditionalInitialization(f, call, this, initAccess, e) and
|
||||
// Ignore cases where the variable is assigned prior to the call
|
||||
not reaches(this.getAnAssignedValue(), initAccess) and
|
||||
// Ignore cases where the variable is assigned field-wise prior to the call.
|
||||
not exists(FieldAccess fa |
|
||||
exists(Assignment a |
|
||||
fa = getAFieldAccess(this) and
|
||||
a.getLValue() = fa
|
||||
)
|
||||
|
|
||||
reaches(fa, initAccess)
|
||||
) and
|
||||
// Ignore cases where the variable is assigned by a prior call to an initialization function
|
||||
not exists(Call c |
|
||||
this.getAnAccess() = getAnInitializedArgument(c).(AddressOfExpr).getOperand() and
|
||||
reaches(c, initAccess)
|
||||
)
|
||||
|
|
||||
reaches(fa, initAccess)
|
||||
) and
|
||||
// Ignore cases where the variable is assigned by a prior call to an initialization function
|
||||
not exists(Call c |
|
||||
this.getAnAccess() = getAnInitializedArgument(c).(AddressOfExpr).getOperand() and
|
||||
reaches(c, initAccess)
|
||||
) and
|
||||
/*
|
||||
* Static local variables with constant initializers do not have the initializer expr as part of
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 8.8
|
||||
* @precision high
|
||||
* @precision medium
|
||||
* @id cpp/suspicious-add-sizeof
|
||||
* @tags security
|
||||
* external/cwe/cwe-468
|
||||
@@ -24,7 +24,6 @@ private predicate isCharSzPtrExpr(Expr e) {
|
||||
|
||||
from Expr sizeofExpr, Expr e
|
||||
where
|
||||
not any(Compilation c).buildModeNone() and
|
||||
// If we see an addWithSizeof then we expect the type of
|
||||
// the pointer expression to be `char*` or `void*`. Otherwise it
|
||||
// is probably a mistake.
|
||||
|
||||
@@ -41,7 +41,7 @@ predicate deleteMayThrow(DeleteOrDeleteArrayExpr deleteExpr) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the function may throw an exception when called. That is, if the body of the function looks
|
||||
* Holds if the function `f` may throw an exception when called. That is, if the body of the function looks
|
||||
* like it might throw an exception, and the function does not have a `noexcept` or `throw()` specifier.
|
||||
*/
|
||||
predicate functionMayThrow(Function f) {
|
||||
|
||||
11
cpp/ql/src/change-notes/released/1.5.0.md
Normal file
11
cpp/ql/src/change-notes/released/1.5.0.md
Normal file
@@ -0,0 +1,11 @@
|
||||
## 1.5.0
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* The queries `cpp/wrong-type-format-argument`, `cpp/comparison-with-wider-type`, `cpp/integer-multiplication-cast-to-long`, `cpp/implicit-function-declaration` and `cpp/suspicious-add-sizeof` have had their precisions reduced from `high` to `medium`. They will also now give alerts for projects built with `build-mode: none`.
|
||||
* The queries `cpp/wrong-type-format-argument`, `cpp/comparison-with-wider-type`, `cpp/integer-multiplication-cast-to-long` and `cpp/suspicious-add-sizeof` are no longer included in the `code-scanning` suite.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* The predicate `occurenceCount` in the file module `MagicConstants` has been deprecated. Use `occurrenceCount` instead.
|
||||
* The predicate `additionalAdditionOrSubstractionCheckForLeapYear` in the file module `LeapYear` has been deprecated. Use `additionalAdditionOrSubtractionCheckForLeapYear` instead.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.4.7
|
||||
lastReleaseVersion: 1.5.0
|
||||
|
||||
@@ -13,6 +13,6 @@ where
|
||||
def = definitionOf(e, kind) and
|
||||
// We need to exclude definitions for elements inside template instantiations,
|
||||
// as these often lead to multiple links to definitions from the same source location.
|
||||
// LGTM does not support this behaviour.
|
||||
// LGTM does not support this behavior.
|
||||
not e.isFromTemplateInstantiation(_)
|
||||
select e, def, kind
|
||||
|
||||
@@ -47,7 +47,7 @@ where
|
||||
// for a function parameter
|
||||
unchecked.getTarget() = param and
|
||||
// this function parameter is not overwritten
|
||||
count(param.getAnAssignment()) = 0 and
|
||||
not exists(param.getAnAssignment()) and
|
||||
check.getTarget() = param and
|
||||
// which is once checked
|
||||
candidateResultChecked(check, eqop) and
|
||||
|
||||
@@ -19,16 +19,17 @@ import cpp
|
||||
* Errors when using a variable declaration inside a loop.
|
||||
*/
|
||||
class DangerousWhileLoop extends WhileStmt {
|
||||
Expr exp;
|
||||
Declaration dl;
|
||||
|
||||
DangerousWhileLoop() {
|
||||
this = dl.getParentScope().(BlockStmt).getParent*() and
|
||||
exp = this.getCondition().getAChild*() and
|
||||
not exp instanceof PointerFieldAccess and
|
||||
not exp instanceof ValueFieldAccess and
|
||||
exp.(VariableAccess).getTarget().getName() = dl.getName() and
|
||||
not exp.getParent*() instanceof FunctionCall
|
||||
exists(Expr exp |
|
||||
exp = this.getCondition().getAChild*() and
|
||||
not exp instanceof PointerFieldAccess and
|
||||
not exp instanceof ValueFieldAccess and
|
||||
exp.(VariableAccess).getTarget().getName() = dl.getName() and
|
||||
not exp.getParent*() instanceof FunctionCall
|
||||
)
|
||||
}
|
||||
|
||||
Declaration getDeclaration() { result = dl }
|
||||
|
||||
@@ -46,7 +46,7 @@ predicate exprMayBeString(Expr exp) {
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if expression is constant or operator call `sizeof`. */
|
||||
/** Holds if expression `exp` is constant or operator call `sizeof`. */
|
||||
predicate argConstOrSizeof(Expr exp) {
|
||||
exp.getValue().toInt() > 1 or
|
||||
exp.(SizeofTypeOperator).getTypeOperand().getSize() > 1
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.commons.Exclusions
|
||||
|
||||
/** Holds if a `fc` function call is available before or after a `chdir` function call. */
|
||||
/** Holds if a `fcp` function call is available before or after a `chdir` function call. */
|
||||
predicate inExistsChdir(FunctionCall fcp) {
|
||||
exists(FunctionCall fctmp |
|
||||
(
|
||||
@@ -29,7 +29,7 @@ predicate inExistsChdir(FunctionCall fcp) {
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if a `fc` function call is available before or after a function call containing a `chdir` call. */
|
||||
/** Holds if a `fcp` function call is available before or after a function call containing a `chdir` call. */
|
||||
predicate outExistsChdir(FunctionCall fcp) {
|
||||
exists(FunctionCall fctmp |
|
||||
exists(FunctionCall fctmp2 |
|
||||
|
||||
@@ -266,7 +266,7 @@ class LifetimePointerType extends LifetimeIndirectionType {
|
||||
class FullExpr extends Expr {
|
||||
FullExpr() {
|
||||
// A full-expression is not a subexpression
|
||||
not exists(Expr p | this.getParent() = p)
|
||||
not this.getParent() instanceof Expr
|
||||
or
|
||||
// A sub-expression that is an unevaluated operand
|
||||
this.isUnevaluated()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user