mirror of
https://github.com/github/codeql.git
synced 2026-07-07 20:45:28 +02:00
Compare commits
462 Commits
codeql-cli
...
criemen/de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c870c5e3da | ||
|
|
9d1a1d41de | ||
|
|
4db2c68aee | ||
|
|
a8060e45fd | ||
|
|
de6ae4d92b | ||
|
|
0a90ba981e | ||
|
|
99547ee165 | ||
|
|
5c5084aca0 | ||
|
|
b343734083 | ||
|
|
5ddccd00e4 | ||
|
|
ef71cf5d26 | ||
|
|
196baa99b2 | ||
|
|
bdec751527 | ||
|
|
1d9767a163 | ||
|
|
50ec2549c0 | ||
|
|
bd08bc7923 | ||
|
|
b5bfd06624 | ||
|
|
079ab77a38 | ||
|
|
5b2eb88672 | ||
|
|
168f7f5d34 | ||
|
|
af6fc676ce | ||
|
|
15bc417a17 | ||
|
|
9ba8045837 | ||
|
|
24d98eef83 | ||
|
|
255f55cf1a | ||
|
|
1626af0ae1 | ||
|
|
248eb7f00c | ||
|
|
7d9a3e1399 | ||
|
|
508e8157b3 | ||
|
|
5e33d9a145 | ||
|
|
8169ccd21e | ||
|
|
cc1e33fb64 | ||
|
|
57875554f4 | ||
|
|
e5885f65db | ||
|
|
528641c55a | ||
|
|
134539060d | ||
|
|
25b592fc89 | ||
|
|
5115216c2d | ||
|
|
da5e9ac18c | ||
|
|
ade5686e52 | ||
|
|
96ea9507a4 | ||
|
|
9d8d7ab237 | ||
|
|
ae7afa7aff | ||
|
|
867c8a7fa6 | ||
|
|
ef1592fe32 | ||
|
|
493a68a232 | ||
|
|
22261c1480 | ||
|
|
d0f978d937 | ||
|
|
de612963de | ||
|
|
3402a729d0 | ||
|
|
e83f1d17bf | ||
|
|
8e4e663739 | ||
|
|
2f07f1c730 | ||
|
|
23ee7b955c | ||
|
|
1456ec2119 | ||
|
|
6290be2922 | ||
|
|
b0ea175021 | ||
|
|
8f681154ce | ||
|
|
c4256f21c7 | ||
|
|
5b57826915 | ||
|
|
9f340279cb | ||
|
|
2af60f1390 | ||
|
|
fc298b23c9 | ||
|
|
5f45402cf7 | ||
|
|
5650694313 | ||
|
|
e2eb08b543 | ||
|
|
22588c9f85 | ||
|
|
c013d4a59c | ||
|
|
4a291147e0 | ||
|
|
bb78c2a67e | ||
|
|
e91efaa92e | ||
|
|
156ddd3fae | ||
|
|
ac8b9739c5 | ||
|
|
ffd6b9864c | ||
|
|
659ce6f1ca | ||
|
|
b4bb24aa43 | ||
|
|
6ade2a8054 | ||
|
|
0ec40afa4c | ||
|
|
8cc349e85f | ||
|
|
b284a2a7c0 | ||
|
|
854d7660eb | ||
|
|
57c6e4d9cb | ||
|
|
f3bf347bd6 | ||
|
|
9fad5410c0 | ||
|
|
c66bd72620 | ||
|
|
575eb24073 | ||
|
|
d013c8940d | ||
|
|
756affa4aa | ||
|
|
2f14ec9f2a | ||
|
|
f6f54c6e3b | ||
|
|
665da3958a | ||
|
|
f1a350c96a | ||
|
|
d0f73acc25 | ||
|
|
5f353b72cd | ||
|
|
1398575b97 | ||
|
|
04c7319b6b | ||
|
|
7420d07935 | ||
|
|
e7da53d838 | ||
|
|
6d43eed1e6 | ||
|
|
3ef49f31aa | ||
|
|
f97a159163 | ||
|
|
88e5ce3cf8 | ||
|
|
ca27785ace | ||
|
|
db28f1b29e | ||
|
|
8372a2e562 | ||
|
|
58d2c71c20 | ||
|
|
f70f8a3536 | ||
|
|
1135bf6bcd | ||
|
|
3e877ffaac | ||
|
|
ae19b2fd89 | ||
|
|
faa168993c | ||
|
|
0c10f083cb | ||
|
|
796da126b8 | ||
|
|
0b3b95ab54 | ||
|
|
cad2b74137 | ||
|
|
6ede20cccc | ||
|
|
69f0e8bcf7 | ||
|
|
7986fc7036 | ||
|
|
396bf93ac0 | ||
|
|
8a895740ba | ||
|
|
513efe222d | ||
|
|
6f6b4a0bfe | ||
|
|
d295cac697 | ||
|
|
89f43fb917 | ||
|
|
6015524589 | ||
|
|
c364fd7e56 | ||
|
|
32e9881cfb | ||
|
|
30034b4254 | ||
|
|
b80b6aafdd | ||
|
|
4df9cd88ef | ||
|
|
0c9a2896d8 | ||
|
|
b18f8d3935 | ||
|
|
6322270926 | ||
|
|
3711a7e3e6 | ||
|
|
25b3d76f71 | ||
|
|
09c2f901f4 | ||
|
|
6a87eb0c73 | ||
|
|
acac3a06ad | ||
|
|
719cef8298 | ||
|
|
5ac9c2db74 | ||
|
|
0abc0d1a67 | ||
|
|
aa7215bbd5 | ||
|
|
dfeb35fe1a | ||
|
|
8352d17e2c | ||
|
|
f171eeb229 | ||
|
|
6bd46148e7 | ||
|
|
a66f31d844 | ||
|
|
6965cf7246 | ||
|
|
4de0fefe86 | ||
|
|
b087fdecfe | ||
|
|
918e435a48 | ||
|
|
04d1c82005 | ||
|
|
954235ecdd | ||
|
|
338e82064e | ||
|
|
201842d2f9 | ||
|
|
61a012fc6c | ||
|
|
c883aa09f8 | ||
|
|
79871aa51e | ||
|
|
4c21444dd5 | ||
|
|
ed39c465a6 | ||
|
|
5d4ceeebb5 | ||
|
|
f3d727fadc | ||
|
|
fa1c92dbe7 | ||
|
|
0ac4a10345 | ||
|
|
494b8bd7e1 | ||
|
|
073189ed6b | ||
|
|
7a6eabc8a3 | ||
|
|
6ffdf576d0 | ||
|
|
0b0e8a4bf5 | ||
|
|
58fd1a2241 | ||
|
|
ad630bc6ff | ||
|
|
4d251b96a6 | ||
|
|
bdb793ba92 | ||
|
|
3a098d7449 | ||
|
|
5d925d36d3 | ||
|
|
3d95369608 | ||
|
|
11016e193c | ||
|
|
41218fb89f | ||
|
|
5afd2d5bf0 | ||
|
|
a3a0c2b269 | ||
|
|
9952997b48 | ||
|
|
f3cbf86c43 | ||
|
|
723236d15b | ||
|
|
c90d0faaf6 | ||
|
|
837387aeae | ||
|
|
629a7a601d | ||
|
|
d401891d30 | ||
|
|
c79da8b2b5 | ||
|
|
ed9a6bd820 | ||
|
|
bf5ba33c2e | ||
|
|
365ccf4903 | ||
|
|
36a031833f | ||
|
|
ab99509a11 | ||
|
|
0f95a8d724 | ||
|
|
288e0ec565 | ||
|
|
c1a1edf24e | ||
|
|
74cba9056b | ||
|
|
d04a0f4b87 | ||
|
|
1511927a2b | ||
|
|
fd615fb7a3 | ||
|
|
442e58188b | ||
|
|
e1963a5fcd | ||
|
|
7a7ff4a91e | ||
|
|
5d14070cd4 | ||
|
|
22ed2f9ae3 | ||
|
|
9bb2a4bfce | ||
|
|
dcbb66d366 | ||
|
|
f1e22687ab | ||
|
|
1f1b1b7aab | ||
|
|
3c1a19c5ab | ||
|
|
92bca9c268 | ||
|
|
98f52589b0 | ||
|
|
fcf1b6d6f5 | ||
|
|
08d6d54961 | ||
|
|
70d530a49c | ||
|
|
a7dbe29448 | ||
|
|
7235ba8f91 | ||
|
|
3b1d917c2b | ||
|
|
cb1ca4c75c | ||
|
|
4ab925507d | ||
|
|
6bde26d9fd | ||
|
|
5d7a92cf13 | ||
|
|
40096ebb62 | ||
|
|
9e3f4cd183 | ||
|
|
483370d5f4 | ||
|
|
f084bb7bcf | ||
|
|
36937a0988 | ||
|
|
51d189d30d | ||
|
|
3d6965a550 | ||
|
|
b00c545799 | ||
|
|
d6618edf01 | ||
|
|
f7392d6498 | ||
|
|
6ca978e1cc | ||
|
|
823d5acd69 | ||
|
|
8bb21e1b49 | ||
|
|
a2cdb9c173 | ||
|
|
c3d9ea1820 | ||
|
|
afb5e4f841 | ||
|
|
f6f5f5d4b4 | ||
|
|
c9bd9e9303 | ||
|
|
61c3aa6288 | ||
|
|
328f322692 | ||
|
|
26ac84aa6e | ||
|
|
96dda8808c | ||
|
|
5a4cd1c578 | ||
|
|
ed266dac5f | ||
|
|
1ce0ba5083 | ||
|
|
9bfd461fad | ||
|
|
26f8e64a35 | ||
|
|
770774ed52 | ||
|
|
c15749f342 | ||
|
|
6196fd2cc1 | ||
|
|
c04315a7cf | ||
|
|
16feaf15e2 | ||
|
|
f1afa2bf59 | ||
|
|
927b402a3a | ||
|
|
d24bdbb4e4 | ||
|
|
6bb98b02a8 | ||
|
|
b8eb2ab100 | ||
|
|
6f5b949ec8 | ||
|
|
04a4fb2143 | ||
|
|
a4c1a622b7 | ||
|
|
50c2d108ca | ||
|
|
306b087b6e | ||
|
|
977767b0d6 | ||
|
|
201c4aad13 | ||
|
|
c064a9e092 | ||
|
|
db5e452178 | ||
|
|
c629867191 | ||
|
|
d0ca39fb03 | ||
|
|
b3b9406e45 | ||
|
|
953461d1aa | ||
|
|
bf0675e5ba | ||
|
|
2832318711 | ||
|
|
aa5e0c39ba | ||
|
|
a9cf33ce18 | ||
|
|
8542992b0d | ||
|
|
05f85497ed | ||
|
|
d4414dabff | ||
|
|
86cc2dc5a1 | ||
|
|
1ea94faccf | ||
|
|
4c7ec59306 | ||
|
|
321eb34eff | ||
|
|
2e772a80c4 | ||
|
|
64720adccb | ||
|
|
7600c243de | ||
|
|
369241e1ea | ||
|
|
ccaf2dd9ea | ||
|
|
88b3d1ffd7 | ||
|
|
cd04500dd9 | ||
|
|
3c777b7605 | ||
|
|
32dbdb3913 | ||
|
|
da84889242 | ||
|
|
9902874ddd | ||
|
|
0304aa846c | ||
|
|
777279dc29 | ||
|
|
821398715c | ||
|
|
768d866e72 | ||
|
|
0462809edc | ||
|
|
5c68bad2f1 | ||
|
|
91f1cf10a7 | ||
|
|
97c2387904 | ||
|
|
56d0affe38 | ||
|
|
6d486f9931 | ||
|
|
9e808c17af | ||
|
|
0dc036abd1 | ||
|
|
98d587c482 | ||
|
|
88abc8f72f | ||
|
|
a4c06b2bbc | ||
|
|
12fbd18f3a | ||
|
|
ad7c96554f | ||
|
|
f30a642c8f | ||
|
|
ba9c2f1e3a | ||
|
|
f7db47b771 | ||
|
|
0b6ec4624e | ||
|
|
d6848f5c5d | ||
|
|
01abcf8537 | ||
|
|
8c87b66bea | ||
|
|
05d2e16de3 | ||
|
|
6da3972433 | ||
|
|
1266f9757d | ||
|
|
000dedf3e8 | ||
|
|
d6415cd0c8 | ||
|
|
51623c3837 | ||
|
|
104d448b16 | ||
|
|
3a1f6efce4 | ||
|
|
8243f87179 | ||
|
|
fb9ec2423c | ||
|
|
3fa52ad680 | ||
|
|
9c7216fe4f | ||
|
|
69e0ad0181 | ||
|
|
8b536f54fd | ||
|
|
d3695dce4d | ||
|
|
2458d16426 | ||
|
|
f8335e6163 | ||
|
|
91b7a6cbd8 | ||
|
|
1f932d407f | ||
|
|
26b49dd0df | ||
|
|
d80a1487be | ||
|
|
e18389718c | ||
|
|
8f0b7f0969 | ||
|
|
c4eafb2cf3 | ||
|
|
8b66dc16ad | ||
|
|
e8cb3490e6 | ||
|
|
85957767c9 | ||
|
|
071076875c | ||
|
|
26c69b8f8a | ||
|
|
bbd0aa929f | ||
|
|
17770af491 | ||
|
|
a507854288 | ||
|
|
8c1fd8fa7a | ||
|
|
f3e3734424 | ||
|
|
5444a5bf8a | ||
|
|
3a54c10f36 | ||
|
|
5fb61b0304 | ||
|
|
6af5afc184 | ||
|
|
cd1f10cdea | ||
|
|
74826032ef | ||
|
|
6ef2aed3aa | ||
|
|
9a82ea48f2 | ||
|
|
315890680c | ||
|
|
a9b3c0d91b | ||
|
|
38b1eb7c71 | ||
|
|
323b7cb96f | ||
|
|
901f756c69 | ||
|
|
01c9509741 | ||
|
|
6081ba5902 | ||
|
|
f39dc41903 | ||
|
|
91e26d0f44 | ||
|
|
a172063e6a | ||
|
|
05910de8d1 | ||
|
|
cef8744a37 | ||
|
|
7816f34d75 | ||
|
|
64890a1a6b | ||
|
|
2b6aab108d | ||
|
|
fe00c8819d | ||
|
|
cb0b388345 | ||
|
|
4712ae1cfc | ||
|
|
59a77d70c0 | ||
|
|
4b5aa1497b | ||
|
|
2eac11edd6 | ||
|
|
d689db23d8 | ||
|
|
62509a10c2 | ||
|
|
60abea17e6 | ||
|
|
66d156d386 | ||
|
|
e0a3c8a1c4 | ||
|
|
b0efffd8f0 | ||
|
|
bd68986fa4 | ||
|
|
a282efc43e | ||
|
|
1d6626c821 | ||
|
|
2427227b84 | ||
|
|
9357762e06 | ||
|
|
204e4c5bb0 | ||
|
|
e97878ed63 | ||
|
|
be389b4c19 | ||
|
|
c9d6c80913 | ||
|
|
684aedf6aa | ||
|
|
c496503053 | ||
|
|
eeddb176f8 | ||
|
|
162519185d | ||
|
|
9e9469f3ca | ||
|
|
318e75c094 | ||
|
|
c91f7f4918 | ||
|
|
31324fc778 | ||
|
|
51e787b316 | ||
|
|
c4737c7fbb | ||
|
|
338ab96593 | ||
|
|
5c4b4d644a | ||
|
|
dacc0ab8fe | ||
|
|
438e664116 | ||
|
|
a8f55d93cb | ||
|
|
0459d136d3 | ||
|
|
a22ea6c1c8 | ||
|
|
7392d186bc | ||
|
|
fb07a56de6 | ||
|
|
ec0bd4494c | ||
|
|
ded39749a7 | ||
|
|
f9f46f0f98 | ||
|
|
3ef05a628f | ||
|
|
310819d392 | ||
|
|
d4ea62edec | ||
|
|
e73d1c7b76 | ||
|
|
b73fe0ba0a | ||
|
|
92c8d39ba3 | ||
|
|
cc24f1ed9f | ||
|
|
26e58532ee | ||
|
|
7c6239b077 | ||
|
|
72530a8312 | ||
|
|
294092b671 | ||
|
|
caca4950e6 | ||
|
|
f8ce11b3a7 | ||
|
|
7da2845cad | ||
|
|
fc2dc28f87 | ||
|
|
112e7c95fa | ||
|
|
e7f9b5bbbc | ||
|
|
f95926e1a8 | ||
|
|
3e0d30f13a | ||
|
|
58b9355c69 | ||
|
|
1eaa998648 | ||
|
|
e7e0c6bf12 | ||
|
|
35378aa714 | ||
|
|
3434c38da7 | ||
|
|
e30f725e71 | ||
|
|
e40ae2e52d | ||
|
|
77a00873a9 | ||
|
|
5ddfe75a0d | ||
|
|
59f953269a | ||
|
|
bbc3ff2dfe | ||
|
|
a3076f4f72 | ||
|
|
b261145f43 | ||
|
|
571be8be3e | ||
|
|
eb32cbe8a5 | ||
|
|
bdc48088e6 | ||
|
|
bc551174f9 | ||
|
|
501cda4e8c | ||
|
|
2118f233b9 | ||
|
|
b80a711b27 | ||
|
|
1e97600c4a | ||
|
|
d410136852 | ||
|
|
c004ffaca8 | ||
|
|
281ac05868 | ||
|
|
df406b4fca |
1
.bazelrc
1
.bazelrc
@@ -25,5 +25,6 @@ common --registry=https://bcr.bazel.build
|
||||
|
||||
common --@rules_dotnet//dotnet/settings:strict_deps=false
|
||||
common --experimental_isolated_extension_usages
|
||||
common --incompatible_use_plus_in_repo_names
|
||||
|
||||
try-import %workspace%/local.bazelrc
|
||||
|
||||
37
.github/workflows/go-tests-other-os.yml
vendored
37
.github/workflows/go-tests-other-os.yml
vendored
@@ -10,26 +10,35 @@ on:
|
||||
- MODULE.bazel
|
||||
- .bazelrc
|
||||
- misc/bazel/**
|
||||
|
||||
push:
|
||||
branches:
|
||||
- criemen/debug
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
test-mac:
|
||||
name: Test MacOS
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
- name: Run tests
|
||||
uses: ./go/actions/test
|
||||
|
||||
test-win:
|
||||
if: github.repository_owner == 'github'
|
||||
name: Test Windows
|
||||
runs-on: windows-latest-xl
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
- name: Run tests
|
||||
uses: ./go/actions/test
|
||||
with:
|
||||
sparse-checkout: go
|
||||
|
||||
- name: dump env bash
|
||||
shell: bash
|
||||
run: |
|
||||
set -x
|
||||
cd go
|
||||
type -a bazel
|
||||
where bazel
|
||||
echo $PATH
|
||||
bazel version
|
||||
- name: Test
|
||||
shell: bash
|
||||
run: |
|
||||
cd go
|
||||
make gen
|
||||
# - name: Run tests
|
||||
# uses: ./go/actions/test
|
||||
|
||||
22
Cargo.lock
generated
22
Cargo.lock
generated
@@ -112,6 +112,16 @@ version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||
|
||||
[[package]]
|
||||
name = "ast-generator"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"itertools 0.10.5",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"ungrammar",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic"
|
||||
version = "0.6.0"
|
||||
@@ -380,11 +390,13 @@ dependencies = [
|
||||
"ra_ap_base_db",
|
||||
"ra_ap_hir",
|
||||
"ra_ap_hir_def",
|
||||
"ra_ap_hir_expand",
|
||||
"ra_ap_ide_db",
|
||||
"ra_ap_load-cargo",
|
||||
"ra_ap_parser",
|
||||
"ra_ap_paths",
|
||||
"ra_ap_project_model",
|
||||
"ra_ap_span",
|
||||
"ra_ap_syntax",
|
||||
"ra_ap_vfs",
|
||||
"rust-extractor-macros",
|
||||
@@ -681,16 +693,6 @@ version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a"
|
||||
|
||||
[[package]]
|
||||
name = "generate-schema"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"itertools 0.10.5",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"ungrammar",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.15"
|
||||
|
||||
@@ -7,7 +7,7 @@ members = [
|
||||
"ruby/extractor",
|
||||
"rust/extractor",
|
||||
"rust/extractor/macros",
|
||||
"rust/generate-schema",
|
||||
"rust/ast-generator",
|
||||
]
|
||||
|
||||
[patch.crates-io]
|
||||
|
||||
@@ -23,11 +23,11 @@ bazel_dep(name = "bazel_skylib", version = "1.6.1")
|
||||
bazel_dep(name = "abseil-cpp", version = "20240116.0", repo_name = "absl")
|
||||
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 = "1.9.4-codeql.1")
|
||||
bazel_dep(name = "rules_kotlin", version = "2.0.0-codeql.1")
|
||||
bazel_dep(name = "gazelle", version = "0.38.0")
|
||||
bazel_dep(name = "rules_dotnet", version = "0.15.1")
|
||||
bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
|
||||
bazel_dep(name = "rules_rust", version = "0.50.0")
|
||||
bazel_dep(name = "rules_rust", version = "0.52.2")
|
||||
|
||||
bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True)
|
||||
|
||||
@@ -61,7 +61,7 @@ r.from_cargo(
|
||||
"//ruby/extractor:Cargo.toml",
|
||||
"//rust/extractor:Cargo.toml",
|
||||
"//rust/extractor/macros:Cargo.toml",
|
||||
"//rust/generate-schema:Cargo.toml",
|
||||
"//rust/ast-generator:Cargo.toml",
|
||||
"//shared/tree-sitter-extractor:Cargo.toml",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
class Expr extends @expr {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Location extends @location_expr {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
predicate isExprRequires(Expr expr) { exists(int kind | exprs(expr, kind, _) | kind = 390) }
|
||||
|
||||
from Expr expr, int kind, int kind_new, Location location
|
||||
where
|
||||
exprs(expr, kind, location) and
|
||||
if isExprRequires(expr) then kind_new = 1 else kind_new = kind
|
||||
select expr, kind_new, location
|
||||
2316
cpp/downgrades/6f5d51e89e762fe4609fd4ac8ee3afb04221e873/old.dbscheme
Normal file
2316
cpp/downgrades/6f5d51e89e762fe4609fd4ac8ee3afb04221e873/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
description: Add requires expr
|
||||
compatibility: partial
|
||||
exprs.rel: run exprs.qlo
|
||||
@@ -0,0 +1,17 @@
|
||||
class Expr extends @expr {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Location extends @location_expr {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
predicate isExprRequirement(Expr expr) {
|
||||
exists(int kind | exprs(expr, kind, _) | kind = [391, 392, 393])
|
||||
}
|
||||
|
||||
from Expr expr, int kind, int kind_new, Location location
|
||||
where
|
||||
exprs(expr, kind, location) and
|
||||
if isExprRequirement(expr) then kind_new = 1 else kind_new = kind
|
||||
select expr, kind_new, location
|
||||
2323
cpp/downgrades/e51fad7a2436caefab0c6bd52f05e28e7cce4d92/old.dbscheme
Normal file
2323
cpp/downgrades/e51fad7a2436caefab0c6bd52f05e28e7cce4d92/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,17 @@
|
||||
class Parameter extends @parameter {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class ParameterizedElement extends @parameterized_element {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Type extends @type {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from Parameter param, ParameterizedElement pe, int index, Type type
|
||||
where
|
||||
params(param, pe, index, type) and
|
||||
not pe instanceof @requires_expr
|
||||
select param, pe, index, type
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
description: Support C++20 requires expressions
|
||||
compatibility: partial
|
||||
compound_requirement_is_noexcept.rel: delete
|
||||
exprs.rel: run exprs.qlo
|
||||
params.rel: run params.qlo
|
||||
@@ -1,3 +1,10 @@
|
||||
## 2.0.2
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Added taint flow model for `fopen` and related functions.
|
||||
* The `SimpleRangeAnalysis` library (`semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis`) now generates more precise ranges for calls to `fgetc` and `getc`.
|
||||
|
||||
## 2.0.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Added classes `RequiresExpr`, `SimpleRequirementExpr`, `TypeRequirementExpr`, `CompoundRequirementExpr`, and `NestedRequirementExpr` to represent C++20 requires expressions and the simple, type, compound, and nested requirements that can occur in `requires` expressions.
|
||||
6
cpp/ql/lib/change-notes/released/2.0.2.md
Normal file
6
cpp/ql/lib/change-notes/released/2.0.2.md
Normal file
@@ -0,0 +1,6 @@
|
||||
## 2.0.2
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Added taint flow model for `fopen` and related functions.
|
||||
* The `SimpleRangeAnalysis` library (`semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis`) now generates more precise ranges for calls to `fgetc` and `getc`.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 2.0.1
|
||||
lastReleaseVersion: 2.0.2
|
||||
|
||||
@@ -17,6 +17,7 @@ import semmle.code.cpp.File
|
||||
import semmle.code.cpp.Linkage
|
||||
import semmle.code.cpp.Location
|
||||
import semmle.code.cpp.Compilation
|
||||
import semmle.code.cpp.Concept
|
||||
import semmle.code.cpp.Element
|
||||
import semmle.code.cpp.Namespace
|
||||
import semmle.code.cpp.Specifier
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 2.0.1
|
||||
version: 2.0.3-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
161
cpp/ql/lib/semmle/code/cpp/Concept.qll
Normal file
161
cpp/ql/lib/semmle/code/cpp/Concept.qll
Normal file
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
* Provides classes for working with C++ concepts.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.exprs.Expr
|
||||
|
||||
/**
|
||||
* A C++ requires expression.
|
||||
*
|
||||
* For example, with `T` and `U` template parameters:
|
||||
* ```cpp
|
||||
* requires (T x, U y) { x + y; };
|
||||
* ```
|
||||
*/
|
||||
class RequiresExpr extends Expr, @requires_expr {
|
||||
override string toString() {
|
||||
if exists(this.getAParameter())
|
||||
then result = "requires(...) { ... }"
|
||||
else result = "requires { ... }"
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "RequiresExpr" }
|
||||
|
||||
/**
|
||||
* Gets a requirement in this requires expression.
|
||||
*/
|
||||
RequirementExpr getARequirement() { result = this.getAChild() }
|
||||
|
||||
/**
|
||||
* Gets the nth requirement in this requires expression.
|
||||
*/
|
||||
RequirementExpr getRequirement(int n) { result = this.getChild(n) }
|
||||
|
||||
/**
|
||||
* Gets the number of requirements in this requires expression.
|
||||
*/
|
||||
int getNumberOfRequirements() { result = count(this.getARequirement()) }
|
||||
|
||||
/**
|
||||
* Gets a parameter of this requires expression, if any.
|
||||
*/
|
||||
Parameter getAParameter() { result.getRequiresExpr() = underlyingElement(this) }
|
||||
|
||||
/**
|
||||
* Gets the the nth parameter of this requires expression.
|
||||
*/
|
||||
Parameter getParameter(int n) {
|
||||
result.getRequiresExpr() = underlyingElement(this) and result.getIndex() = n
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of parameters of this requires expression.
|
||||
*/
|
||||
int getNumberOfParameters() { result = count(this.getAParameter()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ requirement in a requires expression.
|
||||
*/
|
||||
class RequirementExpr extends Expr { }
|
||||
|
||||
/**
|
||||
* A C++ simple requirement in a requires expression.
|
||||
*
|
||||
* For example, if:
|
||||
* ```cpp
|
||||
* requires(T x, U y) { x + y; };
|
||||
* ```
|
||||
* with `T` and `U` template parameters, then `x + y;` is a simple requirement.
|
||||
*/
|
||||
class SimpleRequirementExpr extends RequirementExpr {
|
||||
SimpleRequirementExpr() {
|
||||
this.getParent() instanceof RequiresExpr and
|
||||
not this instanceof TypeRequirementExpr and
|
||||
not this instanceof CompoundRequirementExpr and
|
||||
not this instanceof NestedRequirementExpr
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "SimpleRequirementExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ type requirement in a requires expression.
|
||||
*
|
||||
* For example, if:
|
||||
* ```cpp
|
||||
* requires { typename T::a_field; };
|
||||
* ```
|
||||
* with `T` a template parameter, then `typename T::a_field;` is a type requirement.
|
||||
*/
|
||||
class TypeRequirementExpr extends RequirementExpr, TypeName {
|
||||
TypeRequirementExpr() { this.getParent() instanceof RequiresExpr }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "TypeRequirementExpr" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ compound requirement in a requires expression.
|
||||
*
|
||||
* For example, if:
|
||||
* ```cpp
|
||||
* requires(T x) { { x } noexcept -> std::same_as<int>; };
|
||||
* ```
|
||||
* with `T` a template parameter, then `{ x } noexcept -> std::same_as<int>;` is
|
||||
* a compound requirement.
|
||||
*/
|
||||
class CompoundRequirementExpr extends RequirementExpr, @compound_requirement {
|
||||
override string toString() {
|
||||
if exists(this.getReturnTypeRequirement())
|
||||
then result = "{ ... } -> ..."
|
||||
else result = "{ ... }"
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "CompoundRequirementExpr" }
|
||||
|
||||
/**
|
||||
* Gets the expression from the compound requirement.
|
||||
*/
|
||||
Expr getExpr() { result = this.getChild(0) }
|
||||
|
||||
/**
|
||||
* Gets the return type requirement from the compound requirement, if any.
|
||||
*/
|
||||
Expr getReturnTypeRequirement() { result = this.getChild(1) }
|
||||
|
||||
/**
|
||||
* Holds if the expression from the compound requirement must not be
|
||||
* potentially throwing.
|
||||
*/
|
||||
predicate isNoExcept() { compound_requirement_is_noexcept(underlyingElement(this)) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ nested requirement in a requires expression.
|
||||
*
|
||||
* For example, if:
|
||||
* ```cpp
|
||||
* requires { requires std::is_same<T, int>::value; };
|
||||
* ```
|
||||
* with `T` a template parameter, then `requires std::is_same<T, int>::value;` is
|
||||
* a nested requirement.
|
||||
*/
|
||||
class NestedRequirementExpr extends Expr, @nested_requirement {
|
||||
override string toString() { result = "requires ..." }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "NestedRequirementExpr" }
|
||||
|
||||
/**
|
||||
* Gets the constraint from the nested requirement.
|
||||
*/
|
||||
Expr getConstraint() { result = this.getChild(0) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ concept id expression.
|
||||
*/
|
||||
class ConceptIdExpr extends RequirementExpr, @concept_id {
|
||||
override string toString() { result = "concept<...>" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ConceptIdExpr" }
|
||||
}
|
||||
@@ -500,6 +500,17 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
|
||||
* Gets the nearest enclosing AccessHolder.
|
||||
*/
|
||||
override AccessHolder getEnclosingAccessHolder() { result = this.getDeclaringType() }
|
||||
|
||||
/**
|
||||
* Holds if this function has extraction errors that create an `ErrorExpr`.
|
||||
*/
|
||||
predicate hasErrors() {
|
||||
exists(ErrorExpr e |
|
||||
e.getEnclosingFunction() = this and
|
||||
// Exclude the first allocator call argument because it is always extracted as `ErrorExpr`.
|
||||
not exists(NewOrNewArrayExpr new | e = new.getAllocatorCall().getArgument(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
|
||||
@@ -7,8 +7,8 @@ import semmle.code.cpp.Declaration
|
||||
private import semmle.code.cpp.internal.ResolveClass
|
||||
|
||||
/**
|
||||
* A C/C++ function parameter or catch block parameter. For example the
|
||||
* function parameter `p` and the catch block parameter `e` in the following
|
||||
* A C/C++ function parameter, catch block parameter, or requires expression parameter.
|
||||
* For example the function parameter `p` and the catch block parameter `e` in the following
|
||||
* code:
|
||||
* ```
|
||||
* void myFunction(int p) {
|
||||
@@ -20,8 +20,8 @@ private import semmle.code.cpp.internal.ResolveClass
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* For catch block parameters, there is a one-to-one correspondence between
|
||||
* the `Parameter` and its `ParameterDeclarationEntry`.
|
||||
* For catch block parameters and expression , there is a one-to-one
|
||||
* correspondence between the `Parameter` and its `VariableDeclarationEntry`.
|
||||
*
|
||||
* For function parameters, there is a one-to-many relationship between
|
||||
* `Parameter` and `ParameterDeclarationEntry`, because one function can
|
||||
@@ -118,6 +118,12 @@ class Parameter extends LocalScopeVariable, @parameter {
|
||||
*/
|
||||
BlockStmt getCatchBlock() { params(underlyingElement(this), unresolveElement(result), _, _) }
|
||||
|
||||
/**
|
||||
* Gets the requires expression to which the parameter belongs, if it is a
|
||||
* requires expression parameter.
|
||||
*/
|
||||
RequiresExpr getRequiresExpr() { params(underlyingElement(this), unresolveElement(result), _, _) }
|
||||
|
||||
/**
|
||||
* Gets the zero-based index of this parameter.
|
||||
*
|
||||
|
||||
@@ -80,6 +80,10 @@ private Declaration getAnEnclosingDeclaration(Locatable ast) {
|
||||
or
|
||||
result = ast.(Parameter).getFunction()
|
||||
or
|
||||
result = ast.(Parameter).getCatchBlock().getEnclosingFunction()
|
||||
or
|
||||
result = ast.(Parameter).getRequiresExpr().getEnclosingFunction()
|
||||
or
|
||||
result = ast.(Expr).getEnclosingDeclaration()
|
||||
or
|
||||
result = ast.(Initializer).getDeclaration()
|
||||
@@ -99,7 +103,10 @@ private newtype TPrintAstNode =
|
||||
stmt.getADeclarationEntry() = entry and
|
||||
shouldPrintDeclaration(stmt.getEnclosingFunction())
|
||||
} or
|
||||
TParametersNode(Function func) { shouldPrintDeclaration(func) } or
|
||||
TFunctionParametersNode(Function func) { shouldPrintDeclaration(func) } or
|
||||
TRequiresExprParametersNode(RequiresExpr req) {
|
||||
shouldPrintDeclaration(getAnEnclosingDeclaration(req))
|
||||
} or
|
||||
TConstructorInitializersNode(Constructor ctor) {
|
||||
ctor.hasEntryPoint() and
|
||||
shouldPrintDeclaration(ctor)
|
||||
@@ -303,14 +310,14 @@ class ExprNode extends AstNode {
|
||||
|
||||
ExprNode() { expr = ast }
|
||||
|
||||
override AstNode getChildInternal(int childIndex) {
|
||||
result.getAst() = expr.getChild(childIndex)
|
||||
override PrintAstNode getChildInternal(int childIndex) {
|
||||
result.(AstNode).getAst() = expr.getChild(childIndex)
|
||||
or
|
||||
childIndex = max(int index | exists(expr.getChild(index)) or index = 0) + 1 and
|
||||
result.getAst() = expr.(ConditionDeclExpr).getInitializingExpr()
|
||||
result.(AstNode).getAst() = expr.(ConditionDeclExpr).getInitializingExpr()
|
||||
or
|
||||
exists(int destructorIndex |
|
||||
result.getAst() = expr.getImplicitDestructorCall(destructorIndex) and
|
||||
result.(AstNode).getAst() = expr.getImplicitDestructorCall(destructorIndex) and
|
||||
childIndex = destructorIndex + max(int index | exists(expr.getChild(index)) or index = 0) + 2
|
||||
)
|
||||
}
|
||||
@@ -329,7 +336,8 @@ class ExprNode extends AstNode {
|
||||
}
|
||||
|
||||
override string getChildAccessorPredicateInternal(int childIndex) {
|
||||
result = getChildAccessorWithoutConversions(ast, this.getChildInternal(childIndex).getAst())
|
||||
result =
|
||||
getChildAccessorWithoutConversions(ast, this.getChildInternal(childIndex).(AstNode).getAst())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -409,6 +417,26 @@ class StmtExprNode extends ExprNode {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing a `RequiresExpr`
|
||||
*/
|
||||
class RequiresExprNode extends ExprNode {
|
||||
override RequiresExpr expr;
|
||||
|
||||
override PrintAstNode getChildInternal(int childIndex) {
|
||||
result = super.getChildInternal(childIndex)
|
||||
or
|
||||
childIndex = -1 and
|
||||
result.(RequiresExprParametersNode).getRequiresExpr() = expr
|
||||
}
|
||||
|
||||
override string getChildAccessorPredicateInternal(int childIndex) {
|
||||
result = super.getChildAccessorPredicateInternal(childIndex)
|
||||
or
|
||||
childIndex = -1 and result = "<params>"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing a `DeclarationEntry`.
|
||||
*/
|
||||
@@ -510,6 +538,22 @@ class DeclStmtNode extends StmtNode {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing a `Handler`.
|
||||
*/
|
||||
class HandlerNode extends ChildStmtNode {
|
||||
Handler handler;
|
||||
|
||||
HandlerNode() { handler = stmt }
|
||||
|
||||
override BaseAstNode getChildInternal(int childIndex) {
|
||||
result = super.getChildInternal(childIndex)
|
||||
or
|
||||
childIndex = -1 and
|
||||
result.getAst() = handler.getParameter()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing a `Parameter`.
|
||||
*/
|
||||
@@ -552,10 +596,10 @@ class InitializerNode extends AstNode {
|
||||
/**
|
||||
* A node representing the parameters of a `Function`.
|
||||
*/
|
||||
class ParametersNode extends PrintAstNode, TParametersNode {
|
||||
class FunctionParametersNode extends PrintAstNode, TFunctionParametersNode {
|
||||
Function func;
|
||||
|
||||
ParametersNode() { this = TParametersNode(func) }
|
||||
FunctionParametersNode() { this = TFunctionParametersNode(func) }
|
||||
|
||||
final override string toString() { result = "" }
|
||||
|
||||
@@ -576,6 +620,33 @@ class ParametersNode extends PrintAstNode, TParametersNode {
|
||||
final Function getFunction() { result = func }
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing the parameters of a `RequiresExpr`.
|
||||
*/
|
||||
class RequiresExprParametersNode extends PrintAstNode, TRequiresExprParametersNode {
|
||||
RequiresExpr req;
|
||||
|
||||
RequiresExprParametersNode() { this = TRequiresExprParametersNode(req) }
|
||||
|
||||
final override string toString() { result = "" }
|
||||
|
||||
final override Location getLocation() { result = getRepresentativeLocation(req) }
|
||||
|
||||
override AstNode getChildInternal(int childIndex) {
|
||||
result.getAst() = req.getParameter(childIndex)
|
||||
}
|
||||
|
||||
override string getChildAccessorPredicateInternal(int childIndex) {
|
||||
exists(this.getChildInternal(childIndex)) and
|
||||
result = "getParameter(" + childIndex.toString() + ")"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `RequiresExpr` for which this node represents the parameters.
|
||||
*/
|
||||
final RequiresExpr getRequiresExpr() { result = req }
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing the initializer list of a `Constructor`.
|
||||
*/
|
||||
@@ -679,7 +750,7 @@ class FunctionNode extends FunctionOrGlobalOrNamespaceVariableNode {
|
||||
|
||||
override PrintAstNode getChildInternal(int childIndex) {
|
||||
childIndex = 0 and
|
||||
result.(ParametersNode).getFunction() = func
|
||||
result.(FunctionParametersNode).getFunction() = func
|
||||
or
|
||||
childIndex = 1 and
|
||||
result.(ConstructorInitializersNode).getConstructor() = func
|
||||
@@ -754,6 +825,8 @@ private predicate namedStmtChildPredicates(Locatable s, Element e, string pred)
|
||||
or
|
||||
s.(ConstexprIfStmt).getElse() = e and pred = "getElse()"
|
||||
or
|
||||
s.(Handler).getParameter() = e and pred = "getParameter()"
|
||||
or
|
||||
s.(IfStmt).getInitialization() = e and pred = "getInitialization()"
|
||||
or
|
||||
s.(IfStmt).getCondition() = e and pred = "getCondition()"
|
||||
@@ -901,6 +974,11 @@ private predicate namedExprChildPredicates(Expr expr, Element ele, string pred)
|
||||
or
|
||||
expr.(CommaExpr).getRightOperand() = ele and pred = "getRightOperand()"
|
||||
or
|
||||
expr.(CompoundRequirementExpr).getExpr() = ele and pred = "getExpr()"
|
||||
or
|
||||
expr.(CompoundRequirementExpr).getReturnTypeRequirement() = ele and
|
||||
pred = "getReturnTypeRequirement()"
|
||||
or
|
||||
expr.(ConditionDeclExpr).getVariableAccess() = ele and pred = "getVariableAccess()"
|
||||
or
|
||||
expr.(ConstructorFieldInit).getExpr() = ele and pred = "getExpr()"
|
||||
@@ -921,6 +999,8 @@ private predicate namedExprChildPredicates(Expr expr, Element ele, string pred)
|
||||
or
|
||||
expr.(LambdaExpression).getInitializer() = ele and pred = "getInitializer()"
|
||||
or
|
||||
expr.(NestedRequirementExpr).getConstraint() = ele and pred = "getConstraint()"
|
||||
or
|
||||
expr.(NewOrNewArrayExpr).getAllocatorCall() = ele and pred = "getAllocatorCall()"
|
||||
or
|
||||
expr.(NewOrNewArrayExpr).getAlignmentArgument() = ele and pred = "getAlignmentArgument()"
|
||||
@@ -960,6 +1040,11 @@ private predicate namedExprChildPredicates(Expr expr, Element ele, string pred)
|
||||
or
|
||||
expr.(UnaryOperation).getOperand() = ele and pred = "getOperand()"
|
||||
or
|
||||
exists(int n |
|
||||
expr.(RequiresExpr).getRequirement(n) = ele and
|
||||
pred = "getRequirement(" + n + ")"
|
||||
)
|
||||
or
|
||||
expr.(SizeofExprOperator).getExprOperand() = ele and pred = "getExprOperand()"
|
||||
or
|
||||
expr.(StmtExpr).getStmt() = ele and pred = "getStmt()"
|
||||
|
||||
@@ -181,12 +181,7 @@ class VariableDeclarationEntry extends @var_decl {
|
||||
string getName() { var_decls(this, _, _, result, _) and result != "" }
|
||||
}
|
||||
|
||||
class Parameter extends LocalScopeVariable, @parameter {
|
||||
@functionorblock function;
|
||||
int index;
|
||||
|
||||
Parameter() { params(this, function, index, _) }
|
||||
}
|
||||
class Parameter extends LocalScopeVariable, @parameter { }
|
||||
|
||||
class GlobalOrNamespaceVariable extends Variable, @globalvariable { }
|
||||
|
||||
|
||||
@@ -6,6 +6,112 @@
|
||||
* uses, however, it is better to write a query that imports `PrintIR.qll`, extends
|
||||
* `PrintIRConfiguration`, and overrides `shouldPrintDeclaration()` to select a subset of declarations
|
||||
* to dump.
|
||||
*
|
||||
* Anatomy of a printed IR instruction
|
||||
*
|
||||
* An instruction:
|
||||
*
|
||||
* ```
|
||||
* # 2281| v2281_19(void) = Call[~String] : func:r2281_18, this:r2281_17
|
||||
* ```
|
||||
*
|
||||
* The prefix `# 2281|` specifies that this instruction was generated by the C++ source code on line 2281.
|
||||
* Scrolling up in the printed output, one will eventually find the name of the file to which the line
|
||||
* belongs.
|
||||
*
|
||||
* `v2281_19(void)` is the result of the instruction. Here, `v` means this is a void result or operand (so
|
||||
* there should be no later uses of the result; see below for other possible values). The `2281_19` is a
|
||||
* unique ID for the result. This is usually just the line number plus a small integer suffix to make it
|
||||
* unique within the function. The type of the result is `void`. In this case, it is `void`, because
|
||||
* `~String` returns `void`. The type of the result is usually just the name of the appropriate C++ type,
|
||||
* but it will sometimes be a type like `glval<int>`, which means result holds a glvalue, which at the
|
||||
* IR level works like a pointer. In other words, in the source code the type was `int`, but it is really
|
||||
* more like an `int*`. We see this, for example, in `x = y;`, where `x` is a glvalue.
|
||||
*
|
||||
* `Call` is the opcode of the instruction. Common opcodes include:
|
||||
*
|
||||
* * Arithmetic operations: `Add`, `Sub`, `Mul`, etc.
|
||||
* * Memory access operations: `Load`, `Store`.
|
||||
* * Function calls: `Call`.
|
||||
* * Literals: `Constant`.
|
||||
* * Variable addresses: `VariableAddress`.
|
||||
* * Function entry points: `EnterFunction`.
|
||||
* * Return from a function: `Return`, `ReturnVoid`. Note that the value being returned is set separately by a
|
||||
* `Store` to a special `#return` variable.
|
||||
* * Stack unwinding for C++ function that throw and where the exception escapes the function: `Unwind`.
|
||||
* * Common exit point for `Unwind` and `Return`: `ExitFunction`.
|
||||
* * SSA-related opcodes: `Phi`, `Chi`.
|
||||
*
|
||||
* `[~String]` denotes additional information. The information might be present earlier in the IR, as is the case
|
||||
* for `Call`, where it is the name of the called function. This is also the case for `Load` and `Store`, where it
|
||||
* is the name of the variable that loaded or stored (if known). In the case of `Constant`, `FieldAddress`, and
|
||||
* `VariableAddress`, the information between brackets does not occur earlier.
|
||||
*
|
||||
* `func:r2281_18` and `this:r28281_17` are the operands of the instruction. The `func:` prefix denotes the operand
|
||||
* that holds the address of the called function. The `this:` prefix denotes the argument to the special `this`
|
||||
* parameter of an instance member function. `r2281_18`, `r2281_17` are the unique IDs of the operands. Each of these
|
||||
* matches the ID of a previously seen result, showing where that value came from. The `r` means that these are
|
||||
* "register" operands (see below).
|
||||
*
|
||||
* Result and operand kinds:
|
||||
*
|
||||
* Every result and operand is one of these three kinds:
|
||||
*
|
||||
* * `r` "register". These operands are not stored in any particular memory location. We can think of them as
|
||||
* temporary values created during the evaluation of an expression. A register operand almost always has one
|
||||
* use, often in the same block as its definition.
|
||||
* * `m` "memory". These operands represents accesses to a specific memory location. The location could be a
|
||||
* local variable, a global variable, a field of an object, an element of an array, or any memory that we happen
|
||||
* to have a pointer to. These only occur as the result of a `Store`, the source operand of a `Load` or on the
|
||||
* SSA instructions (`Phi`, `Chi`).
|
||||
* * `v` "void". Really just a register operand, but we mark register operands of type void with this special prefix
|
||||
* so we know that there is no actual value there.
|
||||
*
|
||||
* Branches in the IR:
|
||||
*
|
||||
* The IR is divided into basic blocks. At the end of each block, there are one or more edges showing the possible
|
||||
* control flow successors of the block.
|
||||
*
|
||||
* ```
|
||||
* # 44| v44_3(void) = ConditionalBranch : r44_2
|
||||
* #-----| False -> Block 4
|
||||
* #-----| True -> Block 3
|
||||
* ```
|
||||
* Here we have a block that ends with a conditional branch. The two edges show where the control flows to depending
|
||||
* on whether the condition is true or false.
|
||||
*
|
||||
* SSA instructions:
|
||||
*
|
||||
* We use `Phi` instructions in SSA to create a single definition for a variable that might be assigned on multiple
|
||||
* control flow paths. The `Phi` instruction merges the potential values of that variable from each predecessor edge,
|
||||
* and the resulting definition is then used wherever that variable is accessed later on.
|
||||
*
|
||||
* When dealing with aliased memory, we use the `Chi` instruction to create a single definition for memory that might
|
||||
* or might not have been updated by a store, depending on the actual address that was written to. For example, take:
|
||||
*
|
||||
* ```cpp
|
||||
* int x = 5;
|
||||
* int y = 7;
|
||||
* int* p = condition ? &x : &y;
|
||||
* *p = 6;
|
||||
* return x;
|
||||
* ```
|
||||
*
|
||||
* At the point where we store to `*p`, we do not know whether `p` points to `x` or `y`. Thus, we do not know whether
|
||||
* `return x;` is going to return the value that `x` was originally initialized to (5), or whether it will return 6,
|
||||
* because it was overwritten by `*p = 6;`. We insert a `Chi` instruction immediately after the store to `*p`:
|
||||
*
|
||||
* ```
|
||||
* r2(int) = Constant[6]
|
||||
* r3(int*) = <<value of p>>
|
||||
* m4(int) = Store : &r3, r2 // Stores the constant 6 to *p
|
||||
* m5(unknown) = Chi : total:m1, partial:m4
|
||||
* ```
|
||||
* The `partial:` operand represents the memory that was just stored. The `total:` operand represents the previous
|
||||
* contents of all of the memory that `p` might have pointed to (in this case, both `x` and `y`). The result of the
|
||||
* `Chi` represents the new contents of whatever memory the `total:` operand referred to. We usually do not know exactly
|
||||
* which parts of that memory were overwritten, but it does model that any of that memory could have been modified, so
|
||||
* that later instructions do not assume that the memory was unchanged.
|
||||
*/
|
||||
|
||||
private import internal.IRInternal
|
||||
|
||||
@@ -6,6 +6,112 @@
|
||||
* uses, however, it is better to write a query that imports `PrintIR.qll`, extends
|
||||
* `PrintIRConfiguration`, and overrides `shouldPrintDeclaration()` to select a subset of declarations
|
||||
* to dump.
|
||||
*
|
||||
* Anatomy of a printed IR instruction
|
||||
*
|
||||
* An instruction:
|
||||
*
|
||||
* ```
|
||||
* # 2281| v2281_19(void) = Call[~String] : func:r2281_18, this:r2281_17
|
||||
* ```
|
||||
*
|
||||
* The prefix `# 2281|` specifies that this instruction was generated by the C++ source code on line 2281.
|
||||
* Scrolling up in the printed output, one will eventually find the name of the file to which the line
|
||||
* belongs.
|
||||
*
|
||||
* `v2281_19(void)` is the result of the instruction. Here, `v` means this is a void result or operand (so
|
||||
* there should be no later uses of the result; see below for other possible values). The `2281_19` is a
|
||||
* unique ID for the result. This is usually just the line number plus a small integer suffix to make it
|
||||
* unique within the function. The type of the result is `void`. In this case, it is `void`, because
|
||||
* `~String` returns `void`. The type of the result is usually just the name of the appropriate C++ type,
|
||||
* but it will sometimes be a type like `glval<int>`, which means result holds a glvalue, which at the
|
||||
* IR level works like a pointer. In other words, in the source code the type was `int`, but it is really
|
||||
* more like an `int*`. We see this, for example, in `x = y;`, where `x` is a glvalue.
|
||||
*
|
||||
* `Call` is the opcode of the instruction. Common opcodes include:
|
||||
*
|
||||
* * Arithmetic operations: `Add`, `Sub`, `Mul`, etc.
|
||||
* * Memory access operations: `Load`, `Store`.
|
||||
* * Function calls: `Call`.
|
||||
* * Literals: `Constant`.
|
||||
* * Variable addresses: `VariableAddress`.
|
||||
* * Function entry points: `EnterFunction`.
|
||||
* * Return from a function: `Return`, `ReturnVoid`. Note that the value being returned is set separately by a
|
||||
* `Store` to a special `#return` variable.
|
||||
* * Stack unwinding for C++ function that throw and where the exception escapes the function: `Unwind`.
|
||||
* * Common exit point for `Unwind` and `Return`: `ExitFunction`.
|
||||
* * SSA-related opcodes: `Phi`, `Chi`.
|
||||
*
|
||||
* `[~String]` denotes additional information. The information might be present earlier in the IR, as is the case
|
||||
* for `Call`, where it is the name of the called function. This is also the case for `Load` and `Store`, where it
|
||||
* is the name of the variable that loaded or stored (if known). In the case of `Constant`, `FieldAddress`, and
|
||||
* `VariableAddress`, the information between brackets does not occur earlier.
|
||||
*
|
||||
* `func:r2281_18` and `this:r28281_17` are the operands of the instruction. The `func:` prefix denotes the operand
|
||||
* that holds the address of the called function. The `this:` prefix denotes the argument to the special `this`
|
||||
* parameter of an instance member function. `r2281_18`, `r2281_17` are the unique IDs of the operands. Each of these
|
||||
* matches the ID of a previously seen result, showing where that value came from. The `r` means that these are
|
||||
* "register" operands (see below).
|
||||
*
|
||||
* Result and operand kinds:
|
||||
*
|
||||
* Every result and operand is one of these three kinds:
|
||||
*
|
||||
* * `r` "register". These operands are not stored in any particular memory location. We can think of them as
|
||||
* temporary values created during the evaluation of an expression. A register operand almost always has one
|
||||
* use, often in the same block as its definition.
|
||||
* * `m` "memory". These operands represents accesses to a specific memory location. The location could be a
|
||||
* local variable, a global variable, a field of an object, an element of an array, or any memory that we happen
|
||||
* to have a pointer to. These only occur as the result of a `Store`, the source operand of a `Load` or on the
|
||||
* SSA instructions (`Phi`, `Chi`).
|
||||
* * `v` "void". Really just a register operand, but we mark register operands of type void with this special prefix
|
||||
* so we know that there is no actual value there.
|
||||
*
|
||||
* Branches in the IR:
|
||||
*
|
||||
* The IR is divided into basic blocks. At the end of each block, there are one or more edges showing the possible
|
||||
* control flow successors of the block.
|
||||
*
|
||||
* ```
|
||||
* # 44| v44_3(void) = ConditionalBranch : r44_2
|
||||
* #-----| False -> Block 4
|
||||
* #-----| True -> Block 3
|
||||
* ```
|
||||
* Here we have a block that ends with a conditional branch. The two edges show where the control flows to depending
|
||||
* on whether the condition is true or false.
|
||||
*
|
||||
* SSA instructions:
|
||||
*
|
||||
* We use `Phi` instructions in SSA to create a single definition for a variable that might be assigned on multiple
|
||||
* control flow paths. The `Phi` instruction merges the potential values of that variable from each predecessor edge,
|
||||
* and the resulting definition is then used wherever that variable is accessed later on.
|
||||
*
|
||||
* When dealing with aliased memory, we use the `Chi` instruction to create a single definition for memory that might
|
||||
* or might not have been updated by a store, depending on the actual address that was written to. For example, take:
|
||||
*
|
||||
* ```cpp
|
||||
* int x = 5;
|
||||
* int y = 7;
|
||||
* int* p = condition ? &x : &y;
|
||||
* *p = 6;
|
||||
* return x;
|
||||
* ```
|
||||
*
|
||||
* At the point where we store to `*p`, we do not know whether `p` points to `x` or `y`. Thus, we do not know whether
|
||||
* `return x;` is going to return the value that `x` was originally initialized to (5), or whether it will return 6,
|
||||
* because it was overwritten by `*p = 6;`. We insert a `Chi` instruction immediately after the store to `*p`:
|
||||
*
|
||||
* ```
|
||||
* r2(int) = Constant[6]
|
||||
* r3(int*) = <<value of p>>
|
||||
* m4(int) = Store : &r3, r2 // Stores the constant 6 to *p
|
||||
* m5(unknown) = Chi : total:m1, partial:m4
|
||||
* ```
|
||||
* The `partial:` operand represents the memory that was just stored. The `total:` operand represents the previous
|
||||
* contents of all of the memory that `p` might have pointed to (in this case, both `x` and `y`). The result of the
|
||||
* `Chi` represents the new contents of whatever memory the `total:` operand referred to. We usually do not know exactly
|
||||
* which parts of that memory were overwritten, but it does model that any of that memory could have been modified, so
|
||||
* that later instructions do not assume that the memory was unchanged.
|
||||
*/
|
||||
|
||||
private import internal.IRInternal
|
||||
|
||||
@@ -6,6 +6,112 @@
|
||||
* uses, however, it is better to write a query that imports `PrintIR.qll`, extends
|
||||
* `PrintIRConfiguration`, and overrides `shouldPrintDeclaration()` to select a subset of declarations
|
||||
* to dump.
|
||||
*
|
||||
* Anatomy of a printed IR instruction
|
||||
*
|
||||
* An instruction:
|
||||
*
|
||||
* ```
|
||||
* # 2281| v2281_19(void) = Call[~String] : func:r2281_18, this:r2281_17
|
||||
* ```
|
||||
*
|
||||
* The prefix `# 2281|` specifies that this instruction was generated by the C++ source code on line 2281.
|
||||
* Scrolling up in the printed output, one will eventually find the name of the file to which the line
|
||||
* belongs.
|
||||
*
|
||||
* `v2281_19(void)` is the result of the instruction. Here, `v` means this is a void result or operand (so
|
||||
* there should be no later uses of the result; see below for other possible values). The `2281_19` is a
|
||||
* unique ID for the result. This is usually just the line number plus a small integer suffix to make it
|
||||
* unique within the function. The type of the result is `void`. In this case, it is `void`, because
|
||||
* `~String` returns `void`. The type of the result is usually just the name of the appropriate C++ type,
|
||||
* but it will sometimes be a type like `glval<int>`, which means result holds a glvalue, which at the
|
||||
* IR level works like a pointer. In other words, in the source code the type was `int`, but it is really
|
||||
* more like an `int*`. We see this, for example, in `x = y;`, where `x` is a glvalue.
|
||||
*
|
||||
* `Call` is the opcode of the instruction. Common opcodes include:
|
||||
*
|
||||
* * Arithmetic operations: `Add`, `Sub`, `Mul`, etc.
|
||||
* * Memory access operations: `Load`, `Store`.
|
||||
* * Function calls: `Call`.
|
||||
* * Literals: `Constant`.
|
||||
* * Variable addresses: `VariableAddress`.
|
||||
* * Function entry points: `EnterFunction`.
|
||||
* * Return from a function: `Return`, `ReturnVoid`. Note that the value being returned is set separately by a
|
||||
* `Store` to a special `#return` variable.
|
||||
* * Stack unwinding for C++ function that throw and where the exception escapes the function: `Unwind`.
|
||||
* * Common exit point for `Unwind` and `Return`: `ExitFunction`.
|
||||
* * SSA-related opcodes: `Phi`, `Chi`.
|
||||
*
|
||||
* `[~String]` denotes additional information. The information might be present earlier in the IR, as is the case
|
||||
* for `Call`, where it is the name of the called function. This is also the case for `Load` and `Store`, where it
|
||||
* is the name of the variable that loaded or stored (if known). In the case of `Constant`, `FieldAddress`, and
|
||||
* `VariableAddress`, the information between brackets does not occur earlier.
|
||||
*
|
||||
* `func:r2281_18` and `this:r28281_17` are the operands of the instruction. The `func:` prefix denotes the operand
|
||||
* that holds the address of the called function. The `this:` prefix denotes the argument to the special `this`
|
||||
* parameter of an instance member function. `r2281_18`, `r2281_17` are the unique IDs of the operands. Each of these
|
||||
* matches the ID of a previously seen result, showing where that value came from. The `r` means that these are
|
||||
* "register" operands (see below).
|
||||
*
|
||||
* Result and operand kinds:
|
||||
*
|
||||
* Every result and operand is one of these three kinds:
|
||||
*
|
||||
* * `r` "register". These operands are not stored in any particular memory location. We can think of them as
|
||||
* temporary values created during the evaluation of an expression. A register operand almost always has one
|
||||
* use, often in the same block as its definition.
|
||||
* * `m` "memory". These operands represents accesses to a specific memory location. The location could be a
|
||||
* local variable, a global variable, a field of an object, an element of an array, or any memory that we happen
|
||||
* to have a pointer to. These only occur as the result of a `Store`, the source operand of a `Load` or on the
|
||||
* SSA instructions (`Phi`, `Chi`).
|
||||
* * `v` "void". Really just a register operand, but we mark register operands of type void with this special prefix
|
||||
* so we know that there is no actual value there.
|
||||
*
|
||||
* Branches in the IR:
|
||||
*
|
||||
* The IR is divided into basic blocks. At the end of each block, there are one or more edges showing the possible
|
||||
* control flow successors of the block.
|
||||
*
|
||||
* ```
|
||||
* # 44| v44_3(void) = ConditionalBranch : r44_2
|
||||
* #-----| False -> Block 4
|
||||
* #-----| True -> Block 3
|
||||
* ```
|
||||
* Here we have a block that ends with a conditional branch. The two edges show where the control flows to depending
|
||||
* on whether the condition is true or false.
|
||||
*
|
||||
* SSA instructions:
|
||||
*
|
||||
* We use `Phi` instructions in SSA to create a single definition for a variable that might be assigned on multiple
|
||||
* control flow paths. The `Phi` instruction merges the potential values of that variable from each predecessor edge,
|
||||
* and the resulting definition is then used wherever that variable is accessed later on.
|
||||
*
|
||||
* When dealing with aliased memory, we use the `Chi` instruction to create a single definition for memory that might
|
||||
* or might not have been updated by a store, depending on the actual address that was written to. For example, take:
|
||||
*
|
||||
* ```cpp
|
||||
* int x = 5;
|
||||
* int y = 7;
|
||||
* int* p = condition ? &x : &y;
|
||||
* *p = 6;
|
||||
* return x;
|
||||
* ```
|
||||
*
|
||||
* At the point where we store to `*p`, we do not know whether `p` points to `x` or `y`. Thus, we do not know whether
|
||||
* `return x;` is going to return the value that `x` was originally initialized to (5), or whether it will return 6,
|
||||
* because it was overwritten by `*p = 6;`. We insert a `Chi` instruction immediately after the store to `*p`:
|
||||
*
|
||||
* ```
|
||||
* r2(int) = Constant[6]
|
||||
* r3(int*) = <<value of p>>
|
||||
* m4(int) = Store : &r3, r2 // Stores the constant 6 to *p
|
||||
* m5(unknown) = Chi : total:m1, partial:m4
|
||||
* ```
|
||||
* The `partial:` operand represents the memory that was just stored. The `total:` operand represents the previous
|
||||
* contents of all of the memory that `p` might have pointed to (in this case, both `x` and `y`). The result of the
|
||||
* `Chi` represents the new contents of whatever memory the `total:` operand referred to. We usually do not know exactly
|
||||
* which parts of that memory were overwritten, but it does model that any of that memory could have been modified, so
|
||||
* that later instructions do not assume that the memory was unchanged.
|
||||
*/
|
||||
|
||||
private import internal.IRInternal
|
||||
|
||||
@@ -7,7 +7,7 @@ import semmle.code.cpp.models.interfaces.Alias
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
|
||||
/** The function `fopen` and friends. */
|
||||
private class Fopen extends Function, AliasFunction, SideEffectFunction {
|
||||
private class Fopen extends Function, AliasFunction, SideEffectFunction, TaintFunction {
|
||||
Fopen() {
|
||||
this.hasGlobalOrStdName(["fopen", "fopen_s", "freopen"])
|
||||
or
|
||||
@@ -47,4 +47,22 @@ private class Fopen extends Function, AliasFunction, SideEffectFunction {
|
||||
i = 0 and
|
||||
buffer = true
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
(
|
||||
this.hasGlobalOrStdName(["fopen", "freopen"]) or
|
||||
this.hasGlobalName(["_wfopen", "_fsopen", "_wfsopen"])
|
||||
) and
|
||||
input.isParameterDeref(0) and
|
||||
output.isReturnValueDeref()
|
||||
or
|
||||
// The out parameter is a pointer to a `FILE*`.
|
||||
this.hasGlobalOrStdName("fopen_s") and
|
||||
input.isParameterDeref(1) and
|
||||
output.isParameterDeref(0, 2)
|
||||
or
|
||||
this.hasGlobalName(["_open", "_wopen"]) and
|
||||
input.isParameterDeref(0) and
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,6 +192,37 @@ private class UnsignedMulExpr extends MulExpr {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the `EOF` macro.
|
||||
*
|
||||
* This is typically `"-1"`, but this is not guaranteed to be the case on all
|
||||
* systems.
|
||||
*/
|
||||
private int getEofValue() {
|
||||
exists(MacroInvocation mi |
|
||||
mi.getMacroName() = "EOF" and
|
||||
result = unique( | | mi.getExpr().getValue().toInt())
|
||||
)
|
||||
}
|
||||
|
||||
/** Get standard `getc` function or related variants. */
|
||||
private class Getc extends Function {
|
||||
Getc() { this.hasGlobalOrStdOrBslName(["fgetc", "getc"]) }
|
||||
}
|
||||
|
||||
/** A call to `getc` */
|
||||
private class CallToGetc extends FunctionCall {
|
||||
CallToGetc() { this.getTarget() instanceof Getc }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `getc` that we can analyze because we know
|
||||
* the value of the `EOF` macro.
|
||||
*/
|
||||
private class AnalyzableCallToGetc extends CallToGetc {
|
||||
AnalyzableCallToGetc() { exists(getEofValue()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `expr` is effectively a multiplication of `operand` with the
|
||||
* positive constant `positive`.
|
||||
@@ -287,6 +318,8 @@ private predicate analyzableExpr(Expr e) {
|
||||
or
|
||||
e instanceof RemExpr
|
||||
or
|
||||
e instanceof AnalyzableCallToGetc
|
||||
or
|
||||
// A conversion is analyzable, provided that its child has an arithmetic
|
||||
// type. (Sometimes the child is a reference type, and so does not get
|
||||
// any bounds.) Rather than checking whether the type of the child is
|
||||
@@ -861,6 +894,14 @@ private float getLowerBoundsImpl(Expr expr) {
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(AnalyzableCallToGetc getc |
|
||||
expr = getc and
|
||||
// from https://en.cppreference.com/w/c/io/fgetc:
|
||||
// On success, returns the obtained character as an unsigned char
|
||||
// converted to an int. On failure, returns EOF.
|
||||
result = min([typeLowerBound(any(UnsignedCharType pct)), getEofValue()])
|
||||
)
|
||||
or
|
||||
// If the conversion is to an arithmetic type then we just return the
|
||||
// lower bound of the child. We do not need to handle truncation and
|
||||
// overflow here, because that is done in `getTruncatedLowerBounds`.
|
||||
@@ -1055,6 +1096,14 @@ private float getUpperBoundsImpl(Expr expr) {
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(AnalyzableCallToGetc getc |
|
||||
expr = getc and
|
||||
// from https://en.cppreference.com/w/c/io/fgetc:
|
||||
// On success, returns the obtained character as an unsigned char
|
||||
// converted to an int. On failure, returns EOF.
|
||||
result = max([typeUpperBound(any(UnsignedCharType pct)), getEofValue()])
|
||||
)
|
||||
or
|
||||
// If the conversion is to an arithmetic type then we just return the
|
||||
// upper bound of the child. We do not need to handle truncation and
|
||||
// overflow here, because that is done in `getTruncatedUpperBounds`.
|
||||
|
||||
@@ -534,7 +534,7 @@ static_asserts(
|
||||
#keyset[function, index, type_id]
|
||||
params(
|
||||
int id: @parameter,
|
||||
int function: @functionorblock ref,
|
||||
int function: @parameterized_element ref,
|
||||
int index: int ref,
|
||||
int type_id: @type ref
|
||||
);
|
||||
@@ -1790,6 +1790,10 @@ case @expr.kind of
|
||||
| 387 = @istriviallyrelocatable
|
||||
| 388 = @datasizeof
|
||||
| 389 = @c11_generic
|
||||
| 390 = @requires_expr
|
||||
| 391 = @nested_requirement
|
||||
| 392 = @compound_requirement
|
||||
| 393 = @concept_id
|
||||
;
|
||||
|
||||
@var_args_expr = @vastartexpr
|
||||
@@ -1908,6 +1912,10 @@ case @expr.kind of
|
||||
| @istriviallyrelocatable
|
||||
;
|
||||
|
||||
compound_requirement_is_noexcept(
|
||||
int expr: @compound_requirement ref
|
||||
);
|
||||
|
||||
new_allocated_type(
|
||||
unique int expr: @new_expr ref,
|
||||
int type_id: @type ref
|
||||
@@ -2167,11 +2175,11 @@ stmt_decl_entry_bind(
|
||||
int decl_entry: @element ref
|
||||
);
|
||||
|
||||
@functionorblock = @function | @stmt_block;
|
||||
@parameterized_element = @function | @stmt_block | @requires_expr;
|
||||
|
||||
blockscope(
|
||||
unique int block: @stmt_block ref,
|
||||
int enclosing: @functionorblock ref
|
||||
int enclosing: @parameterized_element ref
|
||||
);
|
||||
|
||||
@jump = @stmt_goto | @stmt_break | @stmt_continue;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Support C++20 requires expressions
|
||||
compatibility: backwards
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Add requires expressions
|
||||
compatibility: full
|
||||
@@ -57,5 +57,5 @@ where
|
||||
not declarationHasSideEffects(v) and
|
||||
not exists(AsmStmt s | f = s.getEnclosingFunction()) and
|
||||
not v.getAnAttribute().getName() = "unused" and
|
||||
not any(ErrorExpr e).getEnclosingFunction() = f // unextracted expr may use `v`
|
||||
not f.hasErrors() // Unextracted expressions may use `v`
|
||||
select v, "Variable " + v.getName() + " is not used."
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
## 1.2.5
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `cpp/unclear-array-index-validation` ("Unclear validation of array index") query has been improved to reduce false positives and increase true positives.
|
||||
* Fixed false positives in the `cpp/uninitialized-local` ("Potentially uninitialized local variable") query if there are extraction errors in the function.
|
||||
* The `cpp/incorrect-string-type-conversion` query now produces fewer false positives caused by failure to detect byte arrays.
|
||||
* The `cpp/incorrect-string-type-conversion` query now produces fewer false positives caused by failure to recognize dynamic checks prior to possible dangerous widening.
|
||||
|
||||
## 1.2.4
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
@@ -29,7 +29,7 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
|
||||
override predicate isSource(Instruction source) {
|
||||
exists(Function func |
|
||||
// Rule out FPs caused by extraction errors.
|
||||
not any(ErrorExpr e).getEnclosingFunction() = func and
|
||||
not func.hasErrors() and
|
||||
not intentionallyReturnsStackPointer(func) and
|
||||
func = source.getEnclosingFunction()
|
||||
|
|
||||
|
||||
@@ -65,6 +65,7 @@ predicate isSinkImpl(Instruction sink, VariableAccess va) {
|
||||
exists(LoadInstruction load |
|
||||
va = load.getUnconvertedResultExpression() and
|
||||
not va = commonException() and
|
||||
not va.getTarget().(LocalVariable).getFunction().hasErrors() and
|
||||
sink = load.getSourceValue()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ predicate instructionHasVariable(VariableAddressInstruction vai, StackVariable v
|
||||
// Pointer-to-member types aren't properly handled in the dbscheme.
|
||||
not vai.getResultType() instanceof PointerToMemberType and
|
||||
// Rule out FPs caused by extraction errors.
|
||||
not any(ErrorExpr e).getEnclosingFunction() = f
|
||||
not f.hasErrors()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,102 +14,56 @@
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.IRGuards
|
||||
import semmle.code.cpp.security.FlowSources
|
||||
import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||
import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
|
||||
import semmle.code.cpp.security.FlowSources as FS
|
||||
import semmle.code.cpp.dataflow.new.TaintTracking
|
||||
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
|
||||
import ImproperArrayIndexValidation::PathGraph
|
||||
import semmle.code.cpp.security.Security
|
||||
|
||||
predicate hasUpperBound(VariableAccess offsetExpr) {
|
||||
exists(BasicBlock controlled, StackVariable offsetVar, SsaDefinition def |
|
||||
controlled.contains(offsetExpr) and
|
||||
linearBoundControls(controlled, def, offsetVar) and
|
||||
offsetExpr = def.getAUse(offsetVar)
|
||||
predicate isFlowSource(FS::FlowSource source, string sourceType) {
|
||||
sourceType = source.getSourceType()
|
||||
}
|
||||
|
||||
predicate guardChecks(IRGuardCondition g, Expr e, boolean branch) {
|
||||
exists(Operand op | op.getDef().getConvertedResultExpression() = e |
|
||||
// `op < k` is true and `k > 0`
|
||||
g.comparesLt(op, any(int k | k > 0), true, any(BooleanValue bv | bv.getValue() = branch))
|
||||
or
|
||||
// `op < _ + k` is true and `k > 0`.
|
||||
g.comparesLt(op, _, any(int k | k > 0), true, branch)
|
||||
or
|
||||
// op == k
|
||||
g.comparesEq(op, _, true, any(BooleanValue bv | bv.getValue() = branch))
|
||||
or
|
||||
// op == _ + k
|
||||
g.comparesEq(op, _, _, true, branch)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
predicate linearBoundControls(BasicBlock controlled, SsaDefinition def, StackVariable offsetVar) {
|
||||
exists(GuardCondition guard, boolean branch |
|
||||
guard.controls(controlled, branch) and
|
||||
cmpWithLinearBound(guard, def.getAUse(offsetVar), Lesser(), branch)
|
||||
/**
|
||||
* Holds if `arrayExpr` accesses an `ArrayType` with a constant size `N`, and
|
||||
* the value of `offsetExpr` is known to be smaller than `N`.
|
||||
*/
|
||||
predicate offsetIsAlwaysInBounds(ArrayExpr arrayExpr, VariableAccess offsetExpr) {
|
||||
exists(ArrayType arrayType |
|
||||
arrayType = arrayExpr.getArrayBase().getUnspecifiedType() and
|
||||
arrayType.getArraySize() > upperBound(offsetExpr.getFullyConverted())
|
||||
)
|
||||
}
|
||||
|
||||
predicate readsVariable(LoadInstruction load, Variable var) {
|
||||
load.getSourceAddress().(VariableAddressInstruction).getAstVariable() = var
|
||||
}
|
||||
|
||||
predicate hasUpperBoundsCheck(Variable var) {
|
||||
exists(RelationalOperation oper, VariableAccess access |
|
||||
oper.getAnOperand() = access and
|
||||
access.getTarget() = var and
|
||||
// Comparing to 0 is not an upper bound check
|
||||
not oper.getAnOperand().getValue() = "0"
|
||||
)
|
||||
}
|
||||
|
||||
predicate nodeIsBarrierEqualityCandidate(DataFlow::Node node, Operand access, Variable checkedVar) {
|
||||
readsVariable(node.asInstruction(), checkedVar) and
|
||||
any(IRGuardCondition guard).ensuresEq(access, _, _, node.asInstruction().getBlock(), true)
|
||||
}
|
||||
|
||||
predicate isFlowSource(FlowSource source, string sourceType) { sourceType = source.getSourceType() }
|
||||
|
||||
predicate predictableInstruction(Instruction instr) {
|
||||
instr instanceof ConstantInstruction
|
||||
or
|
||||
instr instanceof StringConstantInstruction
|
||||
or
|
||||
// This could be a conversion on a string literal
|
||||
predictableInstruction(instr.(UnaryInstruction).getUnary())
|
||||
}
|
||||
|
||||
module ImproperArrayIndexValidationConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { isFlowSource(source, _) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
hasUpperBound(node.asExpr())
|
||||
or
|
||||
// These barriers are ported from `DefaultTaintTracking` because this query is quite noisy
|
||||
// otherwise.
|
||||
exists(Variable checkedVar |
|
||||
readsVariable(node.asInstruction(), checkedVar) and
|
||||
hasUpperBoundsCheck(checkedVar)
|
||||
)
|
||||
or
|
||||
exists(Variable checkedVar, Operand access |
|
||||
readsVariable(access.getDef(), checkedVar) and
|
||||
nodeIsBarrierEqualityCandidate(node, access, checkedVar)
|
||||
)
|
||||
or
|
||||
// Don't use dataflow into binary instructions if both operands are unpredictable
|
||||
exists(BinaryInstruction iTo |
|
||||
iTo = node.asInstruction() and
|
||||
not predictableInstruction(iTo.getLeft()) and
|
||||
not predictableInstruction(iTo.getRight()) and
|
||||
// propagate taint from either the pointer or the offset, regardless of predictability
|
||||
not iTo instanceof PointerArithmeticInstruction
|
||||
)
|
||||
or
|
||||
// don't use dataflow through calls to pure functions if two or more operands
|
||||
// are unpredictable
|
||||
exists(Instruction iFrom1, Instruction iFrom2, CallInstruction iTo |
|
||||
iTo = node.asInstruction() and
|
||||
isPureFunction(iTo.getStaticCallTarget().getName()) and
|
||||
iFrom1 = iTo.getAnArgument() and
|
||||
iFrom2 = iTo.getAnArgument() and
|
||||
not predictableInstruction(iFrom1) and
|
||||
not predictableInstruction(iFrom2) and
|
||||
iFrom1 != iFrom2
|
||||
)
|
||||
node = DataFlow::BarrierGuard<guardChecks/3>::getABarrierNode()
|
||||
}
|
||||
|
||||
predicate isBarrierOut(DataFlow::Node node) { isSink(node) }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(ArrayExpr arrayExpr, VariableAccess offsetExpr |
|
||||
offsetExpr = arrayExpr.getArrayOffset() and
|
||||
sink.asExpr() = offsetExpr and
|
||||
not hasUpperBound(offsetExpr)
|
||||
not offsetIsAlwaysInBounds(arrayExpr, offsetExpr)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,23 +13,85 @@
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.Guards
|
||||
|
||||
class WideCharPointerType extends PointerType {
|
||||
WideCharPointerType() { this.getBaseType() instanceof WideCharType }
|
||||
}
|
||||
|
||||
/**
|
||||
* Given type `t`, recurses through and returns all
|
||||
* intermediate base types, including `t`.
|
||||
*/
|
||||
Type getABaseType(Type t) {
|
||||
result = t
|
||||
or
|
||||
result = getABaseType(t.(DerivedType).getBaseType())
|
||||
or
|
||||
result = getABaseType(t.(TypedefType).getBaseType())
|
||||
}
|
||||
|
||||
/**
|
||||
* A type that may also be `CharPointerType`, but that are likely used as arbitrary buffers.
|
||||
*/
|
||||
class UnlikelyToBeAStringType extends Type {
|
||||
UnlikelyToBeAStringType() {
|
||||
this.(PointerType).getBaseType().(CharType).isUnsigned() or
|
||||
this.(PointerType).getBaseType().getName().toLowerCase().matches("%byte") or
|
||||
this.getName().toLowerCase().matches("%byte") or
|
||||
this.(PointerType).getBaseType().hasName("uint8_t")
|
||||
exists(Type targ | getABaseType(this) = targ |
|
||||
// NOTE: not using CharType isUnsigned, but rather look for any explicitly declared unsigned
|
||||
// char types. Assuming these are used for buffers, not strings.
|
||||
targ.(CharType).getName().toLowerCase().matches("unsigned%") or
|
||||
targ.getName().toLowerCase().matches(["uint8_t", "%byte%"])
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Types that can be wide depending on the UNICODE macro
|
||||
// see https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types
|
||||
class UnicodeMacroDependentWidthType extends Type {
|
||||
UnicodeMacroDependentWidthType() {
|
||||
exists(Type targ | getABaseType(this) = targ |
|
||||
targ.getName() in [
|
||||
"LPCTSTR",
|
||||
"LPTSTR",
|
||||
"PCTSTR",
|
||||
"PTSTR",
|
||||
"TBYTE",
|
||||
"TCHAR"
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class UnicodeMacro extends Macro {
|
||||
UnicodeMacro() { this.getName().toLowerCase().matches("%unicode%") }
|
||||
}
|
||||
|
||||
class UnicodeMacroInvocation extends MacroInvocation {
|
||||
UnicodeMacroInvocation() { this.getMacro() instanceof UnicodeMacro }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds when a expression whose type is UnicodeMacroDependentWidthType and
|
||||
* is observed to be guarded by a check involving a bitwise-and operation
|
||||
* with a UnicodeMacroInvocation.
|
||||
* Such expressions are assumed to be checked dynamically, i.e.,
|
||||
* the flag would indicate if UNICODE typing is set correctly to allow
|
||||
* or disallow a widening cast.
|
||||
*/
|
||||
predicate isLikelyDynamicallyChecked(Expr e) {
|
||||
e.getType() instanceof UnicodeMacroDependentWidthType and
|
||||
exists(GuardCondition gc, BitwiseAndExpr bai, UnicodeMacroInvocation umi |
|
||||
bai.getAnOperand() = umi.getExpr()
|
||||
|
|
||||
// bai == 0 is false when reaching `e.getBasicBlock()`.
|
||||
// That is, bai != 0 when reaching `e.getBasicBlock()`.
|
||||
gc.ensuresEq(bai, 0, e.getBasicBlock(), false)
|
||||
or
|
||||
// bai == k and k != 0 is true when reaching `e.getBasicBlock()`.
|
||||
gc.ensuresEq(bai, any(int k | k != 0), e.getBasicBlock(), true)
|
||||
)
|
||||
}
|
||||
|
||||
from Expr e1, Cast e2
|
||||
where
|
||||
e2 = e1.getConversion() and
|
||||
@@ -42,7 +104,11 @@ where
|
||||
not e1.getType() instanceof UnlikelyToBeAStringType and
|
||||
// Avoid castings from 'new' expressions as typically these will be safe
|
||||
// Example: `__Type* ret = reinterpret_cast<__Type*>(New(m_pmo) char[num * sizeof(__Type)]);`
|
||||
not exists(NewOrNewArrayExpr newExpr | newExpr.getAChild*() = e1)
|
||||
not exists(NewOrNewArrayExpr newExpr | newExpr.getAChild*() = e1) and
|
||||
// Avoid cases where the cast is guarded by a check to determine if
|
||||
// unicode encoding is enabled in such a way to disallow the dangerous cast
|
||||
// at runtime.
|
||||
not isLikelyDynamicallyChecked(e1)
|
||||
select e1,
|
||||
"Conversion from " + e1.getType().toString() + " to " + e2.getType().toString() +
|
||||
". Use of invalid string can lead to undefined behavior."
|
||||
|
||||
8
cpp/ql/src/change-notes/released/1.2.5.md
Normal file
8
cpp/ql/src/change-notes/released/1.2.5.md
Normal file
@@ -0,0 +1,8 @@
|
||||
## 1.2.5
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `cpp/unclear-array-index-validation` ("Unclear validation of array index") query has been improved to reduce false positives and increase true positives.
|
||||
* Fixed false positives in the `cpp/uninitialized-local` ("Potentially uninitialized local variable") query if there are extraction errors in the function.
|
||||
* The `cpp/incorrect-string-type-conversion` query now produces fewer false positives caused by failure to detect byte arrays.
|
||||
* The `cpp/incorrect-string-type-conversion` query now produces fewer false positives caused by failure to recognize dynamic checks prior to possible dangerous widening.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.2.4
|
||||
lastReleaseVersion: 1.2.5
|
||||
|
||||
@@ -49,7 +49,7 @@ predicate functionsMissingReturnStmt(Function f, ControlFlowNode blame) {
|
||||
predicate functionImperfectlyExtracted(Function f) {
|
||||
exists(CompilerError e | f.getBlock().getLocation().subsumes(e.getLocation()))
|
||||
or
|
||||
exists(ErrorExpr ee | ee.getEnclosingFunction() = f)
|
||||
f.hasErrors()
|
||||
or
|
||||
count(f.getType()) > 1
|
||||
or
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 1.2.4
|
||||
version: 1.2.6-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -870,6 +870,8 @@ Throw.cpp:
|
||||
# 8| Type = [BoolType] bool
|
||||
# 8| ValueCategory = prvalue
|
||||
# 12| getChild(1): [Handler] <handler>
|
||||
# 12| getParameter(): [Parameter] e
|
||||
# 12| Type = [PointerType] E *
|
||||
# 12| getBlock(): [CatchBlock] { ... }
|
||||
# 13| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 13| getExpr(): [ReThrowExpr] re-throw exception
|
||||
|
||||
@@ -6,7 +6,7 @@ int wprintf (const wchar_t* format, ...);
|
||||
int strlen( const char * string );
|
||||
int checkErrors();
|
||||
|
||||
void goodTest0()
|
||||
static void goodTest0()
|
||||
{
|
||||
char * ptr = "123456789";
|
||||
int ret;
|
||||
@@ -17,7 +17,7 @@ void goodTest0()
|
||||
ptr += ret;
|
||||
}
|
||||
}
|
||||
void goodTest1(const char* ptr)
|
||||
static void goodTest1(const char* ptr)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
@@ -27,7 +27,7 @@ void goodTest1(const char* ptr)
|
||||
ptr += ret;
|
||||
}
|
||||
}
|
||||
void goodTest2(char* ptr)
|
||||
static void goodTest2(char* ptr)
|
||||
{
|
||||
int ret;
|
||||
ptr[10]=0;
|
||||
@@ -38,7 +38,7 @@ void goodTest2(char* ptr)
|
||||
}
|
||||
}
|
||||
|
||||
void goodTest3(const char* ptr)
|
||||
static void goodTest3(const char* ptr)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
@@ -48,7 +48,7 @@ void goodTest3(const char* ptr)
|
||||
ptr += ret;
|
||||
}
|
||||
}
|
||||
void goodTest4(const char* ptr)
|
||||
static void goodTest4(const char* ptr)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
@@ -58,7 +58,7 @@ void goodTest4(const char* ptr)
|
||||
ptr += ret;
|
||||
}
|
||||
}
|
||||
void badTest1(const char* ptr)
|
||||
static void badTest1(const char* ptr)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
@@ -68,7 +68,7 @@ void badTest1(const char* ptr)
|
||||
ptr += ret;
|
||||
}
|
||||
}
|
||||
void badTest2(const char* ptr)
|
||||
static void badTest2(const char* ptr)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
@@ -79,7 +79,7 @@ void badTest2(const char* ptr)
|
||||
}
|
||||
}
|
||||
|
||||
void goodTest5(const char* ptr,wchar_t *wc,int wc_len)
|
||||
static void goodTest5(const char* ptr,wchar_t *wc,int wc_len)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
@@ -96,7 +96,7 @@ void goodTest5(const char* ptr,wchar_t *wc,int wc_len)
|
||||
}
|
||||
}
|
||||
|
||||
void badTest3(const char* ptr,int wc_len)
|
||||
static void badTest3(const char* ptr,int wc_len)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
@@ -113,7 +113,7 @@ void badTest3(const char* ptr,int wc_len)
|
||||
wc++;
|
||||
}
|
||||
}
|
||||
void badTest4(const char* ptr,int wc_len)
|
||||
static void badTest4(const char* ptr,int wc_len)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
@@ -130,7 +130,7 @@ void badTest4(const char* ptr,int wc_len)
|
||||
wc++;
|
||||
}
|
||||
}
|
||||
void badTest5(const char* ptr,int wc_len)
|
||||
static void badTest5(const char* ptr,int wc_len)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
@@ -148,7 +148,7 @@ void badTest5(const char* ptr,int wc_len)
|
||||
}
|
||||
}
|
||||
|
||||
void badTest6(const char* ptr,int wc_len)
|
||||
static void badTest6(const char* ptr,int wc_len)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
@@ -171,7 +171,7 @@ void badTest6(const char* ptr,int wc_len)
|
||||
ptr+=ret;
|
||||
}
|
||||
}
|
||||
void badTest7(const char* ptr,int wc_len)
|
||||
static void badTest7(const char* ptr,int wc_len)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
@@ -188,7 +188,7 @@ void badTest7(const char* ptr,int wc_len)
|
||||
ptr+=ret;
|
||||
}
|
||||
}
|
||||
void badTest8(const char* ptr,wchar_t *wc)
|
||||
static void badTest8(const char* ptr,wchar_t *wc)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
|
||||
@@ -24,7 +24,7 @@ typedef unsigned int size_t;
|
||||
void* calloc (size_t num, size_t size);
|
||||
void* malloc (size_t size);
|
||||
|
||||
void badTest1(void *src, int size) {
|
||||
static void badTest1(void *src, int size) {
|
||||
WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1, (LPSTR)src, size, 0, 0); // BAD
|
||||
MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1, (LPCWSTR)src, 30); // BAD
|
||||
}
|
||||
@@ -39,43 +39,43 @@ void goodTest2(){
|
||||
}
|
||||
printf("%s\n", dst);
|
||||
}
|
||||
void badTest2(){
|
||||
static void badTest2(){
|
||||
wchar_t src[] = L"0123456789ABCDEF";
|
||||
char dst[16];
|
||||
WideCharToMultiByte(CP_UTF8, 0, src, -1, dst, 16, NULL, NULL); // BAD
|
||||
printf("%s\n", dst);
|
||||
}
|
||||
void goodTest3(){
|
||||
static void goodTest3(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
int size = MultiByteToWideChar(CP_UTF8, 0, src,sizeof(src),NULL,0);
|
||||
wchar_t * dst = (wchar_t*)calloc(size + 1, sizeof(wchar_t));
|
||||
MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, size+1); // GOOD
|
||||
}
|
||||
void badTest3(){
|
||||
static void badTest3(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
int size = MultiByteToWideChar(CP_UTF8, 0, src,sizeof(src),NULL,0);
|
||||
wchar_t * dst = (wchar_t*)calloc(size + 1, 1);
|
||||
MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, size+1); // BAD
|
||||
}
|
||||
void goodTest4(){
|
||||
static void goodTest4(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
int size = MultiByteToWideChar(CP_UTF8, 0, src,sizeof(src),NULL,0);
|
||||
wchar_t * dst = (wchar_t*)malloc((size + 1)*sizeof(wchar_t));
|
||||
MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, size+1); // GOOD
|
||||
}
|
||||
void badTest4(){
|
||||
static void badTest4(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
int size = MultiByteToWideChar(CP_UTF8, 0, src,sizeof(src),NULL,0);
|
||||
wchar_t * dst = (wchar_t*)malloc(size + 1);
|
||||
MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, size+1); // BAD
|
||||
}
|
||||
int goodTest5(void *src){
|
||||
static int goodTest5(void *src){
|
||||
return WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1, 0, 0, 0, 0); // GOOD
|
||||
}
|
||||
int badTest5 (void *src) {
|
||||
static int badTest5 (void *src) {
|
||||
return WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)src, -1, 0, 3, 0, 0); // BAD
|
||||
}
|
||||
void goodTest6(WCHAR *src)
|
||||
static void goodTest6(WCHAR *src)
|
||||
{
|
||||
int size;
|
||||
char dst[5] ="";
|
||||
@@ -87,7 +87,7 @@ void goodTest6(WCHAR *src)
|
||||
WideCharToMultiByte(CP_ACP, 0, src, -1, dst, sizeof(dst), 0, 0); // GOOD
|
||||
printf("%s\n", dst);
|
||||
}
|
||||
void badTest6(WCHAR *src)
|
||||
static void badTest6(WCHAR *src)
|
||||
{
|
||||
char dst[5] ="";
|
||||
WideCharToMultiByte(CP_ACP, 0, src, -1, dst, 260, 0, 0); // BAD
|
||||
|
||||
@@ -11,14 +11,14 @@ size_t _mbstowcs_l(wchar_t *wcstr,const char *mbstr,size_t count, _locale_t loca
|
||||
size_t mbsrtowcs(wchar_t *wcstr,const char *mbstr,size_t count, mbstate_t *mbstate);
|
||||
|
||||
|
||||
void badTest1(void *src, int size) {
|
||||
static void badTest1(void *src, int size) {
|
||||
mbstowcs((wchar_t*)src,(char*)src,size); // BAD
|
||||
_locale_t locale;
|
||||
_mbstowcs_l((wchar_t*)src,(char*)src,size,locale); // BAD
|
||||
mbstate_t *mbstate;
|
||||
mbsrtowcs((wchar_t*)src,(char*)src,size,mbstate); // BAD
|
||||
}
|
||||
void goodTest2(){
|
||||
static void goodTest2(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
wchar_t dst[16];
|
||||
int res = mbstowcs(dst, src,16); // GOOD
|
||||
@@ -29,43 +29,43 @@ void goodTest2(){
|
||||
}
|
||||
printf("%s\n", dst);
|
||||
}
|
||||
void badTest2(){
|
||||
static void badTest2(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
wchar_t dst[16];
|
||||
mbstowcs(dst, src,16); // BAD
|
||||
printf("%s\n", dst);
|
||||
}
|
||||
void goodTest3(){
|
||||
static void goodTest3(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
int size = mbstowcs(NULL, src,NULL);
|
||||
wchar_t * dst = (wchar_t*)calloc(size + 1, sizeof(wchar_t));
|
||||
mbstowcs(dst, src,size+1); // GOOD
|
||||
}
|
||||
void badTest3(){
|
||||
static void badTest3(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
int size = mbstowcs(NULL, src,NULL);
|
||||
wchar_t * dst = (wchar_t*)calloc(size + 1, 1);
|
||||
mbstowcs(dst, src,size+1); // BAD
|
||||
}
|
||||
void goodTest4(){
|
||||
static void goodTest4(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
int size = mbstowcs(NULL, src,NULL);
|
||||
wchar_t * dst = (wchar_t*)malloc((size + 1)*sizeof(wchar_t));
|
||||
mbstowcs(dst, src,size+1); // GOOD
|
||||
}
|
||||
void badTest4(){
|
||||
static void badTest4(){
|
||||
char src[] = "0123456789ABCDEF";
|
||||
int size = mbstowcs(NULL, src,NULL);
|
||||
wchar_t * dst = (wchar_t*)malloc(size + 1);
|
||||
mbstowcs(dst, src,size+1); // BAD
|
||||
}
|
||||
int goodTest5(void *src){
|
||||
static int goodTest5(void *src){
|
||||
return mbstowcs(NULL, (char*)src,NULL); // GOOD
|
||||
}
|
||||
int badTest5 (void *src) {
|
||||
static int badTest5 (void *src) {
|
||||
return mbstowcs(NULL, (char*)src,3); // BAD
|
||||
}
|
||||
void goodTest6(void *src){
|
||||
static void goodTest6(void *src){
|
||||
wchar_t dst[5];
|
||||
int size = mbstowcs(NULL, (char*)src,NULL);
|
||||
if(size>=sizeof(dst)){
|
||||
@@ -75,7 +75,7 @@ void goodTest6(void *src){
|
||||
mbstowcs(dst, (char*)src,sizeof(dst)); // GOOD
|
||||
printf("%s\n", dst);
|
||||
}
|
||||
void badTest6(void *src){
|
||||
static void badTest6(void *src){
|
||||
wchar_t dst[5];
|
||||
mbstowcs(dst, (char*)src,260); // BAD
|
||||
printf("%s\n", dst);
|
||||
|
||||
@@ -9,14 +9,14 @@ void goodTest1(unsigned char *src){
|
||||
unsigned char dst[50];
|
||||
_mbsnbcpy(dst,src,sizeof(dst)); // GOOD
|
||||
}
|
||||
size_t badTest1(unsigned char *src){
|
||||
static size_t badTest1(unsigned char *src){
|
||||
int cb = 0;
|
||||
unsigned char dst[50];
|
||||
while( cb < sizeof(dst) )
|
||||
dst[cb++]=*src++; // BAD
|
||||
return _mbclen(dst);
|
||||
}
|
||||
void goodTest2(unsigned char *src){
|
||||
static void goodTest2(unsigned char *src){
|
||||
|
||||
int cb = 0;
|
||||
unsigned char dst[50];
|
||||
@@ -27,7 +27,7 @@ void goodTest2(unsigned char *src){
|
||||
src=_mbsinc(src);
|
||||
}
|
||||
}
|
||||
void badTest2(unsigned char *src){
|
||||
static void badTest2(unsigned char *src){
|
||||
|
||||
int cb = 0;
|
||||
unsigned char dst[50];
|
||||
@@ -38,11 +38,11 @@ void badTest2(unsigned char *src){
|
||||
src=_mbsinc(src);
|
||||
}
|
||||
}
|
||||
void goodTest3(){
|
||||
static void goodTest3(){
|
||||
wchar_t name[50];
|
||||
name[sizeof(name) / sizeof(*name) - 1] = L'\0'; // GOOD
|
||||
}
|
||||
void badTest3(){
|
||||
static void badTest3(){
|
||||
wchar_t name[50];
|
||||
name[sizeof(name) - 1] = L'\0'; // BAD
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ int* deref(int** p) { // $ ast-def=p ir-def=*p ir-def=**p
|
||||
return q;
|
||||
}
|
||||
|
||||
void test1() {
|
||||
void flowout_test1() {
|
||||
int x = 0;
|
||||
int* p = &x;
|
||||
deref(&p)[0] = source();
|
||||
@@ -95,7 +95,7 @@ void addtaint2(int** p) { // $ ast-def=p ir-def=*p ir-def=**p
|
||||
addtaint1(q);
|
||||
}
|
||||
|
||||
void test2() {
|
||||
void flowout_test2() {
|
||||
int x = 0;
|
||||
int* p = &x;
|
||||
addtaint2(&p);
|
||||
|
||||
@@ -15,7 +15,7 @@ template<> struct std::iterator_traits<unsigned long>
|
||||
};
|
||||
|
||||
|
||||
int test() {
|
||||
int iterator_test() {
|
||||
unsigned long x = source();
|
||||
sink(x); // $ ast ir
|
||||
}
|
||||
@@ -5,7 +5,7 @@ int source();
|
||||
void sink(...);
|
||||
bool random();
|
||||
|
||||
void test1() {
|
||||
void on_entry_test1() {
|
||||
int x = source();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
x = 0;
|
||||
@@ -13,7 +13,7 @@ void test1() {
|
||||
sink(x); // $ SPURIOUS: ir
|
||||
}
|
||||
|
||||
void test2(int iterations) {
|
||||
void on_entry_test2(int iterations) {
|
||||
int x = source();
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
x = 0;
|
||||
@@ -21,7 +21,7 @@ void test2(int iterations) {
|
||||
sink(x); // $ ast,ir
|
||||
}
|
||||
|
||||
void test3() {
|
||||
void on_entry_test3() {
|
||||
int x = 0;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
x = source();
|
||||
@@ -29,7 +29,7 @@ void test3() {
|
||||
sink(x); // $ ast,ir
|
||||
}
|
||||
|
||||
void test4() {
|
||||
void on_entry_test4() {
|
||||
int x = source();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (random())
|
||||
@@ -39,7 +39,7 @@ void test4() {
|
||||
sink(x); // $ ast,ir
|
||||
}
|
||||
|
||||
void test5() {
|
||||
void on_entry_test5() {
|
||||
int x = source();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (random())
|
||||
@@ -49,7 +49,7 @@ void test5() {
|
||||
sink(x); // $ ast,ir
|
||||
}
|
||||
|
||||
void test6() {
|
||||
void on_entry_test6() {
|
||||
int y;
|
||||
int x = source();
|
||||
for (int i = 0; i < 10 && (y = 1); i++) {
|
||||
@@ -57,7 +57,7 @@ void test6() {
|
||||
sink(x); // $ ast,ir
|
||||
}
|
||||
|
||||
void test7() {
|
||||
void on_entry_test7() {
|
||||
int y;
|
||||
int x = source();
|
||||
for (int i = 0; i < 10 && (y = 1); i++) {
|
||||
@@ -66,7 +66,7 @@ void test7() {
|
||||
sink(x); // $ SPURIOUS: ir
|
||||
}
|
||||
|
||||
void test8() {
|
||||
void on_entry_test8() {
|
||||
int x = source();
|
||||
// It appears to the analysis that the condition can exit after `i < 10`
|
||||
// without having assigned to `x`. That is an effect of how the
|
||||
@@ -78,7 +78,7 @@ void test8() {
|
||||
sink(x); // $ SPURIOUS: ast,ir
|
||||
}
|
||||
|
||||
void test9() {
|
||||
void on_entry_test9() {
|
||||
int y;
|
||||
int x = source();
|
||||
for (int i = 0; (y = 1) && i < 10; i++) {
|
||||
@@ -86,14 +86,14 @@ void test9() {
|
||||
sink(x); // $ ast,ir
|
||||
}
|
||||
|
||||
void test10() {
|
||||
void on_entry_test10() {
|
||||
int x = source();
|
||||
for (int i = 0; (x = 1) && i < 10; i++) {
|
||||
}
|
||||
sink(x); // no flow
|
||||
}
|
||||
|
||||
void test10(int b, int d) {
|
||||
void on_entry_test10(int b, int d) {
|
||||
int i = 0;
|
||||
int x = source();
|
||||
if (b)
|
||||
|
||||
@@ -6584,6 +6584,16 @@ WARNING: module 'TaintTracking' has been deprecated and may be removed in future
|
||||
| taint.cpp:767:21:767:24 | ref arg path | taint.cpp:768:8:768:11 | path | |
|
||||
| taint.cpp:768:8:768:11 | path | taint.cpp:768:7:768:11 | * ... | |
|
||||
| taint.cpp:778:37:778:42 | call to source | taint.cpp:779:7:779:9 | obj | |
|
||||
| taint.cpp:785:23:785:28 | source | taint.cpp:785:23:785:28 | source | |
|
||||
| taint.cpp:785:23:785:28 | source | taint.cpp:786:18:786:23 | source | |
|
||||
| taint.cpp:785:23:785:28 | source | taint.cpp:790:15:790:20 | source | |
|
||||
| taint.cpp:786:12:786:16 | call to fopen | taint.cpp:787:7:787:7 | f | |
|
||||
| taint.cpp:786:18:786:23 | source | taint.cpp:786:12:786:16 | call to fopen | TAINT |
|
||||
| taint.cpp:789:8:789:9 | f2 | taint.cpp:790:11:790:12 | f2 | |
|
||||
| taint.cpp:789:8:789:9 | f2 | taint.cpp:791:7:791:8 | f2 | |
|
||||
| taint.cpp:790:10:790:12 | ref arg & ... | taint.cpp:790:11:790:12 | f2 [inner post update] | |
|
||||
| taint.cpp:790:10:790:12 | ref arg & ... | taint.cpp:791:7:791:8 | f2 | |
|
||||
| taint.cpp:790:11:790:12 | f2 | taint.cpp:790:10:790:12 | & ... | |
|
||||
| vector.cpp:16:43:16:49 | source1 | vector.cpp:17:26:17:32 | source1 | |
|
||||
| vector.cpp:16:43:16:49 | source1 | vector.cpp:31:38:31:44 | source1 | |
|
||||
| vector.cpp:17:21:17:33 | call to vector | vector.cpp:19:14:19:14 | v | |
|
||||
|
||||
@@ -777,4 +777,16 @@ TaintInheritingContentObject source(bool);
|
||||
void test_TaintInheritingContent() {
|
||||
TaintInheritingContentObject obj = source(true);
|
||||
sink(obj.flowFromObject); // $ ir MISSING: ast
|
||||
}
|
||||
|
||||
FILE* fopen(const char*, const char*);
|
||||
int fopen_s(FILE** pFile, const char *filename, const char *mode);
|
||||
|
||||
void fopen_test(char* source) {
|
||||
FILE* f = fopen(source, "r");
|
||||
sink(f); // $ ast,ir
|
||||
|
||||
FILE* f2;
|
||||
fopen_s(&f2, source, "r");
|
||||
sink(f2); // $ ast,ir
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
| c.c | library-tests/files/c.c | CFile, MetricFile | C | | |
|
||||
| files1.cpp | library-tests/files/files1.cpp | CppFile, MetricFile | C++ | swap | t |
|
||||
| files1.h | library-tests/files/files1.h | HeaderFile, MetricFile | | swap | |
|
||||
| files2.cpp | library-tests/files/files2.cpp | CppFile, MetricFile | C++ | g | x, y |
|
||||
| c.c | c.c | CFile, MetricFile | C | | |
|
||||
| files1.cpp | files1.cpp | CppFile, MetricFile | C++ | swap | t |
|
||||
| files1.h | files1.h | HeaderFile, MetricFile | | swap | |
|
||||
| files2.cpp | files2.cpp | CppFile, MetricFile | C++ | g | x, y |
|
||||
|
||||
@@ -9055,6 +9055,8 @@ ir.cpp:
|
||||
# 733| Value = [Literal] 7
|
||||
# 733| ValueCategory = prvalue
|
||||
# 735| getChild(1): [Handler] <handler>
|
||||
# 735| getParameter(): [Parameter] s
|
||||
# 735| Type = [PointerType] const char *
|
||||
# 735| getBlock(): [CatchBlock] { ... }
|
||||
# 736| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 736| getExpr(): [ThrowExpr] throw ...
|
||||
@@ -9067,6 +9069,8 @@ ir.cpp:
|
||||
# 736| Type = [PointerType] const char *
|
||||
# 736| ValueCategory = prvalue(load)
|
||||
# 738| getChild(2): [Handler] <handler>
|
||||
# 738| getParameter(): [Parameter] e
|
||||
# 738| Type = [LValueReferenceType] const String &
|
||||
# 738| getBlock(): [CatchBlock] { ... }
|
||||
# 740| getChild(3): [Handler] <handler>
|
||||
# 740| getBlock(): [CatchAnyBlock] { ... }
|
||||
@@ -12852,6 +12856,8 @@ ir.cpp:
|
||||
# 1200| Value = [Literal] 7
|
||||
# 1200| ValueCategory = prvalue
|
||||
# 1202| getChild(1): [Handler] <handler>
|
||||
# 1202| getParameter(): [Parameter] s
|
||||
# 1202| Type = [PointerType] const char *
|
||||
# 1202| getBlock(): [CatchBlock] { ... }
|
||||
# 1203| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 1203| getExpr(): [ThrowExpr] throw ...
|
||||
@@ -12864,6 +12870,8 @@ ir.cpp:
|
||||
# 1203| Type = [PointerType] const char *
|
||||
# 1203| ValueCategory = prvalue(load)
|
||||
# 1205| getChild(2): [Handler] <handler>
|
||||
# 1205| getParameter(): [Parameter] e
|
||||
# 1205| Type = [LValueReferenceType] const String &
|
||||
# 1205| getBlock(): [CatchBlock] { ... }
|
||||
# 1207| getStmt(1): [ReturnStmt] return ...
|
||||
# 1211| [TopLevelFunction] void VectorTypes(int)
|
||||
@@ -20586,6 +20594,8 @@ ir.cpp:
|
||||
# 2281| Type = [Struct] String
|
||||
# 2281| ValueCategory = lvalue
|
||||
# 2282| getChild(1): [Handler] <handler>
|
||||
# 2282| getParameter(): [Parameter] s
|
||||
# 2282| Type = [PointerType] const char *
|
||||
# 2282| getBlock(): [CatchBlock] { ... }
|
||||
# 2283| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 2283| getExpr(): [ThrowExpr] throw ...
|
||||
@@ -20598,6 +20608,8 @@ ir.cpp:
|
||||
# 2283| Type = [PointerType] const char *
|
||||
# 2283| ValueCategory = prvalue(load)
|
||||
# 2285| getChild(2): [Handler] <handler>
|
||||
# 2285| getParameter(): [Parameter] e
|
||||
# 2285| Type = [LValueReferenceType] const String &
|
||||
# 2285| getBlock(): [CatchBlock] { ... }
|
||||
# 2287| getChild(3): [Handler] <handler>
|
||||
# 2287| getBlock(): [CatchAnyBlock] { ... }
|
||||
@@ -22845,6 +22857,8 @@ ir.cpp:
|
||||
# 2537| Value = [Literal] 42
|
||||
# 2537| ValueCategory = prvalue
|
||||
# 2539| getChild(1): [Handler] <handler>
|
||||
# 2539| getParameter(): [Parameter] (unnamed parameter 0)
|
||||
# 2539| Type = [PlainCharType] char
|
||||
# 2539| getBlock(): [CatchBlock] { ... }
|
||||
# 2541| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
|
||||
# 2541| Type = [VoidType] void
|
||||
@@ -23564,6 +23578,42 @@ ir.cpp:
|
||||
# 2686| Value = [CStyleCast] 0
|
||||
# 2686| ValueCategory = prvalue
|
||||
# 2687| getStmt(1): [ReturnStmt] return ...
|
||||
# 2691| [TopLevelFunction] int concepts::requires_use()
|
||||
# 2691| <params>:
|
||||
# 2691| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 2692| getStmt(0): [DeclStmt] declaration
|
||||
# 2692| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y
|
||||
# 2692| Type = [IntType] int
|
||||
# 2692| getVariable().getInitializer(): [Initializer] initializer for y
|
||||
#-----| getExpr(): [RequiresExpr] requires { ... }
|
||||
#-----| Type = [BoolType] bool
|
||||
#-----| Value = [RequiresExpr] 1
|
||||
#-----| ValueCategory = prvalue
|
||||
#-----| <params>:
|
||||
# 2692| getRequirement(0): [GTExpr,SimpleRequirementExpr] ... > ...
|
||||
# 2692| Type = [BoolType] bool
|
||||
# 2692| ValueCategory = prvalue
|
||||
# 2692| getGreaterOperand(): [SizeofTypeOperator] sizeof(int)
|
||||
# 2692| Type = [LongType] unsigned long
|
||||
# 2692| Value = [SizeofTypeOperator] 4
|
||||
# 2692| ValueCategory = prvalue
|
||||
# 2692| getLesserOperand(): [Literal] 0
|
||||
# 2692| Type = [IntType] int
|
||||
# 2692| Value = [Literal] 0
|
||||
# 2692| ValueCategory = prvalue
|
||||
# 2692| getLesserOperand().getFullyConverted(): [CStyleCast] (unsigned long)...
|
||||
# 2692| Conversion = [IntegralConversion] integral conversion
|
||||
# 2692| Type = [LongType] unsigned long
|
||||
# 2692| ValueCategory = prvalue
|
||||
#-----| getExpr().getFullyConverted(): [CStyleCast] (int)...
|
||||
#-----| Conversion = [IntegralConversion] integral conversion
|
||||
#-----| Type = [IntType] int
|
||||
#-----| Value = [CStyleCast] 1
|
||||
#-----| ValueCategory = prvalue
|
||||
# 2693| getStmt(1): [ReturnStmt] return ...
|
||||
# 2693| getExpr(): [VariableAccess] y
|
||||
# 2693| Type = [IntType] int
|
||||
# 2693| ValueCategory = prvalue(load)
|
||||
many-defs-per-use.cpp:
|
||||
# 34| [TopLevelFunction] void many_defs_per_use()
|
||||
# 34| <params>:
|
||||
|
||||
@@ -19099,6 +19099,24 @@ ir.cpp:
|
||||
# 2684| Block 8
|
||||
# 2684| v2684_14(void) = Unreached :
|
||||
|
||||
# 2691| int concepts::requires_use()
|
||||
# 2691| Block 0
|
||||
# 2691| v2691_1(void) = EnterFunction :
|
||||
# 2691| m2691_2(unknown) = AliasedDefinition :
|
||||
# 2691| m2691_3(unknown) = InitializeNonLocal :
|
||||
# 2691| m2691_4(unknown) = Chi : total:m2691_2, partial:m2691_3
|
||||
# 2692| r2692_1(glval<int>) = VariableAddress[y] :
|
||||
#-----| r0_1(int) = Constant[1] :
|
||||
#-----| m0_2(int) = Store[y] : &:r2692_1, r0_1
|
||||
# 2693| r2693_1(glval<int>) = VariableAddress[#return] :
|
||||
# 2693| r2693_2(glval<int>) = VariableAddress[y] :
|
||||
# 2693| r2693_3(int) = Load[y] : &:r2693_2, m0_2
|
||||
# 2693| m2693_4(int) = Store[#return] : &:r2693_1, r2693_3
|
||||
# 2691| r2691_5(glval<int>) = VariableAddress[#return] :
|
||||
# 2691| v2691_6(void) = ReturnValue : &:r2691_5, m2693_4
|
||||
# 2691| v2691_7(void) = AliasedUse : m2691_3
|
||||
# 2691| v2691_8(void) = ExitFunction :
|
||||
|
||||
many-defs-per-use.cpp:
|
||||
# 34| void many_defs_per_use()
|
||||
# 34| Block 0
|
||||
|
||||
@@ -2686,4 +2686,13 @@ void test(bool b)
|
||||
twice_call_use(b ? "" : "");
|
||||
}
|
||||
|
||||
namespace concepts {
|
||||
|
||||
int requires_use() {
|
||||
int y = requires { sizeof(int) > 0; };
|
||||
return y;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// semmle-extractor-options: -std=c++20 --clang
|
||||
|
||||
@@ -17422,6 +17422,23 @@ ir.cpp:
|
||||
# 2684| v2684_7(void) = AliasedUse : ~m?
|
||||
# 2684| v2684_8(void) = ExitFunction :
|
||||
|
||||
# 2691| int concepts::requires_use()
|
||||
# 2691| Block 0
|
||||
# 2691| v2691_1(void) = EnterFunction :
|
||||
# 2691| mu2691_2(unknown) = AliasedDefinition :
|
||||
# 2691| mu2691_3(unknown) = InitializeNonLocal :
|
||||
# 2692| r2692_1(glval<int>) = VariableAddress[y] :
|
||||
#-----| r0_1(int) = Constant[1] :
|
||||
#-----| mu0_2(int) = Store[y] : &:r2692_1, r0_1
|
||||
# 2693| r2693_1(glval<int>) = VariableAddress[#return] :
|
||||
# 2693| r2693_2(glval<int>) = VariableAddress[y] :
|
||||
# 2693| r2693_3(int) = Load[y] : &:r2693_2, ~m?
|
||||
# 2693| mu2693_4(int) = Store[#return] : &:r2693_1, r2693_3
|
||||
# 2691| r2691_4(glval<int>) = VariableAddress[#return] :
|
||||
# 2691| v2691_5(void) = ReturnValue : &:r2691_4, ~m?
|
||||
# 2691| v2691_6(void) = AliasedUse : ~m?
|
||||
# 2691| v2691_7(void) = ExitFunction :
|
||||
|
||||
many-defs-per-use.cpp:
|
||||
# 34| void many_defs_per_use()
|
||||
# 34| Block 0
|
||||
|
||||
@@ -2,25 +2,168 @@
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | false |
|
||||
| file://:0:0:0:0 | __super | false |
|
||||
| file://:0:0:0:0 | __va_list_tag | false |
|
||||
| file://:0:0:0:0 | decltype([...](...){...}) | false |
|
||||
| file://:0:0:0:0 | operator= | false |
|
||||
| file://:0:0:0:0 | operator= | false |
|
||||
| test.cpp:0:0:0:0 | test.cpp | false |
|
||||
| test.cpp:2:1:2:61 | #define FOO class S{int i; void f(void) { int j; return; } }; | false |
|
||||
| test.cpp:2:1:2:68 | #define CLASS_DECL class S{int i; void f(void) { int j; return; } }; | false |
|
||||
| test.cpp:4:1:4:1 | S | false |
|
||||
| test.cpp:4:1:4:1 | declaration of S | false |
|
||||
| test.cpp:4:1:4:1 | declaration of operator= | false |
|
||||
| test.cpp:4:1:4:1 | declaration of operator= | false |
|
||||
| test.cpp:4:1:4:1 | operator= | false |
|
||||
| test.cpp:4:1:4:1 | operator= | false |
|
||||
| test.cpp:4:1:4:3 | FOO | false |
|
||||
| test.cpp:4:1:4:3 | S | false |
|
||||
| test.cpp:4:1:4:3 | declaration | true |
|
||||
| test.cpp:4:1:4:3 | definition of S | true |
|
||||
| test.cpp:4:1:4:3 | definition of f | true |
|
||||
| test.cpp:4:1:4:3 | definition of i | true |
|
||||
| test.cpp:4:1:4:3 | definition of j | true |
|
||||
| test.cpp:4:1:4:3 | f | false |
|
||||
| test.cpp:4:1:4:3 | i | false |
|
||||
| test.cpp:4:1:4:3 | j | true |
|
||||
| test.cpp:4:1:4:3 | return ... | true |
|
||||
| test.cpp:4:1:4:3 | { ... } | true |
|
||||
| test.cpp:4:1:4:10 | CLASS_DECL | false |
|
||||
| test.cpp:4:1:4:10 | S | false |
|
||||
| test.cpp:4:1:4:10 | declaration | true |
|
||||
| test.cpp:4:1:4:10 | definition of S | true |
|
||||
| test.cpp:4:1:4:10 | definition of f | true |
|
||||
| test.cpp:4:1:4:10 | definition of i | true |
|
||||
| test.cpp:4:1:4:10 | definition of j | true |
|
||||
| test.cpp:4:1:4:10 | f | false |
|
||||
| test.cpp:4:1:4:10 | i | false |
|
||||
| test.cpp:4:1:4:10 | j | true |
|
||||
| test.cpp:4:1:4:10 | return ... | true |
|
||||
| test.cpp:4:1:4:10 | { ... } | true |
|
||||
| test.cpp:6:1:6:42 | #define FUNCTION_DECL void f1() { int k; } | false |
|
||||
| test.cpp:8:1:8:13 | FUNCTION_DECL | false |
|
||||
| test.cpp:8:1:8:13 | declaration | true |
|
||||
| test.cpp:8:1:8:13 | definition of f1 | true |
|
||||
| test.cpp:8:1:8:13 | definition of k | true |
|
||||
| test.cpp:8:1:8:13 | f1 | false |
|
||||
| test.cpp:8:1:8:13 | k | true |
|
||||
| test.cpp:8:1:8:13 | return ... | true |
|
||||
| test.cpp:8:1:8:13 | { ... } | true |
|
||||
| test.cpp:10:1:10:33 | #define VARIABLE_DECL int v1 = 1; | false |
|
||||
| test.cpp:12:1:12:13 | 1 | true |
|
||||
| test.cpp:12:1:12:13 | VARIABLE_DECL | false |
|
||||
| test.cpp:12:1:12:13 | definition of v1 | true |
|
||||
| test.cpp:12:1:12:13 | initializer for v1 | true |
|
||||
| test.cpp:12:1:12:13 | v1 | true |
|
||||
| test.cpp:14:1:14:35 | #define TYPE_DECL_1 typedef int t1; | false |
|
||||
| test.cpp:16:1:16:11 | TYPE_DECL_1 | false |
|
||||
| test.cpp:16:1:16:11 | declaration of t1 | true |
|
||||
| test.cpp:16:1:16:11 | t1 | false |
|
||||
| test.cpp:18:1:18:35 | #define TYPE_DECL_2 using t2 = int; | false |
|
||||
| test.cpp:20:1:20:11 | TYPE_DECL_2 | false |
|
||||
| test.cpp:20:1:20:11 | declaration of t2 | true |
|
||||
| test.cpp:20:1:20:11 | t2 | false |
|
||||
| test.cpp:22:1:22:47 | #define NAMESPACE_DECL namespace ns { int v2; } | false |
|
||||
| test.cpp:24:1:24:14 | NAMESPACE_DECL | false |
|
||||
| test.cpp:24:1:24:14 | definition of v2 | true |
|
||||
| test.cpp:24:1:24:14 | ns | false |
|
||||
| test.cpp:24:1:24:14 | ns | false |
|
||||
| test.cpp:24:1:24:14 | v2 | true |
|
||||
| test.cpp:26:1:26:43 | #define USING_NAMESPACE using namespace ns; | false |
|
||||
| test.cpp:28:1:28:34 | #define ENUM_CONSTANT enum_element | false |
|
||||
| test.cpp:30:12:30:21 | definition of enum_class | false |
|
||||
| test.cpp:30:12:30:21 | enum_class | false |
|
||||
| test.cpp:30:25:30:37 | ENUM_CONSTANT | false |
|
||||
| test.cpp:30:25:30:37 | enum_element | false |
|
||||
| test.cpp:32:1:32:41 | #define USING_ENUM using enum enum_class; | false |
|
||||
| test.cpp:34:1:34:10 | USING_ENUM | false |
|
||||
| test.cpp:34:1:34:10 | using enum enum_class | false |
|
||||
| test.cpp:36:1:36:48 | #define STATIC_ASSERT static_assert(1 == 1, ""); | false |
|
||||
| test.cpp:38:1:38:13 | 1 | true |
|
||||
| test.cpp:38:1:38:13 | 1 | true |
|
||||
| test.cpp:38:1:38:13 | ... == ... | true |
|
||||
| test.cpp:38:1:38:13 | STATIC_ASSERT | false |
|
||||
| test.cpp:38:1:38:13 | static_assert(..., "") | false |
|
||||
| test.cpp:40:1:40:42 | #define ATTRIBUTE [[nodiscard("reason1")]] | false |
|
||||
| test.cpp:42:1:42:9 | ATTRIBUTE | false |
|
||||
| test.cpp:42:1:42:9 | nodiscard | false |
|
||||
| test.cpp:42:1:42:9 | reason1 | false |
|
||||
| test.cpp:42:1:42:9 | reason1 | true |
|
||||
| test.cpp:43:5:43:6 | declaration of f2 | false |
|
||||
| test.cpp:43:5:43:6 | f2 | false |
|
||||
| test.cpp:45:1:45:31 | #define ATTRIBUTE_ARG "reason2" | false |
|
||||
| test.cpp:47:3:47:11 | nodiscard | false |
|
||||
| test.cpp:47:13:47:25 | ATTRIBUTE_ARG | false |
|
||||
| test.cpp:47:13:47:25 | reason2 | false |
|
||||
| test.cpp:47:13:47:25 | reason2 | true |
|
||||
| test.cpp:48:5:48:6 | declaration of f3 | false |
|
||||
| test.cpp:48:5:48:6 | f3 | false |
|
||||
| test.cpp:50:1:50:16 | #define TYPE int | false |
|
||||
| test.cpp:52:1:52:4 | TYPE | false |
|
||||
| test.cpp:52:6:52:7 | definition of v3 | true |
|
||||
| test.cpp:52:6:52:7 | v3 | true |
|
||||
| test.cpp:52:11:52:11 | 1 | false |
|
||||
| test.cpp:52:11:52:11 | initializer for v3 | false |
|
||||
| test.cpp:54:1:54:29 | #define DERIVATION : public S | false |
|
||||
| test.cpp:56:7:56:7 | T | false |
|
||||
| test.cpp:56:7:56:7 | T | false |
|
||||
| test.cpp:56:7:56:7 | declaration of T | false |
|
||||
| test.cpp:56:7:56:7 | declaration of operator= | false |
|
||||
| test.cpp:56:7:56:7 | declaration of operator= | false |
|
||||
| test.cpp:56:7:56:7 | definition of T | false |
|
||||
| test.cpp:56:7:56:7 | operator= | false |
|
||||
| test.cpp:56:7:56:7 | operator= | false |
|
||||
| test.cpp:56:9:56:18 | DERIVATION | false |
|
||||
| test.cpp:56:9:56:18 | derivation | false |
|
||||
| test.cpp:58:1:58:31 | #define FRIEND friend int f3(); | false |
|
||||
| test.cpp:60:7:60:7 | U | false |
|
||||
| test.cpp:60:7:60:7 | declaration of operator= | false |
|
||||
| test.cpp:60:7:60:7 | declaration of operator= | false |
|
||||
| test.cpp:60:7:60:7 | definition of U | false |
|
||||
| test.cpp:60:7:60:7 | operator= | false |
|
||||
| test.cpp:60:7:60:7 | operator= | false |
|
||||
| test.cpp:61:3:61:8 | FRIEND | false |
|
||||
| test.cpp:61:3:61:8 | U's friend | false |
|
||||
| test.cpp:64:1:64:24 | #define NAME_QUAL_1 ns:: | false |
|
||||
| test.cpp:66:1:66:22 | #define NAME_QUAL_2 ns | false |
|
||||
| test.cpp:68:1:68:19 | #define LOCAL_VAR m | false |
|
||||
| test.cpp:70:6:70:7 | definition of f4 | false |
|
||||
| test.cpp:70:6:70:7 | f4 | false |
|
||||
| test.cpp:70:11:76:1 | { ... } | false |
|
||||
| test.cpp:71:5:71:8 | ns:: | false |
|
||||
| test.cpp:71:5:71:15 | NAME_QUAL_1 | false |
|
||||
| test.cpp:71:5:71:18 | v2 | false |
|
||||
| test.cpp:71:5:71:19 | ExprStmt | false |
|
||||
| test.cpp:72:5:72:8 | ns:: | false |
|
||||
| test.cpp:72:5:72:15 | NAME_QUAL_2 | false |
|
||||
| test.cpp:72:5:72:21 | v2 | false |
|
||||
| test.cpp:72:5:72:22 | ExprStmt | false |
|
||||
| test.cpp:73:5:73:23 | declaration | false |
|
||||
| test.cpp:73:9:73:17 | LOCAL_VAR | false |
|
||||
| test.cpp:73:9:73:17 | definition of m | true |
|
||||
| test.cpp:73:9:73:17 | m | true |
|
||||
| test.cpp:73:20:73:22 | 42 | false |
|
||||
| test.cpp:73:20:73:22 | initializer for m | false |
|
||||
| test.cpp:74:5:74:41 | declaration | false |
|
||||
| test.cpp:74:10:74:10 | definition of l | false |
|
||||
| test.cpp:74:10:74:10 | l | false |
|
||||
| test.cpp:74:13:74:40 | [...](...){...} | false |
|
||||
| test.cpp:74:13:74:40 | initializer for l | false |
|
||||
| test.cpp:74:13:74:40 | {...} | false |
|
||||
| test.cpp:74:14:74:14 | (unnamed constructor) | false |
|
||||
| test.cpp:74:14:74:14 | (unnamed constructor) | false |
|
||||
| test.cpp:74:14:74:14 | (unnamed constructor) | false |
|
||||
| test.cpp:74:14:74:14 | declaration of (unnamed constructor) | false |
|
||||
| test.cpp:74:14:74:14 | declaration of (unnamed constructor) | false |
|
||||
| test.cpp:74:14:74:14 | definition of (unnamed constructor) | false |
|
||||
| test.cpp:74:14:74:14 | definition of operator= | false |
|
||||
| test.cpp:74:14:74:14 | operator= | false |
|
||||
| test.cpp:74:15:74:15 | definition of m | false |
|
||||
| test.cpp:74:15:74:15 | m | false |
|
||||
| test.cpp:74:15:74:15 | m | false |
|
||||
| test.cpp:74:15:74:23 | LOCAL_VAR | false |
|
||||
| test.cpp:74:15:74:23 | m | true |
|
||||
| test.cpp:74:25:74:25 | definition of operator() | false |
|
||||
| test.cpp:74:25:74:25 | operator() | false |
|
||||
| test.cpp:74:28:74:40 | { ... } | false |
|
||||
| test.cpp:74:30:74:38 | return ... | false |
|
||||
| test.cpp:74:37:74:37 | (int)... | false |
|
||||
| test.cpp:75:5:75:5 | (const lambda [] type at line 74, col. 14)... | false |
|
||||
| test.cpp:75:5:75:5 | l | false |
|
||||
| test.cpp:75:5:75:8 | ExprStmt | false |
|
||||
| test.cpp:75:6:75:6 | call to operator() | false |
|
||||
| test.cpp:76:1:76:1 | return ... | false |
|
||||
| test.cpp:78:1:78:15 | #define ID(x) x | false |
|
||||
| test.cpp:79:1:79:23 | #define NESTED(x) ID(x) | false |
|
||||
| test.cpp:80:5:80:6 | definition of v4 | false |
|
||||
| test.cpp:80:5:80:6 | v4 | false |
|
||||
| test.cpp:80:10:80:18 | ID(x) | false |
|
||||
| test.cpp:80:10:80:18 | NESTED(x) | false |
|
||||
| test.cpp:80:17:80:17 | 1 | true |
|
||||
| test.cpp:80:17:80:17 | initializer for v4 | true |
|
||||
| test.cpp:82:1:82:39 | // semmle-extractor-options: -std=c++20 | false |
|
||||
|
||||
@@ -1,5 +1,82 @@
|
||||
|
||||
#define FOO class S{int i; void f(void) { int j; return; } };
|
||||
#define CLASS_DECL class S{int i; void f(void) { int j; return; } };
|
||||
|
||||
FOO
|
||||
CLASS_DECL
|
||||
|
||||
#define FUNCTION_DECL void f1() { int k; }
|
||||
|
||||
FUNCTION_DECL
|
||||
|
||||
#define VARIABLE_DECL int v1 = 1;
|
||||
|
||||
VARIABLE_DECL
|
||||
|
||||
#define TYPE_DECL_1 typedef int t1;
|
||||
|
||||
TYPE_DECL_1
|
||||
|
||||
#define TYPE_DECL_2 using t2 = int;
|
||||
|
||||
TYPE_DECL_2
|
||||
|
||||
#define NAMESPACE_DECL namespace ns { int v2; }
|
||||
|
||||
NAMESPACE_DECL
|
||||
|
||||
#define USING_NAMESPACE using namespace ns;
|
||||
|
||||
#define ENUM_CONSTANT enum_element
|
||||
|
||||
enum class enum_class { ENUM_CONSTANT };
|
||||
|
||||
#define USING_ENUM using enum enum_class;
|
||||
|
||||
USING_ENUM
|
||||
|
||||
#define STATIC_ASSERT static_assert(1 == 1, "");
|
||||
|
||||
STATIC_ASSERT
|
||||
|
||||
#define ATTRIBUTE [[nodiscard("reason1")]]
|
||||
|
||||
ATTRIBUTE
|
||||
int f2();
|
||||
|
||||
#define ATTRIBUTE_ARG "reason2"
|
||||
|
||||
[[nodiscard(ATTRIBUTE_ARG)]]
|
||||
int f3();
|
||||
|
||||
#define TYPE int
|
||||
|
||||
TYPE v3 = 1;
|
||||
|
||||
#define DERIVATION : public S
|
||||
|
||||
class T DERIVATION {};
|
||||
|
||||
#define FRIEND friend int f3();
|
||||
|
||||
class U {
|
||||
FRIEND
|
||||
};
|
||||
|
||||
#define NAME_QUAL_1 ns::
|
||||
|
||||
#define NAME_QUAL_2 ns
|
||||
|
||||
#define LOCAL_VAR m
|
||||
|
||||
void f4() {
|
||||
NAME_QUAL_1 v2;
|
||||
NAME_QUAL_2 :: v2;
|
||||
int LOCAL_VAR = 42;
|
||||
auto l = [LOCAL_VAR]() { return m; };
|
||||
l();
|
||||
}
|
||||
|
||||
#define ID(x) x
|
||||
#define NESTED(x) ID(x)
|
||||
int v4 = NESTED(1);
|
||||
|
||||
// semmle-extractor-options: -std=c++20
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
| containserror.cpp:0:0:0:0 | containserror.cpp | query-tests/Diagnostics/containserror.cpp | fromSource, normalTermination |
|
||||
| containswarning.cpp:0:0:0:0 | containswarning.cpp | query-tests/Diagnostics/containswarning.cpp | fromSource, normalTermination |
|
||||
| doesnotcompile.cpp:0:0:0:0 | doesnotcompile.cpp | query-tests/Diagnostics/doesnotcompile.cpp | ExtractionProblem (severity 1), fromSource, normalTermination |
|
||||
| containserror.cpp:0:0:0:0 | containserror.cpp | containserror.cpp | fromSource, normalTermination |
|
||||
| containswarning.cpp:0:0:0:0 | containswarning.cpp | containswarning.cpp | fromSource, normalTermination |
|
||||
| doesnotcompile.cpp:0:0:0:0 | doesnotcompile.cpp | doesnotcompile.cpp | ExtractionProblem (severity 1), fromSource, normalTermination |
|
||||
| file://:0:0:0:0 | | | |
|
||||
| header.h:0:0:0:0 | header.h | query-tests/Diagnostics/header.h | fromSource |
|
||||
| successful.cpp:0:0:0:0 | successful.cpp | query-tests/Diagnostics/successful.cpp | fromSource, normalTermination |
|
||||
| header.h:0:0:0:0 | header.h | header.h | fromSource |
|
||||
| successful.cpp:0:0:0:0 | successful.cpp | successful.cpp | fromSource, normalTermination |
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
| comment_prototypes.c:29:6:29:11 | proto6 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:9:5:9:10 | call to proto6 | query-tests/Documentation/DocumentApi/comment_prototypes_caller1.c |
|
||||
| comment_prototypes.c:29:6:29:11 | proto6 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:9:5:9:10 | call to proto6 | query-tests/Documentation/DocumentApi/comment_prototypes_caller2.c |
|
||||
| comment_prototypes.c:34:6:34:11 | proto7 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:10:5:10:10 | call to proto7 | query-tests/Documentation/DocumentApi/comment_prototypes_caller1.c |
|
||||
| comment_prototypes.c:34:6:34:11 | proto7 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:10:5:10:10 | call to proto7 | query-tests/Documentation/DocumentApi/comment_prototypes_caller2.c |
|
||||
| comment_prototypes.c:45:6:45:11 | proto9 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:12:5:12:10 | call to proto9 | query-tests/Documentation/DocumentApi/comment_prototypes_caller1.c |
|
||||
| comment_prototypes.c:45:6:45:11 | proto9 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:12:5:12:10 | call to proto9 | query-tests/Documentation/DocumentApi/comment_prototypes_caller2.c |
|
||||
| comment_prototypes.c:50:6:50:12 | proto10 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:13:5:13:11 | call to proto10 | query-tests/Documentation/DocumentApi/comment_prototypes_caller1.c |
|
||||
| comment_prototypes.c:50:6:50:12 | proto10 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:13:5:13:11 | call to proto10 | query-tests/Documentation/DocumentApi/comment_prototypes_caller2.c |
|
||||
| comment_prototypes.c:55:6:55:12 | proto11 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:14:5:14:11 | call to proto11 | query-tests/Documentation/DocumentApi/comment_prototypes_caller1.c |
|
||||
| comment_prototypes.c:55:6:55:12 | proto11 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:14:5:14:11 | call to proto11 | query-tests/Documentation/DocumentApi/comment_prototypes_caller2.c |
|
||||
| comment_prototypes.c:66:6:66:12 | proto13 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:16:5:16:11 | call to proto13 | query-tests/Documentation/DocumentApi/comment_prototypes_caller1.c |
|
||||
| comment_prototypes.c:66:6:66:12 | proto13 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:16:5:16:11 | call to proto13 | query-tests/Documentation/DocumentApi/comment_prototypes_caller2.c |
|
||||
| definition.c:2:6:2:7 | f1 | Functions called from other files should be documented (called from $@). | user1.c:9:5:9:6 | call to f1 | query-tests/Documentation/DocumentApi/user1.c |
|
||||
| definition.c:2:6:2:7 | f1 | Functions called from other files should be documented (called from $@). | user2.c:7:5:7:6 | call to f1 | query-tests/Documentation/DocumentApi/user2.c |
|
||||
| definition.c:32:6:32:7 | f6 | Functions called from other files should be documented (called from $@). | user1.c:14:5:14:6 | call to f6 | query-tests/Documentation/DocumentApi/user1.c |
|
||||
| definition.c:32:6:32:7 | f6 | Functions called from other files should be documented (called from $@). | user2.c:10:5:10:6 | call to f6 | query-tests/Documentation/DocumentApi/user2.c |
|
||||
| comment_prototypes.c:29:6:29:11 | proto6 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:9:5:9:10 | call to proto6 | comment_prototypes_caller1.c |
|
||||
| comment_prototypes.c:29:6:29:11 | proto6 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:9:5:9:10 | call to proto6 | comment_prototypes_caller2.c |
|
||||
| comment_prototypes.c:34:6:34:11 | proto7 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:10:5:10:10 | call to proto7 | comment_prototypes_caller1.c |
|
||||
| comment_prototypes.c:34:6:34:11 | proto7 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:10:5:10:10 | call to proto7 | comment_prototypes_caller2.c |
|
||||
| comment_prototypes.c:45:6:45:11 | proto9 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:12:5:12:10 | call to proto9 | comment_prototypes_caller1.c |
|
||||
| comment_prototypes.c:45:6:45:11 | proto9 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:12:5:12:10 | call to proto9 | comment_prototypes_caller2.c |
|
||||
| comment_prototypes.c:50:6:50:12 | proto10 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:13:5:13:11 | call to proto10 | comment_prototypes_caller1.c |
|
||||
| comment_prototypes.c:50:6:50:12 | proto10 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:13:5:13:11 | call to proto10 | comment_prototypes_caller2.c |
|
||||
| comment_prototypes.c:55:6:55:12 | proto11 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:14:5:14:11 | call to proto11 | comment_prototypes_caller1.c |
|
||||
| comment_prototypes.c:55:6:55:12 | proto11 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:14:5:14:11 | call to proto11 | comment_prototypes_caller2.c |
|
||||
| comment_prototypes.c:66:6:66:12 | proto13 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller1.c:16:5:16:11 | call to proto13 | comment_prototypes_caller1.c |
|
||||
| comment_prototypes.c:66:6:66:12 | proto13 | Functions called from other files should be documented (called from $@). | comment_prototypes_caller2.c:16:5:16:11 | call to proto13 | comment_prototypes_caller2.c |
|
||||
| definition.c:2:6:2:7 | f1 | Functions called from other files should be documented (called from $@). | user1.c:9:5:9:6 | call to f1 | user1.c |
|
||||
| definition.c:2:6:2:7 | f1 | Functions called from other files should be documented (called from $@). | user2.c:7:5:7:6 | call to f1 | user2.c |
|
||||
| definition.c:32:6:32:7 | f6 | Functions called from other files should be documented (called from $@). | user1.c:14:5:14:6 | call to f6 | user1.c |
|
||||
| definition.c:32:6:32:7 | f6 | Functions called from other files should be documented (called from $@). | user2.c:10:5:10:6 | call to f6 | user2.c |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
| /query-tests/Metrics/Dependencies/main.cpp<\|>LibC<\|>unknown | 5 |
|
||||
| /query-tests/Metrics/Dependencies/include.h<\|>LibD<\|>unknown | 1 |
|
||||
| /query-tests/Metrics/Dependencies/main.cpp<\|>LibA<\|>unknown | 1 |
|
||||
| /query-tests/Metrics/Dependencies/main.cpp<\|>LibB<\|>unknown | 1 |
|
||||
| /main.cpp<\|>LibC<\|>unknown | 5 |
|
||||
| /include.h<\|>LibD<\|>unknown | 1 |
|
||||
| /main.cpp<\|>LibA<\|>unknown | 1 |
|
||||
| /main.cpp<\|>LibB<\|>unknown | 1 |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
| /query-tests/Metrics/Dependencies/include.h<\|>LibD<\|>unknown | include.h:0:0:0:0 | include.h |
|
||||
| /query-tests/Metrics/Dependencies/main.cpp<\|>LibA<\|>unknown | main.cpp:0:0:0:0 | main.cpp |
|
||||
| /query-tests/Metrics/Dependencies/main.cpp<\|>LibB<\|>unknown | main.cpp:0:0:0:0 | main.cpp |
|
||||
| /query-tests/Metrics/Dependencies/main.cpp<\|>LibC<\|>unknown | main.cpp:0:0:0:0 | main.cpp |
|
||||
| /include.h<\|>LibD<\|>unknown | include.h:0:0:0:0 | include.h |
|
||||
| /main.cpp<\|>LibA<\|>unknown | main.cpp:0:0:0:0 | main.cpp |
|
||||
| /main.cpp<\|>LibB<\|>unknown | main.cpp:0:0:0:0 | main.cpp |
|
||||
| /main.cpp<\|>LibC<\|>unknown | main.cpp:0:0:0:0 | main.cpp |
|
||||
|
||||
@@ -2,29 +2,36 @@ edges
|
||||
| test1.c:7:26:7:29 | **argv | test1.c:8:11:8:14 | call to atoi | provenance | TaintFunction |
|
||||
| test1.c:8:11:8:14 | call to atoi | test1.c:9:9:9:9 | i | provenance | |
|
||||
| test1.c:8:11:8:14 | call to atoi | test1.c:11:9:11:9 | i | provenance | |
|
||||
| test1.c:8:11:8:14 | call to atoi | test1.c:12:9:12:9 | i | provenance | |
|
||||
| test1.c:8:11:8:14 | call to atoi | test1.c:13:9:13:9 | i | provenance | |
|
||||
| test1.c:9:9:9:9 | i | test1.c:16:16:16:16 | i | provenance | |
|
||||
| test1.c:11:9:11:9 | i | test1.c:32:16:32:16 | i | provenance | |
|
||||
| test1.c:13:9:13:9 | i | test1.c:48:16:48:16 | i | provenance | |
|
||||
| test1.c:16:16:16:16 | i | test1.c:18:16:18:16 | i | provenance | |
|
||||
| test1.c:32:16:32:16 | i | test1.c:33:11:33:11 | i | provenance | |
|
||||
| test1.c:48:16:48:16 | i | test1.c:51:3:51:7 | ... = ... | provenance | |
|
||||
| test1.c:51:3:51:7 | ... = ... | test1.c:53:15:53:15 | j | provenance | |
|
||||
| test1.c:9:9:9:9 | i | test1.c:18:16:18:16 | i | provenance | |
|
||||
| test1.c:11:9:11:9 | i | test1.c:34:16:34:16 | i | provenance | |
|
||||
| test1.c:12:9:12:9 | i | test1.c:42:16:42:16 | i | provenance | |
|
||||
| test1.c:13:9:13:9 | i | test1.c:50:16:50:16 | i | provenance | |
|
||||
| test1.c:18:16:18:16 | i | test1.c:20:16:20:16 | i | provenance | |
|
||||
| test1.c:34:16:34:16 | i | test1.c:35:11:35:11 | i | provenance | |
|
||||
| test1.c:42:16:42:16 | i | test1.c:43:11:43:11 | i | provenance | |
|
||||
| test1.c:50:16:50:16 | i | test1.c:53:3:53:7 | ... = ... | provenance | |
|
||||
| test1.c:53:3:53:7 | ... = ... | test1.c:55:15:55:15 | j | provenance | |
|
||||
nodes
|
||||
| test1.c:7:26:7:29 | **argv | semmle.label | **argv |
|
||||
| test1.c:8:11:8:14 | call to atoi | semmle.label | call to atoi |
|
||||
| test1.c:9:9:9:9 | i | semmle.label | i |
|
||||
| test1.c:11:9:11:9 | i | semmle.label | i |
|
||||
| test1.c:12:9:12:9 | i | semmle.label | i |
|
||||
| test1.c:13:9:13:9 | i | semmle.label | i |
|
||||
| test1.c:16:16:16:16 | i | semmle.label | i |
|
||||
| test1.c:18:16:18:16 | i | semmle.label | i |
|
||||
| test1.c:32:16:32:16 | i | semmle.label | i |
|
||||
| test1.c:33:11:33:11 | i | semmle.label | i |
|
||||
| test1.c:48:16:48:16 | i | semmle.label | i |
|
||||
| test1.c:51:3:51:7 | ... = ... | semmle.label | ... = ... |
|
||||
| test1.c:53:15:53:15 | j | semmle.label | j |
|
||||
| test1.c:20:16:20:16 | i | semmle.label | i |
|
||||
| test1.c:34:16:34:16 | i | semmle.label | i |
|
||||
| test1.c:35:11:35:11 | i | semmle.label | i |
|
||||
| test1.c:42:16:42:16 | i | semmle.label | i |
|
||||
| test1.c:43:11:43:11 | i | semmle.label | i |
|
||||
| test1.c:50:16:50:16 | i | semmle.label | i |
|
||||
| test1.c:53:3:53:7 | ... = ... | semmle.label | ... = ... |
|
||||
| test1.c:55:15:55:15 | j | semmle.label | j |
|
||||
subpaths
|
||||
#select
|
||||
| test1.c:18:16:18:16 | i | test1.c:7:26:7:29 | **argv | test1.c:18:16:18:16 | i | An array indexing expression depends on $@ that might be outside the bounds of the array. | test1.c:7:26:7:29 | **argv | a command-line argument |
|
||||
| test1.c:33:11:33:11 | i | test1.c:7:26:7:29 | **argv | test1.c:33:11:33:11 | i | An array indexing expression depends on $@ that might be outside the bounds of the array. | test1.c:7:26:7:29 | **argv | a command-line argument |
|
||||
| test1.c:53:15:53:15 | j | test1.c:7:26:7:29 | **argv | test1.c:53:15:53:15 | j | An array indexing expression depends on $@ that might be outside the bounds of the array. | test1.c:7:26:7:29 | **argv | a command-line argument |
|
||||
| test1.c:20:16:20:16 | i | test1.c:7:26:7:29 | **argv | test1.c:20:16:20:16 | i | An array indexing expression depends on $@ that might be outside the bounds of the array. | test1.c:7:26:7:29 | **argv | a command-line argument |
|
||||
| test1.c:35:11:35:11 | i | test1.c:7:26:7:29 | **argv | test1.c:35:11:35:11 | i | An array indexing expression depends on $@ that might be outside the bounds of the array. | test1.c:7:26:7:29 | **argv | a command-line argument |
|
||||
| test1.c:43:11:43:11 | i | test1.c:7:26:7:29 | **argv | test1.c:43:11:43:11 | i | An array indexing expression depends on $@ that might be outside the bounds of the array. | test1.c:7:26:7:29 | **argv | a command-line argument |
|
||||
| test1.c:55:15:55:15 | j | test1.c:7:26:7:29 | **argv | test1.c:55:15:55:15 | j | An array indexing expression depends on $@ that might be outside the bounds of the array. | test1.c:7:26:7:29 | **argv | a command-line argument |
|
||||
|
||||
@@ -11,6 +11,8 @@ int main(int argc, char *argv[]) {
|
||||
test3(i);
|
||||
test4(i);
|
||||
test5(i);
|
||||
test6(i);
|
||||
test7(argv[1]);
|
||||
}
|
||||
|
||||
void test1(int i) {
|
||||
@@ -38,7 +40,7 @@ void test3(int i) {
|
||||
}
|
||||
|
||||
void test4(int i) {
|
||||
myArray[i] = 0; // BAD: i has not been validated [NOT REPORTED]
|
||||
myArray[i] = 0; // BAD: i has not been validated
|
||||
|
||||
if ((i < 0) || (i >= 10)) return;
|
||||
|
||||
@@ -52,3 +54,26 @@ void test5(int i) {
|
||||
|
||||
j = myArray[j]; // BAD: j has not been validated
|
||||
}
|
||||
|
||||
extern int myTable[256];
|
||||
|
||||
void test6(int i) {
|
||||
unsigned char s = i;
|
||||
|
||||
myTable[s] = 0; // GOOD: Input is small [FALSE POSITIVE]
|
||||
}
|
||||
|
||||
typedef void FILE;
|
||||
#define EOF (-1)
|
||||
|
||||
int getc(FILE*);
|
||||
|
||||
extern int myMaxCharTable[256];
|
||||
|
||||
void test7(FILE* fp) {
|
||||
int ch;
|
||||
while ((ch = getc(fp)) != EOF) {
|
||||
myMaxCharTable[ch] = 0; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,14 +11,14 @@ char *strcpy(char *s1, const char *s2);
|
||||
|
||||
//// Test code /////
|
||||
|
||||
void bad0(char *str) {
|
||||
static void bad0(char *str) {
|
||||
// BAD -- Not allocating space for '\0' terminator
|
||||
char *buffer = malloc(strlen(str));
|
||||
strcpy(buffer, str);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void good0(char *str) {
|
||||
static void good0(char *str) {
|
||||
// GOOD -- Allocating extra byte for terminator
|
||||
char *buffer = malloc(strlen(str)+1);
|
||||
strcpy(buffer, str);
|
||||
@@ -26,7 +26,7 @@ void good0(char *str) {
|
||||
}
|
||||
|
||||
|
||||
void bad1(char *str) {
|
||||
static void bad1(char *str) {
|
||||
int len = strlen(str);
|
||||
// BAD -- Not allocating space for '\0' terminator
|
||||
char *buffer = malloc(len);
|
||||
@@ -34,7 +34,7 @@ void bad1(char *str) {
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void good1(char *str) {
|
||||
static void good1(char *str) {
|
||||
int len = strlen(str);
|
||||
// GOOD -- Allocating extra byte for terminator
|
||||
char *buffer = malloc(len+1);
|
||||
@@ -43,7 +43,7 @@ void good1(char *str) {
|
||||
}
|
||||
|
||||
|
||||
void bad2(char *str) {
|
||||
static void bad2(char *str) {
|
||||
int len = strlen(str);
|
||||
// BAD -- Not allocating space for '\0' terminator
|
||||
char *buffer = malloc(len);
|
||||
@@ -51,7 +51,7 @@ void bad2(char *str) {
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void good2(char *str) {
|
||||
static void good2(char *str) {
|
||||
int len = strlen(str)+1;
|
||||
// GOOD -- Allocating extra byte for terminator
|
||||
char *buffer = malloc(len);
|
||||
@@ -59,14 +59,14 @@ void good2(char *str) {
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void bad3(char *str) {
|
||||
static void bad3(char *str) {
|
||||
// BAD -- Not allocating space for '\0' terminator
|
||||
char *buffer = malloc(strlen(str) * sizeof(char));
|
||||
strcpy(buffer, str);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void good3(char *str) {
|
||||
static void good3(char *str) {
|
||||
// GOOD -- Allocating extra byte for terminator
|
||||
char *buffer = malloc((strlen(str) + 1) * sizeof(char));
|
||||
strcpy(buffer, str);
|
||||
@@ -75,7 +75,7 @@ void good3(char *str) {
|
||||
|
||||
void *memcpy(void *s1, const void *s2, size_t n);
|
||||
|
||||
void good4(char *str) {
|
||||
static void good4(char *str) {
|
||||
// GOOD -- allocating a non zero-terminated string
|
||||
int len = strlen(str);
|
||||
char *buffer = malloc(len);
|
||||
|
||||
@@ -19,28 +19,28 @@ int strcmp(const char *s1, const char *s2);
|
||||
|
||||
//// Test code /////
|
||||
|
||||
void bad1(wchar_t *wstr) {
|
||||
static void bad1(wchar_t *wstr) {
|
||||
// BAD -- Not allocating space for '\0' terminator
|
||||
wchar_t *wbuffer = (wchar_t *)malloc(wcslen(wstr));
|
||||
wcscpy(wbuffer, wstr);
|
||||
free(wbuffer);
|
||||
}
|
||||
|
||||
void bad2(wchar_t *wstr) {
|
||||
static void bad2(wchar_t *wstr) {
|
||||
// BAD -- Not allocating space for '\0' terminator
|
||||
wchar_t *wbuffer = (wchar_t *)malloc(wcslen(wstr) * sizeof(wchar_t));
|
||||
wcscpy(wbuffer, wstr);
|
||||
free(wbuffer);
|
||||
}
|
||||
|
||||
void good1(wchar_t *wstr) {
|
||||
static void good1(wchar_t *wstr) {
|
||||
// GOOD -- Allocating extra character for terminator
|
||||
wchar_t *wbuffer = (wchar_t *)malloc((wcslen(wstr) + 1) * sizeof(wchar_t));
|
||||
wcscpy(wbuffer, wstr);
|
||||
free(wbuffer);
|
||||
}
|
||||
|
||||
void bad3(char *str) {
|
||||
static void bad3(char *str) {
|
||||
// BAD -- zero-termination proved by sprintf (as destination)
|
||||
char *buffer = (char *)malloc(strlen(str));
|
||||
sprintf(buffer, "%s", str);
|
||||
@@ -50,7 +50,7 @@ void bad3(char *str) {
|
||||
void decode(char *dest, char *src);
|
||||
void wdecode(wchar_t *dest, wchar_t *src);
|
||||
|
||||
void bad4(char *str) {
|
||||
static void bad4(char *str) {
|
||||
// BAD -- zero-termination proved by wprintf (as parameter)
|
||||
char *buffer = (char *)malloc(strlen(str));
|
||||
decode(buffer, str);
|
||||
@@ -58,7 +58,7 @@ void bad4(char *str) {
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void bad5(char *str) {
|
||||
static void bad5(char *str) {
|
||||
// BAD -- zero-termination proved by strcat (as destination)
|
||||
char *buffer = (char *)malloc(strlen(str));
|
||||
buffer[0] = 0;
|
||||
@@ -66,7 +66,7 @@ void bad5(char *str) {
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void bad6(char *str, char *dest) {
|
||||
static void bad6(char *str, char *dest) {
|
||||
// BAD -- zero-termination proved by strcat (as source)
|
||||
char *buffer = (char *)malloc(strlen(str));
|
||||
decode(buffer, str);
|
||||
@@ -74,7 +74,7 @@ void bad6(char *str, char *dest) {
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void bad7(char *str, char *str2) {
|
||||
static void bad7(char *str, char *str2) {
|
||||
// BAD -- zero-termination proved by strcmp
|
||||
char *buffer = (char *)malloc(strlen(str));
|
||||
decode(buffer, str);
|
||||
@@ -84,7 +84,7 @@ void bad7(char *str, char *str2) {
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void bad8(wchar_t *str) {
|
||||
static void bad8(wchar_t *str) {
|
||||
// BAD -- zero-termination proved by wcslen
|
||||
wchar_t *wbuffer = (wchar_t *)malloc(wcslen(str));
|
||||
wdecode(wbuffer, str);
|
||||
@@ -94,21 +94,21 @@ void bad8(wchar_t *str) {
|
||||
free(wbuffer);
|
||||
}
|
||||
|
||||
void good2(char *str, char *dest) {
|
||||
static void good2(char *str, char *dest) {
|
||||
// GOOD -- zero-termination not proven
|
||||
char *buffer = (char *)malloc(strlen(str));
|
||||
decode(buffer, str);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void bad9(wchar_t *wstr) {
|
||||
static void bad9(wchar_t *wstr) {
|
||||
// BAD -- using new
|
||||
wchar_t *wbuffer = new wchar_t[wcslen(wstr)];
|
||||
wcscpy(wbuffer, wstr);
|
||||
delete wbuffer;
|
||||
}
|
||||
|
||||
void good3(char *str) {
|
||||
static void good3(char *str) {
|
||||
// GOOD -- zero-termination not required for this printf
|
||||
char *buffer = (char *)malloc(strlen(str));
|
||||
decode(buffer, str);
|
||||
@@ -116,7 +116,7 @@ void good3(char *str) {
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void good4(char *str) {
|
||||
static void good4(char *str) {
|
||||
// GOOD -- zero-termination not required for this printf
|
||||
char *buffer = (char *)malloc(strlen(str));
|
||||
decode(buffer, str);
|
||||
|
||||
@@ -38,35 +38,35 @@ namespace std
|
||||
|
||||
//// Test code /////
|
||||
|
||||
void bad1(char *str) {
|
||||
static void bad1(char *str) {
|
||||
// BAD -- Not allocating space for '\0' terminator [NOT DETECTED]
|
||||
char *buffer = (char *)malloc(strlen(str));
|
||||
std::string str2(buffer);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void good1(char *str) {
|
||||
static void good1(char *str) {
|
||||
// GOOD --- copy does not overrun due to size limit
|
||||
char *buffer = (char *)malloc(strlen(str));
|
||||
std::string str2(buffer, strlen(str));
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void bad2(wchar_t *str) {
|
||||
static void bad2(wchar_t *str) {
|
||||
// BAD -- Not allocating space for '\0' terminator [NOT DETECTED]
|
||||
wchar_t *buffer = (wchar_t *)calloc(wcslen(str), sizeof(wchar_t));
|
||||
wcscpy(buffer, str);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void bad3(wchar_t *str) {
|
||||
static void bad3(wchar_t *str) {
|
||||
// BAD -- Not allocating space for '\0' terminator
|
||||
wchar_t *buffer = (wchar_t *)calloc(sizeof(wchar_t), wcslen(str));
|
||||
wcscpy(buffer, str);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void bad4(char *str) {
|
||||
static void bad4(char *str) {
|
||||
// BAD -- Not allocating space for '\0' terminator
|
||||
char *buffer = (char *)realloc(0, strlen(str));
|
||||
strcpy(buffer, str);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
edges
|
||||
| main.cpp:7:27:7:30 | **argv | main.cpp:8:17:8:20 | **argv | provenance | |
|
||||
| main.cpp:8:17:8:20 | **argv | test.c:10:28:10:31 | **argv | provenance | |
|
||||
| test2.cpp:12:21:12:21 | v | test2.cpp:14:11:14:11 | v | provenance | |
|
||||
| test2.cpp:25:22:25:23 | fscanf output argument | test2.cpp:27:13:27:13 | v | provenance | |
|
||||
| test2.cpp:27:13:27:13 | v | test2.cpp:12:21:12:21 | v | provenance | |
|
||||
@@ -6,18 +8,15 @@ edges
|
||||
| test2.cpp:38:13:38:16 | call to atoi | test2.cpp:39:3:39:18 | ... = ... | provenance | |
|
||||
| test2.cpp:38:13:38:16 | call to atoi | test2.cpp:39:9:39:11 | num | provenance | |
|
||||
| test2.cpp:39:3:39:18 | ... = ... | test2.cpp:40:3:40:5 | num | provenance | |
|
||||
| test3.c:10:27:10:30 | **argv | test.c:11:24:11:27 | call to atoi | provenance | TaintFunction |
|
||||
| test3.c:10:27:10:30 | **argv | test.c:41:5:41:24 | ... = ... | provenance | TaintFunction |
|
||||
| test3.c:10:27:10:30 | **argv | test.c:51:5:51:24 | ... = ... | provenance | TaintFunction |
|
||||
| test5.cpp:5:5:5:17 | *getTaintedInt | test5.cpp:17:6:17:18 | call to getTaintedInt | provenance | |
|
||||
| test5.cpp:5:5:5:17 | *getTaintedInt | test5.cpp:18:6:18:18 | call to getTaintedInt | provenance | |
|
||||
| test5.cpp:9:7:9:9 | gets output argument | test5.cpp:10:9:10:27 | call to strtoul | provenance | TaintFunction |
|
||||
| test5.cpp:10:9:10:27 | call to strtoul | test5.cpp:5:5:5:17 | *getTaintedInt | provenance | |
|
||||
| test5.cpp:18:2:18:20 | ... = ... | test5.cpp:19:6:19:6 | y | provenance | |
|
||||
| test5.cpp:18:6:18:18 | call to getTaintedInt | test5.cpp:18:2:18:20 | ... = ... | provenance | |
|
||||
| test.c:10:27:10:30 | **argv | test.c:11:24:11:27 | call to atoi | provenance | TaintFunction |
|
||||
| test.c:10:27:10:30 | **argv | test.c:41:5:41:24 | ... = ... | provenance | TaintFunction |
|
||||
| test.c:10:27:10:30 | **argv | test.c:51:5:51:24 | ... = ... | provenance | TaintFunction |
|
||||
| test.c:10:28:10:31 | **argv | test.c:11:24:11:27 | call to atoi | provenance | TaintFunction |
|
||||
| test.c:10:28:10:31 | **argv | test.c:41:5:41:24 | ... = ... | provenance | TaintFunction |
|
||||
| test.c:10:28:10:31 | **argv | test.c:51:5:51:24 | ... = ... | provenance | TaintFunction |
|
||||
| test.c:11:24:11:27 | call to atoi | test.c:14:15:14:28 | maxConnections | provenance | |
|
||||
| test.c:41:5:41:24 | ... = ... | test.c:44:7:44:10 | len2 | provenance | |
|
||||
| test.c:41:5:41:24 | ... = ... | test.c:44:7:44:12 | ... -- | provenance | |
|
||||
@@ -26,6 +25,8 @@ edges
|
||||
| test.c:51:5:51:24 | ... = ... | test.c:54:7:54:12 | ... -- | provenance | |
|
||||
| test.c:54:7:54:12 | ... -- | test.c:54:7:54:10 | len3 | provenance | |
|
||||
nodes
|
||||
| main.cpp:7:27:7:30 | **argv | semmle.label | **argv |
|
||||
| main.cpp:8:17:8:20 | **argv | semmle.label | **argv |
|
||||
| test2.cpp:12:21:12:21 | v | semmle.label | v |
|
||||
| test2.cpp:14:11:14:11 | v | semmle.label | v |
|
||||
| test2.cpp:25:22:25:23 | fscanf output argument | semmle.label | fscanf output argument |
|
||||
@@ -35,7 +36,6 @@ nodes
|
||||
| test2.cpp:39:3:39:18 | ... = ... | semmle.label | ... = ... |
|
||||
| test2.cpp:39:9:39:11 | num | semmle.label | num |
|
||||
| test2.cpp:40:3:40:5 | num | semmle.label | num |
|
||||
| test3.c:10:27:10:30 | **argv | semmle.label | **argv |
|
||||
| test5.cpp:5:5:5:17 | *getTaintedInt | semmle.label | *getTaintedInt |
|
||||
| test5.cpp:9:7:9:9 | gets output argument | semmle.label | gets output argument |
|
||||
| test5.cpp:10:9:10:27 | call to strtoul | semmle.label | call to strtoul |
|
||||
@@ -43,7 +43,7 @@ nodes
|
||||
| test5.cpp:18:2:18:20 | ... = ... | semmle.label | ... = ... |
|
||||
| test5.cpp:18:6:18:18 | call to getTaintedInt | semmle.label | call to getTaintedInt |
|
||||
| test5.cpp:19:6:19:6 | y | semmle.label | y |
|
||||
| test.c:10:27:10:30 | **argv | semmle.label | **argv |
|
||||
| test.c:10:28:10:31 | **argv | semmle.label | **argv |
|
||||
| test.c:11:24:11:27 | call to atoi | semmle.label | call to atoi |
|
||||
| test.c:14:15:14:28 | maxConnections | semmle.label | maxConnections |
|
||||
| test.c:41:5:41:24 | ... = ... | semmle.label | ... = ... |
|
||||
@@ -61,19 +61,7 @@ subpaths
|
||||
| test5.cpp:17:6:17:18 | call to getTaintedInt | test5.cpp:9:7:9:9 | gets output argument | test5.cpp:17:6:17:18 | call to getTaintedInt | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets |
|
||||
| test5.cpp:19:6:19:6 | y | test5.cpp:9:7:9:9 | gets output argument | test5.cpp:19:6:19:6 | y | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets |
|
||||
| test5.cpp:19:6:19:6 | y | test5.cpp:9:7:9:9 | gets output argument | test5.cpp:19:6:19:6 | y | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets |
|
||||
| test.c:14:15:14:28 | maxConnections | test3.c:10:27:10:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test3.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:14:15:14:28 | maxConnections | test3.c:10:27:10:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:14:15:14:28 | maxConnections | test3.c:10:27:10:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:14:15:14:28 | maxConnections | test3.c:10:27:10:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:14:15:14:28 | maxConnections | test.c:10:27:10:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test3.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:14:15:14:28 | maxConnections | test.c:10:27:10:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | test.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:14:15:14:28 | maxConnections | test.c:10:27:10:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:14:15:14:28 | maxConnections | test.c:10:27:10:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:44:7:44:10 | len2 | test3.c:10:27:10:30 | **argv | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:44:7:44:10 | len2 | test3.c:10:27:10:30 | **argv | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:44:7:44:10 | len2 | test.c:10:27:10:30 | **argv | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:44:7:44:10 | len2 | test.c:10:27:10:30 | **argv | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:54:7:54:10 | len3 | test3.c:10:27:10:30 | **argv | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:54:7:54:10 | len3 | test3.c:10:27:10:30 | **argv | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:54:7:54:10 | len3 | test.c:10:27:10:30 | **argv | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test3.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:54:7:54:10 | len3 | test.c:10:27:10:30 | **argv | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | test.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:14:15:14:28 | maxConnections | main.cpp:7:27:7:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an overflow. | main.cpp:7:27:7:30 | **argv | a command-line argument |
|
||||
| test.c:14:15:14:28 | maxConnections | main.cpp:7:27:7:30 | **argv | test.c:14:15:14:28 | maxConnections | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | main.cpp:7:27:7:30 | **argv | a command-line argument |
|
||||
| test.c:44:7:44:10 | len2 | main.cpp:7:27:7:30 | **argv | test.c:44:7:44:10 | len2 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | main.cpp:7:27:7:30 | **argv | a command-line argument |
|
||||
| test.c:54:7:54:10 | len3 | main.cpp:7:27:7:30 | **argv | test.c:54:7:54:10 | len3 | $@ flows to an operand of an arithmetic expression, potentially causing an underflow. | main.cpp:7:27:7:30 | **argv | a command-line argument |
|
||||
|
||||
@@ -4,20 +4,15 @@
|
||||
| test2.cpp:17:11:17:22 | ... * ... | $@ flows an expression which might overflow. | test2.cpp:25:22:25:23 | fscanf output argument | value read by fscanf |
|
||||
| test2.cpp:39:9:39:18 | ... + ... | $@ flows an expression which might overflow. | test2.cpp:36:9:36:14 | fgets output argument | string read by fgets |
|
||||
| test2.cpp:40:3:40:13 | ... += ... | $@ flows an expression which might overflow. | test2.cpp:36:9:36:14 | fgets output argument | string read by fgets |
|
||||
| test3.c:12:11:12:34 | * ... | $@ flows an expression which might overflow negatively. | test3.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test3.c:12:11:12:34 | * ... | $@ flows an expression which might overflow negatively. | test.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test3.c:13:11:13:20 | * ... | $@ flows an expression which might overflow negatively. | test3.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test3.c:13:11:13:20 | * ... | $@ flows an expression which might overflow negatively. | test.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test4.cpp:13:7:13:20 | access to array | $@ flows an expression which might overflow negatively. | test4.cpp:8:27:8:30 | **argv | a command-line argument |
|
||||
| test3.c:12:11:12:34 | * ... | $@ flows an expression which might overflow negatively. | main.cpp:7:27:7:30 | **argv | a command-line argument |
|
||||
| test3.c:13:11:13:20 | * ... | $@ flows an expression which might overflow negatively. | main.cpp:7:27:7:30 | **argv | a command-line argument |
|
||||
| test4.cpp:13:7:13:20 | access to array | $@ flows an expression which might overflow negatively. | main.cpp:7:27:7:30 | **argv | a command-line argument |
|
||||
| test5.cpp:10:9:10:27 | call to strtoul | $@ flows an expression which might overflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets |
|
||||
| test5.cpp:17:6:17:27 | ... * ... | $@ flows an expression which might overflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets |
|
||||
| test5.cpp:19:6:19:13 | ... * ... | $@ flows an expression which might overflow. | test5.cpp:9:7:9:9 | gets output argument | string read by gets |
|
||||
| test6.cpp:11:10:11:15 | s | $@ flows an expression which might overflow. | test6.cpp:39:23:39:24 | fscanf output argument | value read by fscanf |
|
||||
| test6.cpp:16:10:16:15 | s | $@ flows an expression which might overflow. | test6.cpp:39:23:39:24 | fscanf output argument | value read by fscanf |
|
||||
| test6.cpp:30:11:30:16 | s | $@ flows an expression which might overflow. | test6.cpp:39:23:39:24 | fscanf output argument | value read by fscanf |
|
||||
| test.c:14:15:14:35 | ... * ... | $@ flows an expression which might overflow. | test3.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:14:15:14:35 | ... * ... | $@ flows an expression which might overflow. | test.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:44:7:44:12 | ... -- | $@ flows an expression which might overflow negatively. | test3.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:44:7:44:12 | ... -- | $@ flows an expression which might overflow negatively. | test.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:54:7:54:12 | ... -- | $@ flows an expression which might overflow negatively. | test3.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:54:7:54:12 | ... -- | $@ flows an expression which might overflow negatively. | test.c:10:27:10:30 | **argv | a command-line argument |
|
||||
| test.c:14:15:14:35 | ... * ... | $@ flows an expression which might overflow. | main.cpp:7:27:7:30 | **argv | a command-line argument |
|
||||
| test.c:44:7:44:12 | ... -- | $@ flows an expression which might overflow negatively. | main.cpp:7:27:7:30 | **argv | a command-line argument |
|
||||
| test.c:54:7:54:12 | ... -- | $@ flows an expression which might overflow negatively. | main.cpp:7:27:7:30 | **argv | a command-line argument |
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
extern "C" {
|
||||
int main1(int argc, char** argv);
|
||||
int main3(int argc, char** argv);
|
||||
}
|
||||
int main4(int argc, char** argv);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
main1(argc, argv);
|
||||
main3(argc, argv);
|
||||
main4(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
@@ -7,7 +7,7 @@ void startServer(int heapSize);
|
||||
typedef unsigned long size_t;
|
||||
size_t strlen(const char *s);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int main1(int argc, char** argv) {
|
||||
int maxConnections = atoi(argv[1]);
|
||||
|
||||
// BAD: arithmetic on a user input without any validation
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
// Regression test for ODASA-6054: IntegerOverflowTainted should
|
||||
// not report a result if the overflow happens in a macro expansion
|
||||
// from a macro that is defined in a system header.
|
||||
int main(int argc, char **argv) {
|
||||
int main3(int argc, char **argv) {
|
||||
char *cmd = argv[0];
|
||||
int x = (int)(unsigned char)*cmd; // BAD: overflow
|
||||
int y = CAST(*cmd); // BAD: overflow in macro expansion (macro is not from a system header)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
// by comparing the value to 0. This means that the cast cannot overflow,
|
||||
// regardless of what the input type is.
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int main4(int argc, char **argv) {
|
||||
char *p = argv[0];
|
||||
if (!p[0]) { // GOOD: cast to bool.
|
||||
return 1;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
edges
|
||||
nodes
|
||||
| errors.cpp:13:7:13:7 | definition of x | semmle.label | definition of x |
|
||||
| test.cpp:11:6:11:8 | definition of foo | semmle.label | definition of foo |
|
||||
| test.cpp:111:6:111:8 | definition of foo | semmle.label | definition of foo |
|
||||
| test.cpp:226:7:226:7 | definition of x | semmle.label | definition of x |
|
||||
@@ -14,6 +15,7 @@ nodes
|
||||
| test.cpp:472:6:472:6 | definition of x | semmle.label | definition of x |
|
||||
| test.cpp:479:6:479:6 | definition of x | semmle.label | definition of x |
|
||||
#select
|
||||
| errors.cpp:14:18:14:18 | x | errors.cpp:13:7:13:7 | definition of x | errors.cpp:13:7:13:7 | definition of x | The variable $@ may not be initialized at this access. | errors.cpp:13:7:13:7 | x | x |
|
||||
| test.cpp:12:6:12:8 | foo | test.cpp:11:6:11:8 | definition of foo | test.cpp:11:6:11:8 | definition of foo | The variable $@ may not be initialized at this access. | test.cpp:11:6:11:8 | foo | foo |
|
||||
| test.cpp:113:6:113:8 | foo | test.cpp:111:6:111:8 | definition of foo | test.cpp:111:6:111:8 | definition of foo | The variable $@ may not be initialized at this access. | test.cpp:111:6:111:8 | foo | foo |
|
||||
| test.cpp:227:3:227:3 | x | test.cpp:226:7:226:7 | definition of x | test.cpp:226:7:226:7 | definition of x | The variable $@ may not be initialized at this access. | test.cpp:226:7:226:7 | x | x |
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// semmle-extractor-options: --expect_errors
|
||||
|
||||
int f1() {
|
||||
int x;
|
||||
initialize(&x); // error expression - initialize() is not defined
|
||||
return x; // GOOD - assume x is initialized
|
||||
}
|
||||
|
||||
void * operator new(unsigned long, bool);
|
||||
void operator delete(void*, bool);
|
||||
|
||||
int f2() {
|
||||
int x;
|
||||
new(true) int (x); // BAD, ignore implicit error expression
|
||||
}
|
||||
@@ -50,7 +50,7 @@ int val();
|
||||
const char *global1 = mysql_get_client_info();
|
||||
const char *global2 = "abc";
|
||||
|
||||
void test1()
|
||||
void test7()
|
||||
{
|
||||
int sock = socket(val(), val(), val());
|
||||
|
||||
|
||||
@@ -53,4 +53,59 @@ void NonStringFalsePositiveTest2(unsigned char* buffer)
|
||||
{
|
||||
wchar_t *lpWchar = NULL;
|
||||
lpWchar = (LPWSTR)buffer; // Possible False Positive
|
||||
}
|
||||
}
|
||||
|
||||
typedef unsigned char BYTE;
|
||||
using FOO = BYTE*;
|
||||
|
||||
void NonStringFalsePositiveTest3(FOO buffer)
|
||||
{
|
||||
wchar_t *lpWchar = NULL;
|
||||
lpWchar = (LPWSTR)buffer; // GOOD
|
||||
}
|
||||
|
||||
#define UNICODE 0x8
|
||||
|
||||
// assume EMPTY_MACRO is tied to if UNICODE is enabled
|
||||
#ifdef EMPTY_MACRO
|
||||
typedef WCHAR* LPTSTR;
|
||||
#else
|
||||
typedef char* LPTSTR;
|
||||
#endif
|
||||
|
||||
void CheckedConversionFalsePositiveTest3(unsigned short flags, LPTSTR buffer)
|
||||
{
|
||||
wchar_t *lpWchar = NULL;
|
||||
if(flags & UNICODE)
|
||||
lpWchar = (LPWSTR)buffer; // GOOD
|
||||
else
|
||||
lpWchar = (LPWSTR)buffer; // BUG
|
||||
|
||||
if((flags & UNICODE) == 0x8)
|
||||
lpWchar = (LPWSTR)buffer; // GOOD
|
||||
else
|
||||
lpWchar = (LPWSTR)buffer; // BUG
|
||||
|
||||
if((flags & UNICODE) != 0x8)
|
||||
lpWchar = (LPWSTR)buffer; // BUG
|
||||
else
|
||||
lpWchar = (LPWSTR)buffer; // GOOD
|
||||
|
||||
// Bad operator precedence
|
||||
if(flags & UNICODE == 0x8)
|
||||
lpWchar = (LPWSTR)buffer; // BUG
|
||||
else
|
||||
lpWchar = (LPWSTR)buffer; // BUG
|
||||
|
||||
if((flags & UNICODE) != 0)
|
||||
lpWchar = (LPWSTR)buffer; // GOOD
|
||||
else
|
||||
lpWchar = (LPWSTR)buffer; // BUG
|
||||
|
||||
if((flags & UNICODE) == 0)
|
||||
lpWchar = (LPWSTR)buffer; // BUG
|
||||
else
|
||||
lpWchar = (LPWSTR)buffer; // GOOD
|
||||
|
||||
lpWchar = (LPWSTR)buffer; // BUG
|
||||
}
|
||||
|
||||
@@ -3,3 +3,11 @@
|
||||
| WcharCharConversion.cpp:24:22:24:27 | lpChar | Conversion from char * to wchar_t *. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:26:23:26:28 | lpChar | Conversion from char * to LPCWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:27:17:27:22 | lpChar | Conversion from char * to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:82:21:82:26 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:87:21:87:26 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:90:21:90:26 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:96:21:96:26 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:98:21:98:26 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:103:21:103:26 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:106:21:106:26 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:110:20:110:25 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.7.27
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.7.26
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
## 1.7.27
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.7.26
|
||||
lastReleaseVersion: 1.7.27
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-all
|
||||
version: 1.7.26
|
||||
version: 1.7.28-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.7.27
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.7.26
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
## 1.7.27
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.7.26
|
||||
lastReleaseVersion: 1.7.27
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-queries
|
||||
version: 1.7.26
|
||||
version: 1.7.28-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 3.0.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 3.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
3
csharp/ql/lib/change-notes/released/3.0.1.md
Normal file
3
csharp/ql/lib/change-notes/released/3.0.1.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 3.0.1
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 3.0.0
|
||||
lastReleaseVersion: 3.0.1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-all
|
||||
version: 3.0.0
|
||||
version: 3.0.2-dev
|
||||
groups: csharp
|
||||
dbscheme: semmlecode.csharp.dbscheme
|
||||
extractor: csharp
|
||||
|
||||
@@ -53,7 +53,6 @@ private predicate idOf(AstNode x, int y) = equivalenceRelation(id/2)(x, y)
|
||||
private module CfgInput implements CfgShared::InputSig<Location> {
|
||||
private import ControlFlowGraphImpl as Impl
|
||||
private import Completion as Comp
|
||||
private import Splitting as Splitting
|
||||
private import SuccessorType as ST
|
||||
private import semmle.code.csharp.Caching
|
||||
|
||||
@@ -80,10 +79,6 @@ private module CfgInput implements CfgShared::InputSig<Location> {
|
||||
Impl::scopeLast(scope, last, c)
|
||||
}
|
||||
|
||||
class SplitKindBase = Splitting::TSplitKind;
|
||||
|
||||
class Split = Splitting::Split;
|
||||
|
||||
class SuccessorType = ST::SuccessorType;
|
||||
|
||||
SuccessorType getAMatchingSuccessorType(Completion c) { result = c.getAMatchingSuccessorType() }
|
||||
@@ -102,7 +97,21 @@ private module CfgInput implements CfgShared::InputSig<Location> {
|
||||
}
|
||||
}
|
||||
|
||||
import CfgShared::Make<Location, CfgInput>
|
||||
private module CfgSplittingInput implements CfgShared::SplittingInputSig<Location, CfgInput> {
|
||||
private import Splitting as S
|
||||
|
||||
class SplitKindBase = S::TSplitKind;
|
||||
|
||||
class Split = S::Split;
|
||||
}
|
||||
|
||||
private module ConditionalCompletionSplittingInput implements
|
||||
CfgShared::ConditionalCompletionSplittingInputSig<Location, CfgInput, CfgSplittingInput>
|
||||
{
|
||||
import Splitting::ConditionalCompletionSplitting::ConditionalCompletionSplittingInput
|
||||
}
|
||||
|
||||
import CfgShared::MakeWithSplitting<Location, CfgInput, CfgSplittingInput, ConditionalCompletionSplittingInput>
|
||||
|
||||
/**
|
||||
* A compilation.
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
private import Completion
|
||||
private import Completion as Comp
|
||||
private import Comp
|
||||
private import ControlFlowGraphImpl
|
||||
private import semmle.code.csharp.controlflow.ControlFlowGraph::ControlFlow as Cfg
|
||||
private import semmle.code.csharp.controlflow.internal.PreSsa
|
||||
@@ -260,10 +261,12 @@ module ConditionalCompletionSplitting {
|
||||
|
||||
ConditionalCompletionSplit() { this = TConditionalCompletionSplit(completion) }
|
||||
|
||||
ConditionalCompletion getCompletion() { result = completion }
|
||||
|
||||
override string toString() { result = completion.toString() }
|
||||
}
|
||||
|
||||
private class ConditionalCompletionSplitKind extends SplitKind, TConditionalCompletionSplitKind {
|
||||
private class ConditionalCompletionSplitKind_ extends SplitKind, TConditionalCompletionSplitKind {
|
||||
override int getListOrder() { result = InitializerSplitting::getNextListOrder() }
|
||||
|
||||
override predicate isEnabled(AstNode cfe) { this.appliesTo(cfe) }
|
||||
@@ -271,89 +274,64 @@ module ConditionalCompletionSplitting {
|
||||
override string toString() { result = "ConditionalCompletion" }
|
||||
}
|
||||
|
||||
int getNextListOrder() { result = InitializerSplitting::getNextListOrder() + 1 }
|
||||
module ConditionalCompletionSplittingInput {
|
||||
private import Completion as Comp
|
||||
|
||||
private class ConditionalCompletionSplitImpl extends SplitImpl instanceof ConditionalCompletionSplit
|
||||
{
|
||||
ConditionalCompletion completion;
|
||||
class ConditionalCompletion = Comp::ConditionalCompletion;
|
||||
|
||||
ConditionalCompletionSplitImpl() { this = TConditionalCompletionSplit(completion) }
|
||||
class ConditionalCompletionSplitKind extends ConditionalCompletionSplitKind_, TSplitKind { }
|
||||
|
||||
override ConditionalCompletionSplitKind getKind() { any() }
|
||||
class ConditionalCompletionSplit = ConditionalCompletionSplitting::ConditionalCompletionSplit;
|
||||
|
||||
override predicate hasEntry(AstNode pred, AstNode succ, Completion c) {
|
||||
succ(pred, succ, c) and
|
||||
last(succ, _, completion) and
|
||||
bindingset[parent, parentCompletion]
|
||||
predicate condPropagateExpr(
|
||||
AstNode parent, ConditionalCompletion parentCompletion, AstNode child,
|
||||
ConditionalCompletion childCompletion
|
||||
) {
|
||||
child = parent.(LogicalNotExpr).getOperand() and
|
||||
childCompletion.getDual() = parentCompletion
|
||||
or
|
||||
childCompletion = parentCompletion and
|
||||
(
|
||||
last(succ.(LogicalNotExpr).getOperand(), pred, c) and
|
||||
completion.(BooleanCompletion).getDual() = c
|
||||
child = parent.(LogicalAndExpr).getAnOperand()
|
||||
or
|
||||
last(succ.(LogicalAndExpr).getAnOperand(), pred, c) and
|
||||
completion = c
|
||||
child = parent.(LogicalOrExpr).getAnOperand()
|
||||
or
|
||||
last(succ.(LogicalOrExpr).getAnOperand(), pred, c) and
|
||||
completion = c
|
||||
parent = any(ConditionalExpr ce | child = [ce.getThen(), ce.getElse()])
|
||||
or
|
||||
succ =
|
||||
any(ConditionalExpr ce |
|
||||
last([ce.getThen(), ce.getElse()], pred, c) and
|
||||
completion = c
|
||||
)
|
||||
child = parent.(SwitchExpr).getACase()
|
||||
or
|
||||
succ =
|
||||
child = parent.(SwitchCaseExpr).getBody()
|
||||
or
|
||||
parent =
|
||||
any(NullCoalescingExpr nce |
|
||||
exists(Expr operand |
|
||||
last(operand, pred, c) and
|
||||
completion = c
|
||||
|
|
||||
if c instanceof NullnessCompletion
|
||||
then operand = nce.getRightOperand()
|
||||
else operand = nce.getAnOperand()
|
||||
)
|
||||
if childCompletion instanceof NullnessCompletion
|
||||
then child = nce.getRightOperand()
|
||||
else child = nce.getAnOperand()
|
||||
)
|
||||
)
|
||||
or
|
||||
child = parent.(NotPatternExpr).getPattern() and
|
||||
childCompletion.getDual() = parentCompletion
|
||||
or
|
||||
child = parent.(IsExpr).getPattern() and
|
||||
parentCompletion.(BooleanCompletion).getValue() =
|
||||
childCompletion.(MatchingCompletion).getValue()
|
||||
or
|
||||
childCompletion = parentCompletion and
|
||||
(
|
||||
child = parent.(AndPatternExpr).getAnOperand()
|
||||
or
|
||||
last(succ.(SwitchExpr).getACase(), pred, c) and
|
||||
completion = c
|
||||
child = parent.(OrPatternExpr).getAnOperand()
|
||||
or
|
||||
last(succ.(SwitchCaseExpr).getBody(), pred, c) and
|
||||
completion = c
|
||||
child = parent.(RecursivePatternExpr).getAChildExpr()
|
||||
or
|
||||
last(succ.(NotPatternExpr).getPattern(), pred, c) and
|
||||
completion.(MatchingCompletion).getDual() = c
|
||||
or
|
||||
last(succ.(IsExpr).getPattern(), pred, c) and
|
||||
completion.(BooleanCompletion).getValue() = c.(MatchingCompletion).getValue()
|
||||
or
|
||||
last(succ.(AndPatternExpr).getAnOperand(), pred, c) and
|
||||
completion = c
|
||||
or
|
||||
last(succ.(OrPatternExpr).getAnOperand(), pred, c) and
|
||||
completion = c
|
||||
or
|
||||
last(succ.(RecursivePatternExpr).getAChildExpr(), pred, c) and
|
||||
completion = c
|
||||
or
|
||||
last(succ.(PropertyPatternExpr).getPattern(_), pred, c) and
|
||||
completion = c
|
||||
child = parent.(PropertyPatternExpr).getPattern(_)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasEntryScope(CfgScope scope, AstNode first) { none() }
|
||||
|
||||
override predicate hasExit(AstNode pred, AstNode succ, Completion c) {
|
||||
this.appliesTo(pred) and
|
||||
succ(pred, succ, c) and
|
||||
if c instanceof ConditionalCompletion then completion = c else any()
|
||||
}
|
||||
|
||||
override predicate hasExitScope(CfgScope scope, AstNode last, Completion c) {
|
||||
this.appliesTo(last) and
|
||||
scopeLast(scope, last, c) and
|
||||
if c instanceof ConditionalCompletion then completion = c else any()
|
||||
}
|
||||
|
||||
override predicate hasSuccessor(AstNode pred, AstNode succ, Completion c) { none() }
|
||||
}
|
||||
|
||||
int getNextListOrder() { result = InitializerSplitting::getNextListOrder() + 1 }
|
||||
}
|
||||
|
||||
module AssertionSplitting {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user