mirror of
https://github.com/github/codeql.git
synced 2026-05-26 09:01:22 +02:00
Compare commits
480 Commits
criemen/as
...
redsun82/m
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b3f8c372ba | ||
|
|
d545585de1 | ||
|
|
44e25eee56 | ||
|
|
272132a09a | ||
|
|
9d8ee99c1c | ||
|
|
e1f65d1f8b | ||
|
|
c4cc30fb7a | ||
|
|
53a7d823ec | ||
|
|
81f4786643 | ||
|
|
e258d9fa74 | ||
|
|
a52a412c24 | ||
|
|
a30b34c4bd | ||
|
|
418a56d385 | ||
|
|
081f32141c | ||
|
|
d4e8e4c943 | ||
|
|
46d0c6ff9c | ||
|
|
c8a3bedf44 | ||
|
|
cb2ccef5fa | ||
|
|
c045e77d61 | ||
|
|
7d11fc2c7d | ||
|
|
a9afbfa993 | ||
|
|
3e2bbd38d4 | ||
|
|
47d946fb1c | ||
|
|
ea0db4d55e | ||
|
|
f9ae44ca5c | ||
|
|
37da3e1bb3 | ||
|
|
2413332553 | ||
|
|
c12adbeeaa | ||
|
|
d18915a1e4 | ||
|
|
e15a47d58c | ||
|
|
dd65d960be | ||
|
|
8dc95ce9b0 | ||
|
|
58b6b3f601 | ||
|
|
5058727980 | ||
|
|
1cc49af454 | ||
|
|
6a3bb4dd28 | ||
|
|
17edfdf801 | ||
|
|
6524b8e25d | ||
|
|
09905ee228 | ||
|
|
6d4e993dea | ||
|
|
aa4fd1992e | ||
|
|
b902dd5680 | ||
|
|
e0e5bdec8a | ||
|
|
921afb71e2 | ||
|
|
890da5377e | ||
|
|
551743e000 | ||
|
|
982f845be7 | ||
|
|
bb8b0d0bf5 | ||
|
|
285ed3630b | ||
|
|
1e46e431e8 | ||
|
|
d2a00fa773 | ||
|
|
351b908f62 | ||
|
|
0669186713 | ||
|
|
a02cf07833 | ||
|
|
5b1b60cc92 | ||
|
|
25d520a7f1 | ||
|
|
36d59cef7e | ||
|
|
82ed1ee671 | ||
|
|
d8df38c683 | ||
|
|
19b6d24bc2 | ||
|
|
fdf6e30888 | ||
|
|
a26132e818 | ||
|
|
3ede3af6f2 | ||
|
|
8c23e21073 | ||
|
|
06a7e3f3ee | ||
|
|
bd99f32a4b | ||
|
|
24685a07c0 | ||
|
|
c687dcb094 | ||
|
|
30249e4f2b | ||
|
|
854674a71c | ||
|
|
b27a9d948a | ||
|
|
2657e7f56d | ||
|
|
00d772f980 | ||
|
|
abc7cc39d4 | ||
|
|
9cd16fd9d6 | ||
|
|
8630583856 | ||
|
|
b7bc540325 | ||
|
|
65e150b416 | ||
|
|
f04a85e121 | ||
|
|
94d12edfdb | ||
|
|
4626e134fa | ||
|
|
00fbada41d | ||
|
|
21a0f8af07 | ||
|
|
d603b48884 | ||
|
|
a1743aa12e | ||
|
|
513ec16691 | ||
|
|
1bb762bea9 | ||
|
|
7d41e8ef73 | ||
|
|
3b585b4196 | ||
|
|
4a448f445e | ||
|
|
accc73d1d0 | ||
|
|
49f74bacf2 | ||
|
|
bbdae5188d | ||
|
|
fa13861e53 | ||
|
|
b75514c990 | ||
|
|
cfb48ace73 | ||
|
|
988d0671bb | ||
|
|
dff3ce2a9f | ||
|
|
c357cc9f08 | ||
|
|
69490c62cd | ||
|
|
6bf22bda58 | ||
|
|
8ea4f85de3 | ||
|
|
95c764eff6 | ||
|
|
db768960f4 | ||
|
|
555d7e5958 | ||
|
|
60ed51781e | ||
|
|
e84028d01e | ||
|
|
d308178781 | ||
|
|
ce5ab4c4b7 | ||
|
|
3457551264 | ||
|
|
0e04a59c08 | ||
|
|
e5c20b13cf | ||
|
|
4c4c15b425 | ||
|
|
aa35bd771b | ||
|
|
a36e39359f | ||
|
|
a7386b6670 | ||
|
|
f0e68887d4 | ||
|
|
b4fdf3c342 | ||
|
|
596102d3fb | ||
|
|
754fd8e84c | ||
|
|
68a661f3c7 | ||
|
|
b79711b17e | ||
|
|
2be171746b | ||
|
|
5cb37f5c4c | ||
|
|
aa962f9b03 | ||
|
|
1185e28ea2 | ||
|
|
ed3f1e40db | ||
|
|
99907471b2 | ||
|
|
40204911bc | ||
|
|
6dbdc9e17f | ||
|
|
b7a2ea8981 | ||
|
|
59f8f8a394 | ||
|
|
45ece48b6f | ||
|
|
919ddccfdb | ||
|
|
7adfa6bbed | ||
|
|
eb1999f8b3 | ||
|
|
ccb923a436 | ||
|
|
5bbd003dfc | ||
|
|
b53712cae0 | ||
|
|
6a0be6ad09 | ||
|
|
46e16b88bb | ||
|
|
cfd5f53eb0 | ||
|
|
8997f2cdf2 | ||
|
|
1f99559e9f | ||
|
|
cb39ae7dd3 | ||
|
|
8a7fdfa6fe | ||
|
|
59a77a873c | ||
|
|
9403bf25d8 | ||
|
|
6c8e391a63 | ||
|
|
5170585515 | ||
|
|
1c3ceacf04 | ||
|
|
dfaa40a1d2 | ||
|
|
b5d6a6db7e | ||
|
|
031e44b157 | ||
|
|
2c4a95bb5e | ||
|
|
6c3d90e8a0 | ||
|
|
9ca74de3e9 | ||
|
|
33704779ea | ||
|
|
cd9d58fdc8 | ||
|
|
eee7f5a896 | ||
|
|
0f98d9e815 | ||
|
|
4da5d6660a | ||
|
|
38ee085782 | ||
|
|
822f6eebfb | ||
|
|
b4ecc81145 | ||
|
|
fa2c50616b | ||
|
|
b6adff6377 | ||
|
|
53dd269f9f | ||
|
|
7f19f449eb | ||
|
|
49fb372eb9 | ||
|
|
df6449cfc7 | ||
|
|
b697068e9a | ||
|
|
5686efd25c | ||
|
|
f41bd41bd0 | ||
|
|
197cdab43d | ||
|
|
0e8af39b77 | ||
|
|
96b6ddefe0 | ||
|
|
57925373c6 | ||
|
|
833b4f90bf | ||
|
|
0fabca94db | ||
|
|
3d53ddf919 | ||
|
|
e1317ddcb6 | ||
|
|
b8b95fd81d | ||
|
|
c3862660e4 | ||
|
|
327dab69d0 | ||
|
|
1d1a84962b | ||
|
|
abe2deb6a6 | ||
|
|
3d3a315456 | ||
|
|
d238b9198d | ||
|
|
b0afba49a2 | ||
|
|
39a8af6519 | ||
|
|
14b5114aa6 | ||
|
|
c0df22950b | ||
|
|
b7b0f84e8b | ||
|
|
c75e66c433 | ||
|
|
9aa0c9f1f3 | ||
|
|
1046d03486 | ||
|
|
7d97463e4d | ||
|
|
079717bbc0 | ||
|
|
3fc8401370 | ||
|
|
3f2befc3e5 | ||
|
|
269f8ca2cd | ||
|
|
68ccec3d43 | ||
|
|
2f00a0d323 | ||
|
|
6cfd9458b0 | ||
|
|
7a13c31021 | ||
|
|
5973f3fadc | ||
|
|
098b732937 | ||
|
|
194ef607f7 | ||
|
|
78729180ad | ||
|
|
f3a9c9a9dc | ||
|
|
4e1f7a930d | ||
|
|
e2a47e7c18 | ||
|
|
c808953b1d | ||
|
|
3525967143 | ||
|
|
c7b4f51077 | ||
|
|
039537f7ba | ||
|
|
be66ea2178 | ||
|
|
a29446a566 | ||
|
|
58f69c9385 | ||
|
|
02100e58d9 | ||
|
|
ede0b5bdf4 | ||
|
|
f9db7864e1 | ||
|
|
0198806658 | ||
|
|
bb03a9faba | ||
|
|
f0a467e80b | ||
|
|
84b9d4d1ac | ||
|
|
3d037e73f0 | ||
|
|
b8de2ea03b | ||
|
|
b47831af14 | ||
|
|
1834a399d2 | ||
|
|
4bbeda08d6 | ||
|
|
83108e3e25 | ||
|
|
bcabc88649 | ||
|
|
4079de125f | ||
|
|
eec259279a | ||
|
|
e244eef3b5 | ||
|
|
7f7c5d7c94 | ||
|
|
e247d5b316 | ||
|
|
e56c185f32 | ||
|
|
0150269503 | ||
|
|
9384f6189e | ||
|
|
11c37734c3 | ||
|
|
854c6fa813 | ||
|
|
9ea2b463f0 | ||
|
|
78d23ee044 | ||
|
|
ec18786488 | ||
|
|
5b3403c4b1 | ||
|
|
e10e2899bd | ||
|
|
54a0e6dc45 | ||
|
|
8629e00686 | ||
|
|
9ed6da1072 | ||
|
|
a90968d277 | ||
|
|
1027ca266d | ||
|
|
90d6f2ece3 | ||
|
|
605fe54a06 | ||
|
|
5f08371f19 | ||
|
|
07f03be8cc | ||
|
|
b0c03f6d68 | ||
|
|
8b51ee8fe8 | ||
|
|
a04f08f026 | ||
|
|
a756f86847 | ||
|
|
0df6a1c4b1 | ||
|
|
48739da565 | ||
|
|
91ebeee429 | ||
|
|
5aee35256d | ||
|
|
4b62cb64ed | ||
|
|
0bbf131fdb | ||
|
|
7c2ee80bc3 | ||
|
|
e3cbf1479a | ||
|
|
4ee80653e2 | ||
|
|
3551386a1a | ||
|
|
6af1ed9d75 | ||
|
|
cdca607828 | ||
|
|
af2a78ea4d | ||
|
|
183a825841 | ||
|
|
bbeebfae73 | ||
|
|
f441c68f7e | ||
|
|
1db5e32e86 | ||
|
|
45a48f360f | ||
|
|
e9bd85e0ba | ||
|
|
202d77d94f | ||
|
|
24c9062b35 | ||
|
|
d8d1ae632c | ||
|
|
0f56e408f8 | ||
|
|
864d629a13 | ||
|
|
20b7def543 | ||
|
|
cf4736c8f6 | ||
|
|
67b327a0f7 | ||
|
|
a299afaf51 | ||
|
|
3d3652c63f | ||
|
|
92957a63ad | ||
|
|
3351b9547d | ||
|
|
2ae7fa4897 | ||
|
|
6fd2ab7cef | ||
|
|
b88a1b2d1e | ||
|
|
700604a1c2 | ||
|
|
93f10fcf14 | ||
|
|
6a6978398a | ||
|
|
333df03f64 | ||
|
|
a464a8e48e | ||
|
|
11faf08ed0 | ||
|
|
214db5c20d | ||
|
|
3cf719cb39 | ||
|
|
3574b9fd4f | ||
|
|
29e3816412 | ||
|
|
01416838a1 | ||
|
|
4226270ef9 | ||
|
|
73caa48302 | ||
|
|
3172054073 | ||
|
|
939ae4a561 | ||
|
|
90db894d01 | ||
|
|
87316784ad | ||
|
|
bb5ef3ccd9 | ||
|
|
e9dba59f11 | ||
|
|
ae0bf037ac | ||
|
|
2f33b9422b | ||
|
|
83860acdde | ||
|
|
f2b1e09650 | ||
|
|
317790eac3 | ||
|
|
ec34007a88 | ||
|
|
8a25081a0e | ||
|
|
7336dd1ae5 | ||
|
|
496fff4273 | ||
|
|
00319c5010 | ||
|
|
092bc6445d | ||
|
|
d4adc373c6 | ||
|
|
a160b891c8 | ||
|
|
877bfa2468 | ||
|
|
c3bba38950 | ||
|
|
7ecf1f9010 | ||
|
|
1aea120e89 | ||
|
|
b0c4fcec57 | ||
|
|
9e088f3e4a | ||
|
|
84c1341b62 | ||
|
|
d76700497b | ||
|
|
9c98652116 | ||
|
|
000a81fd29 | ||
|
|
7c0ce6486b | ||
|
|
027c7d0d43 | ||
|
|
1d44f45be2 | ||
|
|
7819cc1c36 | ||
|
|
71505f4003 | ||
|
|
06aa2664bf | ||
|
|
9db334d02f | ||
|
|
2c9340331d | ||
|
|
5e0a78c4c7 | ||
|
|
e7a60b72f1 | ||
|
|
b9586a81ef | ||
|
|
6c0c3365cf | ||
|
|
d344f720aa | ||
|
|
5f98f2aec9 | ||
|
|
6731bccc92 | ||
|
|
16f8be4ba4 | ||
|
|
beffc2a49d | ||
|
|
881b2586e1 | ||
|
|
504a233299 | ||
|
|
1d6f09c750 | ||
|
|
44a16cef6c | ||
|
|
7f62085be5 | ||
|
|
1033bf9c4c | ||
|
|
b9e3b3310e | ||
|
|
97cb0c89c8 | ||
|
|
ed525fce70 | ||
|
|
b5a3575130 | ||
|
|
7b92554cf2 | ||
|
|
9564ae1ca4 | ||
|
|
528afba919 | ||
|
|
36aac3ffd8 | ||
|
|
703832f5a1 | ||
|
|
0298755975 | ||
|
|
12df7dee17 | ||
|
|
af016f9416 | ||
|
|
8258e377dd | ||
|
|
d27a378008 | ||
|
|
dabc33bf66 | ||
|
|
7dcbbbac91 | ||
|
|
798a736d16 | ||
|
|
65af2556ed | ||
|
|
97f9a882c6 | ||
|
|
0f63f0dda2 | ||
|
|
80bf7cdb52 | ||
|
|
dd223ed704 | ||
|
|
e3e59e02e5 | ||
|
|
6ff7fb2a70 | ||
|
|
9331c2c33a | ||
|
|
6ac46b8436 | ||
|
|
1100b75a3c | ||
|
|
0473655752 | ||
|
|
22858249f9 | ||
|
|
4644f08195 | ||
|
|
25f9449f53 | ||
|
|
af9ed21c36 | ||
|
|
1f112467ce | ||
|
|
b9edcb7943 | ||
|
|
52a809145e | ||
|
|
fd9e6f48d7 | ||
|
|
171486641e | ||
|
|
5299c4a845 | ||
|
|
66cba89fdb | ||
|
|
8c3994bc9c | ||
|
|
b1242e464e | ||
|
|
fcd2bd6776 | ||
|
|
2b929c4d2d | ||
|
|
1fc481ce81 | ||
|
|
ea05b297a3 | ||
|
|
14daf58767 | ||
|
|
8fde8c2db4 | ||
|
|
b397f57357 | ||
|
|
300c82a8ff | ||
|
|
76beffb04a | ||
|
|
f1533f40b6 | ||
|
|
d2d945c66d | ||
|
|
4af4040bd6 | ||
|
|
f905ac10c4 | ||
|
|
0895f7d971 | ||
|
|
c470c078dc | ||
|
|
8dad622de2 | ||
|
|
c7adb32bc4 | ||
|
|
37d33186e5 | ||
|
|
fb3d34ce11 | ||
|
|
7f153ed07b | ||
|
|
90da07159e | ||
|
|
a87d27b53e | ||
|
|
9435a62a86 | ||
|
|
0e80e867af | ||
|
|
f93d4a0dd5 | ||
|
|
3a52cd186e | ||
|
|
0043d93fc1 | ||
|
|
9b4ea8877b | ||
|
|
4a2ab49efb | ||
|
|
8b93e815b9 | ||
|
|
6b9cc1a278 | ||
|
|
c4a38d0a2f | ||
|
|
0a765cc94a | ||
|
|
7e93102097 | ||
|
|
ead247469d | ||
|
|
4df73f9975 | ||
|
|
5fea71e5d6 | ||
|
|
6520e2fdfb | ||
|
|
2708e57e4b | ||
|
|
cffdc5b452 | ||
|
|
fc7fef3dd8 | ||
|
|
0c88d05a65 | ||
|
|
b20b733172 | ||
|
|
a636c47c84 | ||
|
|
4321c5c2da | ||
|
|
7dd1389b9e | ||
|
|
ab219902a9 | ||
|
|
3e6b4a161b | ||
|
|
95c9a3fc9a | ||
|
|
385c3ba7ff | ||
|
|
70282f9ebe | ||
|
|
d234a53c50 | ||
|
|
076faa3a4e | ||
|
|
3d7db0e46b | ||
|
|
102f09aa23 | ||
|
|
18d0b28024 | ||
|
|
48a9b107b9 | ||
|
|
5cc4206e00 | ||
|
|
0652afced3 | ||
|
|
a9c8bc082f | ||
|
|
faa483a282 | ||
|
|
9da815a5c0 | ||
|
|
ee4d87bd96 | ||
|
|
7891e64d3e | ||
|
|
3f41a42c38 | ||
|
|
15671682c5 | ||
|
|
00b6e1f0b0 | ||
|
|
41e7b91d78 | ||
|
|
f41bc1f631 | ||
|
|
75f0fc4a98 | ||
|
|
921198ed30 | ||
|
|
f6737b3d90 | ||
|
|
344869f0d7 | ||
|
|
06114d91d8 | ||
|
|
7a577ddd98 | ||
|
|
3f64cc82eb | ||
|
|
4f04dc8f6e | ||
|
|
65b97745c2 |
@@ -1 +1 @@
|
||||
7.1.2
|
||||
7.2.1
|
||||
|
||||
2
.github/workflows/ruby-build.yml
vendored
2
.github/workflows/ruby-build.yml
vendored
@@ -7,6 +7,7 @@ on:
|
||||
- .github/workflows/ruby-build.yml
|
||||
- .github/actions/fetch-codeql/action.yml
|
||||
- codeql-workspace.yml
|
||||
- "shared/tree-sitter-extractor/**"
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
@@ -16,6 +17,7 @@ on:
|
||||
- .github/workflows/ruby-build.yml
|
||||
- .github/actions/fetch-codeql/action.yml
|
||||
- codeql-workspace.yml
|
||||
- "shared/tree-sitter-extractor/**"
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
|
||||
39
MODULE.bazel
39
MODULE.bazel
@@ -13,22 +13,45 @@ local_path_override(
|
||||
|
||||
# see https://registry.bazel.build/ for a list of available packages
|
||||
|
||||
bazel_dep(name = "platforms", version = "0.0.9")
|
||||
bazel_dep(name = "rules_go", version = "0.47.0")
|
||||
bazel_dep(name = "platforms", version = "0.0.10")
|
||||
bazel_dep(name = "rules_go", version = "0.48.0")
|
||||
bazel_dep(name = "rules_pkg", version = "0.10.1")
|
||||
bazel_dep(name = "rules_nodejs", version = "6.0.3")
|
||||
bazel_dep(name = "rules_python", version = "0.31.0")
|
||||
bazel_dep(name = "bazel_skylib", version = "1.5.0")
|
||||
bazel_dep(name = "rules_nodejs", version = "6.2.0-codeql.1")
|
||||
bazel_dep(name = "rules_python", version = "0.32.2")
|
||||
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 = "gazelle", version = "0.36.0")
|
||||
bazel_dep(name = "gazelle", version = "0.37.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.46.0")
|
||||
|
||||
bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True)
|
||||
|
||||
crate = use_extension(
|
||||
"@rules_rust//crate_universe:extension.bzl",
|
||||
"crate",
|
||||
)
|
||||
crate.from_cargo(
|
||||
name = "py_deps",
|
||||
cargo_lockfile = "//python/extractor/tsg-python:Cargo.lock",
|
||||
manifests = [
|
||||
"//python/extractor/tsg-python:Cargo.toml",
|
||||
"//python/extractor/tsg-python/tsp:Cargo.toml",
|
||||
],
|
||||
)
|
||||
crate.from_cargo(
|
||||
name = "ruby_deps",
|
||||
cargo_lockfile = "//ruby/extractor:Cargo.lock",
|
||||
manifests = [
|
||||
"//ruby/extractor:Cargo.toml",
|
||||
"//ruby/extractor/codeql-extractor-fake-crate:Cargo.toml",
|
||||
],
|
||||
)
|
||||
use_repo(crate, "py_deps", "ruby_deps")
|
||||
|
||||
dotnet = use_extension("@rules_dotnet//dotnet:extensions.bzl", "dotnet")
|
||||
dotnet.toolchain(dotnet_version = "8.0.101")
|
||||
use_repo(dotnet, "dotnet_toolchains")
|
||||
@@ -62,6 +85,10 @@ use_repo(
|
||||
node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node")
|
||||
node.toolchain(
|
||||
name = "nodejs",
|
||||
node_urls = [
|
||||
"https://nodejs.org/dist/v{version}/{filename}",
|
||||
"https://mirrors.dotsrc.org/nodejs/release/v{version}/{filename}",
|
||||
],
|
||||
node_version = "18.15.0",
|
||||
)
|
||||
use_repo(node, "nodejs", "nodejs_toolchains")
|
||||
|
||||
@@ -61,10 +61,6 @@
|
||||
"java/ql/src/utils/modelgenerator/internal/CaptureModels.qll",
|
||||
"csharp/ql/src/utils/modelgenerator/internal/CaptureModels.qll"
|
||||
],
|
||||
"Model as Data Generation Java/C# - CaptureModelsPrinting": [
|
||||
"java/ql/src/utils/modelgenerator/internal/CaptureModelsPrinting.qll",
|
||||
"csharp/ql/src/utils/modelgenerator/internal/CaptureModelsPrinting.qll"
|
||||
],
|
||||
"Sign Java/C#": [
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/Sign.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/Sign.qll"
|
||||
@@ -185,11 +181,6 @@
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysisImports.qll"
|
||||
],
|
||||
"C++ IR ValueNumberingImports": [
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingImports.qll"
|
||||
],
|
||||
"IR SSA SSAConstruction": [
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll"
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
## 1.1.0
|
||||
|
||||
### New Features
|
||||
|
||||
* Data models can now be added with data extensions. In this way source, sink and summary models can be added in extension `.model.yml` files, rather than by writing classes in QL code. New models should be added in the `lib/ext` folder.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* A partial model for the `Boost.Asio` network library has been added. This includes sources, sinks and summaries for certain functions in `Boost.Asio`, such as `read_until` and `write`.
|
||||
|
||||
## 1.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
4
cpp/ql/lib/change-notes/2024-06-10-builtin-expect.md
Normal file
4
cpp/ql/lib/change-notes/2024-06-10-builtin-expect.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The "Guards" library (`semmle.code.cpp.controlflow.Guards`) now also infers guards from calls to the builtin operation `__builtin_expect`. As a result, some queries may produce fewer false positives.
|
||||
4
cpp/ql/lib/change-notes/2024-06-13-double-free.md
Normal file
4
cpp/ql/lib/change-notes/2024-06-13-double-free.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The queries "Potential double free" (`cpp/double-free`) and "Potential use after free" (`cpp/use-after-free`) now produce fewer false positives.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* A partial model for the `Boost.Asio` network library has been added. This includes sources, sinks and summaries for certain functions in `Boost.Asio`, such as `read_until` and `write`.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Data models can now be added with data extensions. In this way source, sink and summary models can be added in extension `.model.yml` files, rather than by writing classes in QL code. New models should be added in the `lib/ext` folder.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* It is now possible to extend the classes `AllocationFunction` and `DeallocationFunction` via data extensions. Extensions of these classes should be added to the `lib/ext/allocation` and `lib/ext/deallocation` directories respectively.
|
||||
9
cpp/ql/lib/change-notes/released/1.1.0.md
Normal file
9
cpp/ql/lib/change-notes/released/1.1.0.md
Normal file
@@ -0,0 +1,9 @@
|
||||
## 1.1.0
|
||||
|
||||
### New Features
|
||||
|
||||
* Data models can now be added with data extensions. In this way source, sink and summary models can be added in extension `.model.yml` files, rather than by writing classes in QL code. New models should be added in the `lib/ext` folder.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* A partial model for the `Boost.Asio` network library has been added. This includes sources, sinks and summaries for certain functions in `Boost.Asio`, such as `read_until` and `write`.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.0.0
|
||||
lastReleaseVersion: 1.1.0
|
||||
|
||||
7
cpp/ql/lib/ext/allocation/Bsd.allocation.model.yml
Normal file
7
cpp/ql/lib/ext/allocation/Bsd.allocation.model.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: allocationFunctionModel
|
||||
data:
|
||||
- ["", "", False, "kmem_alloc", "0", "", "", True]
|
||||
- ["", "", False, "kmem_zalloc", "0", "", "", True]
|
||||
7
cpp/ql/lib/ext/allocation/Glibc.allocation.model.yml
Normal file
7
cpp/ql/lib/ext/allocation/Glibc.allocation.model.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: allocationFunctionModel
|
||||
data:
|
||||
- ["", "", False, "g_malloc", "0", "", "", True]
|
||||
- ["", "", False, "g_try_malloc", "0", "", "", True]
|
||||
10
cpp/ql/lib/ext/allocation/OpenSSL.allocation.model.yml
Normal file
10
cpp/ql/lib/ext/allocation/OpenSSL.allocation.model.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: allocationFunctionModel
|
||||
data:
|
||||
- ["", "", False, "CRYPTO_malloc", "0", "", "", True]
|
||||
- ["", "", False, "CRYPTO_zalloc", "0", "", "", True]
|
||||
- ["", "", False, "CRYPTO_secure_malloc", "0", "", "", True]
|
||||
- ["", "", False, "CRYPTO_secure_zalloc", "0", "", "", True]
|
||||
|
||||
15
cpp/ql/lib/ext/allocation/Std.allocation.model.yml
Normal file
15
cpp/ql/lib/ext/allocation/Std.allocation.model.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: allocationFunctionModel
|
||||
data:
|
||||
- ["", "", False, "malloc", "0", "", "", True]
|
||||
- ["std", "", False, "malloc", "0", "", "", True]
|
||||
- ["bsl", "", False, "malloc", "0", "", "", True]
|
||||
- ["", "", False, "alloca", "0", "", "", False]
|
||||
- ["", "", False, "__builtin_alloca", "0", "", "", False]
|
||||
- ["", "", False, "_alloca", "0", "", "", False]
|
||||
- ["", "", False, "_malloca", "0", "", "", False]
|
||||
- ["", "", False, "calloc", "1", "0", "", True]
|
||||
- ["std", "", False, "calloc", "1", "0", "", True]
|
||||
- ["bsl", "", False, "calloc", "1", "0", "", True]
|
||||
29
cpp/ql/lib/ext/allocation/Windows.allocation.model.yml
Normal file
29
cpp/ql/lib/ext/allocation/Windows.allocation.model.yml
Normal file
@@ -0,0 +1,29 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: allocationFunctionModel
|
||||
data:
|
||||
- ["", "", False, "MmAllocateContiguousMemory", "0", "", "", True]
|
||||
- ["", "", False, "MmAllocateContiguousNodeMemory", "0", "", "", True]
|
||||
- ["", "", False, "MmAllocateContiguousMemorySpecifyCache", "0", "", "", True]
|
||||
- ["", "", False, "MmAllocateContiguousMemorySpecifyCacheNode", "0", "", "", True]
|
||||
- ["", "", False, "MmAllocateNonCachedMemory", "0", "", "", True]
|
||||
- ["", "", False, "MmAllocateMappingAddress", "0", "", "", True]
|
||||
- ["", "", False, "CoTaskMemAlloc", "0", "", "", True]
|
||||
- ["", "", False, "ExAllocatePool", "1", "", "", True]
|
||||
- ["", "", False, "ExAllocatePool2", "1", "", "", True]
|
||||
- ["", "", False, "ExAllocatePool3", "1", "", "", True]
|
||||
- ["", "", False, "ExAllocatePoolWithTag", "1", "", "", True]
|
||||
- ["", "", False, "ExAllocatePoolWithTagPriority", "1", "", "", True]
|
||||
- ["", "", False, "ExAllocatePoolWithQuota", "1", "", "", True]
|
||||
- ["", "", False, "ExAllocatePoolWithQuotaTag", "1", "", "", True]
|
||||
- ["", "", False, "ExAllocatePoolZero", "1", "", "", True]
|
||||
- ["", "", False, "IoAllocateMdl", "1", "", "", True]
|
||||
- ["", "", False, "IoAllocateErrorLogEntry", "1", "", "", True]
|
||||
- ["", "", False, "LocalAlloc", "1", "", "", True]
|
||||
- ["", "", False, "GlobalAlloc", "1", "", "", True]
|
||||
- ["", "", False, "VirtualAlloc", "1", "", "", True]
|
||||
- ["", "", False, "HeapAlloc", "2", "", "", True]
|
||||
- ["", "", False, "MmAllocatePagesForMdl", "3", "", "", True]
|
||||
- ["", "", False, "MmAllocatePagesForMdlEx", "3", "", "", True]
|
||||
- ["", "", False, "MmAllocateNodePagesForMdlEx", "3", "", "", True]
|
||||
5
cpp/ql/lib/ext/allocation/empty.allocation.model.yml
Normal file
5
cpp/ql/lib/ext/allocation/empty.allocation.model.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: allocationFunctionModel
|
||||
data: []
|
||||
8
cpp/ql/lib/ext/deallocation/Bsd.deallocation.model.yml
Normal file
8
cpp/ql/lib/ext/deallocation/Bsd.deallocation.model.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: deallocationFunctionModel
|
||||
data:
|
||||
- ["", "", False, "pool_put", "1"]
|
||||
- ["", "", False, "pool_cache_put", "1"]
|
||||
- ["", "", False, "kmem_free", "0"]
|
||||
42
cpp/ql/lib/ext/deallocation/Std.deallocation.model.yml
Normal file
42
cpp/ql/lib/ext/deallocation/Std.deallocation.model.yml
Normal file
@@ -0,0 +1,42 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: deallocationFunctionModel
|
||||
data:
|
||||
- ["", "", False, "free", "0"]
|
||||
- ["std", "", False, "free", "0"]
|
||||
- ["bsl", "", False, "free", "0"]
|
||||
- ["", "", False, "realloc", "0"]
|
||||
- ["std", "", False, "realloc", "0"]
|
||||
- ["bsl", "", False, "realloc", "0"]
|
||||
- ["", "", False, "CRYPTO_free", "0"]
|
||||
- ["", "", False, "CRYPTO_secure_free", "0"]
|
||||
- ["", "", False, "g_free", "0"]
|
||||
- ["", "", False, "ExFreePool", "0"]
|
||||
- ["", "", False, "ExFreePoolWithTag", "0"]
|
||||
- ["", "", False, "ExDeleteTimer", "0"]
|
||||
- ["", "", False, "IoFreeIrp", "0"]
|
||||
- ["", "", False, "IoFreeMdl", "0"]
|
||||
- ["", "", False, "IoFreeErrorLogEntry", "0"]
|
||||
- ["", "", False, "IoFreeWorkItem", "0"]
|
||||
- ["", "", False, "MmFreeContiguousMemory", "0"]
|
||||
- ["", "", False, "MmFreeContiguousMemorySpecifyCache", "0"]
|
||||
- ["", "", False, "MmFreeNonCachedMemory", "0"]
|
||||
- ["", "", False, "MmFreeMappingAddress", "0"]
|
||||
- ["", "", False, "MmFreePagesFromMdl", "0"]
|
||||
- ["", "", False, "MmUnmapReservedMapping", "0"]
|
||||
- ["", "", False, "MmUnmapLockedPages", "0"]
|
||||
- ["", "", False, "NdisFreeGenericObject", "0"]
|
||||
- ["", "", False, "NdisFreeMemory", "0"]
|
||||
- ["", "", False, "NdisFreeMemoryWithTag", "0"]
|
||||
- ["", "", False, "NdisFreeMdl", "0"]
|
||||
- ["", "", False, "NdisFreeNetBufferListPool", "0"]
|
||||
- ["", "", False, "NdisFreeNetBufferPool", "0"]
|
||||
- ["", "", False, "LocalFree", "0"]
|
||||
- ["", "", False, "GlobalFree", "0"]
|
||||
- ["", "", False, "LocalReAlloc", "0"]
|
||||
- ["", "", False, "GlobalReAlloc", "0"]
|
||||
- ["", "", False, "VirtualFree", "0"]
|
||||
- ["", "", False, "CoTaskMemFree", "0"]
|
||||
- ["", "", False, "CoTaskMemRealloc", "0"]
|
||||
- ["", "", False, "SysFreeString", "0"]
|
||||
41
cpp/ql/lib/ext/deallocation/Windows.deallocation.model.yml
Normal file
41
cpp/ql/lib/ext/deallocation/Windows.deallocation.model.yml
Normal file
@@ -0,0 +1,41 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: deallocationFunctionModel
|
||||
data:
|
||||
- ["", "", False, "ExFreePool", "0"]
|
||||
- ["", "", False, "ExFreePoolWithTag", "0"]
|
||||
- ["", "", False, "ExDeleteTimer", "0"]
|
||||
- ["", "", False, "IoFreeIrp", "0"]
|
||||
- ["", "", False, "IoFreeMdl", "0"]
|
||||
- ["", "", False, "IoFreeErrorLogEntry", "0"]
|
||||
- ["", "", False, "IoFreeWorkItem", "0"]
|
||||
- ["", "", False, "MmFreeContiguousMemory", "0"]
|
||||
- ["", "", False, "MmFreeContiguousMemorySpecifyCache", "0"]
|
||||
- ["", "", False, "MmFreeNonCachedMemory", "0"]
|
||||
- ["", "", False, "MmFreeMappingAddress", "0"]
|
||||
- ["", "", False, "MmFreePagesFromMdl", "0"]
|
||||
- ["", "", False, "MmUnmapReservedMapping", "0"]
|
||||
- ["", "", False, "MmUnmapLockedPages", "0"]
|
||||
- ["", "", False, "NdisFreeGenericObject", "0"]
|
||||
- ["", "", False, "NdisFreeMemory", "0"]
|
||||
- ["", "", False, "NdisFreeMemoryWithTag", "0"]
|
||||
- ["", "", False, "NdisFreeMdl", "0"]
|
||||
- ["", "", False, "NdisFreeNetBufferListPool", "0"]
|
||||
- ["", "", False, "NdisFreeNetBufferPool", "0"]
|
||||
- ["", "", False, "LocalFree", "0"]
|
||||
- ["", "", False, "GlobalFree", "0"]
|
||||
- ["", "", False, "LocalReAlloc", "0"]
|
||||
- ["", "", False, "GlobalReAlloc", "0"]
|
||||
- ["", "", False, "VirtualFree", "0"]
|
||||
- ["", "", False, "CoTaskMemFree", "0"]
|
||||
- ["", "", False, "CoTaskMemRealloc", "0"]
|
||||
- ["", "", False, "SysFreeString", "0"]
|
||||
- ["", "", False, "ExFreeToLookasideListEx", "1"]
|
||||
- ["", "", False, "ExFreeToPagedLookasideList", "1"]
|
||||
- ["", "", False, "ExFreeToNPagedLookasideList", "1"]
|
||||
- ["", "", False, "NdisFreeMemoryWithTagPriority", "1"]
|
||||
- ["", "", False, "StorPortFreeMdl", "1"]
|
||||
- ["", "", False, "StorPortFreePool", "1"]
|
||||
- ["", "", False, "HeapFree", "2"]
|
||||
- ["", "", False, "HeapReAlloc", "2"]
|
||||
5
cpp/ql/lib/ext/deallocation/empty.deallocation.model.yml
Normal file
5
cpp/ql/lib/ext/deallocation/empty.deallocation.model.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: deallocationFunctionModel
|
||||
data: []
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 1.0.1-dev
|
||||
version: 1.1.1-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
@@ -16,4 +16,6 @@ dependencies:
|
||||
codeql/xml: ${workspace}
|
||||
dataExtensions:
|
||||
- ext/*.model.yml
|
||||
- ext/deallocation/*.model.yml
|
||||
- ext/allocation/*.model.yml
|
||||
warnOnImplicitThis: true
|
||||
|
||||
@@ -375,6 +375,33 @@ cached
|
||||
class IRGuardCondition extends Instruction {
|
||||
Instruction branch;
|
||||
|
||||
/*
|
||||
* An `IRGuardCondition` supports reasoning about four different kinds of
|
||||
* relations:
|
||||
* 1. A unary equality relation of the form `e == k`
|
||||
* 2. A binary equality relation of the form `e1 == e2 + k`
|
||||
* 3. A unary inequality relation of the form `e < k`
|
||||
* 4. A binary inequality relation of the form `e1 < e2 + k`
|
||||
*
|
||||
* where `k` is a constant.
|
||||
*
|
||||
* Furthermore, the unary relations (i.e., case 1 and case 3) are also
|
||||
* inferred from `switch` statement guards: equality relations are inferred
|
||||
* from the unique `case` statement, if any, and inequality relations are
|
||||
* inferred from the [case range](https://gcc.gnu.org/onlinedocs/gcc/Case-Ranges.html)
|
||||
* gcc extension.
|
||||
*
|
||||
* The implementation of all four follows the same structure: Each relation
|
||||
* has a cached user-facing predicate that. For example,
|
||||
* `GuardCondition::comparesEq` calls `compares_eq`. This predicate has
|
||||
* several cases that recursively decompose the relation to bring it to a
|
||||
* canonical form (i.e., a relation of the form `e1 == e2 + k`). The base
|
||||
* case for this relation (i.e., `simple_comparison_eq`) handles
|
||||
* `CompareEQInstruction`s and `CompareNEInstruction`, and recursive
|
||||
* predicates (e.g., `complex_eq`) rewrites larger expressions such as
|
||||
* `e1 + k1 == e2 + k2` into canonical the form `e1 == e2 + (k2 - k1)`.
|
||||
*/
|
||||
|
||||
cached
|
||||
IRGuardCondition() { branch = getBranchForCondition(this) }
|
||||
|
||||
@@ -735,6 +762,8 @@ private predicate compares_eq(
|
||||
exists(AbstractValue dual | value = dual.getDualValue() |
|
||||
compares_eq(test.(LogicalNotInstruction).getUnary(), left, right, k, areEqual, dual)
|
||||
)
|
||||
or
|
||||
compares_eq(test.(BuiltinExpectCallInstruction).getCondition(), left, right, k, areEqual, value)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -776,7 +805,9 @@ private predicate unary_compares_eq(
|
||||
Instruction test, Operand op, int k, boolean areEqual, boolean inNonZeroCase, AbstractValue value
|
||||
) {
|
||||
/* The simple case where the test *is* the comparison so areEqual = testIsTrue xor eq. */
|
||||
exists(AbstractValue v | unary_simple_comparison_eq(test, op, k, inNonZeroCase, v) |
|
||||
exists(AbstractValue v |
|
||||
unary_simple_comparison_eq(test, k, inNonZeroCase, v) and op.getDef() = test
|
||||
|
|
||||
areEqual = true and value = v
|
||||
or
|
||||
areEqual = false and value = v.getDualValue()
|
||||
@@ -802,6 +833,9 @@ private predicate unary_compares_eq(
|
||||
int_value(const) = k1 and
|
||||
k = k1 + k2
|
||||
)
|
||||
or
|
||||
unary_compares_eq(test.(BuiltinExpectCallInstruction).getCondition(), op, k, areEqual,
|
||||
inNonZeroCase, value)
|
||||
}
|
||||
|
||||
/** Rearrange various simple comparisons into `left == right + k` form. */
|
||||
@@ -821,45 +855,55 @@ private predicate simple_comparison_eq(
|
||||
value.(BooleanValue).getValue() = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `test` is an instruction that is part of test that eventually is
|
||||
* used in a conditional branch.
|
||||
*/
|
||||
private predicate relevantUnaryComparison(Instruction test) {
|
||||
not test instanceof CompareInstruction and
|
||||
exists(IRType type, ConditionalBranchInstruction branch |
|
||||
type instanceof IRAddressType or type instanceof IRIntegerType
|
||||
|
|
||||
type = test.getResultIRType() and
|
||||
branch.getCondition() = test
|
||||
)
|
||||
or
|
||||
exists(LogicalNotInstruction logicalNot |
|
||||
relevantUnaryComparison(logicalNot) and
|
||||
test = logicalNot.getUnary()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Rearrange various simple comparisons into `op == k` form.
|
||||
*/
|
||||
private predicate unary_simple_comparison_eq(
|
||||
Instruction test, Operand op, int k, boolean inNonZeroCase, AbstractValue value
|
||||
Instruction test, int k, boolean inNonZeroCase, AbstractValue value
|
||||
) {
|
||||
exists(SwitchInstruction switch, CaseEdge case |
|
||||
test = switch.getExpression() and
|
||||
op.getDef() = test and
|
||||
case = value.(MatchValue).getCase() and
|
||||
exists(switch.getSuccessor(case)) and
|
||||
case.getValue().toInt() = k and
|
||||
inNonZeroCase = false
|
||||
)
|
||||
or
|
||||
// There's no implicit CompareInstruction in files compiled as C since C
|
||||
// doesn't have implicit boolean conversions. So instead we check whether
|
||||
// there's a branch on a value of pointer or integer type.
|
||||
relevantUnaryComparison(test) and
|
||||
op.getDef() = test and
|
||||
// Any instruction with an integral type could potentially be part of a
|
||||
// check for nullness when used in a guard. So we include all integral
|
||||
// typed instructions here. However, since some of these instructions are
|
||||
// already included as guards in other cases, we exclude those here.
|
||||
// These are instructions that compute a binary equality or inequality
|
||||
// relation. For example, the following:
|
||||
// ```cpp
|
||||
// if(a == b + 42) { ... }
|
||||
// ```
|
||||
// generates the following IR:
|
||||
// ```
|
||||
// r1(glval<int>) = VariableAddress[a] :
|
||||
// r2(int) = Load[a] : &:r1, m1
|
||||
// r3(glval<int>) = VariableAddress[b] :
|
||||
// r4(int) = Load[b] : &:r3, m2
|
||||
// r5(int) = Constant[42] :
|
||||
// r6(int) = Add : r4, r5
|
||||
// r7(bool) = CompareEQ : r2, r6
|
||||
// v1(void) = ConditionalBranch : r7
|
||||
// ```
|
||||
// and since `r7` is an integral typed instruction this predicate could
|
||||
// include a case for when `r7` evaluates to true (in which case we would
|
||||
// infer that `r6` was non-zero, and a case for when `r7` evaluates to false
|
||||
// (in which case we would infer that `r6` was zero).
|
||||
// However, since `a == b + 42` is already supported when reasoning about
|
||||
// binary equalities we exclude those cases here.
|
||||
not test.isGLValue() and
|
||||
not simple_comparison_eq(test, _, _, _, _) and
|
||||
not simple_comparison_lt(test, _, _, _) and
|
||||
not test = any(SwitchInstruction switch).getExpression() and
|
||||
(
|
||||
test.getResultIRType() instanceof IRAddressType or
|
||||
test.getResultIRType() instanceof IRIntegerType or
|
||||
test.getResultIRType() instanceof IRBooleanType
|
||||
) and
|
||||
(
|
||||
k = 1 and
|
||||
value.(BooleanValue).getValue() = true and
|
||||
@@ -871,12 +915,68 @@ private predicate unary_simple_comparison_eq(
|
||||
)
|
||||
}
|
||||
|
||||
/** A call to the builtin operation `__builtin_expect`. */
|
||||
private class BuiltinExpectCallInstruction extends CallInstruction {
|
||||
BuiltinExpectCallInstruction() { this.getStaticCallTarget().hasName("__builtin_expect") }
|
||||
|
||||
/** Gets the condition of this call. */
|
||||
Instruction getCondition() {
|
||||
// The first parameter of `__builtin_expect` has type `long`. So we skip
|
||||
// the conversion when inferring guards.
|
||||
result = this.getArgument(0).(ConvertInstruction).getUnary()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `left == right + k` is `areEqual` if `cmp` evaluates to `value`,
|
||||
* and `cmp` is an instruction that compares the value of
|
||||
* `__builtin_expect(left == right + k, _)` to `0`.
|
||||
*/
|
||||
private predicate builtin_expect_eq(
|
||||
CompareInstruction cmp, Operand left, Operand right, int k, boolean areEqual, AbstractValue value
|
||||
) {
|
||||
exists(BuiltinExpectCallInstruction call, Instruction const, AbstractValue innerValue |
|
||||
int_value(const) = 0 and
|
||||
cmp.hasOperands(call.getAUse(), const.getAUse()) and
|
||||
compares_eq(call.getCondition(), left, right, k, areEqual, innerValue)
|
||||
|
|
||||
cmp instanceof CompareNEInstruction and
|
||||
value = innerValue
|
||||
or
|
||||
cmp instanceof CompareEQInstruction and
|
||||
value.getDualValue() = innerValue
|
||||
)
|
||||
}
|
||||
|
||||
private predicate complex_eq(
|
||||
CompareInstruction cmp, Operand left, Operand right, int k, boolean areEqual, AbstractValue value
|
||||
) {
|
||||
sub_eq(cmp, left, right, k, areEqual, value)
|
||||
or
|
||||
add_eq(cmp, left, right, k, areEqual, value)
|
||||
or
|
||||
builtin_expect_eq(cmp, left, right, k, areEqual, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `op == k` is `areEqual` if `cmp` evaluates to `value`, and `cmp` is
|
||||
* an instruction that compares the value of `__builtin_expect(op == k, _)` to `0`.
|
||||
*/
|
||||
private predicate unary_builtin_expect_eq(
|
||||
CompareInstruction cmp, Operand op, int k, boolean areEqual, boolean inNonZeroCase,
|
||||
AbstractValue value
|
||||
) {
|
||||
exists(BuiltinExpectCallInstruction call, Instruction const, AbstractValue innerValue |
|
||||
int_value(const) = 0 and
|
||||
cmp.hasOperands(call.getAUse(), const.getAUse()) and
|
||||
unary_compares_eq(call.getCondition(), op, k, areEqual, inNonZeroCase, innerValue)
|
||||
|
|
||||
cmp instanceof CompareNEInstruction and
|
||||
value = innerValue
|
||||
or
|
||||
cmp instanceof CompareEQInstruction and
|
||||
value.getDualValue() = innerValue
|
||||
)
|
||||
}
|
||||
|
||||
private predicate unary_complex_eq(
|
||||
@@ -885,6 +985,8 @@ private predicate unary_complex_eq(
|
||||
unary_sub_eq(test, op, k, areEqual, inNonZeroCase, value)
|
||||
or
|
||||
unary_add_eq(test, op, k, areEqual, inNonZeroCase, value)
|
||||
or
|
||||
unary_builtin_expect_eq(test, op, k, areEqual, inNonZeroCase, value)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -913,7 +1015,8 @@ private predicate compares_lt(
|
||||
|
||||
/** Holds if `op < k` evaluates to `isLt` given that `test` evaluates to `value`. */
|
||||
private predicate compares_lt(Instruction test, Operand op, int k, boolean isLt, AbstractValue value) {
|
||||
simple_comparison_lt(test, op, k, isLt, value)
|
||||
unary_simple_comparison_lt(test, k, isLt, value) and
|
||||
op.getDef() = test
|
||||
or
|
||||
complex_lt(test, op, k, isLt, value)
|
||||
or
|
||||
@@ -960,12 +1063,11 @@ private predicate simple_comparison_lt(CompareInstruction cmp, Operand left, Ope
|
||||
}
|
||||
|
||||
/** Rearrange various simple comparisons into `op < k` form. */
|
||||
private predicate simple_comparison_lt(
|
||||
Instruction test, Operand op, int k, boolean isLt, AbstractValue value
|
||||
private predicate unary_simple_comparison_lt(
|
||||
Instruction test, int k, boolean isLt, AbstractValue value
|
||||
) {
|
||||
exists(SwitchInstruction switch, CaseEdge case |
|
||||
test = switch.getExpression() and
|
||||
op.getDef() = test and
|
||||
case = value.(MatchValue).getCase() and
|
||||
exists(switch.getSuccessor(case)) and
|
||||
case.getMaxValue() > case.getMinValue()
|
||||
|
||||
@@ -216,7 +216,7 @@ predicate localMustFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/** Gets the type of `n` used for type pruning. */
|
||||
Type getNodeType(Node n) {
|
||||
suppressUnusedNode(n) and
|
||||
exists(n) and
|
||||
result instanceof VoidType // stub implementation
|
||||
}
|
||||
|
||||
@@ -227,13 +227,10 @@ string ppReprType(Type t) { none() } // stub implementation
|
||||
* Holds if `t1` and `t2` are compatible, that is, whether data can flow from
|
||||
* a node of type `t1` to a node of type `t2`.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate compatibleTypes(Type t1, Type t2) {
|
||||
any() // stub implementation
|
||||
t1 instanceof VoidType and t2 instanceof VoidType // stub implementation
|
||||
}
|
||||
|
||||
private predicate suppressUnusedNode(Node n) { any() }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Java QL library compatibility wrappers
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -988,7 +988,7 @@ predicate localMustFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/** Gets the type of `n` used for type pruning. */
|
||||
DataFlowType getNodeType(Node n) {
|
||||
suppressUnusedNode(n) and
|
||||
exists(n) and
|
||||
result instanceof VoidType // stub implementation
|
||||
}
|
||||
|
||||
@@ -999,13 +999,10 @@ string ppReprType(DataFlowType t) { none() } // stub implementation
|
||||
* Holds if `t1` and `t2` are compatible, that is, whether data can flow from
|
||||
* a node of type `t1` to a node of type `t2`.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate compatibleTypes(DataFlowType t1, DataFlowType t2) {
|
||||
any() // stub implementation
|
||||
t1 instanceof VoidType and t2 instanceof VoidType // stub implementation
|
||||
}
|
||||
|
||||
private predicate suppressUnusedNode(Node n) { any() }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Java QL library compatibility wrappers
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -17,6 +17,7 @@ private import SsaInternals as Ssa
|
||||
private import DataFlowImplCommon as DataFlowImplCommon
|
||||
private import codeql.util.Unit
|
||||
private import Node0ToString
|
||||
import ExprNodes
|
||||
|
||||
/**
|
||||
* The IR dataflow graph consists of the following nodes:
|
||||
@@ -1296,466 +1297,6 @@ class UninitializedNode extends Node {
|
||||
LocalVariable getLocalVariable() { result = v }
|
||||
}
|
||||
|
||||
private module GetConvertedResultExpression {
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedExpr
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.InstructionTag
|
||||
|
||||
private Operand getAnInitializeDynamicAllocationInstructionAddress() {
|
||||
result = any(InitializeDynamicAllocationInstruction init).getAllocationAddressOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expression that should be returned as the result expression from `instr`.
|
||||
*
|
||||
* Note that this predicate may return multiple results in cases where a conversion belongs to a
|
||||
* different AST element than its operand.
|
||||
*/
|
||||
Expr getConvertedResultExpression(Instruction instr, int n) {
|
||||
// Only fully converted instructions have a result for `asConvertedExpr`
|
||||
not conversionFlow(unique(Operand op |
|
||||
// The address operand of a `InitializeDynamicAllocationInstruction` is
|
||||
// special: we need to handle it during dataflow (since it's
|
||||
// effectively a store to an indirection), but it doesn't appear in
|
||||
// source syntax, so dataflow node <-> expression conversion shouldn't
|
||||
// care about it.
|
||||
op = getAUse(instr) and not op = getAnInitializeDynamicAllocationInstructionAddress()
|
||||
|
|
||||
op
|
||||
), _, false, false) and
|
||||
result = getConvertedResultExpressionImpl(instr) and
|
||||
n = 0
|
||||
or
|
||||
// If the conversion also has a result then we return multiple results
|
||||
exists(Operand operand | conversionFlow(operand, instr, false, false) |
|
||||
n = 1 and
|
||||
result = getConvertedResultExpressionImpl(operand.getDef())
|
||||
or
|
||||
result = getConvertedResultExpression(operand.getDef(), n - 1)
|
||||
)
|
||||
}
|
||||
|
||||
private Expr getConvertedResultExpressionImpl0(Instruction instr) {
|
||||
// IR construction inserts an additional cast to a `size_t` on the extent
|
||||
// of a `new[]` expression. The resulting `ConvertInstruction` doesn't have
|
||||
// a result for `getConvertedResultExpression`. We remap this here so that
|
||||
// this `ConvertInstruction` maps to the result of the expression that
|
||||
// represents the extent.
|
||||
exists(TranslatedNonConstantAllocationSize tas |
|
||||
result = tas.getExtent().getExpr() and
|
||||
instr = tas.getInstruction(AllocationExtentConvertTag())
|
||||
)
|
||||
or
|
||||
// There's no instruction that returns `ParenthesisExpr`, but some queries
|
||||
// expect this
|
||||
exists(TranslatedTransparentConversion ttc |
|
||||
result = ttc.getExpr().(ParenthesisExpr) and
|
||||
instr = ttc.getResult()
|
||||
)
|
||||
or
|
||||
// Certain expressions generate `CopyValueInstruction`s only when they
|
||||
// are needed. Examples of this include crement operations and compound
|
||||
// assignment operations. For example:
|
||||
// ```cpp
|
||||
// int x = ...
|
||||
// int y = x++;
|
||||
// ```
|
||||
// this generate IR like:
|
||||
// ```
|
||||
// r1(glval<int>) = VariableAddress[x] :
|
||||
// r2(int) = Constant[0] :
|
||||
// m3(int) = Store[x] : &:r1, r2
|
||||
// r4(glval<int>) = VariableAddress[y] :
|
||||
// r5(glval<int>) = VariableAddress[x] :
|
||||
// r6(int) = Load[x] : &:r5, m3
|
||||
// r7(int) = Constant[1] :
|
||||
// r8(int) = Add : r6, r7
|
||||
// m9(int) = Store[x] : &:r5, r8
|
||||
// r11(int) = CopyValue : r6
|
||||
// m12(int) = Store[y] : &:r4, r11
|
||||
// ```
|
||||
// When the `CopyValueInstruction` is not generated there is no instruction
|
||||
// whose `getConvertedResultExpression` maps back to the expression. When
|
||||
// such an instruction doesn't exist it means that the old value is not
|
||||
// needed, and in that case the only value that will propagate forward in
|
||||
// the program is the value that's been updated. So in those cases we just
|
||||
// use the result of `node.asDefinition()` as the result of `node.asExpr()`.
|
||||
exists(TranslatedCoreExpr tco |
|
||||
tco.getInstruction(_) = instr and
|
||||
tco.producesExprResult() and
|
||||
result = asDefinitionImpl0(instr)
|
||||
)
|
||||
}
|
||||
|
||||
private Expr getConvertedResultExpressionImpl(Instruction instr) {
|
||||
result = getConvertedResultExpressionImpl0(instr)
|
||||
or
|
||||
not exists(getConvertedResultExpressionImpl0(instr)) and
|
||||
result = instr.getConvertedResultExpression()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the result for `node.asDefinition()` (when `node` is the instruction
|
||||
* node that wraps `store`) in the cases where `store.getAst()` should not be
|
||||
* used to define the result of `node.asDefinition()`.
|
||||
*/
|
||||
private Expr asDefinitionImpl0(StoreInstruction store) {
|
||||
// For an expression such as `i += 2` we pretend that the generated
|
||||
// `StoreInstruction` contains the result of the expression even though
|
||||
// this isn't totally aligned with the C/C++ standard.
|
||||
exists(TranslatedAssignOperation tao |
|
||||
store = tao.getInstruction(AssignmentStoreTag()) and
|
||||
result = tao.getExpr()
|
||||
)
|
||||
or
|
||||
// Similarly for `i++` and `++i` we pretend that the generated
|
||||
// `StoreInstruction` is contains the result of the expression even though
|
||||
// this isn't totally aligned with the C/C++ standard.
|
||||
exists(TranslatedCrementOperation tco |
|
||||
store = tco.getInstruction(CrementStoreTag()) and
|
||||
result = tco.getExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the expression returned by `store.getAst()` should not be
|
||||
* returned as the result of `node.asDefinition()` when `node` is the
|
||||
* instruction node that wraps `store`.
|
||||
*/
|
||||
private predicate excludeAsDefinitionResult(StoreInstruction store) {
|
||||
// Exclude the store to the temporary generated by a ternary expression.
|
||||
exists(TranslatedConditionalExpr tce |
|
||||
store = tce.getInstruction(ConditionValueFalseStoreTag())
|
||||
or
|
||||
store = tce.getInstruction(ConditionValueTrueStoreTag())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expression that represents the result of `StoreInstruction` for
|
||||
* dataflow purposes.
|
||||
*
|
||||
* For example, consider the following example
|
||||
* ```cpp
|
||||
* int x = 42; // 1
|
||||
* x = 34; // 2
|
||||
* ++x; // 3
|
||||
* x++; // 4
|
||||
* x += 1; // 5
|
||||
* int y = x += 2; // 6
|
||||
* ```
|
||||
* For (1) the result is `42`.
|
||||
* For (2) the result is `x = 34`.
|
||||
* For (3) the result is `++x`.
|
||||
* For (4) the result is `x++`.
|
||||
* For (5) the result is `x += 1`.
|
||||
* For (6) there are two results:
|
||||
* - For the `StoreInstruction` generated by `x += 2` the result
|
||||
* is `x += 2`
|
||||
* - For the `StoreInstruction` generated by `int y = ...` the result
|
||||
* is also `x += 2`
|
||||
*/
|
||||
Expr asDefinitionImpl(StoreInstruction store) {
|
||||
not exists(asDefinitionImpl0(store)) and
|
||||
not excludeAsDefinitionResult(store) and
|
||||
result = store.getAst().(Expr).getUnconverted()
|
||||
or
|
||||
result = asDefinitionImpl0(store)
|
||||
}
|
||||
}
|
||||
|
||||
private import GetConvertedResultExpression
|
||||
|
||||
/** Holds if `node` is an `OperandNode` that should map `node.asExpr()` to `e`. */
|
||||
predicate exprNodeShouldBeOperand(OperandNode node, Expr e, int n) {
|
||||
not exprNodeShouldBeIndirectOperand(_, e, n) and
|
||||
exists(Instruction def |
|
||||
unique( | | getAUse(def)) = node.getOperand() and
|
||||
e = getConvertedResultExpression(def, n)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `node` should be an `IndirectOperand` that maps `node.asIndirectExpr()` to `e`. */
|
||||
private predicate indirectExprNodeShouldBeIndirectOperand(
|
||||
IndirectOperand node, Expr e, int n, int indirectionIndex
|
||||
) {
|
||||
exists(Instruction def |
|
||||
node.hasOperandAndIndirectionIndex(unique( | | getAUse(def)), indirectionIndex) and
|
||||
e = getConvertedResultExpression(def, n)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `node` should be an `IndirectOperand` that maps `node.asExpr()` to `e`. */
|
||||
private predicate exprNodeShouldBeIndirectOperand(IndirectOperand node, Expr e, int n) {
|
||||
exists(ArgumentOperand operand |
|
||||
// When an argument (qualifier or positional) is a prvalue and the
|
||||
// parameter (qualifier or positional) is a (const) reference, IR
|
||||
// construction introduces a temporary `IRVariable`. The `VariableAddress`
|
||||
// instruction has the argument as its `getConvertedResultExpression`
|
||||
// result. However, the instruction actually represents the _address_ of
|
||||
// the argument. So to fix this mismatch, we have the indirection of the
|
||||
// `VariableAddressInstruction` map to the expression.
|
||||
node.hasOperandAndIndirectionIndex(operand, 1) and
|
||||
e = getConvertedResultExpression(operand.getDef(), n) and
|
||||
operand.getDef().(VariableAddressInstruction).getIRVariable() instanceof IRTempVariable
|
||||
)
|
||||
}
|
||||
|
||||
private predicate exprNodeShouldBeIndirectOutNode(IndirectArgumentOutNode node, Expr e, int n) {
|
||||
exists(CallInstruction call |
|
||||
call.getStaticCallTarget() instanceof Constructor and
|
||||
e = getConvertedResultExpression(call, n) and
|
||||
call.getThisArgumentOperand() = node.getAddressOperand()
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `node` should be an instruction node that maps `node.asExpr()` to `e`. */
|
||||
predicate exprNodeShouldBeInstruction(Node node, Expr e, int n) {
|
||||
not exprNodeShouldBeOperand(_, e, n) and
|
||||
not exprNodeShouldBeIndirectOutNode(_, e, n) and
|
||||
not exprNodeShouldBeIndirectOperand(_, e, n) and
|
||||
e = getConvertedResultExpression(node.asInstruction(), n)
|
||||
}
|
||||
|
||||
/** Holds if `node` should be an `IndirectInstruction` that maps `node.asIndirectExpr()` to `e`. */
|
||||
predicate indirectExprNodeShouldBeIndirectInstruction(
|
||||
IndirectInstruction node, Expr e, int n, int indirectionIndex
|
||||
) {
|
||||
not indirectExprNodeShouldBeIndirectOperand(_, e, n, indirectionIndex) and
|
||||
exists(Instruction instr |
|
||||
node.hasInstructionAndIndirectionIndex(instr, indirectionIndex) and
|
||||
e = getConvertedResultExpression(instr, n)
|
||||
)
|
||||
}
|
||||
|
||||
abstract private class ExprNodeBase extends Node {
|
||||
/**
|
||||
* Gets the expression corresponding to this node, if any. The returned
|
||||
* expression may be a `Conversion`.
|
||||
*/
|
||||
abstract Expr getConvertedExpr(int n);
|
||||
|
||||
/** Gets the non-conversion expression corresponding to this node, if any. */
|
||||
final Expr getExpr(int n) { result = this.getConvertedExpr(n).getUnconverted() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there exists a dataflow node whose `asExpr(n)` should evaluate
|
||||
* to `e`.
|
||||
*/
|
||||
private predicate exprNodeShouldBe(Expr e, int n) {
|
||||
exprNodeShouldBeInstruction(_, e, n) or
|
||||
exprNodeShouldBeOperand(_, e, n) or
|
||||
exprNodeShouldBeIndirectOutNode(_, e, n) or
|
||||
exprNodeShouldBeIndirectOperand(_, e, n)
|
||||
}
|
||||
|
||||
private class InstructionExprNode extends ExprNodeBase, InstructionNode {
|
||||
InstructionExprNode() {
|
||||
exists(Expr e, int n |
|
||||
exprNodeShouldBeInstruction(this, e, n) and
|
||||
not exists(Expr conv |
|
||||
exprNodeShouldBe(conv, n + 1) and
|
||||
conv.getUnconverted() = e.getUnconverted()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
final override Expr getConvertedExpr(int n) { exprNodeShouldBeInstruction(this, result, n) }
|
||||
}
|
||||
|
||||
private class OperandExprNode extends ExprNodeBase, OperandNode {
|
||||
OperandExprNode() {
|
||||
exists(Expr e, int n |
|
||||
exprNodeShouldBeOperand(this, e, n) and
|
||||
not exists(Expr conv |
|
||||
exprNodeShouldBe(conv, n + 1) and
|
||||
conv.getUnconverted() = e.getUnconverted()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
final override Expr getConvertedExpr(int n) { exprNodeShouldBeOperand(this, result, n) }
|
||||
}
|
||||
|
||||
abstract private class IndirectExprNodeBase extends Node {
|
||||
/**
|
||||
* Gets the expression corresponding to this node, if any. The returned
|
||||
* expression may be a `Conversion`.
|
||||
*/
|
||||
abstract Expr getConvertedExpr(int n, int indirectionIndex);
|
||||
|
||||
/** Gets the non-conversion expression corresponding to this node, if any. */
|
||||
final Expr getExpr(int n, int indirectionIndex) {
|
||||
result = this.getConvertedExpr(n, indirectionIndex).getUnconverted()
|
||||
}
|
||||
}
|
||||
|
||||
/** A signature for converting an indirect node to an expression. */
|
||||
private signature module IndirectNodeToIndirectExprSig {
|
||||
/** The indirect node class to be converted to an expression */
|
||||
class IndirectNode;
|
||||
|
||||
/**
|
||||
* Holds if the indirect expression at indirection index `indirectionIndex`
|
||||
* of `node` is `e`. The integer `n` specifies how many conversions has been
|
||||
* applied to `node`.
|
||||
*/
|
||||
predicate indirectNodeHasIndirectExpr(IndirectNode node, Expr e, int n, int indirectionIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* A module that implements the logic for deciding whether an indirect node
|
||||
* should be an `IndirectExprNode`.
|
||||
*/
|
||||
private module IndirectNodeToIndirectExpr<IndirectNodeToIndirectExprSig Sig> {
|
||||
import Sig
|
||||
|
||||
/**
|
||||
* This predicate shifts the indirection index by one when `conv` is a
|
||||
* `ReferenceDereferenceExpr`.
|
||||
*
|
||||
* This is necessary because `ReferenceDereferenceExpr` is a conversion
|
||||
* in the AST, but appears as a `LoadInstruction` in the IR.
|
||||
*/
|
||||
bindingset[e, indirectionIndex]
|
||||
private predicate adjustForReference(
|
||||
Expr e, int indirectionIndex, Expr conv, int adjustedIndirectionIndex
|
||||
) {
|
||||
conv.(ReferenceDereferenceExpr).getExpr() = e and
|
||||
adjustedIndirectionIndex = indirectionIndex - 1
|
||||
or
|
||||
not conv instanceof ReferenceDereferenceExpr and
|
||||
conv = e and
|
||||
adjustedIndirectionIndex = indirectionIndex
|
||||
}
|
||||
|
||||
/** Holds if `node` should be an `IndirectExprNode`. */
|
||||
predicate charpred(IndirectNode node) {
|
||||
exists(Expr e, int n, int indirectionIndex |
|
||||
indirectNodeHasIndirectExpr(node, e, n, indirectionIndex) and
|
||||
not exists(Expr conv, int adjustedIndirectionIndex |
|
||||
adjustForReference(e, indirectionIndex, conv, adjustedIndirectionIndex) and
|
||||
indirectExprNodeShouldBe(conv, n + 1, adjustedIndirectionIndex)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate indirectExprNodeShouldBe(Expr e, int n, int indirectionIndex) {
|
||||
indirectExprNodeShouldBeIndirectOperand(_, e, n, indirectionIndex) or
|
||||
indirectExprNodeShouldBeIndirectInstruction(_, e, n, indirectionIndex)
|
||||
}
|
||||
|
||||
private module IndirectOperandIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
|
||||
class IndirectNode = IndirectOperand;
|
||||
|
||||
predicate indirectNodeHasIndirectExpr = indirectExprNodeShouldBeIndirectOperand/4;
|
||||
}
|
||||
|
||||
module IndirectOperandToIndirectExpr =
|
||||
IndirectNodeToIndirectExpr<IndirectOperandIndirectExprNodeImpl>;
|
||||
|
||||
private class IndirectOperandIndirectExprNode extends IndirectExprNodeBase instanceof IndirectOperand
|
||||
{
|
||||
IndirectOperandIndirectExprNode() { IndirectOperandToIndirectExpr::charpred(this) }
|
||||
|
||||
final override Expr getConvertedExpr(int n, int index) {
|
||||
IndirectOperandToIndirectExpr::indirectNodeHasIndirectExpr(this, result, n, index)
|
||||
}
|
||||
}
|
||||
|
||||
private module IndirectInstructionIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
|
||||
class IndirectNode = IndirectInstruction;
|
||||
|
||||
predicate indirectNodeHasIndirectExpr = indirectExprNodeShouldBeIndirectInstruction/4;
|
||||
}
|
||||
|
||||
module IndirectInstructionToIndirectExpr =
|
||||
IndirectNodeToIndirectExpr<IndirectInstructionIndirectExprNodeImpl>;
|
||||
|
||||
private class IndirectInstructionIndirectExprNode extends IndirectExprNodeBase instanceof IndirectInstruction
|
||||
{
|
||||
IndirectInstructionIndirectExprNode() { IndirectInstructionToIndirectExpr::charpred(this) }
|
||||
|
||||
final override Expr getConvertedExpr(int n, int index) {
|
||||
IndirectInstructionToIndirectExpr::indirectNodeHasIndirectExpr(this, result, n, index)
|
||||
}
|
||||
}
|
||||
|
||||
private class IndirectArgumentOutExprNode extends ExprNodeBase, IndirectArgumentOutNode {
|
||||
IndirectArgumentOutExprNode() { exprNodeShouldBeIndirectOutNode(this, _, _) }
|
||||
|
||||
final override Expr getConvertedExpr(int n) { exprNodeShouldBeIndirectOutNode(this, result, n) }
|
||||
}
|
||||
|
||||
private class IndirectOperandExprNode extends ExprNodeBase instanceof IndirectOperand {
|
||||
IndirectOperandExprNode() { exprNodeShouldBeIndirectOperand(this, _, _) }
|
||||
|
||||
final override Expr getConvertedExpr(int n) { exprNodeShouldBeIndirectOperand(this, result, n) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression, viewed as a node in a data flow graph.
|
||||
*/
|
||||
class ExprNode extends Node instanceof ExprNodeBase {
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
Expr getExpr(int n) { result = super.getExpr(n) }
|
||||
|
||||
/**
|
||||
* Gets the non-conversion expression corresponding to this node, if any. If
|
||||
* this node strictly (in the sense of `getConvertedExpr`) corresponds to a
|
||||
* `Conversion`, then the result is that `Conversion`'s non-`Conversion` base
|
||||
* expression.
|
||||
*/
|
||||
final Expr getExpr() { result = this.getExpr(_) }
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
Expr getConvertedExpr(int n) { result = super.getConvertedExpr(n) }
|
||||
|
||||
/**
|
||||
* Gets the expression corresponding to this node, if any. The returned
|
||||
* expression may be a `Conversion`.
|
||||
*/
|
||||
final Expr getConvertedExpr() { result = this.getConvertedExpr(_) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An indirect expression, viewed as a node in a data flow graph.
|
||||
*/
|
||||
class IndirectExprNode extends Node instanceof IndirectExprNodeBase {
|
||||
/**
|
||||
* Gets the non-conversion expression corresponding to this node, if any. If
|
||||
* this node strictly (in the sense of `getConvertedExpr`) corresponds to a
|
||||
* `Conversion`, then the result is that `Conversion`'s non-`Conversion` base
|
||||
* expression.
|
||||
*/
|
||||
final Expr getExpr(int indirectionIndex) { result = this.getExpr(_, indirectionIndex) }
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
Expr getExpr(int n, int indirectionIndex) { result = super.getExpr(n, indirectionIndex) }
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
Expr getConvertedExpr(int n, int indirectionIndex) {
|
||||
result = super.getConvertedExpr(n, indirectionIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expression corresponding to this node, if any. The returned
|
||||
* expression may be a `Conversion`.
|
||||
*/
|
||||
Expr getConvertedExpr(int indirectionIndex) {
|
||||
result = this.getConvertedExpr(_, indirectionIndex)
|
||||
}
|
||||
}
|
||||
|
||||
abstract private class AbstractParameterNode extends Node {
|
||||
/**
|
||||
* Holds if this node is the parameter of `f` at the specified position. The
|
||||
|
||||
518
cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ExprNodes.qll
Normal file
518
cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ExprNodes.qll
Normal file
@@ -0,0 +1,518 @@
|
||||
/**
|
||||
* Provides the classes `ExprNode` and `IndirectExprNode` for converting between `Expr` and `Node`.
|
||||
*/
|
||||
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import DataFlowUtil
|
||||
private import DataFlowPrivate
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedExpr
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.InstructionTag
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
private Operand getAnInitializeDynamicAllocationInstructionAddress() {
|
||||
result = any(InitializeDynamicAllocationInstruction init).getAllocationAddressOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expression that should be returned as the result expression from `instr`.
|
||||
*
|
||||
* Note that this predicate may return multiple results in cases where a conversion belongs to a
|
||||
* different AST element than its operand.
|
||||
*/
|
||||
private Expr getConvertedResultExpression(Instruction instr, int n) {
|
||||
// Only fully converted instructions have a result for `asConvertedExpr`
|
||||
not conversionFlow(unique(Operand op |
|
||||
// The address operand of a `InitializeDynamicAllocationInstruction` is
|
||||
// special: we need to handle it during dataflow (since it's
|
||||
// effectively a store to an indirection), but it doesn't appear in
|
||||
// source syntax, so dataflow node <-> expression conversion shouldn't
|
||||
// care about it.
|
||||
op = getAUse(instr) and not op = getAnInitializeDynamicAllocationInstructionAddress()
|
||||
|
|
||||
op
|
||||
), _, false, false) and
|
||||
result = getConvertedResultExpressionImpl(instr) and
|
||||
n = 0
|
||||
or
|
||||
// If the conversion also has a result then we return multiple results
|
||||
exists(Operand operand | conversionFlow(operand, instr, false, false) |
|
||||
n = 1 and
|
||||
result = getConvertedResultExpressionImpl(operand.getDef())
|
||||
or
|
||||
result = getConvertedResultExpression(operand.getDef(), n - 1)
|
||||
)
|
||||
}
|
||||
|
||||
private Expr getConvertedResultExpressionImpl0(Instruction instr) {
|
||||
// IR construction inserts an additional cast to a `size_t` on the extent
|
||||
// of a `new[]` expression. The resulting `ConvertInstruction` doesn't have
|
||||
// a result for `getConvertedResultExpression`. We remap this here so that
|
||||
// this `ConvertInstruction` maps to the result of the expression that
|
||||
// represents the extent.
|
||||
exists(TranslatedNonConstantAllocationSize tas |
|
||||
result = tas.getExtent().getExpr() and
|
||||
instr = tas.getInstruction(AllocationExtentConvertTag())
|
||||
)
|
||||
or
|
||||
// There's no instruction that returns `ParenthesisExpr`, but some queries
|
||||
// expect this
|
||||
exists(TranslatedTransparentConversion ttc |
|
||||
result = ttc.getExpr().(ParenthesisExpr) and
|
||||
instr = ttc.getResult()
|
||||
)
|
||||
or
|
||||
// Certain expressions generate `CopyValueInstruction`s only when they
|
||||
// are needed. Examples of this include crement operations and compound
|
||||
// assignment operations. For example:
|
||||
// ```cpp
|
||||
// int x = ...
|
||||
// int y = x++;
|
||||
// ```
|
||||
// this generate IR like:
|
||||
// ```
|
||||
// r1(glval<int>) = VariableAddress[x] :
|
||||
// r2(int) = Constant[0] :
|
||||
// m3(int) = Store[x] : &:r1, r2
|
||||
// r4(glval<int>) = VariableAddress[y] :
|
||||
// r5(glval<int>) = VariableAddress[x] :
|
||||
// r6(int) = Load[x] : &:r5, m3
|
||||
// r7(int) = Constant[1] :
|
||||
// r8(int) = Add : r6, r7
|
||||
// m9(int) = Store[x] : &:r5, r8
|
||||
// r11(int) = CopyValue : r6
|
||||
// m12(int) = Store[y] : &:r4, r11
|
||||
// ```
|
||||
// When the `CopyValueInstruction` is not generated there is no instruction
|
||||
// whose `getConvertedResultExpression` maps back to the expression. When
|
||||
// such an instruction doesn't exist it means that the old value is not
|
||||
// needed, and in that case the only value that will propagate forward in
|
||||
// the program is the value that's been updated. So in those cases we just
|
||||
// use the result of `node.asDefinition()` as the result of `node.asExpr()`.
|
||||
exists(TranslatedCoreExpr tco |
|
||||
tco.getInstruction(_) = instr and
|
||||
tco.producesExprResult() and
|
||||
result = asDefinitionImpl0(instr)
|
||||
)
|
||||
}
|
||||
|
||||
private Expr getConvertedResultExpressionImpl(Instruction instr) {
|
||||
result = getConvertedResultExpressionImpl0(instr)
|
||||
or
|
||||
not exists(getConvertedResultExpressionImpl0(instr)) and
|
||||
result = instr.getConvertedResultExpression()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the result for `node.asDefinition()` (when `node` is the instruction
|
||||
* node that wraps `store`) in the cases where `store.getAst()` should not be
|
||||
* used to define the result of `node.asDefinition()`.
|
||||
*/
|
||||
private Expr asDefinitionImpl0(StoreInstruction store) {
|
||||
// For an expression such as `i += 2` we pretend that the generated
|
||||
// `StoreInstruction` contains the result of the expression even though
|
||||
// this isn't totally aligned with the C/C++ standard.
|
||||
exists(TranslatedAssignOperation tao |
|
||||
store = tao.getInstruction(AssignmentStoreTag()) and
|
||||
result = tao.getExpr()
|
||||
)
|
||||
or
|
||||
// Similarly for `i++` and `++i` we pretend that the generated
|
||||
// `StoreInstruction` is contains the result of the expression even though
|
||||
// this isn't totally aligned with the C/C++ standard.
|
||||
exists(TranslatedCrementOperation tco |
|
||||
store = tco.getInstruction(CrementStoreTag()) and
|
||||
result = tco.getExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the expression returned by `store.getAst()` should not be
|
||||
* returned as the result of `node.asDefinition()` when `node` is the
|
||||
* instruction node that wraps `store`.
|
||||
*/
|
||||
private predicate excludeAsDefinitionResult(StoreInstruction store) {
|
||||
// Exclude the store to the temporary generated by a ternary expression.
|
||||
exists(TranslatedConditionalExpr tce |
|
||||
store = tce.getInstruction(ConditionValueFalseStoreTag())
|
||||
or
|
||||
store = tce.getInstruction(ConditionValueTrueStoreTag())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expression that represents the result of `StoreInstruction` for
|
||||
* dataflow purposes.
|
||||
*
|
||||
* For example, consider the following example
|
||||
* ```cpp
|
||||
* int x = 42; // 1
|
||||
* x = 34; // 2
|
||||
* ++x; // 3
|
||||
* x++; // 4
|
||||
* x += 1; // 5
|
||||
* int y = x += 2; // 6
|
||||
* ```
|
||||
* For (1) the result is `42`.
|
||||
* For (2) the result is `x = 34`.
|
||||
* For (3) the result is `++x`.
|
||||
* For (4) the result is `x++`.
|
||||
* For (5) the result is `x += 1`.
|
||||
* For (6) there are two results:
|
||||
* - For the `StoreInstruction` generated by `x += 2` the result
|
||||
* is `x += 2`
|
||||
* - For the `StoreInstruction` generated by `int y = ...` the result
|
||||
* is also `x += 2`
|
||||
*/
|
||||
cached
|
||||
Expr asDefinitionImpl(StoreInstruction store) {
|
||||
not exists(asDefinitionImpl0(store)) and
|
||||
not excludeAsDefinitionResult(store) and
|
||||
result = store.getAst().(Expr).getUnconverted()
|
||||
or
|
||||
result = asDefinitionImpl0(store)
|
||||
}
|
||||
|
||||
/** Holds if `node` is an `OperandNode` that should map `node.asExpr()` to `e`. */
|
||||
private predicate exprNodeShouldBeOperand(OperandNode node, Expr e, int n) {
|
||||
not exprNodeShouldBeIndirectOperand(_, e, n) and
|
||||
exists(Instruction def |
|
||||
unique( | | getAUse(def)) = node.getOperand() and
|
||||
e = getConvertedResultExpression(def, n)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `node` should be an `IndirectOperand` that maps `node.asIndirectExpr()` to `e`. */
|
||||
private predicate indirectExprNodeShouldBeIndirectOperand(
|
||||
IndirectOperand node, Expr e, int n, int indirectionIndex
|
||||
) {
|
||||
exists(Instruction def |
|
||||
node.hasOperandAndIndirectionIndex(unique( | | getAUse(def)), indirectionIndex) and
|
||||
e = getConvertedResultExpression(def, n)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `operand`'s definition is a `VariableAddressInstruction` whose variable is a temporary */
|
||||
private predicate isIRTempVariable(Operand operand) {
|
||||
operand.getDef().(VariableAddressInstruction).getIRVariable() instanceof IRTempVariable
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is an indirect operand whose operand is an argument, and
|
||||
* the `n`'th expression associated with the operand is `e`.
|
||||
*/
|
||||
private predicate isIndirectOperandOfArgument(
|
||||
IndirectOperand node, ArgumentOperand operand, Expr e, int n
|
||||
) {
|
||||
node.hasOperandAndIndirectionIndex(operand, 1) and
|
||||
e = getConvertedResultExpression(operand.getDef(), n)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `opFrom` is an operand to a conversion, and `opTo` is the unique
|
||||
* use of the conversion.
|
||||
*/
|
||||
private predicate isConversionStep(Operand opFrom, Operand opTo) {
|
||||
exists(Instruction mid |
|
||||
conversionFlow(opFrom, mid, false, false) and
|
||||
opTo = unique( | | getAUse(mid))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an operand that satisfies `isIRTempVariable` flows to `op`
|
||||
* through a (possibly empty) sequence of conversions.
|
||||
*/
|
||||
private predicate irTempOperandConversionFlows(Operand op) {
|
||||
isIRTempVariable(op)
|
||||
or
|
||||
exists(Operand mid |
|
||||
irTempOperandConversionFlows(mid) and
|
||||
isConversionStep(mid, op)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `node` should be an `IndirectOperand` that maps `node.asExpr()` to `e`. */
|
||||
private predicate exprNodeShouldBeIndirectOperand(IndirectOperand node, Expr e, int n) {
|
||||
exists(ArgumentOperand operand |
|
||||
// When an argument (qualifier or positional) is a prvalue and the
|
||||
// parameter (qualifier or positional) is a (const) reference, IR
|
||||
// construction introduces a temporary `IRVariable`. The `VariableAddress`
|
||||
// instruction has the argument as its `getConvertedResultExpression`
|
||||
// result. However, the instruction actually represents the _address_ of
|
||||
// the argument. So to fix this mismatch, we have the indirection of the
|
||||
// `VariableAddressInstruction` map to the expression.
|
||||
isIndirectOperandOfArgument(node, operand, e, n) and
|
||||
irTempOperandConversionFlows(operand)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate exprNodeShouldBeIndirectOutNode(IndirectArgumentOutNode node, Expr e, int n) {
|
||||
exists(CallInstruction call |
|
||||
call.getStaticCallTarget() instanceof Constructor and
|
||||
e = getConvertedResultExpression(call, n) and
|
||||
call.getThisArgumentOperand() = node.getAddressOperand()
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `node` should be an instruction node that maps `node.asExpr()` to `e`. */
|
||||
private predicate exprNodeShouldBeInstruction(Node node, Expr e, int n) {
|
||||
not exprNodeShouldBeOperand(_, e, n) and
|
||||
not exprNodeShouldBeIndirectOutNode(_, e, n) and
|
||||
not exprNodeShouldBeIndirectOperand(_, e, n) and
|
||||
e = getConvertedResultExpression(node.asInstruction(), n)
|
||||
}
|
||||
|
||||
/** Holds if `node` should be an `IndirectInstruction` that maps `node.asIndirectExpr()` to `e`. */
|
||||
private predicate indirectExprNodeShouldBeIndirectInstruction(
|
||||
IndirectInstruction node, Expr e, int n, int indirectionIndex
|
||||
) {
|
||||
not indirectExprNodeShouldBeIndirectOperand(_, e, n, indirectionIndex) and
|
||||
exists(Instruction instr |
|
||||
node.hasInstructionAndIndirectionIndex(instr, indirectionIndex) and
|
||||
e = getConvertedResultExpression(instr, n)
|
||||
)
|
||||
}
|
||||
|
||||
abstract private class ExprNodeBase extends Node {
|
||||
/**
|
||||
* Gets the expression corresponding to this node, if any. The returned
|
||||
* expression may be a `Conversion`.
|
||||
*/
|
||||
abstract Expr getConvertedExpr(int n);
|
||||
|
||||
/** Gets the non-conversion expression corresponding to this node, if any. */
|
||||
final Expr getExpr(int n) { result = this.getConvertedExpr(n).getUnconverted() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there exists a dataflow node whose `asExpr(n)` should evaluate
|
||||
* to `e`.
|
||||
*/
|
||||
private predicate exprNodeShouldBe(Expr e, int n) {
|
||||
exprNodeShouldBeInstruction(_, e, n) or
|
||||
exprNodeShouldBeOperand(_, e, n) or
|
||||
exprNodeShouldBeIndirectOutNode(_, e, n) or
|
||||
exprNodeShouldBeIndirectOperand(_, e, n)
|
||||
}
|
||||
|
||||
private class InstructionExprNode extends ExprNodeBase, InstructionNode {
|
||||
InstructionExprNode() {
|
||||
exists(Expr e, int n |
|
||||
exprNodeShouldBeInstruction(this, e, n) and
|
||||
not exists(Expr conv |
|
||||
exprNodeShouldBe(conv, n + 1) and
|
||||
conv.getUnconverted() = e.getUnconverted()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
final override Expr getConvertedExpr(int n) { exprNodeShouldBeInstruction(this, result, n) }
|
||||
}
|
||||
|
||||
private class OperandExprNode extends ExprNodeBase, OperandNode {
|
||||
OperandExprNode() {
|
||||
exists(Expr e, int n |
|
||||
exprNodeShouldBeOperand(this, e, n) and
|
||||
not exists(Expr conv |
|
||||
exprNodeShouldBe(conv, n + 1) and
|
||||
conv.getUnconverted() = e.getUnconverted()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
final override Expr getConvertedExpr(int n) { exprNodeShouldBeOperand(this, result, n) }
|
||||
}
|
||||
|
||||
abstract private class IndirectExprNodeBase extends Node {
|
||||
/**
|
||||
* Gets the expression corresponding to this node, if any. The returned
|
||||
* expression may be a `Conversion`.
|
||||
*/
|
||||
abstract Expr getConvertedExpr(int n, int indirectionIndex);
|
||||
|
||||
/** Gets the non-conversion expression corresponding to this node, if any. */
|
||||
final Expr getExpr(int n, int indirectionIndex) {
|
||||
result = this.getConvertedExpr(n, indirectionIndex).getUnconverted()
|
||||
}
|
||||
}
|
||||
|
||||
/** A signature for converting an indirect node to an expression. */
|
||||
private signature module IndirectNodeToIndirectExprSig {
|
||||
/** The indirect node class to be converted to an expression */
|
||||
class IndirectNode;
|
||||
|
||||
/**
|
||||
* Holds if the indirect expression at indirection index `indirectionIndex`
|
||||
* of `node` is `e`. The integer `n` specifies how many conversions has been
|
||||
* applied to `node`.
|
||||
*/
|
||||
predicate indirectNodeHasIndirectExpr(IndirectNode node, Expr e, int n, int indirectionIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* A module that implements the logic for deciding whether an indirect node
|
||||
* should be an `IndirectExprNode`.
|
||||
*/
|
||||
private module IndirectNodeToIndirectExpr<IndirectNodeToIndirectExprSig Sig> {
|
||||
import Sig
|
||||
|
||||
/**
|
||||
* This predicate shifts the indirection index by one when `conv` is a
|
||||
* `ReferenceDereferenceExpr`.
|
||||
*
|
||||
* This is necessary because `ReferenceDereferenceExpr` is a conversion
|
||||
* in the AST, but appears as a `LoadInstruction` in the IR.
|
||||
*/
|
||||
bindingset[e, indirectionIndex]
|
||||
private predicate adjustForReference(
|
||||
Expr e, int indirectionIndex, Expr conv, int adjustedIndirectionIndex
|
||||
) {
|
||||
conv.(ReferenceDereferenceExpr).getExpr() = e and
|
||||
adjustedIndirectionIndex = indirectionIndex - 1
|
||||
or
|
||||
not conv instanceof ReferenceDereferenceExpr and
|
||||
conv = e and
|
||||
adjustedIndirectionIndex = indirectionIndex
|
||||
}
|
||||
|
||||
/** Holds if `node` should be an `IndirectExprNode`. */
|
||||
predicate charpred(IndirectNode node) {
|
||||
exists(Expr e, int n, int indirectionIndex |
|
||||
indirectNodeHasIndirectExpr(node, e, n, indirectionIndex) and
|
||||
not exists(Expr conv, int adjustedIndirectionIndex |
|
||||
adjustForReference(e, indirectionIndex, conv, adjustedIndirectionIndex) and
|
||||
indirectExprNodeShouldBe(conv, n + 1, adjustedIndirectionIndex)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate indirectExprNodeShouldBe(Expr e, int n, int indirectionIndex) {
|
||||
indirectExprNodeShouldBeIndirectOperand(_, e, n, indirectionIndex) or
|
||||
indirectExprNodeShouldBeIndirectInstruction(_, e, n, indirectionIndex)
|
||||
}
|
||||
|
||||
private module IndirectOperandIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
|
||||
class IndirectNode = IndirectOperand;
|
||||
|
||||
predicate indirectNodeHasIndirectExpr = indirectExprNodeShouldBeIndirectOperand/4;
|
||||
}
|
||||
|
||||
module IndirectOperandToIndirectExpr =
|
||||
IndirectNodeToIndirectExpr<IndirectOperandIndirectExprNodeImpl>;
|
||||
|
||||
private class IndirectOperandIndirectExprNode extends IndirectExprNodeBase instanceof IndirectOperand
|
||||
{
|
||||
IndirectOperandIndirectExprNode() { IndirectOperandToIndirectExpr::charpred(this) }
|
||||
|
||||
final override Expr getConvertedExpr(int n, int index) {
|
||||
IndirectOperandToIndirectExpr::indirectNodeHasIndirectExpr(this, result, n, index)
|
||||
}
|
||||
}
|
||||
|
||||
private module IndirectInstructionIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
|
||||
class IndirectNode = IndirectInstruction;
|
||||
|
||||
predicate indirectNodeHasIndirectExpr = indirectExprNodeShouldBeIndirectInstruction/4;
|
||||
}
|
||||
|
||||
module IndirectInstructionToIndirectExpr =
|
||||
IndirectNodeToIndirectExpr<IndirectInstructionIndirectExprNodeImpl>;
|
||||
|
||||
private class IndirectInstructionIndirectExprNode extends IndirectExprNodeBase instanceof IndirectInstruction
|
||||
{
|
||||
IndirectInstructionIndirectExprNode() { IndirectInstructionToIndirectExpr::charpred(this) }
|
||||
|
||||
final override Expr getConvertedExpr(int n, int index) {
|
||||
IndirectInstructionToIndirectExpr::indirectNodeHasIndirectExpr(this, result, n, index)
|
||||
}
|
||||
}
|
||||
|
||||
private class IndirectArgumentOutExprNode extends ExprNodeBase, IndirectArgumentOutNode {
|
||||
IndirectArgumentOutExprNode() { exprNodeShouldBeIndirectOutNode(this, _, _) }
|
||||
|
||||
final override Expr getConvertedExpr(int n) { exprNodeShouldBeIndirectOutNode(this, result, n) }
|
||||
}
|
||||
|
||||
private class IndirectOperandExprNode extends ExprNodeBase instanceof IndirectOperand {
|
||||
IndirectOperandExprNode() { exprNodeShouldBeIndirectOperand(this, _, _) }
|
||||
|
||||
final override Expr getConvertedExpr(int n) { exprNodeShouldBeIndirectOperand(this, result, n) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression, viewed as a node in a data flow graph.
|
||||
*/
|
||||
cached
|
||||
class ExprNode extends Node instanceof ExprNodeBase {
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
cached
|
||||
Expr getExpr(int n) { result = super.getExpr(n) }
|
||||
|
||||
/**
|
||||
* Gets the non-conversion expression corresponding to this node, if any. If
|
||||
* this node strictly (in the sense of `getConvertedExpr`) corresponds to a
|
||||
* `Conversion`, then the result is that `Conversion`'s non-`Conversion` base
|
||||
* expression.
|
||||
*/
|
||||
cached
|
||||
final Expr getExpr() { result = this.getExpr(_) }
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
cached
|
||||
Expr getConvertedExpr(int n) { result = super.getConvertedExpr(n) }
|
||||
|
||||
/**
|
||||
* Gets the expression corresponding to this node, if any. The returned
|
||||
* expression may be a `Conversion`.
|
||||
*/
|
||||
cached
|
||||
final Expr getConvertedExpr() { result = this.getConvertedExpr(_) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An indirect expression, viewed as a node in a data flow graph.
|
||||
*/
|
||||
cached
|
||||
class IndirectExprNode extends Node instanceof IndirectExprNodeBase {
|
||||
/**
|
||||
* Gets the non-conversion expression corresponding to this node, if any. If
|
||||
* this node strictly (in the sense of `getConvertedExpr`) corresponds to a
|
||||
* `Conversion`, then the result is that `Conversion`'s non-`Conversion` base
|
||||
* expression.
|
||||
*/
|
||||
cached
|
||||
final Expr getExpr(int indirectionIndex) { result = this.getExpr(_, indirectionIndex) }
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
cached
|
||||
Expr getExpr(int n, int indirectionIndex) { result = super.getExpr(n, indirectionIndex) }
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
cached
|
||||
Expr getConvertedExpr(int n, int indirectionIndex) {
|
||||
result = super.getConvertedExpr(n, indirectionIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expression corresponding to this node, if any. The returned
|
||||
* expression may be a `Conversion`.
|
||||
*/
|
||||
cached
|
||||
Expr getConvertedExpr(int indirectionIndex) {
|
||||
result = this.getConvertedExpr(_, indirectionIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
import Cached
|
||||
@@ -1,3 +1,3 @@
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.IR
|
||||
import semmle.code.cpp.ir.implementation.raw.IR
|
||||
import semmle.code.cpp.ir.internal.Overlap
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.IR
|
||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR
|
||||
import semmle.code.cpp.ir.internal.Overlap
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
|
||||
@@ -7,119 +7,6 @@
|
||||
import semmle.code.cpp.models.interfaces.Allocation
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
|
||||
/**
|
||||
* An allocation function (such as `malloc`) that has an argument for the size
|
||||
* in bytes.
|
||||
*/
|
||||
private class MallocAllocationFunction extends AllocationFunction {
|
||||
int sizeArg;
|
||||
|
||||
MallocAllocationFunction() {
|
||||
// --- C library allocation
|
||||
this.hasGlobalOrStdOrBslName("malloc") and // malloc(size)
|
||||
sizeArg = 0
|
||||
or
|
||||
this.hasGlobalName([
|
||||
// --- Windows Memory Management for Windows Drivers
|
||||
"MmAllocateContiguousMemory", // MmAllocateContiguousMemory(size, maxaddress)
|
||||
"MmAllocateContiguousNodeMemory", // MmAllocateContiguousNodeMemory(size, minaddress, maxaddress, bound, flag, prefer)
|
||||
"MmAllocateContiguousMemorySpecifyCache", // MmAllocateContiguousMemorySpecifyCache(size, minaddress, maxaddress, bound, type)
|
||||
"MmAllocateContiguousMemorySpecifyCacheNode", // MmAllocateContiguousMemorySpecifyCacheNode(size, minaddress, maxaddress, bound, type, prefer)
|
||||
"MmAllocateNonCachedMemory", // MmAllocateNonCachedMemory(size)
|
||||
"MmAllocateMappingAddress", // MmAllocateMappingAddress(size, tag)
|
||||
// --- Windows COM allocation
|
||||
"CoTaskMemAlloc", // CoTaskMemAlloc(size)
|
||||
// --- Solaris/BSD kernel memory allocator
|
||||
"kmem_alloc", // kmem_alloc(size, flags)
|
||||
"kmem_zalloc", // kmem_zalloc(size, flags)
|
||||
// --- OpenSSL memory allocation
|
||||
"CRYPTO_malloc", // CRYPTO_malloc(size_t num, const char *file, int line)
|
||||
"CRYPTO_zalloc", // CRYPTO_zalloc(size_t num, const char *file, int line)
|
||||
"CRYPTO_secure_malloc", // CRYPTO_secure_malloc(size_t num, const char *file, int line)
|
||||
"CRYPTO_secure_zalloc", // CRYPTO_secure_zalloc(size_t num, const char *file, int line)
|
||||
"g_malloc", // g_malloc (n_bytes);
|
||||
"g_try_malloc" // g_try_malloc(n_bytes);
|
||||
]) and
|
||||
sizeArg = 0
|
||||
or
|
||||
this.hasGlobalName([
|
||||
// --- Windows Memory Management for Windows Drivers
|
||||
"ExAllocatePool", // ExAllocatePool(type, size)
|
||||
"ExAllocatePool2", // ExAllocatePool2(flags, size, tag)
|
||||
"ExAllocatePool3", // ExAllocatePool3(flags, size, tag, extparams, extparamscount)
|
||||
"ExAllocatePoolWithTag", // ExAllocatePool(type, size, tag)
|
||||
"ExAllocatePoolWithTagPriority", // ExAllocatePoolWithTagPriority(type, size, tag, priority)
|
||||
"ExAllocatePoolWithQuota", // ExAllocatePoolWithQuota(type, size)
|
||||
"ExAllocatePoolWithQuotaTag", // ExAllocatePoolWithQuotaTag(type, size, tag)
|
||||
"ExAllocatePoolZero", // ExAllocatePoolZero(type, size, tag)
|
||||
"IoAllocateMdl", // IoAllocateMdl(address, size, flag, flag, irp)
|
||||
"IoAllocateErrorLogEntry", // IoAllocateErrorLogEntry(object, size)
|
||||
// --- Windows Global / Local legacy allocation
|
||||
"LocalAlloc", // LocalAlloc(flags, size)
|
||||
"GlobalAlloc", // GlobalAlloc(flags, size)
|
||||
// --- Windows System Services allocation
|
||||
"VirtualAlloc" // VirtualAlloc(address, size, type, flag)
|
||||
]) and
|
||||
sizeArg = 1
|
||||
or
|
||||
this.hasGlobalName("HeapAlloc") and // HeapAlloc(heap, flags, size)
|
||||
sizeArg = 2
|
||||
or
|
||||
this.hasGlobalName([
|
||||
// --- Windows Memory Management for Windows Drivers
|
||||
"MmAllocatePagesForMdl", // MmAllocatePagesForMdl(minaddress, maxaddress, skip, size)
|
||||
"MmAllocatePagesForMdlEx", // MmAllocatePagesForMdlEx(minaddress, maxaddress, skip, size, type, flags)
|
||||
"MmAllocateNodePagesForMdlEx" // MmAllocateNodePagesForMdlEx(minaddress, maxaddress, skip, size, type, prefer, flags)
|
||||
]) and
|
||||
sizeArg = 3
|
||||
}
|
||||
|
||||
override int getSizeArg() { result = sizeArg }
|
||||
}
|
||||
|
||||
/**
|
||||
* An allocation function (such as `alloca`) that does not require a
|
||||
* corresponding free (and has an argument for the size in bytes).
|
||||
*/
|
||||
private class AllocaAllocationFunction extends AllocationFunction {
|
||||
int sizeArg;
|
||||
|
||||
AllocaAllocationFunction() {
|
||||
this.hasGlobalName([
|
||||
// --- stack allocation
|
||||
"alloca", // // alloca(size)
|
||||
"__builtin_alloca", // __builtin_alloca(size)
|
||||
"_alloca", // _alloca(size)
|
||||
"_malloca" // _malloca(size)
|
||||
]) and
|
||||
sizeArg = 0
|
||||
}
|
||||
|
||||
override int getSizeArg() { result = sizeArg }
|
||||
|
||||
override predicate requiresDealloc() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An allocation function (such as `calloc`) that has an argument for the size
|
||||
* and another argument for the size of those units (in bytes).
|
||||
*/
|
||||
private class CallocAllocationFunction extends AllocationFunction {
|
||||
int sizeArg;
|
||||
int multArg;
|
||||
|
||||
CallocAllocationFunction() {
|
||||
// --- C library allocation
|
||||
this.hasGlobalOrStdOrBslName("calloc") and // calloc(num, size)
|
||||
sizeArg = 1 and
|
||||
multArg = 0
|
||||
}
|
||||
|
||||
override int getSizeArg() { result = sizeArg }
|
||||
|
||||
override int getSizeMult() { result = multArg }
|
||||
}
|
||||
|
||||
/**
|
||||
* An allocation function (such as `realloc`) that has an argument for the size
|
||||
* in bytes, and an argument for an existing pointer that is to be reallocated.
|
||||
@@ -373,6 +260,63 @@ private class NewArrayAllocationExpr extends AllocationExpr, NewArrayExpr {
|
||||
override predicate requiresDealloc() { not exists(this.getPlacementPointer()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `f` is an allocation function according to the
|
||||
* extensible `allocationFunctionModel` predicate.
|
||||
*/
|
||||
private predicate isAllocationFunctionFromModel(
|
||||
Function f, string namespace, string type, string name
|
||||
) {
|
||||
exists(boolean subtypes | allocationFunctionModel(namespace, type, subtypes, name, _, _, _, _) |
|
||||
if type = ""
|
||||
then f.hasQualifiedName(namespace, "", name)
|
||||
else
|
||||
exists(Class c |
|
||||
c.hasQualifiedName(namespace, type) and f.hasQualifiedName(namespace, _, name)
|
||||
|
|
||||
if subtypes = true
|
||||
then f = c.getADerivedClass*().getAMemberFunction()
|
||||
else f = c.getAMemberFunction()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* An allocation function modeled via the extensible `allocationFunctionModel` predicate.
|
||||
*/
|
||||
private class AllocationFunctionFromModel extends AllocationFunction {
|
||||
string namespace;
|
||||
string type;
|
||||
string name;
|
||||
|
||||
AllocationFunctionFromModel() { isAllocationFunctionFromModel(this, namespace, type, name) }
|
||||
|
||||
final override int getSizeArg() {
|
||||
exists(string sizeArg |
|
||||
allocationFunctionModel(namespace, type, _, name, sizeArg, _, _, _) and
|
||||
result = sizeArg.toInt()
|
||||
)
|
||||
}
|
||||
|
||||
final override int getSizeMult() {
|
||||
exists(string sizeMult |
|
||||
allocationFunctionModel(namespace, type, _, name, _, sizeMult, _, _) and
|
||||
result = sizeMult.toInt()
|
||||
)
|
||||
}
|
||||
|
||||
final override int getReallocPtrArg() {
|
||||
exists(string reallocPtrArg |
|
||||
allocationFunctionModel(namespace, type, _, name, _, _, reallocPtrArg, _) and
|
||||
result = reallocPtrArg.toInt()
|
||||
)
|
||||
}
|
||||
|
||||
final override predicate requiresDealloc() {
|
||||
allocationFunctionModel(namespace, type, _, name, _, _, _, true)
|
||||
}
|
||||
}
|
||||
|
||||
private module HeuristicAllocation {
|
||||
/** A class that maps an `AllocationExpr` to an `HeuristicAllocationExpr`. */
|
||||
private class HeuristicAllocationModeled extends HeuristicAllocationExpr instanceof AllocationExpr
|
||||
|
||||
@@ -7,61 +7,42 @@
|
||||
import semmle.code.cpp.models.interfaces.Deallocation
|
||||
|
||||
/**
|
||||
* A deallocation function such as `free`.
|
||||
* Holds if `f` is an deallocation function according to the
|
||||
* extensible `deallocationFunctionModel` predicate.
|
||||
*/
|
||||
private class StandardDeallocationFunction extends DeallocationFunction {
|
||||
int freedArg;
|
||||
private predicate isDeallocationFunctionFromModel(
|
||||
Function f, string namespace, string type, string name
|
||||
) {
|
||||
exists(boolean subtypes | deallocationFunctionModel(namespace, type, subtypes, name, _) |
|
||||
if type = ""
|
||||
then f.hasQualifiedName(namespace, "", name)
|
||||
else
|
||||
exists(Class c |
|
||||
c.hasQualifiedName(namespace, type) and f.hasQualifiedName(namespace, _, name)
|
||||
|
|
||||
if subtypes = true
|
||||
then f = c.getADerivedClass*().getAMemberFunction()
|
||||
else f = c.getAMemberFunction()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
StandardDeallocationFunction() {
|
||||
this.hasGlobalOrStdOrBslName([
|
||||
// --- C library allocation
|
||||
"free", "realloc"
|
||||
]) and
|
||||
freedArg = 0
|
||||
or
|
||||
this.hasGlobalName([
|
||||
// --- OpenSSL memory deallocation
|
||||
"CRYPTO_free", "CRYPTO_secure_free",
|
||||
// --- glib memory deallocation
|
||||
"g_free"
|
||||
]) and
|
||||
freedArg = 0
|
||||
or
|
||||
this.hasGlobalOrStdName([
|
||||
// --- Windows Memory Management for Windows Drivers
|
||||
"ExFreePool", "ExFreePoolWithTag", "ExDeleteTimer", "IoFreeIrp", "IoFreeMdl",
|
||||
"IoFreeErrorLogEntry", "IoFreeWorkItem", "MmFreeContiguousMemory",
|
||||
"MmFreeContiguousMemorySpecifyCache", "MmFreeNonCachedMemory", "MmFreeMappingAddress",
|
||||
"MmFreePagesFromMdl", "MmUnmapReservedMapping", "MmUnmapLockedPages",
|
||||
"NdisFreeGenericObject", "NdisFreeMemory", "NdisFreeMemoryWithTag", "NdisFreeMdl",
|
||||
"NdisFreeNetBufferListPool", "NdisFreeNetBufferPool",
|
||||
// --- Windows Global / Local legacy allocation
|
||||
"LocalFree", "GlobalFree", "LocalReAlloc", "GlobalReAlloc",
|
||||
// --- Windows System Services allocation
|
||||
"VirtualFree",
|
||||
// --- Windows COM allocation
|
||||
"CoTaskMemFree", "CoTaskMemRealloc",
|
||||
// --- Windows Automation
|
||||
"SysFreeString",
|
||||
// --- Solaris/BSD kernel memory allocator
|
||||
"kmem_free"
|
||||
]) and
|
||||
freedArg = 0
|
||||
or
|
||||
this.hasGlobalOrStdName([
|
||||
// --- Windows Memory Management for Windows Drivers
|
||||
"ExFreeToLookasideListEx", "ExFreeToPagedLookasideList", "ExFreeToNPagedLookasideList",
|
||||
"NdisFreeMemoryWithTagPriority", "StorPortFreeMdl", "StorPortFreePool",
|
||||
// --- NetBSD pool manager
|
||||
"pool_put", "pool_cache_put"
|
||||
]) and
|
||||
freedArg = 1
|
||||
or
|
||||
this.hasGlobalOrStdName(["HeapFree", "HeapReAlloc"]) and
|
||||
freedArg = 2
|
||||
/**
|
||||
* A deallocation function modeled via the extensible `deallocationFunctionModel` predicate.
|
||||
*/
|
||||
private class DeallocationFunctionFromModel extends DeallocationFunction {
|
||||
string namespace;
|
||||
string type;
|
||||
string name;
|
||||
|
||||
DeallocationFunctionFromModel() { isDeallocationFunctionFromModel(this, namespace, type, name) }
|
||||
|
||||
final override int getFreedArg() {
|
||||
exists(string freedArg |
|
||||
deallocationFunctionModel(namespace, type, _, name, freedArg) and
|
||||
result = freedArg.toInt()
|
||||
)
|
||||
}
|
||||
|
||||
override int getFreedArg() { result = freedArg }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -89,6 +89,14 @@ abstract class AllocationFunction extends Function {
|
||||
predicate requiresDealloc() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an external allocation model exists for the given parameters.
|
||||
*/
|
||||
extensible predicate allocationFunctionModel(
|
||||
string namespace, string type, boolean subtypes, string name, string sizeArg, string multArg,
|
||||
string reallocPtrArg, boolean requiresDealloc
|
||||
);
|
||||
|
||||
/**
|
||||
* An `operator new` or `operator new[]` function that may be associated with
|
||||
* `new` or `new[]` expressions. Note that `new` and `new[]` are not function
|
||||
|
||||
@@ -34,6 +34,13 @@ abstract class DeallocationFunction extends Function {
|
||||
int getFreedArg() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an external deallocation model exists for the given parameters.
|
||||
*/
|
||||
extensible predicate deallocationFunctionModel(
|
||||
string namespace, string type, boolean subtypes, string name, string freedArg
|
||||
);
|
||||
|
||||
/**
|
||||
* An `operator delete` or `operator delete[]` function that may be associated
|
||||
* with `delete` or `delete[]` expressions. Note that `delete` and `delete[]`
|
||||
|
||||
@@ -95,7 +95,7 @@ module FlowFromFree<FlowFromFreeParamSig P> {
|
||||
e = any(StoreInstruction store).getDestinationAddress().getUnconvertedResultExpression()
|
||||
)
|
||||
or
|
||||
n.asExpr() instanceof ArrayExpr
|
||||
[n.asExpr(), n.asIndirectExpr()] instanceof ArrayExpr
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
## 1.0.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `cpp/dangerous-function-overflow` no longer produces a false positive alert when the `gets` function does not have exactly one parameter.
|
||||
|
||||
## 1.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
@@ -215,13 +215,18 @@ predicate noThrowInTryBlock(NewOrNewArrayExpr newExpr, BadAllocCatchBlock catchB
|
||||
*/
|
||||
predicate nullCheckInThrowingNew(NewOrNewArrayExpr newExpr, GuardCondition guard) {
|
||||
newExpr.getAllocator() instanceof ThrowingAllocator and
|
||||
(
|
||||
// Handles null comparisons.
|
||||
guard.ensuresEq(globalValueNumber(newExpr).getAnExpr(), any(NullValue null), _, _, _)
|
||||
or
|
||||
// Handles `if(ptr)` and `if(!ptr)` cases.
|
||||
guard = globalValueNumber(newExpr).getAnExpr()
|
||||
)
|
||||
// There can be many guard conditions that compares `newExpr` againgst 0.
|
||||
// For example, for `if(!p)` both `p` and `!p` are guard conditions. To not
|
||||
// produce duplicates results we pick the "first" guard condition according
|
||||
// to some arbitrary ordering (i.e., location information). This means `!p` is the
|
||||
// element that we use to construct the alert.
|
||||
guard =
|
||||
min(GuardCondition gc, int startline, int startcolumn, int endline, int endcolumn |
|
||||
gc.comparesEq(globalValueNumber(newExpr).getAnExpr(), 0, _, _) and
|
||||
gc.getLocation().hasLocationInfo(_, startline, startcolumn, endline, endcolumn)
|
||||
|
|
||||
gc order by startline, startcolumn, endline, endcolumn
|
||||
)
|
||||
}
|
||||
|
||||
from NewOrNewArrayExpr newExpr, Element element, string msg, string elementString
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
## 1.0.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `cpp/dangerous-function-overflow` no longer produces a false positive alert when the `gets` function does not have exactly one parameter.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.0.0
|
||||
lastReleaseVersion: 1.0.1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 1.0.1-dev
|
||||
version: 1.0.2-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
#include "b.h"
|
||||
static int has_angle_b = __has_include(<b.h>);
|
||||
|
||||
// semmle-extractor-options: -I${testdir}/dir2 -iquote ${testdir}/dir1 --edg --clang
|
||||
// semmle-extractor-options: -I${testdir}/dir2 -iquote ${testdir}/dir1 --clang
|
||||
|
||||
@@ -1 +1 @@
|
||||
semmle-extractor-options: --edg --microsoft
|
||||
semmle-extractor-options: --microsoft
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
| arguments.c | 15 | --edg |
|
||||
| arguments.c | 16 | __CODEQL_TEST__ |
|
||||
| arguments.c | 17 | --gcc |
|
||||
| arguments.c | 18 | --predefined_macros |
|
||||
| arguments.c | 19 | <tools>/qltest/predefined_macros |
|
||||
| arguments.c | 20 | -w |
|
||||
| arguments.c | 21 | -Werror |
|
||||
| arguments.c | 22 | arguments.c |
|
||||
| arguments.c | 18 | -w |
|
||||
| arguments.c | 19 | -Werror |
|
||||
| arguments.c | 20 | arguments.c |
|
||||
|
||||
@@ -4,8 +4,5 @@ from Compilation c, int i, string s
|
||||
// Skip the extractor name; it'll vary depending on platform
|
||||
where
|
||||
i > 0 and
|
||||
s =
|
||||
c.getArgument(i)
|
||||
.replaceAll("\\", "/")
|
||||
.regexpReplaceAll(".*(/qltest/predefined_macros)", "<tools>$1")
|
||||
s = c.getArgument(i).replaceAll("\\", "/")
|
||||
select c.getAFileCompiled().toString(), i, s
|
||||
|
||||
@@ -1 +1 @@
|
||||
semmle-extractor-options: --edg --clang
|
||||
semmle-extractor-options: --clang
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
| declspec.cpp:4:23:4:43 | Use fatal() instead | declspec.cpp:4:59:4:62 | exit | declspec.cpp:4:12:4:21 | deprecated | Use fatal() instead |
|
||||
| routine_attributes2.cpp:5:6:5:11 | hidden | routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.cpp:5:6:5:11 | visibility | hidden |
|
||||
| routine_attributes2.cpp:5:6:5:11 | hidden | routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.cpp:5:6:5:11 | visibility | hidden |
|
||||
| routine_attributes2.h:3:6:3:11 | hidden | routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.h:3:6:3:11 | visibility | hidden |
|
||||
| routine_attributes2.h:3:6:3:11 | hidden | routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.h:3:6:3:11 | visibility | hidden |
|
||||
| routine_attributes.c:3:53:3:59 | dummy | routine_attributes.c:3:12:3:24 | named_weakref | routine_attributes.c:3:44:3:50 | weakref | dummy |
|
||||
| routine_attributes.c:4:62:4:68 | dummy | routine_attributes.c:4:12:4:26 | aliased_weakref | routine_attributes.c:4:55:4:59 | alias | dummy |
|
||||
| routine_attributes.c:6:49:6:55 | dummy | routine_attributes.c:6:12:6:22 | plain_alias | routine_attributes.c:6:42:6:46 | alias | dummy |
|
||||
|
||||
@@ -18,6 +18,10 @@
|
||||
| header_export.cpp:14:16:14:26 | myFunction4 | header_export.cpp:14:1:14:9 | dllexport |
|
||||
| header_export.cpp:18:6:18:16 | myFunction5 | header.h:10:2:10:10 | dllexport |
|
||||
| header_export.cpp:18:6:18:16 | myFunction5 | header.h:10:2:10:10 | dllimport |
|
||||
| routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.cpp:5:6:5:11 | visibility |
|
||||
| routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.cpp:5:6:5:11 | visibility |
|
||||
| routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.h:3:6:3:11 | visibility |
|
||||
| routine_attributes2.cpp:5:13:5:21 | a_routine | routine_attributes2.h:3:6:3:11 | visibility |
|
||||
| routine_attributes.c:3:12:3:24 | named_weakref | routine_attributes.c:3:44:3:50 | weakref |
|
||||
| routine_attributes.c:4:12:4:26 | aliased_weakref | routine_attributes.c:4:46:4:52 | weakref |
|
||||
| routine_attributes.c:4:12:4:26 | aliased_weakref | routine_attributes.c:4:55:4:59 | alias |
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#define HIDDEN __attribute__((visibility("hidden")))
|
||||
|
||||
#include "routine_attributes2.h"
|
||||
|
||||
void HIDDEN a_routine() {
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void HIDDEN a_routine();
|
||||
@@ -0,0 +1,3 @@
|
||||
#define HIDDEN __attribute__((visibility("hidden")))
|
||||
|
||||
#include "routine_attributes2.h"
|
||||
@@ -1,3 +1,6 @@
|
||||
| type_attributes2.cpp:5:14:5:20 | a_class | type_attributes2.cpp:5:7:5:12 | visibility | type_attributes2.cpp:5:7:5:12 | hidden |
|
||||
| type_attributes2.cpp:5:14:5:20 | a_class | type_attributes2.h:3:7:3:12 | visibility | type_attributes2.h:3:7:3:12 | hidden |
|
||||
| type_attributes2.cpp:5:14:5:20 | a_class | type_attributes2.h:3:7:3:12 | visibility | type_attributes2.h:3:7:3:12 | hidden |
|
||||
| type_attributes_ms.cpp:4:67:4:75 | IDispatch | type_attributes_ms.cpp:4:19:4:22 | uuid | type_attributes_ms.cpp:4:24:4:63 | {00020400-0000-0000-c000-000000000046} |
|
||||
| type_attributes_ms.cpp:5:30:5:33 | Str1 | type_attributes_ms.cpp:5:12:5:16 | align | type_attributes_ms.cpp:5:18:5:19 | 32 |
|
||||
| type_attributes_ms.cpp:6:55:6:62 | IUnknown | type_attributes_ms.cpp:6:2:6:2 | uuid | type_attributes_ms.cpp:6:2:6:2 | 00000000-0000-0000-c000-000000000046 |
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
| file://:0:0:0:0 | short __attribute((__may_alias__)) | type_attributes.c:25:30:25:42 | may_alias |
|
||||
| type_attributes2.cpp:5:14:5:20 | a_class | type_attributes2.cpp:5:7:5:12 | visibility |
|
||||
| type_attributes2.cpp:5:14:5:20 | a_class | type_attributes2.h:3:7:3:12 | visibility |
|
||||
| type_attributes2.cpp:5:14:5:20 | a_class | type_attributes2.h:3:7:3:12 | visibility |
|
||||
| type_attributes.c:5:36:5:51 | my_packed_struct | type_attributes.c:5:23:5:32 | packed |
|
||||
| type_attributes.c:10:54:10:54 | (unnamed class/struct/union) | type_attributes.c:10:30:10:50 | transparent_union |
|
||||
| type_attributes.c:16:54:16:54 | (unnamed class/struct/union) | type_attributes.c:16:30:16:50 | transparent_union |
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#define HIDDEN __attribute__((visibility("hidden")))
|
||||
|
||||
#include "type_attributes2.h"
|
||||
|
||||
class HIDDEN a_class {
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
class HIDDEN a_class;
|
||||
@@ -0,0 +1,3 @@
|
||||
#define HIDDEN __attribute__((visibility("hidden")))
|
||||
|
||||
#include "type_attributes2.h"
|
||||
@@ -6,6 +6,10 @@
|
||||
| ms_var_attributes.cpp:12:42:12:46 | field | ms_var_attributes.cpp:12:14:12:21 | property |
|
||||
| ms_var_attributes.cpp:20:34:20:37 | pBuf | ms_var_attributes.cpp:20:12:20:12 | SAL_volatile |
|
||||
| ms_var_attributes.h:5:22:5:27 | myInt3 | ms_var_attributes.h:5:1:5:9 | dllexport |
|
||||
| var_attributes2.cpp:5:12:5:21 | a_variable | var_attributes2.cpp:5:5:5:10 | visibility |
|
||||
| var_attributes2.cpp:5:12:5:21 | a_variable | var_attributes2.cpp:5:5:5:10 | visibility |
|
||||
| var_attributes2.cpp:5:12:5:21 | a_variable | var_attributes2.h:3:12:3:17 | visibility |
|
||||
| var_attributes2.cpp:5:12:5:21 | a_variable | var_attributes2.h:3:12:3:17 | visibility |
|
||||
| var_attributes.c:1:12:1:19 | weak_var | var_attributes.c:1:36:1:39 | weak |
|
||||
| var_attributes.c:2:12:2:22 | weakref_var | var_attributes.c:2:39:2:45 | weakref |
|
||||
| var_attributes.c:3:12:3:19 | used_var | var_attributes.c:3:36:3:39 | used |
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#define HIDDEN __attribute__((visibility("hidden")))
|
||||
|
||||
#include "var_attributes2.h"
|
||||
|
||||
int HIDDEN a_variable;
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
extern int HIDDEN a_variable;
|
||||
@@ -0,0 +1,3 @@
|
||||
#define HIDDEN __attribute__((visibility("hidden")))
|
||||
|
||||
#include "var_attributes2.h"
|
||||
@@ -1,4 +1,4 @@
|
||||
// semmle-extractor-options: --edg --clang
|
||||
// semmle-extractor-options: --clang
|
||||
|
||||
int x = 0;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// semmle-extractor-options: --edg --clang --edg --c++11 --edg --nullptr
|
||||
// semmle-extractor-options: --clang --edg --c++11 --edg --nullptr
|
||||
|
||||
static int has_nullptr_f = __has_feature(cxx_nullptr);
|
||||
static int has_nullptr_e = __has_extension(cxx_nullptr);
|
||||
|
||||
@@ -1 +1 @@
|
||||
semmle-extractor-options: --edg --clang
|
||||
semmle-extractor-options: --clang
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// For the canonical behaviour, run: clang -E -w test.cpp
|
||||
#define __builtin_TRAP __builtin_trap
|
||||
#define BAR "bar.h"
|
||||
// semmle-extractor-options: --edg --clang --expect_errors
|
||||
// semmle-extractor-options: --clang --expect_errors
|
||||
#if defined(__has_include)
|
||||
static int has_include = 1;
|
||||
#else
|
||||
|
||||
@@ -1 +1 @@
|
||||
semmle-extractor-options: --edg --clang --edg --ms_extensions
|
||||
semmle-extractor-options: --clang --edg --ms_extensions
|
||||
|
||||
@@ -74,6 +74,8 @@ astGuardsCompare
|
||||
| 34 | j >= 10+0 when ... < ... is false |
|
||||
| 42 | 10 < j+1 when ... < ... is false |
|
||||
| 42 | 10 >= j+1 when ... < ... is true |
|
||||
| 42 | call to getABool != 0 when call to getABool is true |
|
||||
| 42 | call to getABool == 0 when call to getABool is false |
|
||||
| 42 | j < 10+0 when ... < ... is true |
|
||||
| 42 | j >= 10+0 when ... < ... is false |
|
||||
| 44 | 0 < z+0 when ... > ... is true |
|
||||
@@ -537,6 +539,8 @@ astGuardsEnsure_const
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 34 | 34 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | -1 | 30 | 30 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | -1 | 31 | 32 |
|
||||
| test.cpp:42:13:42:20 | call to getABool | test.cpp:42:13:42:20 | call to getABool | != | 0 | 43 | 45 |
|
||||
| test.cpp:42:13:42:20 | call to getABool | test.cpp:42:13:42:20 | call to getABool | == | 0 | 53 | 53 |
|
||||
irGuards
|
||||
| test.c:7:9:7:13 | CompareGT: ... > ... |
|
||||
| test.c:17:8:17:12 | CompareLT: ... < ... |
|
||||
@@ -613,6 +617,8 @@ irGuardsCompare
|
||||
| 34 | j >= 10+0 when CompareLT: ... < ... is false |
|
||||
| 42 | 10 < j+1 when CompareLT: ... < ... is false |
|
||||
| 42 | 10 >= j+1 when CompareLT: ... < ... is true |
|
||||
| 42 | call to getABool != 0 when Call: call to getABool is true |
|
||||
| 42 | call to getABool == 0 when Call: call to getABool is false |
|
||||
| 42 | j < 10 when CompareLT: ... < ... is true |
|
||||
| 42 | j < 10+0 when CompareLT: ... < ... is true |
|
||||
| 42 | j >= 10 when CompareLT: ... < ... is false |
|
||||
@@ -1081,3 +1087,5 @@ irGuardsEnsure_const
|
||||
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | != | -1 | 34 | 34 |
|
||||
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | == | -1 | 30 | 30 |
|
||||
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | == | -1 | 32 | 32 |
|
||||
| test.cpp:42:13:42:20 | Call: call to getABool | test.cpp:42:13:42:20 | Call: call to getABool | != | 0 | 44 | 44 |
|
||||
| test.cpp:42:13:42:20 | Call: call to getABool | test.cpp:42:13:42:20 | Call: call to getABool | == | 0 | 53 | 53 |
|
||||
|
||||
@@ -42,3 +42,10 @@
|
||||
| test.cpp:99:6:99:6 | f |
|
||||
| test.cpp:105:6:105:14 | ... != ... |
|
||||
| test.cpp:111:6:111:14 | ... != ... |
|
||||
| test.cpp:122:9:122:9 | b |
|
||||
| test.cpp:125:13:125:20 | ! ... |
|
||||
| test.cpp:125:14:125:17 | call to safe |
|
||||
| test.cpp:131:6:131:21 | call to __builtin_expect |
|
||||
| test.cpp:135:6:135:21 | call to __builtin_expect |
|
||||
| test.cpp:141:6:141:21 | call to __builtin_expect |
|
||||
| test.cpp:145:6:145:21 | call to __builtin_expect |
|
||||
|
||||
@@ -44,6 +44,8 @@
|
||||
| 34 | j >= 10+0 when ... < ... is false |
|
||||
| 42 | 10 < j+1 when ... < ... is false |
|
||||
| 42 | 10 >= j+1 when ... < ... is true |
|
||||
| 42 | call to getABool != 0 when call to getABool is true |
|
||||
| 42 | call to getABool == 0 when call to getABool is false |
|
||||
| 42 | j < 10 when ... < ... is true |
|
||||
| 42 | j < 10+0 when ... < ... is true |
|
||||
| 42 | j >= 10 when ... < ... is false |
|
||||
@@ -149,16 +151,59 @@
|
||||
| 111 | 0.0 == i+0 when ... != ... is false |
|
||||
| 111 | i != 0.0+0 when ... != ... is true |
|
||||
| 111 | i == 0.0+0 when ... != ... is false |
|
||||
| 122 | b != 0 when b is true |
|
||||
| 122 | b == 0 when b is false |
|
||||
| 125 | ! ... != 0 when ! ... is true |
|
||||
| 125 | ! ... == 0 when ! ... is false |
|
||||
| 125 | call to safe != 0 when ! ... is false |
|
||||
| 125 | call to safe != 0 when call to safe is true |
|
||||
| 125 | call to safe == 0 when call to safe is false |
|
||||
| 126 | 1 != 0 when 1 is true |
|
||||
| 126 | 1 != 0 when ... && ... is true |
|
||||
| 126 | 1 == 0 when 1 is false |
|
||||
| 126 | call to test3_condition != 0 when ... && ... is true |
|
||||
| 126 | call to test3_condition != 0 when call to test3_condition is true |
|
||||
| 126 | call to test3_condition == 0 when call to test3_condition is false |
|
||||
| 131 | ... + ... != a+0 when call to __builtin_expect is false |
|
||||
| 131 | ... + ... == a+0 when call to __builtin_expect is true |
|
||||
| 131 | a != ... + ...+0 when call to __builtin_expect is false |
|
||||
| 131 | a != b+42 when call to __builtin_expect is false |
|
||||
| 131 | a == ... + ...+0 when call to __builtin_expect is true |
|
||||
| 131 | a == b+42 when call to __builtin_expect is true |
|
||||
| 131 | b != 0 when b is true |
|
||||
| 131 | b != a+-42 when call to __builtin_expect is false |
|
||||
| 131 | b == 0 when b is false |
|
||||
| 131 | b == a+-42 when call to __builtin_expect is true |
|
||||
| 131 | call to __builtin_expect != 0 when call to __builtin_expect is true |
|
||||
| 131 | call to __builtin_expect == 0 when call to __builtin_expect is false |
|
||||
| 135 | ... + ... != a+0 when call to __builtin_expect is true |
|
||||
| 135 | ... + ... == a+0 when call to __builtin_expect is false |
|
||||
| 135 | a != ... + ...+0 when call to __builtin_expect is true |
|
||||
| 135 | a != b+42 when call to __builtin_expect is true |
|
||||
| 135 | a == ... + ...+0 when call to __builtin_expect is false |
|
||||
| 135 | a == b+42 when call to __builtin_expect is false |
|
||||
| 135 | b != a+-42 when call to __builtin_expect is true |
|
||||
| 135 | b == a+-42 when call to __builtin_expect is false |
|
||||
| 135 | call to __builtin_expect != 0 when call to __builtin_expect is true |
|
||||
| 135 | call to __builtin_expect == 0 when call to __builtin_expect is false |
|
||||
| 137 | 0 != 0 when 0 is true |
|
||||
| 137 | 0 == 0 when 0 is false |
|
||||
| 141 | 42 != a+0 when call to __builtin_expect is false |
|
||||
| 141 | 42 == a+0 when call to __builtin_expect is true |
|
||||
| 141 | a != 42 when call to __builtin_expect is false |
|
||||
| 141 | a != 42+0 when call to __builtin_expect is false |
|
||||
| 141 | a == 42 when call to __builtin_expect is true |
|
||||
| 141 | a == 42+0 when call to __builtin_expect is true |
|
||||
| 141 | call to __builtin_expect != 0 when call to __builtin_expect is true |
|
||||
| 141 | call to __builtin_expect == 0 when call to __builtin_expect is false |
|
||||
| 145 | 42 != a+0 when call to __builtin_expect is true |
|
||||
| 145 | 42 == a+0 when call to __builtin_expect is false |
|
||||
| 145 | a != 42 when call to __builtin_expect is true |
|
||||
| 145 | a != 42+0 when call to __builtin_expect is true |
|
||||
| 145 | a == 42 when call to __builtin_expect is false |
|
||||
| 145 | a == 42+0 when call to __builtin_expect is false |
|
||||
| 145 | call to __builtin_expect != 0 when call to __builtin_expect is true |
|
||||
| 145 | call to __builtin_expect == 0 when call to __builtin_expect is false |
|
||||
| 146 | ! ... != 0 when ! ... is true |
|
||||
| 146 | ! ... == 0 when ! ... is false |
|
||||
| 146 | x != 0 when ! ... is false |
|
||||
|
||||
@@ -100,3 +100,11 @@
|
||||
| test.cpp:99:6:99:6 | f | true | 99 | 100 |
|
||||
| test.cpp:105:6:105:14 | ... != ... | true | 105 | 106 |
|
||||
| test.cpp:111:6:111:14 | ... != ... | true | 111 | 112 |
|
||||
| test.cpp:122:9:122:9 | b | true | 123 | 125 |
|
||||
| test.cpp:122:9:122:9 | b | true | 125 | 125 |
|
||||
| test.cpp:125:13:125:20 | ! ... | true | 125 | 125 |
|
||||
| test.cpp:125:14:125:17 | call to safe | false | 125 | 125 |
|
||||
| test.cpp:131:6:131:21 | call to __builtin_expect | true | 131 | 132 |
|
||||
| test.cpp:135:6:135:21 | call to __builtin_expect | true | 135 | 136 |
|
||||
| test.cpp:141:6:141:21 | call to __builtin_expect | true | 141 | 142 |
|
||||
| test.cpp:145:6:145:21 | call to __builtin_expect | true | 145 | 146 |
|
||||
|
||||
@@ -159,6 +159,18 @@ binary
|
||||
| test.cpp:105:6:105:14 | ... != ... | test.cpp:105:11:105:14 | 0.0 | != | test.cpp:105:6:105:6 | f | 0 | 105 | 106 |
|
||||
| test.cpp:111:6:111:14 | ... != ... | test.cpp:111:6:111:6 | i | != | test.cpp:111:11:111:14 | 0.0 | 0 | 111 | 112 |
|
||||
| test.cpp:111:6:111:14 | ... != ... | test.cpp:111:11:111:14 | 0.0 | != | test.cpp:111:6:111:6 | i | 0 | 111 | 112 |
|
||||
| test.cpp:131:6:131:21 | call to __builtin_expect | test.cpp:131:23:131:23 | a | == | test.cpp:131:28:131:28 | b | 42 | 131 | 132 |
|
||||
| test.cpp:131:6:131:21 | call to __builtin_expect | test.cpp:131:23:131:23 | a | == | test.cpp:131:28:131:33 | ... + ... | 0 | 131 | 132 |
|
||||
| test.cpp:131:6:131:21 | call to __builtin_expect | test.cpp:131:28:131:28 | b | == | test.cpp:131:23:131:23 | a | -42 | 131 | 132 |
|
||||
| test.cpp:131:6:131:21 | call to __builtin_expect | test.cpp:131:28:131:33 | ... + ... | == | test.cpp:131:23:131:23 | a | 0 | 131 | 132 |
|
||||
| test.cpp:135:6:135:21 | call to __builtin_expect | test.cpp:135:23:135:23 | a | != | test.cpp:135:28:135:28 | b | 42 | 135 | 136 |
|
||||
| test.cpp:135:6:135:21 | call to __builtin_expect | test.cpp:135:23:135:23 | a | != | test.cpp:135:28:135:33 | ... + ... | 0 | 135 | 136 |
|
||||
| test.cpp:135:6:135:21 | call to __builtin_expect | test.cpp:135:28:135:28 | b | != | test.cpp:135:23:135:23 | a | -42 | 135 | 136 |
|
||||
| test.cpp:135:6:135:21 | call to __builtin_expect | test.cpp:135:28:135:33 | ... + ... | != | test.cpp:135:23:135:23 | a | 0 | 135 | 136 |
|
||||
| test.cpp:141:6:141:21 | call to __builtin_expect | test.cpp:141:23:141:23 | a | == | test.cpp:141:28:141:29 | 42 | 0 | 141 | 142 |
|
||||
| test.cpp:141:6:141:21 | call to __builtin_expect | test.cpp:141:28:141:29 | 42 | == | test.cpp:141:23:141:23 | a | 0 | 141 | 142 |
|
||||
| test.cpp:145:6:145:21 | call to __builtin_expect | test.cpp:145:23:145:23 | a | != | test.cpp:145:28:145:29 | 42 | 0 | 145 | 146 |
|
||||
| test.cpp:145:6:145:21 | call to __builtin_expect | test.cpp:145:28:145:29 | 42 | != | test.cpp:145:23:145:23 | a | 0 | 145 | 146 |
|
||||
unary
|
||||
| test.c:7:9:7:13 | ... > ... | test.c:7:9:7:9 | x | < | 1 | 10 | 11 |
|
||||
| test.c:7:9:7:13 | ... > ... | test.c:7:9:7:9 | x | >= | 1 | 7 | 9 |
|
||||
@@ -257,6 +269,8 @@ unary
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 34 | 34 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | -1 | 30 | 30 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | -1 | 31 | 32 |
|
||||
| test.cpp:42:13:42:20 | call to getABool | test.cpp:42:13:42:20 | call to getABool | != | 0 | 43 | 45 |
|
||||
| test.cpp:42:13:42:20 | call to getABool | test.cpp:42:13:42:20 | call to getABool | == | 0 | 53 | 53 |
|
||||
| test.cpp:61:10:61:10 | i | test.cpp:61:10:61:10 | i | == | 0 | 62 | 64 |
|
||||
| test.cpp:61:10:61:10 | i | test.cpp:61:10:61:10 | i | == | 1 | 65 | 66 |
|
||||
| test.cpp:74:10:74:10 | i | test.cpp:74:10:74:10 | i | < | 11 | 75 | 77 |
|
||||
@@ -264,3 +278,13 @@ unary
|
||||
| test.cpp:74:10:74:10 | i | test.cpp:74:10:74:10 | i | >= | 0 | 75 | 77 |
|
||||
| test.cpp:74:10:74:10 | i | test.cpp:74:10:74:10 | i | >= | 11 | 78 | 79 |
|
||||
| test.cpp:93:6:93:6 | c | test.cpp:93:6:93:6 | c | != | 0 | 93 | 94 |
|
||||
| test.cpp:122:9:122:9 | b | test.cpp:122:9:122:9 | b | != | 0 | 123 | 125 |
|
||||
| test.cpp:122:9:122:9 | b | test.cpp:122:9:122:9 | b | != | 0 | 125 | 125 |
|
||||
| test.cpp:125:13:125:20 | ! ... | test.cpp:125:13:125:20 | ! ... | != | 0 | 125 | 125 |
|
||||
| test.cpp:125:14:125:17 | call to safe | test.cpp:125:14:125:17 | call to safe | == | 0 | 125 | 125 |
|
||||
| test.cpp:131:6:131:21 | call to __builtin_expect | test.cpp:131:6:131:21 | call to __builtin_expect | != | 0 | 131 | 132 |
|
||||
| test.cpp:135:6:135:21 | call to __builtin_expect | test.cpp:135:6:135:21 | call to __builtin_expect | != | 0 | 135 | 136 |
|
||||
| test.cpp:141:6:141:21 | call to __builtin_expect | test.cpp:141:6:141:21 | call to __builtin_expect | != | 0 | 141 | 142 |
|
||||
| test.cpp:141:6:141:21 | call to __builtin_expect | test.cpp:141:23:141:23 | a | == | 42 | 141 | 142 |
|
||||
| test.cpp:145:6:145:21 | call to __builtin_expect | test.cpp:145:6:145:21 | call to __builtin_expect | != | 0 | 145 | 146 |
|
||||
| test.cpp:145:6:145:21 | call to __builtin_expect | test.cpp:145:23:145:23 | a | != | 42 | 145 | 146 |
|
||||
|
||||
@@ -112,3 +112,37 @@ void int_float_comparison(int i) {
|
||||
use(i);
|
||||
}
|
||||
}
|
||||
|
||||
int source();
|
||||
bool safe(int);
|
||||
|
||||
void test(bool b)
|
||||
{
|
||||
int x;
|
||||
if (b)
|
||||
{
|
||||
x = source();
|
||||
if (!safe(x)) return;
|
||||
}
|
||||
use(x);
|
||||
}
|
||||
|
||||
void binary_test_builtin_expected(int a, int b) {
|
||||
if(__builtin_expect(a == b + 42, 0)) {
|
||||
use(a);
|
||||
}
|
||||
|
||||
if(__builtin_expect(a != b + 42, 0)) {
|
||||
use(a);
|
||||
}
|
||||
}
|
||||
|
||||
void unary_test_builtin_expected(int a) {
|
||||
if(__builtin_expect(a == 42, 0)) {
|
||||
use(a);
|
||||
}
|
||||
|
||||
if(__builtin_expect(a != 42, 0)) {
|
||||
use(a);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (additionalEdges.ql:31,6-14)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (additionalEdges.ql:31,31-39)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (additionalEdges.ql:32,7-15)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (additionalEdges.ql:31,6-14)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (additionalEdges.ql:31,31-39)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (additionalEdges.ql:32,7-15)
|
||||
| tryExcept.c:7:7:7:7 | x | tryExcept.c:14:10:14:10 | x |
|
||||
| tryExcept.c:7:13:7:14 | 0 | tryExcept.c:10:9:10:9 | y |
|
||||
| tryExcept.c:10:9:10:9 | y | tryExcept.c:10:5:10:9 | ... = ... |
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (standardEdges.ql:4,6-14)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (standardEdges.ql:4,31-39)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (standardEdges.ql:5,7-15)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (standardEdges.ql:4,6-14)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (standardEdges.ql:4,31-39)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (standardEdges.ql:5,7-15)
|
||||
| tryExcept.c:7:13:7:14 | 0 | tryExcept.c:10:9:10:9 | y |
|
||||
| tryExcept.c:10:9:10:9 | y | tryExcept.c:10:5:10:9 | ... = ... |
|
||||
|
||||
@@ -83,7 +83,7 @@ void test_guard_and_reassign() {
|
||||
if(!guarded(x)) {
|
||||
x = 0;
|
||||
}
|
||||
sink(x); // $ SPURIOUS: ast,ir
|
||||
sink(x); // $ SPURIOUS: ast
|
||||
}
|
||||
|
||||
void test_phi_read_guard(bool b) {
|
||||
@@ -98,7 +98,7 @@ void test_phi_read_guard(bool b) {
|
||||
return;
|
||||
}
|
||||
|
||||
sink(x); // $ SPURIOUS: ast,ir
|
||||
sink(x); // $ SPURIOUS: ast
|
||||
}
|
||||
|
||||
bool unsafe(int);
|
||||
|
||||
@@ -7,14 +7,17 @@ module AstTest {
|
||||
* S in `if (guarded(x)) S`.
|
||||
*/
|
||||
// This is tested in `BarrierGuard.cpp`.
|
||||
predicate testBarrierGuard(GuardCondition g, Expr checked, boolean isTrue) {
|
||||
g.(FunctionCall).getTarget().getName() = "guarded" and
|
||||
checked = g.(FunctionCall).getArgument(0) and
|
||||
isTrue = true
|
||||
or
|
||||
g.(FunctionCall).getTarget().getName() = "unsafe" and
|
||||
checked = g.(FunctionCall).getArgument(0) and
|
||||
isTrue = false
|
||||
predicate testBarrierGuard(GuardCondition g, Expr checked, boolean branch) {
|
||||
exists(Call call, boolean b |
|
||||
checked = call.getArgument(0) and
|
||||
g.comparesEq(call, 0, b, any(BooleanValue bv | bv.getValue() = branch))
|
||||
|
|
||||
call.getTarget().hasName("guarded") and
|
||||
b = false
|
||||
or
|
||||
call.getTarget().hasName("unsafe") and
|
||||
b = true
|
||||
)
|
||||
}
|
||||
|
||||
/** Common data flow configuration to be used by tests. */
|
||||
@@ -106,16 +109,16 @@ module IRTest {
|
||||
* S in `if (guarded(x)) S`.
|
||||
*/
|
||||
// This is tested in `BarrierGuard.cpp`.
|
||||
predicate testBarrierGuard(IRGuardCondition g, Expr checked, boolean isTrue) {
|
||||
exists(Call call |
|
||||
call = g.getUnconvertedResultExpression() and
|
||||
checked = call.getArgument(0)
|
||||
predicate testBarrierGuard(IRGuardCondition g, Expr checked, boolean branch) {
|
||||
exists(CallInstruction call, boolean b |
|
||||
checked = call.getArgument(0).getUnconvertedResultExpression() and
|
||||
g.comparesEq(call.getAUse(), 0, b, any(BooleanValue bv | bv.getValue() = branch))
|
||||
|
|
||||
call.getTarget().hasName("guarded") and
|
||||
isTrue = true
|
||||
call.getStaticCallTarget().hasName("guarded") and
|
||||
b = false
|
||||
or
|
||||
call.getTarget().hasName("unsafe") and
|
||||
isTrue = false
|
||||
call.getStaticCallTarget().hasName("unsafe") and
|
||||
b = true
|
||||
)
|
||||
}
|
||||
|
||||
@@ -148,6 +151,9 @@ module IRTest {
|
||||
or
|
||||
call.getTarget().getName() = "indirect_sink" and
|
||||
sink.asIndirectExpr() = e
|
||||
or
|
||||
call.getTarget().getName() = "indirect_sink_const_ref" and
|
||||
sink.asIndirectExpr() = e
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// semmle-extractor-options: --edg --clang
|
||||
// semmle-extractor-options: --clang
|
||||
|
||||
int source();
|
||||
void sink(int); void sink(const int *); void sink(int **); void indirect_sink(...);
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (has-parameter-flow-out.ql:5,18-61)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (has-parameter-flow-out.ql:5,18-61)
|
||||
testFailures
|
||||
failures
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (localFlow.ql:4,6-14)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (localFlow.ql:4,31-39)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (localFlow.ql:6,3-11)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (localFlow.ql:4,6-14)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (localFlow.ql:4,31-39)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (localFlow.ql:6,3-11)
|
||||
| example.c:15:37:15:37 | b | example.c:15:37:15:37 | b |
|
||||
| example.c:15:37:15:37 | b | example.c:19:6:19:6 | b |
|
||||
| example.c:15:44:15:46 | pos | example.c:24:24:24:26 | pos |
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (test-number-of-outnodes.ql:5,18-61)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (test-number-of-outnodes.ql:5,18-61)
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (test-source-sink.ql:3,25-42)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (test-source-sink.ql:3,57-74)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (test-source-sink.ql:3,25-42)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (test-source-sink.ql:3,57-74)
|
||||
astFlow
|
||||
| BarrierGuard.cpp:5:19:5:24 | source | BarrierGuard.cpp:9:10:9:15 | source |
|
||||
| BarrierGuard.cpp:13:17:13:22 | source | BarrierGuard.cpp:15:10:15:15 | source |
|
||||
@@ -145,8 +145,6 @@ irFlow
|
||||
| BarrierGuard.cpp:49:10:49:15 | call to source | BarrierGuard.cpp:55:13:55:13 | x |
|
||||
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:64:14:64:14 | x |
|
||||
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:66:14:66:14 | x |
|
||||
| BarrierGuard.cpp:81:11:81:16 | call to source | BarrierGuard.cpp:86:8:86:8 | x |
|
||||
| BarrierGuard.cpp:90:11:90:16 | call to source | BarrierGuard.cpp:101:8:101:8 | x |
|
||||
| acrossLinkTargets.cpp:19:27:19:32 | call to source | acrossLinkTargets.cpp:12:8:12:8 | x |
|
||||
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:18:8:18:19 | sourceArray1 |
|
||||
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:23:17:23:29 | *& ... |
|
||||
@@ -315,6 +313,7 @@ irFlow
|
||||
| test.cpp:1021:18:1021:32 | *call to indirect_source | test.cpp:1027:19:1027:28 | *translated |
|
||||
| test.cpp:1021:18:1021:32 | *call to indirect_source | test.cpp:1031:19:1031:28 | *translated |
|
||||
| test.cpp:1045:14:1045:19 | call to source | test.cpp:1046:7:1046:10 | * ... |
|
||||
| test.cpp:1081:27:1081:34 | call to source | test.cpp:1081:27:1081:34 | call to source |
|
||||
| true_upon_entry.cpp:9:11:9:16 | call to source | true_upon_entry.cpp:13:8:13:8 | x |
|
||||
| true_upon_entry.cpp:17:11:17:16 | call to source | true_upon_entry.cpp:21:8:21:8 | x |
|
||||
| true_upon_entry.cpp:27:9:27:14 | call to source | true_upon_entry.cpp:29:8:29:8 | x |
|
||||
|
||||
@@ -1073,3 +1073,10 @@ void single_object_in_both_cases(bool b, int x, int y) {
|
||||
*p = 0;
|
||||
sink(*p); // clean
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void indirect_sink_const_ref(const T&);
|
||||
|
||||
void test_temp_with_conversion_from_materialization() {
|
||||
indirect_sink_const_ref(source()); // $ ir MISSING: ast
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (partial-definition-diff.ql:7,8-51)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (partial-definition-diff.ql:7,8-51)
|
||||
| A.cpp:25:13:25:13 | c | AST only |
|
||||
| A.cpp:27:28:27:28 | c | AST only |
|
||||
| A.cpp:28:23:28:26 | this | IR only |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (partial-definition.ql:6,8-51)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (partial-definition.ql:6,8-51)
|
||||
| A.cpp:25:7:25:10 | this |
|
||||
| A.cpp:25:13:25:13 | c |
|
||||
| A.cpp:27:22:27:25 | this |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (taint.ql:6,48-56)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (taint.ql:7,24-32)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (taint.ql:11,22-30)
|
||||
WARNING: Module TaintTracking has been deprecated and may be removed in future (taint.ql:19,20-33)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (taint.ql:6,48-56)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (taint.ql:7,24-32)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (taint.ql:11,22-30)
|
||||
WARNING: module 'TaintTracking' has been deprecated and may be removed in future (taint.ql:19,20-33)
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (localTaint.ql:4,6-14)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (localTaint.ql:4,31-39)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (localTaint.ql:7,6-14)
|
||||
WARNING: Module TaintTracking has been deprecated and may be removed in future (localTaint.ql:6,3-16)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (localTaint.ql:4,6-14)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (localTaint.ql:4,31-39)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (localTaint.ql:7,6-14)
|
||||
WARNING: module 'TaintTracking' has been deprecated and may be removed in future (localTaint.ql:6,3-16)
|
||||
| arrayassignment.cpp:9:9:9:10 | 0 | arrayassignment.cpp:10:14:10:14 | x | |
|
||||
| arrayassignment.cpp:9:9:9:10 | 0 | arrayassignment.cpp:11:15:11:15 | x | |
|
||||
| arrayassignment.cpp:9:9:9:10 | 0 | arrayassignment.cpp:12:13:12:13 | x | |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (taint.ql:46,45-53)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (taint.ql:47,24-32)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (taint.ql:61,22-30)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (taint.ql:68,25-33)
|
||||
WARNING: Module TaintTracking has been deprecated and may be removed in future (taint.ql:73,20-33)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (taint.ql:46,45-53)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (taint.ql:47,24-32)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (taint.ql:61,22-30)
|
||||
WARNING: module 'DataFlow' has been deprecated and may be removed in future (taint.ql:68,25-33)
|
||||
WARNING: module 'TaintTracking' has been deprecated and may be removed in future (taint.ql:73,20-33)
|
||||
testFailures
|
||||
failures
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// semmle-extractor-options: --edg --microsoft
|
||||
// semmle-extractor-options: --microsoft
|
||||
|
||||
void f(__declspec(guard(overflow)) size_t length) {
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// semmle-extractor-options: --edg --clang --edg --c++20
|
||||
// semmle-extractor-options: --clang --edg --c++20
|
||||
|
||||
namespace cpp20 {
|
||||
|
||||
|
||||
@@ -7,4 +7,4 @@ struct Kiwi {
|
||||
struct Lemon {
|
||||
unsigned int __attribute__ ((vector_size (16))) lemon_x;
|
||||
};
|
||||
// semmle-extractor-options: --edg --c99 --edg --clang --edg --clang_vector_types --gnu_version 40700
|
||||
// semmle-extractor-options: --edg --c99 --clang --edg --clang_vector_types --gnu_version 40700
|
||||
|
||||
@@ -7,4 +7,4 @@ struct Kiwi {
|
||||
struct Lemon {
|
||||
signed int __attribute__ ((vector_size (16))) lemon_x;
|
||||
};
|
||||
// semmle-extractor-options: --edg --c99 --edg --clang --edg --clang_vector_types --gnu_version 40700
|
||||
// semmle-extractor-options: --edg --c99 --clang --edg --clang_vector_types --gnu_version 40700
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// semmle-extractor-options: --edg --clang --edg --ms_extensions
|
||||
// semmle-extractor-options: --clang --edg --ms_extensions
|
||||
|
||||
template <int a> class b {
|
||||
template <bool> struct c;
|
||||
|
||||
@@ -1 +1 @@
|
||||
semmle-extractor-options: --edg --clang --edg --clang_builtin_functions --edg --clang_vector_types --gnu_version 40600
|
||||
semmle-extractor-options: --clang --edg --clang_builtin_functions --edg --clang_vector_types --gnu_version 40600
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// semmle-extractor-options: --edg --clang --edg --clang_version --edg 30801
|
||||
// semmle-extractor-options: --clang --edg --clang_version --edg 30801
|
||||
// Compilable with: clang --std=c++0x -msse4.1 vector_types.cpp
|
||||
// (some bits also compilable with gcc)
|
||||
int printf(...);
|
||||
|
||||
@@ -13,21 +13,6 @@ edges
|
||||
| test_free.cpp:207:10:207:10 | pointer to free output argument | test_free.cpp:209:10:209:10 | a | provenance | |
|
||||
| test_free.cpp:301:12:301:14 | pointer to g_free output argument | test_free.cpp:302:12:302:14 | buf | provenance | |
|
||||
| test_free.cpp:319:16:319:16 | pointer to operator delete output argument | test_free.cpp:322:12:322:12 | a | provenance | |
|
||||
| test_free.cpp:343:12:343:24 | *access to array [post update] [ptr] | test_free.cpp:344:12:344:24 | *access to array [ptr] | provenance | |
|
||||
| test_free.cpp:343:12:343:24 | *access to array [post update] [ptr] | test_free.cpp:345:12:345:24 | *access to array [ptr] | provenance | |
|
||||
| test_free.cpp:343:12:343:24 | *access to array [post update] [ptr] | test_free.cpp:346:12:346:24 | *access to array [ptr] | provenance | |
|
||||
| test_free.cpp:343:26:343:28 | pointer to operator delete output argument | test_free.cpp:343:12:343:24 | *access to array [post update] [ptr] | provenance | |
|
||||
| test_free.cpp:344:12:344:24 | *access to array [post update] [ptr] | test_free.cpp:345:12:345:24 | *access to array [ptr] | provenance | |
|
||||
| test_free.cpp:344:12:344:24 | *access to array [post update] [ptr] | test_free.cpp:346:12:346:24 | *access to array [ptr] | provenance | |
|
||||
| test_free.cpp:344:12:344:24 | *access to array [ptr] | test_free.cpp:344:26:344:28 | ptr | provenance | |
|
||||
| test_free.cpp:344:26:344:28 | pointer to operator delete output argument | test_free.cpp:344:12:344:24 | *access to array [post update] [ptr] | provenance | |
|
||||
| test_free.cpp:345:12:345:24 | *access to array [post update] [ptr] | test_free.cpp:346:12:346:24 | *access to array [ptr] | provenance | |
|
||||
| test_free.cpp:345:12:345:24 | *access to array [ptr] | test_free.cpp:345:26:345:28 | ptr | provenance | |
|
||||
| test_free.cpp:345:12:345:24 | *access to array [ptr] | test_free.cpp:345:26:345:28 | ptr | provenance | |
|
||||
| test_free.cpp:345:26:345:28 | pointer to operator delete output argument | test_free.cpp:345:12:345:24 | *access to array [post update] [ptr] | provenance | |
|
||||
| test_free.cpp:346:12:346:24 | *access to array [ptr] | test_free.cpp:346:26:346:28 | ptr | provenance | |
|
||||
| test_free.cpp:346:12:346:24 | *access to array [ptr] | test_free.cpp:346:26:346:28 | ptr | provenance | |
|
||||
| test_free.cpp:346:12:346:24 | *access to array [ptr] | test_free.cpp:346:26:346:28 | ptr | provenance | |
|
||||
nodes
|
||||
| test_free.cpp:11:10:11:10 | pointer to free output argument | semmle.label | pointer to free output argument |
|
||||
| test_free.cpp:14:10:14:10 | a | semmle.label | a |
|
||||
@@ -57,24 +42,6 @@ nodes
|
||||
| test_free.cpp:302:12:302:14 | buf | semmle.label | buf |
|
||||
| test_free.cpp:319:16:319:16 | pointer to operator delete output argument | semmle.label | pointer to operator delete output argument |
|
||||
| test_free.cpp:322:12:322:12 | a | semmle.label | a |
|
||||
| test_free.cpp:343:12:343:24 | *access to array [post update] [ptr] | semmle.label | *access to array [post update] [ptr] |
|
||||
| test_free.cpp:343:26:343:28 | pointer to operator delete output argument | semmle.label | pointer to operator delete output argument |
|
||||
| test_free.cpp:344:12:344:24 | *access to array [post update] [ptr] | semmle.label | *access to array [post update] [ptr] |
|
||||
| test_free.cpp:344:12:344:24 | *access to array [ptr] | semmle.label | *access to array [ptr] |
|
||||
| test_free.cpp:344:26:344:28 | pointer to operator delete output argument | semmle.label | pointer to operator delete output argument |
|
||||
| test_free.cpp:344:26:344:28 | ptr | semmle.label | ptr |
|
||||
| test_free.cpp:345:12:345:24 | *access to array [post update] [ptr] | semmle.label | *access to array [post update] [ptr] |
|
||||
| test_free.cpp:345:12:345:24 | *access to array [ptr] | semmle.label | *access to array [ptr] |
|
||||
| test_free.cpp:345:12:345:24 | *access to array [ptr] | semmle.label | *access to array [ptr] |
|
||||
| test_free.cpp:345:26:345:28 | pointer to operator delete output argument | semmle.label | pointer to operator delete output argument |
|
||||
| test_free.cpp:345:26:345:28 | ptr | semmle.label | ptr |
|
||||
| test_free.cpp:345:26:345:28 | ptr | semmle.label | ptr |
|
||||
| test_free.cpp:346:12:346:24 | *access to array [ptr] | semmle.label | *access to array [ptr] |
|
||||
| test_free.cpp:346:12:346:24 | *access to array [ptr] | semmle.label | *access to array [ptr] |
|
||||
| test_free.cpp:346:12:346:24 | *access to array [ptr] | semmle.label | *access to array [ptr] |
|
||||
| test_free.cpp:346:26:346:28 | ptr | semmle.label | ptr |
|
||||
| test_free.cpp:346:26:346:28 | ptr | semmle.label | ptr |
|
||||
| test_free.cpp:346:26:346:28 | ptr | semmle.label | ptr |
|
||||
subpaths
|
||||
#select
|
||||
| test_free.cpp:14:10:14:10 | a | test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:14:10:14:10 | a | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:14:10:14:10 | a | a | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||
@@ -91,9 +58,3 @@ subpaths
|
||||
| test_free.cpp:209:10:209:10 | a | test_free.cpp:207:10:207:10 | pointer to free output argument | test_free.cpp:209:10:209:10 | a | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:209:10:209:10 | a | a | test_free.cpp:207:5:207:8 | call to free | call to free |
|
||||
| test_free.cpp:302:12:302:14 | buf | test_free.cpp:301:12:301:14 | pointer to g_free output argument | test_free.cpp:302:12:302:14 | buf | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:302:12:302:14 | buf | buf | test_free.cpp:301:5:301:10 | call to g_free | call to g_free |
|
||||
| test_free.cpp:322:12:322:12 | a | test_free.cpp:319:16:319:16 | pointer to operator delete output argument | test_free.cpp:322:12:322:12 | a | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:322:12:322:12 | a | a | test_free.cpp:319:9:319:16 | delete | delete |
|
||||
| test_free.cpp:344:26:344:28 | ptr | test_free.cpp:343:26:343:28 | pointer to operator delete output argument | test_free.cpp:344:26:344:28 | ptr | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:344:26:344:28 | ptr | ptr | test_free.cpp:343:5:343:28 | delete | delete |
|
||||
| test_free.cpp:345:26:345:28 | ptr | test_free.cpp:343:26:343:28 | pointer to operator delete output argument | test_free.cpp:345:26:345:28 | ptr | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:345:26:345:28 | ptr | ptr | test_free.cpp:343:5:343:28 | delete | delete |
|
||||
| test_free.cpp:345:26:345:28 | ptr | test_free.cpp:344:26:344:28 | pointer to operator delete output argument | test_free.cpp:345:26:345:28 | ptr | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:345:26:345:28 | ptr | ptr | test_free.cpp:344:5:344:28 | delete | delete |
|
||||
| test_free.cpp:346:26:346:28 | ptr | test_free.cpp:343:26:343:28 | pointer to operator delete output argument | test_free.cpp:346:26:346:28 | ptr | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:346:26:346:28 | ptr | ptr | test_free.cpp:343:5:343:28 | delete | delete |
|
||||
| test_free.cpp:346:26:346:28 | ptr | test_free.cpp:344:26:344:28 | pointer to operator delete output argument | test_free.cpp:346:26:346:28 | ptr | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:346:26:346:28 | ptr | ptr | test_free.cpp:344:5:344:28 | delete | delete |
|
||||
| test_free.cpp:346:26:346:28 | ptr | test_free.cpp:345:26:345:28 | pointer to operator delete output argument | test_free.cpp:346:26:346:28 | ptr | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:346:26:346:28 | ptr | ptr | test_free.cpp:345:5:345:28 | delete | delete |
|
||||
|
||||
@@ -115,6 +115,8 @@
|
||||
| test_free.cpp:344:26:344:28 | ptr |
|
||||
| test_free.cpp:345:26:345:28 | ptr |
|
||||
| test_free.cpp:346:26:346:28 | ptr |
|
||||
| test_free.cpp:356:19:356:19 | a |
|
||||
| test_free.cpp:357:19:357:19 | a |
|
||||
| virtual.cpp:18:10:18:10 | a |
|
||||
| virtual.cpp:19:10:19:10 | c |
|
||||
| virtual.cpp:38:10:38:10 | b |
|
||||
|
||||
@@ -341,7 +341,18 @@ struct PtrContainer {
|
||||
|
||||
void test_array(PtrContainer *containers) {
|
||||
delete containers[0].ptr; // GOOD
|
||||
delete containers[1].ptr; // GOOD [FALSE POSITIVE]
|
||||
delete containers[2].ptr; // GOOD [FALSE POSITIVE]
|
||||
delete containers[2].ptr; // BAD (double free)
|
||||
delete containers[1].ptr; // GOOD
|
||||
delete containers[2].ptr; // GOOD
|
||||
delete containers[2].ptr; // BAD (double free) [NOT DETECTED]
|
||||
}
|
||||
|
||||
struct E {
|
||||
struct EC {
|
||||
int* a;
|
||||
} ec[2];
|
||||
};
|
||||
|
||||
void test(E* e) {
|
||||
free(e->ec[0].a);
|
||||
free(e->ec[1].a); // GOOD
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
| test.cpp:21:9:21:15 | new | This allocation cannot return null. $@ is unnecessary. | test.cpp:21:9:21:15 | new | This check |
|
||||
| test.cpp:21:9:21:15 | new | This allocation cannot return null. $@ is unnecessary. | test.cpp:21:7:21:16 | ! ... | This check |
|
||||
| test.cpp:29:13:29:24 | new[] | This allocation cannot return null. $@ is unnecessary. | test.cpp:30:7:30:13 | ... == ... | This check |
|
||||
| test.cpp:33:13:33:24 | new[] | This allocation cannot return null. $@ is unnecessary. | test.cpp:34:8:34:9 | p2 | This check |
|
||||
| test.cpp:33:13:33:24 | new[] | This allocation cannot return null. $@ is unnecessary. | test.cpp:34:7:34:9 | ! ... | This check |
|
||||
| test.cpp:37:13:37:24 | new[] | This allocation cannot return null. $@ is unnecessary. | test.cpp:38:7:38:16 | ... == ... | This check |
|
||||
| test.cpp:41:13:41:24 | new[] | This allocation cannot return null. $@ is unnecessary. | test.cpp:42:7:42:19 | ... == ... | This check |
|
||||
| test.cpp:45:13:45:24 | new[] | This allocation cannot return null. $@ is unnecessary. | test.cpp:46:7:46:8 | p5 | This check |
|
||||
| test.cpp:49:8:49:19 | new[] | This allocation cannot return null. $@ is unnecessary. | test.cpp:50:7:50:13 | ... == ... | This check |
|
||||
| test.cpp:53:8:53:19 | new[] | This allocation cannot return null. $@ is unnecessary. | test.cpp:54:8:54:9 | p7 | This check |
|
||||
| test.cpp:53:8:53:19 | new[] | This allocation cannot return null. $@ is unnecessary. | test.cpp:54:7:54:9 | ! ... | This check |
|
||||
| test.cpp:58:8:58:19 | new[] | This allocation cannot return null. $@ is unnecessary. | test.cpp:59:7:59:16 | ... == ... | This check |
|
||||
| test.cpp:63:8:63:19 | new[] | This allocation cannot return null. $@ is unnecessary. | test.cpp:64:7:64:19 | ... != ... | This check |
|
||||
| test.cpp:69:9:69:20 | new[] | This allocation cannot return null. $@ is unnecessary. | test.cpp:70:7:70:14 | ... != ... | This check |
|
||||
| test.cpp:75:11:75:22 | new[] | This allocation cannot return null. $@ is unnecessary. | test.cpp:76:13:76:15 | p11 | This check |
|
||||
| test.cpp:75:11:75:22 | new[] | This allocation cannot return null. $@ is unnecessary. | test.cpp:76:12:76:15 | ! ... | This check |
|
||||
| test.cpp:92:5:92:31 | new[] | This allocation cannot throw. $@ is unnecessary. | test.cpp:97:36:98:3 | { ... } | This catch block |
|
||||
| test.cpp:93:15:93:41 | new[] | This allocation cannot throw. $@ is unnecessary. | test.cpp:97:36:98:3 | { ... } | This catch block |
|
||||
| test.cpp:96:10:96:36 | new[] | This allocation cannot throw. $@ is unnecessary. | test.cpp:97:36:98:3 | { ... } | This catch block |
|
||||
|
||||
@@ -7,10 +7,11 @@
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
|
||||
<Company>GitHub</Company>
|
||||
<Product>CodeQL</Product>
|
||||
<Copyright>Copyright © $([System.DateTime]::Now.Year) $(Company)</Copyright>
|
||||
<Version>1.0.0.0</Version>
|
||||
<AssemblyVersion>1.0.0.0</AssemblyVersion>
|
||||
<FileVersion>1.0.0.0</FileVersion>
|
||||
<AssemblyVersion>$(Version)</AssemblyVersion>
|
||||
<FileVersion>$(Version)</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -7,7 +7,6 @@ codeql_xunit_test(
|
||||
name = "Semmle.Autobuild.CSharp.Tests",
|
||||
srcs = glob([
|
||||
"*.cs",
|
||||
"Properties/*.cs",
|
||||
]),
|
||||
deps = [
|
||||
"//csharp/autobuilder/Semmle.Autobuild.CSharp:bin/Semmle.Autobuild.CSharp",
|
||||
|
||||
@@ -7,7 +7,6 @@ codeql_csharp_binary(
|
||||
name = "Semmle.Autobuild.CSharp",
|
||||
srcs = glob([
|
||||
"*.cs",
|
||||
"Properties/*.cs",
|
||||
]),
|
||||
visibility = ["//csharp:__subpackages__"],
|
||||
deps = [
|
||||
|
||||
@@ -7,7 +7,6 @@ codeql_xunit_test(
|
||||
name = "Semmle.Autobuild.Cpp.Tests",
|
||||
srcs = glob([
|
||||
"*.cs",
|
||||
"Properties/*.cs",
|
||||
]),
|
||||
deps = [
|
||||
"//csharp/autobuilder/Semmle.Autobuild.Cpp:bin/Semmle.Autobuild.Cpp",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user