mirror of
https://github.com/github/codeql.git
synced 2026-07-06 20:15:37 +02:00
Compare commits
519 Commits
codeql-cli
...
dbartol/ph
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc129e94e4 | ||
|
|
24c9062b35 | ||
|
|
cf4736c8f6 | ||
|
|
67b327a0f7 | ||
|
|
a299afaf51 | ||
|
|
3351b9547d | ||
|
|
2ae7fa4897 | ||
|
|
6fd2ab7cef | ||
|
|
b88a1b2d1e | ||
|
|
700604a1c2 | ||
|
|
6a6978398a | ||
|
|
333df03f64 | ||
|
|
a464a8e48e | ||
|
|
214db5c20d | ||
|
|
3574b9fd4f | ||
|
|
29e3816412 | ||
|
|
4226270ef9 | ||
|
|
73caa48302 | ||
|
|
3172054073 | ||
|
|
939ae4a561 | ||
|
|
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 | ||
|
|
027c7d0d43 | ||
|
|
1d44f45be2 | ||
|
|
7819cc1c36 | ||
|
|
71505f4003 | ||
|
|
06aa2664bf | ||
|
|
5f98f2aec9 | ||
|
|
6731bccc92 | ||
|
|
16f8be4ba4 | ||
|
|
beffc2a49d | ||
|
|
32260e2823 | ||
|
|
881b2586e1 | ||
|
|
504a233299 | ||
|
|
1d6f09c750 | ||
|
|
44a16cef6c | ||
|
|
ea3a3db847 | ||
|
|
9d1c2c6ba1 | ||
|
|
9b1e4d7895 | ||
|
|
0ab67d1790 | ||
|
|
7e980d9524 | ||
|
|
0c47203580 | ||
|
|
68ddae2918 | ||
|
|
5d51b5b97b | ||
|
|
a26c01d7c7 | ||
|
|
0e8d72c126 | ||
|
|
4ec4da4c8c | ||
|
|
68a78fa3ed | ||
|
|
d5af71a6c9 | ||
|
|
9366eb8288 | ||
|
|
7f62085be5 | ||
|
|
456c046b09 | ||
|
|
ed525fce70 | ||
|
|
b5a3575130 | ||
|
|
4488518838 | ||
|
|
5ae8fe502a | ||
|
|
798357ffc6 | ||
|
|
7b92554cf2 | ||
|
|
9f4c1380e5 | ||
|
|
2662808629 | ||
|
|
9564ae1ca4 | ||
|
|
eae6406629 | ||
|
|
528afba919 | ||
|
|
36aac3ffd8 | ||
|
|
703832f5a1 | ||
|
|
0298755975 | ||
|
|
8aaa2a1079 | ||
|
|
f7b2d98c6e | ||
|
|
fa09d21c32 | ||
|
|
6e0f3df573 | ||
|
|
5deb9002bf | ||
|
|
8acb11924d | ||
|
|
314eb5db72 | ||
|
|
38acfcf42e | ||
|
|
7aec488d8a | ||
|
|
894497218d | ||
|
|
f9ef72eca6 | ||
|
|
331f676832 | ||
|
|
31bc4263e7 | ||
|
|
ac6cc38b20 | ||
|
|
2d42ea0f2f | ||
|
|
bd9ece0bd3 | ||
|
|
48f2fd0460 | ||
|
|
d6352b47a1 | ||
|
|
f58757ff9d | ||
|
|
af4d2f1ed3 | ||
|
|
523139259a | ||
|
|
7122db0c45 | ||
|
|
421c68a263 | ||
|
|
0f09198bcd | ||
|
|
2e5d9c34bf | ||
|
|
7b5297b882 | ||
|
|
716e2737d1 | ||
|
|
ef2f01613c | ||
|
|
ac91a5167a | ||
|
|
e704bf353b | ||
|
|
3b51f1f722 | ||
|
|
79ae522349 | ||
|
|
c0142c1a91 | ||
|
|
366fba8b33 | ||
|
|
f830dc6852 | ||
|
|
fcf06c59aa | ||
|
|
e267031f59 | ||
|
|
13dd87f04c | ||
|
|
61847bc58b | ||
|
|
5dd7e136e5 | ||
|
|
54347c2642 | ||
|
|
44a56c420f | ||
|
|
ff46e2c627 | ||
|
|
97f0c759c0 | ||
|
|
44cc19cd6b | ||
|
|
05d46a6793 | ||
|
|
0149fb640d | ||
|
|
25179074c1 | ||
|
|
85d0efcbed | ||
|
|
6f8449cf75 | ||
|
|
6b2e86afea | ||
|
|
63bec5ae3e | ||
|
|
c2bd050e08 | ||
|
|
cc0271715b | ||
|
|
0b9bafc9c3 | ||
|
|
168cba86c1 | ||
|
|
798a736d16 | ||
|
|
65af2556ed | ||
|
|
97f9a882c6 | ||
|
|
0f63f0dda2 | ||
|
|
80bf7cdb52 | ||
|
|
dd223ed704 | ||
|
|
ad2eacfd2f | ||
|
|
d020f93005 | ||
|
|
3e53f3bd13 | ||
|
|
e04c75df24 | ||
|
|
888a831a5c | ||
|
|
556dc282d2 | ||
|
|
ceccc9294c | ||
|
|
a9af28ede0 | ||
|
|
43c7ac36d9 | ||
|
|
3fb5ad2a0d | ||
|
|
b7e16ca55d | ||
|
|
e4653a80d4 | ||
|
|
8791e67789 | ||
|
|
576ee7892d | ||
|
|
7b3e9b4ec1 | ||
|
|
73b18129d9 | ||
|
|
10584b3a7a | ||
|
|
a48d71b42f | ||
|
|
b8bc014297 | ||
|
|
8205f86365 | ||
|
|
be5c82cb88 | ||
|
|
e42de3de6f | ||
|
|
c6039b345b | ||
|
|
e693c2719d | ||
|
|
e7cec01a81 | ||
|
|
4c91bdce48 | ||
|
|
2fe0718e49 | ||
|
|
6a9cb90a57 | ||
|
|
fcd326eb11 | ||
|
|
60970ff015 | ||
|
|
e8c1e50276 | ||
|
|
c8202341bb | ||
|
|
ad99158838 | ||
|
|
858c7cead2 | ||
|
|
c608675212 | ||
|
|
cbbdd01d5a | ||
|
|
7356e747e4 | ||
|
|
6e67e724b4 | ||
|
|
5c5949ba5e | ||
|
|
c964fc2dca | ||
|
|
18fa454d33 | ||
|
|
0870946e05 | ||
|
|
a8112ec62e | ||
|
|
adfaae02e7 | ||
|
|
479ea9f82c | ||
|
|
174712a472 | ||
|
|
40127583fb | ||
|
|
5b04a71169 | ||
|
|
df8e04fcf9 | ||
|
|
209fe731a6 | ||
|
|
e2008e14e2 | ||
|
|
7f0f2d3438 | ||
|
|
961b09d63c | ||
|
|
9f7c47509a | ||
|
|
557adaf6f2 | ||
|
|
8e2e32742c | ||
|
|
83672f545f | ||
|
|
a71e678bb9 | ||
|
|
c3e1592815 | ||
|
|
54a0c03e5d | ||
|
|
e81a98925a | ||
|
|
797e5d0c8a | ||
|
|
7c94120eb7 | ||
|
|
89e7bab0b3 | ||
|
|
78552b8bca | ||
|
|
63116d2779 | ||
|
|
a1415e2b6d | ||
|
|
38c47a4b11 | ||
|
|
c06df5552b | ||
|
|
9c2b4c9446 | ||
|
|
79e9198b20 | ||
|
|
f479649727 | ||
|
|
7e5b7346c0 | ||
|
|
8a5b5d220a | ||
|
|
af6a08893a | ||
|
|
66077dc38d | ||
|
|
a83d50062e | ||
|
|
9af6cb8e4b | ||
|
|
292395b80e | ||
|
|
f16dd8c010 | ||
|
|
f84c2a842d | ||
|
|
2a62bfd0c2 | ||
|
|
839171e557 | ||
|
|
dd8b65130e | ||
|
|
f4d3756894 | ||
|
|
16e9cede3c | ||
|
|
99f70a64e9 | ||
|
|
d1a2c0fbe4 | ||
|
|
48455ec3c9 | ||
|
|
e6dc36b2c4 | ||
|
|
133983678c | ||
|
|
922489c8e8 | ||
|
|
7b8c11379d | ||
|
|
fe8f13e8dd | ||
|
|
5b6f38f821 | ||
|
|
859e8db5f2 | ||
|
|
8783dfbaac | ||
|
|
b0865c2218 | ||
|
|
1bd7aef1b2 | ||
|
|
986babb912 | ||
|
|
2bcf292dd6 | ||
|
|
acdf7df6a4 | ||
|
|
839258897a | ||
|
|
f458ca9568 | ||
|
|
2d760c7cc7 | ||
|
|
6224670884 | ||
|
|
918bee07dd | ||
|
|
2550e113a0 | ||
|
|
c30cc0f665 | ||
|
|
b67309299f | ||
|
|
dd267e126c | ||
|
|
57f7602126 | ||
|
|
5c77b8708c | ||
|
|
7b72018e56 | ||
|
|
04f5f30489 | ||
|
|
b9da01a384 | ||
|
|
5875ec272d | ||
|
|
e87593af75 | ||
|
|
94413c8c2e | ||
|
|
34130d50d3 | ||
|
|
51b000a424 | ||
|
|
8479673419 | ||
|
|
a42bdd9bb0 | ||
|
|
0173cf56f5 | ||
|
|
546b260330 | ||
|
|
46f5b13854 | ||
|
|
eb0925be60 | ||
|
|
213e3918df | ||
|
|
b08a0a303f | ||
|
|
88b978f0ec | ||
|
|
121ca129bc | ||
|
|
cff78cca5e | ||
|
|
58ce3e805e | ||
|
|
beeae69845 | ||
|
|
8d5bb21643 | ||
|
|
a19149032f | ||
|
|
58fb0270fb | ||
|
|
096a31dbef | ||
|
|
06ce40c687 | ||
|
|
e2758f2abb | ||
|
|
01c1acd43f | ||
|
|
d38894a5e5 | ||
|
|
25ab1a934d | ||
|
|
67e2ea195f | ||
|
|
f27d48d03d | ||
|
|
959aa3515c | ||
|
|
8b75bb2ba9 | ||
|
|
02f9aec517 | ||
|
|
b628c2e121 | ||
|
|
5e1801f7be | ||
|
|
121378a262 | ||
|
|
0985a3a5f6 | ||
|
|
9bb7575018 | ||
|
|
90538d4b4c | ||
|
|
cd5168b570 | ||
|
|
38d246a3bd | ||
|
|
db0131d931 | ||
|
|
be4fce26c0 | ||
|
|
bfc37fddff | ||
|
|
14988002fa | ||
|
|
42d87f6d19 | ||
|
|
3f19974bb6 | ||
|
|
b3e29bd8b5 | ||
|
|
07f4288e1f | ||
|
|
8e26f64f89 | ||
|
|
d6a3765597 | ||
|
|
2d3d49f957 | ||
|
|
48fc44baff | ||
|
|
bbe888c2b3 | ||
|
|
e2479a7ce2 | ||
|
|
e2cb5631d9 | ||
|
|
e43b773d7c | ||
|
|
60cb8e7e8e | ||
|
|
1158e92f12 | ||
|
|
dcd44859f5 | ||
|
|
d66d7d8a3a | ||
|
|
60b5317c5f | ||
|
|
9f3310d3d2 | ||
|
|
61593aed7d | ||
|
|
2c4a216dd9 | ||
|
|
1d9a98614a | ||
|
|
7ff1eabfc3 | ||
|
|
655f079329 | ||
|
|
2606d3f6d1 | ||
|
|
8509bcae58 | ||
|
|
31d6b9be4d | ||
|
|
3b246b2422 | ||
|
|
1e6820b6ed | ||
|
|
336ec089cc | ||
|
|
e8061ecd38 | ||
|
|
775625968a | ||
|
|
5672ddf8f3 | ||
|
|
2f95851537 | ||
|
|
491e3a44be | ||
|
|
fbe1b56f2d | ||
|
|
06fd16bbf5 | ||
|
|
906b65d09c | ||
|
|
059ce1ba15 | ||
|
|
332d178298 | ||
|
|
4094db40b8 | ||
|
|
45f1fdfaff | ||
|
|
de484773f0 | ||
|
|
2a62455822 | ||
|
|
5eb12b8503 | ||
|
|
c3ccf4d5a3 | ||
|
|
67d622fa9d | ||
|
|
9c1efb9f0e | ||
|
|
00ed00e1e5 | ||
|
|
e2206e62d6 | ||
|
|
6b971617e7 | ||
|
|
76fbb522d2 | ||
|
|
3b12f69dd9 | ||
|
|
6d798410ce | ||
|
|
a8543d4a88 | ||
|
|
afadc1f1eb | ||
|
|
f7bfe435c8 | ||
|
|
fe9a153f44 | ||
|
|
fbf3b9ae7a | ||
|
|
392ef09d19 | ||
|
|
cde71a915b | ||
|
|
2f95944244 | ||
|
|
2f53c0e640 | ||
|
|
6bbad22672 | ||
|
|
821bd1f27b | ||
|
|
2bec696114 | ||
|
|
b786ea7e5f | ||
|
|
34230369bc | ||
|
|
e992d86d38 | ||
|
|
546d644765 | ||
|
|
0b7a4257d7 | ||
|
|
5d4b61c365 | ||
|
|
b9064c5446 | ||
|
|
f35f077c76 | ||
|
|
e990d75a8f | ||
|
|
ea01ae6534 | ||
|
|
fa2c626e49 | ||
|
|
dcbf42d29c | ||
|
|
e694968012 | ||
|
|
175f0dbb00 | ||
|
|
94d6feffed | ||
|
|
8e132e90cc | ||
|
|
1529b58089 | ||
|
|
e8b857b79e | ||
|
|
4d93e8a732 | ||
|
|
60cf77be7e | ||
|
|
b2deea4606 | ||
|
|
7e5891b443 | ||
|
|
cf997fddf6 | ||
|
|
70d3be0a3a | ||
|
|
b519f13600 | ||
|
|
527dafa346 | ||
|
|
eab940c45d | ||
|
|
8dad622de2 | ||
|
|
0b78d1d953 | ||
|
|
3b211089d6 | ||
|
|
13d01f1ec4 | ||
|
|
14c71a351e | ||
|
|
6f19fc2fcd | ||
|
|
632cce2c16 | ||
|
|
43abc72780 | ||
|
|
5ee7004a62 | ||
|
|
75709bf1ec | ||
|
|
81297aad8c | ||
|
|
fabd7a9c51 | ||
|
|
e0543d1d59 | ||
|
|
6652685f5a | ||
|
|
898383ccff | ||
|
|
054efa648c | ||
|
|
9e618b6961 | ||
|
|
a6d2aa3913 | ||
|
|
010df54657 | ||
|
|
d171750678 | ||
|
|
907c34bae2 | ||
|
|
e546560d7c | ||
|
|
514e24ce62 | ||
|
|
239b6d8c8e | ||
|
|
52a015fb11 | ||
|
|
d4e0a5629d | ||
|
|
b83417301f | ||
|
|
450f6518e2 | ||
|
|
d7ecaae245 | ||
|
|
a841a2b0a2 | ||
|
|
8e1d77bcb2 | ||
|
|
1e622e168c | ||
|
|
a23327c399 | ||
|
|
4aa0a8ebae | ||
|
|
c014cd84f4 | ||
|
|
5b143cee96 | ||
|
|
072e2edd34 | ||
|
|
aaa29d8982 | ||
|
|
f685843a52 | ||
|
|
7952f0e237 | ||
|
|
3678e51f0b | ||
|
|
c5f6c65ff1 | ||
|
|
a7411700ef | ||
|
|
306f0f172d | ||
|
|
27ab4875fd | ||
|
|
aee3c0d249 | ||
|
|
735b3410aa | ||
|
|
fc7fef3dd8 | ||
|
|
0c88d05a65 | ||
|
|
8c705adbe9 | ||
|
|
bd631c5e00 | ||
|
|
5bb2cba66c | ||
|
|
6a83bf9de5 | ||
|
|
1b5675eb21 | ||
|
|
e53ef4acd2 | ||
|
|
b07fa70133 | ||
|
|
9d1901c049 | ||
|
|
bdc8a7f59d | ||
|
|
b36cabb396 | ||
|
|
92a5f3da75 | ||
|
|
a78124b2d5 | ||
|
|
5c2d9fe9a1 | ||
|
|
24c7ad5d28 | ||
|
|
0ad8ed3822 | ||
|
|
65df2bb16d | ||
|
|
b8010f27e7 | ||
|
|
9114131128 | ||
|
|
2d16192bab | ||
|
|
9c3a615794 | ||
|
|
bc89742979 | ||
|
|
c64d02d6df | ||
|
|
a834101d7e | ||
|
|
4822de3313 | ||
|
|
b8c063ed2a | ||
|
|
fc62ed5af0 | ||
|
|
3d1465439a | ||
|
|
59fdbdbb20 | ||
|
|
7f495b1851 | ||
|
|
c18b556f3d | ||
|
|
3b75d63c18 | ||
|
|
54156650d7 | ||
|
|
f0fc8110a0 | ||
|
|
02257eead0 | ||
|
|
fe35902222 | ||
|
|
24ef424d04 | ||
|
|
5df1abcd26 | ||
|
|
1a7f25af35 | ||
|
|
35a2ed87b6 | ||
|
|
a15681a181 | ||
|
|
5bdd724221 | ||
|
|
c9565b3657 | ||
|
|
aca8d047ca | ||
|
|
3bdab70451 | ||
|
|
e7c680e963 | ||
|
|
662fd5c04a | ||
|
|
9c73a9a1db | ||
|
|
4b205ff96d | ||
|
|
11729aaf6e | ||
|
|
4a4bd16eab | ||
|
|
b71ffc658b | ||
|
|
60febcdf1e | ||
|
|
a970c2d11c | ||
|
|
e963b84a5a | ||
|
|
fd77f1a7cb | ||
|
|
38a7bc0580 | ||
|
|
7aefd22e34 | ||
|
|
44f3c0289a | ||
|
|
cbdb1ebb5a | ||
|
|
3a0a219ce7 | ||
|
|
5d6baea174 | ||
|
|
55ff7109fa | ||
|
|
5313288b8e | ||
|
|
47ff1c1ee6 | ||
|
|
c242466d31 | ||
|
|
341816c280 | ||
|
|
0da4130bb9 |
9
.bazelrc
9
.bazelrc
@@ -10,15 +10,16 @@ common --override_module=semmle_code=%workspace%/misc/bazel/semmle_code_stub
|
|||||||
|
|
||||||
build --repo_env=CC=clang --repo_env=CXX=clang++
|
build --repo_env=CC=clang --repo_env=CXX=clang++
|
||||||
|
|
||||||
build:linux --cxxopt=-std=c++20
|
# we use transitions that break builds of `...`, so for `test` to work with that we need the following
|
||||||
# we currently cannot built the swift extractor for ARM
|
test --build_tests_only
|
||||||
build:macos --cxxopt=-std=c++20 --copt=-arch --copt=x86_64 --linkopt=-arch --linkopt=x86_64
|
|
||||||
build:windows --cxxopt=/std:c++20 --cxxopt=/Zc:preprocessor
|
|
||||||
|
|
||||||
# this requires developer mode, but is required to have pack installer functioning
|
# this requires developer mode, but is required to have pack installer functioning
|
||||||
startup --windows_enable_symlinks
|
startup --windows_enable_symlinks
|
||||||
common --enable_runfiles
|
common --enable_runfiles
|
||||||
|
|
||||||
|
# with the above, we can avoid building python zips which is the default on windows as that's expensive
|
||||||
|
build --nobuild_python_zip
|
||||||
|
|
||||||
common --registry=file:///%workspace%/misc/bazel/registry
|
common --registry=file:///%workspace%/misc/bazel/registry
|
||||||
common --registry=https://bcr.bazel.build
|
common --registry=https://bcr.bazel.build
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
7.1.2
|
7.2.0
|
||||||
|
|||||||
37
.gitattributes
vendored
37
.gitattributes
vendored
@@ -50,33 +50,40 @@
|
|||||||
*.dll -text
|
*.dll -text
|
||||||
*.pdb -text
|
*.pdb -text
|
||||||
|
|
||||||
java/ql/test/stubs/**/*.java linguist-generated=true
|
/java/ql/test/stubs/**/*.java linguist-generated=true
|
||||||
java/ql/test/experimental/stubs/**/*.java linguist-generated=true
|
/java/ql/test/experimental/stubs/**/*.java linguist-generated=true
|
||||||
|
/java/kotlin-extractor/deps/*.jar filter=lfs diff=lfs merge=lfs -text
|
||||||
|
|
||||||
# Force git not to modify line endings for go or html files under the go/ql directory
|
# Force git not to modify line endings for go or html files under the go/ql directory
|
||||||
go/ql/**/*.go -text
|
/go/ql/**/*.go -text
|
||||||
go/ql/**/*.html -text
|
/go/ql/**/*.html -text
|
||||||
# Force git not to modify line endings for go dbschemes
|
# Force git not to modify line endings for go dbschemes
|
||||||
go/*.dbscheme -text
|
/go/*.dbscheme -text
|
||||||
# Preserve unusual line ending from codeql-go merge
|
# Preserve unusual line ending from codeql-go merge
|
||||||
go/extractor/opencsv/CSVReader.java -text
|
/go/extractor/opencsv/CSVReader.java -text
|
||||||
|
|
||||||
# For some languages, upgrade script testing references really old dbscheme
|
# For some languages, upgrade script testing references really old dbscheme
|
||||||
# files from legacy upgrades that have CRLF line endings. Since upgrade
|
# files from legacy upgrades that have CRLF line endings. Since upgrade
|
||||||
# resolution relies on object hashes, we must suppress line ending conversion
|
# resolution relies on object hashes, we must suppress line ending conversion
|
||||||
# for those testing dbscheme files.
|
# for those testing dbscheme files.
|
||||||
*/ql/lib/upgrades/initial/*.dbscheme -text
|
/*/ql/lib/upgrades/initial/*.dbscheme -text
|
||||||
|
|
||||||
# Auto-generated modeling for Python
|
# Auto-generated modeling for Python
|
||||||
python/ql/lib/semmle/python/frameworks/data/internal/subclass-capture/*.yml linguist-generated=true
|
/python/ql/lib/semmle/python/frameworks/data/internal/subclass-capture/*.yml linguist-generated=true
|
||||||
|
|
||||||
# auto-generated bazel lock file
|
# auto-generated bazel lock file
|
||||||
ruby/extractor/cargo-bazel-lock.json linguist-generated=true
|
/ruby/extractor/cargo-bazel-lock.json linguist-generated=true
|
||||||
ruby/extractor/cargo-bazel-lock.json -merge
|
/ruby/extractor/cargo-bazel-lock.json -merge
|
||||||
|
|
||||||
# auto-generated files for the C# build
|
# auto-generated files for the C# build
|
||||||
csharp/paket.lock linguist-generated=true
|
/csharp/paket.lock linguist-generated=true
|
||||||
# needs eol=crlf, as `paket` touches this file and saves it als crlf
|
# needs eol=crlf, as `paket` touches this file and saves it as crlf
|
||||||
csharp/.paket/Paket.Restore.targets linguist-generated=true eol=crlf
|
/csharp/.paket/Paket.Restore.targets linguist-generated=true eol=crlf
|
||||||
csharp/paket.main.bzl linguist-generated=true
|
/csharp/paket.main.bzl linguist-generated=true
|
||||||
csharp/paket.main_extension.bzl linguist-generated=true
|
/csharp/paket.main_extension.bzl linguist-generated=true
|
||||||
|
|
||||||
|
# ripunzip tool
|
||||||
|
/misc/ripunzip/ripunzip-* filter=lfs diff=lfs merge=lfs -text
|
||||||
|
|
||||||
|
# swift prebuilt resources
|
||||||
|
/swift/third_party/resource-dir/*.zip filter=lfs diff=lfs merge=lfs -text
|
||||||
|
|||||||
4
.github/workflows/csharp-qltest.yml
vendored
4
.github/workflows/csharp-qltest.yml
vendored
@@ -65,7 +65,7 @@ jobs:
|
|||||||
key: csharp-qltest-${{ matrix.slice }}
|
key: csharp-qltest-${{ matrix.slice }}
|
||||||
- name: Run QL tests
|
- name: Run QL tests
|
||||||
run: |
|
run: |
|
||||||
codeql test run --threads=0 --ram 50000 --slice ${{ matrix.slice }} --search-path extractor-pack --check-databases --check-undefined-labels --check-repeated-labels --check-redefined-labels --consistency-queries ql/consistency-queries ql/test --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
codeql test run --threads=0 --ram 50000 --slice ${{ matrix.slice }} --search-path "${{ github.workspace }}" --check-databases --check-undefined-labels --check-repeated-labels --check-redefined-labels --consistency-queries ql/consistency-queries ql/test --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ github.token }}
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
unit-tests:
|
unit-tests:
|
||||||
@@ -101,6 +101,6 @@ jobs:
|
|||||||
# Update existing stubs in the repo with the freshly generated ones
|
# Update existing stubs in the repo with the freshly generated ones
|
||||||
mv "$STUBS_PATH/output/stubs/_frameworks" ql/test/resources/stubs/
|
mv "$STUBS_PATH/output/stubs/_frameworks" ql/test/resources/stubs/
|
||||||
git status
|
git status
|
||||||
codeql test run --threads=0 --search-path extractor-pack --check-databases --check-undefined-labels --check-repeated-labels --check-redefined-labels --consistency-queries ql/consistency-queries -- ql/test/library-tests/dataflow/flowsources/aspremote
|
codeql test run --threads=0 --search-path "${{ github.workspace }}" --check-databases --check-undefined-labels --check-repeated-labels --check-redefined-labels --consistency-queries ql/consistency-queries -- ql/test/library-tests/dataflow/flowsources/aspremote
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ github.token }}
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
|
|||||||
3
.github/workflows/go-tests-other-os.yml
vendored
3
.github/workflows/go-tests-other-os.yml
vendored
@@ -7,6 +7,9 @@ on:
|
|||||||
- .github/workflows/go-tests-other-os.yml
|
- .github/workflows/go-tests-other-os.yml
|
||||||
- .github/actions/**
|
- .github/actions/**
|
||||||
- codeql-workspace.yml
|
- codeql-workspace.yml
|
||||||
|
- MODULE.bazel
|
||||||
|
- .bazelrc
|
||||||
|
- misc/bazel/**
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|||||||
3
.github/workflows/go-tests.yml
vendored
3
.github/workflows/go-tests.yml
vendored
@@ -15,6 +15,9 @@ on:
|
|||||||
- .github/workflows/go-tests.yml
|
- .github/workflows/go-tests.yml
|
||||||
- .github/actions/**
|
- .github/actions/**
|
||||||
- codeql-workspace.yml
|
- codeql-workspace.yml
|
||||||
|
- MODULE.bazel
|
||||||
|
- .bazelrc
|
||||||
|
- misc/bazel/**
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|||||||
28
.github/workflows/kotlin-build.yml
vendored
Normal file
28
.github/workflows/kotlin-build.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
name: "Kotlin Build"
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- "java/kotlin-extractor/**"
|
||||||
|
- "misc/bazel/**"
|
||||||
|
- "misc/codegen/**"
|
||||||
|
- "*.bazel*"
|
||||||
|
- .github/workflows/kotlin-build.yml
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- rc/*
|
||||||
|
- codeql-cli-*
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- run: |
|
||||||
|
bazel query //java/kotlin-extractor/...
|
||||||
|
# only build the default version as a quick check that we can build from `codeql`
|
||||||
|
# the full official build will be checked by QLucie
|
||||||
|
bazel build //java/kotlin-extractor
|
||||||
10
.github/workflows/ql-for-ql-build.yml
vendored
10
.github/workflows/ql-for-ql-build.yml
vendored
@@ -49,20 +49,20 @@ jobs:
|
|||||||
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-rust-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
|
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-rust-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
|
||||||
- name: Release build
|
- name: Release build
|
||||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||||
run: cd ql; ./scripts/create-extractor-pack.sh
|
run: cd ql; ./scripts/create-extractor-pack.sh
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ github.token }}
|
GH_TOKEN: ${{ github.token }}
|
||||||
- name: Cache compilation cache
|
- name: Cache compilation cache
|
||||||
id: query-cache
|
id: query-cache
|
||||||
uses: ./.github/actions/cache-query-compilation
|
uses: ./.github/actions/cache-query-compilation
|
||||||
with:
|
with:
|
||||||
key: run-ql-for-ql
|
key: run-ql-for-ql
|
||||||
- name: Make database and analyze
|
- name: Make database and analyze
|
||||||
run: |
|
run: |
|
||||||
./ql/target/release/buramu | tee deprecated.blame # Add a blame file for the extractor to parse.
|
./ql/target/release/buramu | tee deprecated.blame # Add a blame file for the extractor to parse.
|
||||||
${CODEQL} database create -l=ql --search-path ql/extractor-pack ${DB}
|
${CODEQL} database create -l=ql ${DB} --search-path "${{ github.workspace }}"
|
||||||
${CODEQL} database analyze -j0 --format=sarif-latest --output=ql-for-ql.sarif ${DB} ql/ql/src/codeql-suites/ql-code-scanning.qls --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
${CODEQL} database analyze -j0 --format=sarif-latest --output=ql-for-ql.sarif ${DB} ql/ql/src/codeql-suites/ql-code-scanning.qls --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||||
env:
|
env:
|
||||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||||
DB: ${{ runner.temp }}/DB
|
DB: ${{ runner.temp }}/DB
|
||||||
LGTM_INDEX_FILTERS: |
|
LGTM_INDEX_FILTERS: |
|
||||||
|
|||||||
@@ -53,8 +53,8 @@ jobs:
|
|||||||
- name: Create database
|
- name: Create database
|
||||||
run: |
|
run: |
|
||||||
"${CODEQL}" database create \
|
"${CODEQL}" database create \
|
||||||
--search-path "ql/extractor-pack" \
|
--search-path "${{ github.workspace }}"
|
||||||
--threads 4 \
|
--threads 4 \
|
||||||
--language ql --source-root "${{ github.workspace }}/repo" \
|
--language ql --source-root "${{ github.workspace }}/repo" \
|
||||||
"${{ runner.temp }}/database"
|
"${{ runner.temp }}/database"
|
||||||
env:
|
env:
|
||||||
|
|||||||
13
.github/workflows/ql-for-ql-tests.yml
vendored
13
.github/workflows/ql-for-ql-tests.yml
vendored
@@ -49,15 +49,15 @@ jobs:
|
|||||||
- name: Cache compilation cache
|
- name: Cache compilation cache
|
||||||
id: query-cache
|
id: query-cache
|
||||||
uses: ./.github/actions/cache-query-compilation
|
uses: ./.github/actions/cache-query-compilation
|
||||||
with:
|
with:
|
||||||
key: ql-for-ql-tests
|
key: ql-for-ql-tests
|
||||||
- name: Run QL tests
|
- name: Run QL tests
|
||||||
run: |
|
run: |
|
||||||
"${CODEQL}" test run --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --search-path "${{ github.workspace }}/ql/extractor-pack" --consistency-queries ql/ql/consistency-queries --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" ql/ql/test
|
"${CODEQL}" test run --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --search-path "${{ github.workspace }}" --consistency-queries ql/ql/consistency-queries --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" ql/ql/test
|
||||||
env:
|
env:
|
||||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||||
|
|
||||||
other-os:
|
other-os:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [macos-latest, windows-latest]
|
os: [macos-latest, windows-latest]
|
||||||
@@ -65,7 +65,7 @@ jobs:
|
|||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Install GNU tar
|
- name: Install GNU tar
|
||||||
if: runner.os == 'macOS'
|
if: runner.os == 'macOS'
|
||||||
run: |
|
run: |
|
||||||
brew install gnu-tar
|
brew install gnu-tar
|
||||||
@@ -100,7 +100,7 @@ jobs:
|
|||||||
- name: Run a single QL tests - Unix
|
- name: Run a single QL tests - Unix
|
||||||
if: runner.os != 'Windows'
|
if: runner.os != 'Windows'
|
||||||
run: |
|
run: |
|
||||||
"${CODEQL}" test run --check-databases --search-path "${{ github.workspace }}/ql/extractor-pack" ql/ql/test/queries/style/DeadCode/DeadCode.qlref
|
"${CODEQL}" test run --check-databases --search-path "${{ github.workspace }}" ql/ql/test/queries/style/DeadCode/DeadCode.qlref
|
||||||
env:
|
env:
|
||||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||||
- name: Run a single QL tests - Windows
|
- name: Run a single QL tests - Windows
|
||||||
@@ -108,5 +108,4 @@ jobs:
|
|||||||
shell: pwsh
|
shell: pwsh
|
||||||
run: |
|
run: |
|
||||||
$Env:PATH += ";$(dirname ${{ steps.find-codeql.outputs.codeql-path }})"
|
$Env:PATH += ";$(dirname ${{ steps.find-codeql.outputs.codeql-path }})"
|
||||||
codeql test run --check-databases --search-path "${{ github.workspace }}/ql/extractor-pack" ql/ql/test/queries/style/DeadCode/DeadCode.qlref
|
codeql test run --check-databases --search-path "${{ github.workspace }}" ql/ql/test/queries/style/DeadCode/DeadCode.qlref
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/ruby-dataset-measure.yml
vendored
2
.github/workflows/ruby-dataset-measure.yml
vendored
@@ -44,7 +44,7 @@ jobs:
|
|||||||
- name: Create database
|
- name: Create database
|
||||||
run: |
|
run: |
|
||||||
codeql database create \
|
codeql database create \
|
||||||
--search-path "${{ github.workspace }}/ruby/extractor-pack" \
|
--search-path "${{ github.workspace }}" \
|
||||||
--threads 4 \
|
--threads 4 \
|
||||||
--language ruby --source-root "${{ github.workspace }}/repo" \
|
--language ruby --source-root "${{ github.workspace }}/repo" \
|
||||||
"${{ runner.temp }}/database"
|
"${{ runner.temp }}/database"
|
||||||
|
|||||||
4
.github/workflows/ruby-qltest.yml
vendored
4
.github/workflows/ruby-qltest.yml
vendored
@@ -64,10 +64,10 @@ jobs:
|
|||||||
- name: Cache compilation cache
|
- name: Cache compilation cache
|
||||||
id: query-cache
|
id: query-cache
|
||||||
uses: ./.github/actions/cache-query-compilation
|
uses: ./.github/actions/cache-query-compilation
|
||||||
with:
|
with:
|
||||||
key: ruby-qltest
|
key: ruby-qltest
|
||||||
- name: Run QL tests
|
- name: Run QL tests
|
||||||
run: |
|
run: |
|
||||||
codeql test run --threads=0 --ram 50000 --search-path "${{ github.workspace }}/ruby/extractor-pack" --check-databases --check-undefined-labels --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --consistency-queries ql/consistency-queries ql/test --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
codeql test run --threads=0 --ram 50000 --search-path "${{ github.workspace }}" --check-databases --check-undefined-labels --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --consistency-queries ql/consistency-queries ql/test --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ github.token }}
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
|
|||||||
15
.github/workflows/swift.yml
vendored
15
.github/workflows/swift.yml
vendored
@@ -68,21 +68,6 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: ./swift/actions/run-ql-tests
|
- uses: ./swift/actions/run-ql-tests
|
||||||
integration-tests-linux:
|
|
||||||
if: github.repository_owner == 'github'
|
|
||||||
needs: build-and-test-linux
|
|
||||||
runs-on: ubuntu-latest-xl
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: ./swift/actions/run-integration-tests
|
|
||||||
integration-tests-macos:
|
|
||||||
if: ${{ github.repository_owner == 'github' && github.event_name == 'pull_request' }}
|
|
||||||
needs: build-and-test-macos
|
|
||||||
runs-on: macos-12-xl
|
|
||||||
timeout-minutes: 60
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: ./swift/actions/run-integration-tests
|
|
||||||
clang-format:
|
clang-format:
|
||||||
if : ${{ github.event_name == 'pull_request' }}
|
if : ${{ github.event_name == 'pull_request' }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
23
.github/workflows/zipmerge-test.yml
vendored
Normal file
23
.github/workflows/zipmerge-test.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
name: "Test zipmerge code"
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- "misc/bazel/internal/zipmerge/**"
|
||||||
|
- "MODULE.bazel"
|
||||||
|
- ".bazelrc*"
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- "rc/*"
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- run: |
|
||||||
|
bazel test //misc/bazel/internal/zipmerge:test --test_output=all
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -62,3 +62,6 @@ node_modules/
|
|||||||
|
|
||||||
# Temporary folders for working with generated models
|
# Temporary folders for working with generated models
|
||||||
.model-temp
|
.model-temp
|
||||||
|
|
||||||
|
# bazel-built in-tree extractor packs
|
||||||
|
/*/extractor-pack
|
||||||
|
|||||||
@@ -2,4 +2,6 @@
|
|||||||
# codeql is publicly forked by many users, and we don't want any LFS file polluting their working
|
# codeql is publicly forked by many users, and we don't want any LFS file polluting their working
|
||||||
# copies. We therefore exclude everything by default.
|
# copies. We therefore exclude everything by default.
|
||||||
# For files required by bazel builds, use rules in `misc/bazel/lfs.bzl` to download them on demand.
|
# For files required by bazel builds, use rules in `misc/bazel/lfs.bzl` to download them on demand.
|
||||||
|
# we go for `fetchinclude` to something not exsiting rather than `fetchexclude = *` because the
|
||||||
|
# former is easier to override (with `git -c` or a local git config) to fetch something specific
|
||||||
fetchinclude = /nothing
|
fetchinclude = /nothing
|
||||||
|
|||||||
112
MODULE.bazel
112
MODULE.bazel
@@ -13,20 +13,45 @@ local_path_override(
|
|||||||
|
|
||||||
# see https://registry.bazel.build/ for a list of available packages
|
# see https://registry.bazel.build/ for a list of available packages
|
||||||
|
|
||||||
bazel_dep(name = "platforms", version = "0.0.9")
|
bazel_dep(name = "platforms", version = "0.0.10")
|
||||||
bazel_dep(name = "rules_go", version = "0.47.0")
|
bazel_dep(name = "rules_go", version = "0.48.0")
|
||||||
bazel_dep(name = "rules_pkg", version = "0.10.1")
|
bazel_dep(name = "rules_pkg", version = "0.10.1")
|
||||||
bazel_dep(name = "rules_nodejs", version = "6.0.3")
|
bazel_dep(name = "rules_nodejs", version = "6.2.0")
|
||||||
bazel_dep(name = "rules_python", version = "0.31.0")
|
bazel_dep(name = "rules_python", version = "0.32.2")
|
||||||
bazel_dep(name = "bazel_skylib", version = "1.5.0")
|
bazel_dep(name = "bazel_skylib", version = "1.6.1")
|
||||||
bazel_dep(name = "abseil-cpp", version = "20240116.0", repo_name = "absl")
|
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 = "nlohmann_json", version = "3.11.3", repo_name = "json")
|
||||||
bazel_dep(name = "fmt", version = "10.0.0")
|
bazel_dep(name = "fmt", version = "10.0.0")
|
||||||
bazel_dep(name = "gazelle", version = "0.36.0")
|
bazel_dep(name = "rules_kotlin", version = "1.9.4-codeql.1")
|
||||||
|
bazel_dep(name = "gazelle", version = "0.37.0")
|
||||||
bazel_dep(name = "rules_dotnet", version = "0.15.1")
|
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)
|
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 = use_extension("@rules_dotnet//dotnet:extensions.bzl", "dotnet")
|
||||||
dotnet.toolchain(dotnet_version = "8.0.101")
|
dotnet.toolchain(dotnet_version = "8.0.101")
|
||||||
use_repo(dotnet, "dotnet_toolchains")
|
use_repo(dotnet, "dotnet_toolchains")
|
||||||
@@ -64,9 +89,84 @@ node.toolchain(
|
|||||||
)
|
)
|
||||||
use_repo(node, "nodejs", "nodejs_toolchains")
|
use_repo(node, "nodejs", "nodejs_toolchains")
|
||||||
|
|
||||||
|
kotlin_extractor_deps = use_extension("//java/kotlin-extractor:deps.bzl", "kotlin_extractor_deps")
|
||||||
|
|
||||||
|
# following list can be kept in sync by running `bazel mod tidy` in `codeql`
|
||||||
|
use_repo(
|
||||||
|
kotlin_extractor_deps,
|
||||||
|
"codeql_kotlin_defaults",
|
||||||
|
"codeql_kotlin_embeddable",
|
||||||
|
"kotlin-compiler-1.5.0",
|
||||||
|
"kotlin-compiler-1.5.10",
|
||||||
|
"kotlin-compiler-1.5.20",
|
||||||
|
"kotlin-compiler-1.5.30",
|
||||||
|
"kotlin-compiler-1.6.0",
|
||||||
|
"kotlin-compiler-1.6.20",
|
||||||
|
"kotlin-compiler-1.7.0",
|
||||||
|
"kotlin-compiler-1.7.20",
|
||||||
|
"kotlin-compiler-1.8.0",
|
||||||
|
"kotlin-compiler-1.9.0-Beta",
|
||||||
|
"kotlin-compiler-1.9.20-Beta",
|
||||||
|
"kotlin-compiler-2.0.0-RC1",
|
||||||
|
"kotlin-compiler-embeddable-1.5.0",
|
||||||
|
"kotlin-compiler-embeddable-1.5.10",
|
||||||
|
"kotlin-compiler-embeddable-1.5.20",
|
||||||
|
"kotlin-compiler-embeddable-1.5.30",
|
||||||
|
"kotlin-compiler-embeddable-1.6.0",
|
||||||
|
"kotlin-compiler-embeddable-1.6.20",
|
||||||
|
"kotlin-compiler-embeddable-1.7.0",
|
||||||
|
"kotlin-compiler-embeddable-1.7.20",
|
||||||
|
"kotlin-compiler-embeddable-1.8.0",
|
||||||
|
"kotlin-compiler-embeddable-1.9.0-Beta",
|
||||||
|
"kotlin-compiler-embeddable-1.9.20-Beta",
|
||||||
|
"kotlin-compiler-embeddable-2.0.0-RC1",
|
||||||
|
"kotlin-stdlib-1.5.0",
|
||||||
|
"kotlin-stdlib-1.5.10",
|
||||||
|
"kotlin-stdlib-1.5.20",
|
||||||
|
"kotlin-stdlib-1.5.30",
|
||||||
|
"kotlin-stdlib-1.6.0",
|
||||||
|
"kotlin-stdlib-1.6.20",
|
||||||
|
"kotlin-stdlib-1.7.0",
|
||||||
|
"kotlin-stdlib-1.7.20",
|
||||||
|
"kotlin-stdlib-1.8.0",
|
||||||
|
"kotlin-stdlib-1.9.0-Beta",
|
||||||
|
"kotlin-stdlib-1.9.20-Beta",
|
||||||
|
"kotlin-stdlib-2.0.0-RC1",
|
||||||
|
)
|
||||||
|
|
||||||
go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")
|
go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")
|
||||||
go_sdk.download(version = "1.22.2")
|
go_sdk.download(version = "1.22.2")
|
||||||
|
|
||||||
|
lfs_files = use_repo_rule("//misc/bazel:lfs.bzl", "lfs_files")
|
||||||
|
|
||||||
|
lfs_files(
|
||||||
|
name = "ripunzip-linux",
|
||||||
|
srcs = ["//misc/ripunzip:ripunzip-linux"],
|
||||||
|
executable = True,
|
||||||
|
)
|
||||||
|
|
||||||
|
lfs_files(
|
||||||
|
name = "ripunzip-windows",
|
||||||
|
srcs = ["//misc/ripunzip:ripunzip-windows.exe"],
|
||||||
|
executable = True,
|
||||||
|
)
|
||||||
|
|
||||||
|
lfs_files(
|
||||||
|
name = "ripunzip-macos",
|
||||||
|
srcs = ["//misc/ripunzip:ripunzip-macos"],
|
||||||
|
executable = True,
|
||||||
|
)
|
||||||
|
|
||||||
|
lfs_files(
|
||||||
|
name = "swift-resource-dir-linux",
|
||||||
|
srcs = ["//swift/third_party/resource-dir:resource-dir-linux.zip"],
|
||||||
|
)
|
||||||
|
|
||||||
|
lfs_files(
|
||||||
|
name = "swift-resource-dir-macos",
|
||||||
|
srcs = ["//swift/third_party/resource-dir:resource-dir-macos.zip"],
|
||||||
|
)
|
||||||
|
|
||||||
register_toolchains(
|
register_toolchains(
|
||||||
"@nodejs_toolchains//:all",
|
"@nodejs_toolchains//:all",
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,19 +6,16 @@ provide:
|
|||||||
- "*/ql/consistency-queries/qlpack.yml"
|
- "*/ql/consistency-queries/qlpack.yml"
|
||||||
- "*/ql/automodel/src/qlpack.yml"
|
- "*/ql/automodel/src/qlpack.yml"
|
||||||
- "*/ql/automodel/test/qlpack.yml"
|
- "*/ql/automodel/test/qlpack.yml"
|
||||||
|
- "*/extractor-pack/codeql-extractor.yml"
|
||||||
- "python/extractor/qlpack.yml"
|
- "python/extractor/qlpack.yml"
|
||||||
- "shared/**/qlpack.yml"
|
- "shared/**/qlpack.yml"
|
||||||
- "cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml"
|
- "cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml"
|
||||||
- "go/ql/config/legacy-support/qlpack.yml"
|
- "go/ql/config/legacy-support/qlpack.yml"
|
||||||
- "go/build/codeql-extractor-go/codeql-extractor.yml"
|
|
||||||
- "csharp/ql/campaigns/Solorigate/lib/qlpack.yml"
|
- "csharp/ql/campaigns/Solorigate/lib/qlpack.yml"
|
||||||
- "csharp/ql/campaigns/Solorigate/src/qlpack.yml"
|
- "csharp/ql/campaigns/Solorigate/src/qlpack.yml"
|
||||||
- "csharp/ql/campaigns/Solorigate/test/qlpack.yml"
|
- "csharp/ql/campaigns/Solorigate/test/qlpack.yml"
|
||||||
- "misc/legacy-support/*/qlpack.yml"
|
- "misc/legacy-support/*/qlpack.yml"
|
||||||
- "misc/suite-helpers/qlpack.yml"
|
- "misc/suite-helpers/qlpack.yml"
|
||||||
- "ruby/extractor-pack/codeql-extractor.yml"
|
|
||||||
- "swift/extractor-pack/codeql-extractor.yml"
|
|
||||||
- "ql/extractor-pack/codeql-extractor.yml"
|
|
||||||
- ".github/codeql/extensions/**/codeql-pack.yml"
|
- ".github/codeql/extensions/**/codeql-pack.yml"
|
||||||
|
|
||||||
versionPolicies:
|
versionPolicies:
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ pkg_files(
|
|||||||
["**"],
|
["**"],
|
||||||
exclude = ["BUILD.bazel"],
|
exclude = ["BUILD.bazel"],
|
||||||
),
|
),
|
||||||
prefix = "cpp/downgrades",
|
prefix = "downgrades",
|
||||||
strip_prefix = strip_prefix.from_pkg(),
|
strip_prefix = strip_prefix.from_pkg(),
|
||||||
visibility = ["//cpp:__pkg__"],
|
visibility = ["//cpp:__pkg__"],
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,11 +5,9 @@ package(default_visibility = ["//cpp:__pkg__"])
|
|||||||
pkg_files(
|
pkg_files(
|
||||||
name = "dbscheme",
|
name = "dbscheme",
|
||||||
srcs = ["semmlecode.cpp.dbscheme"],
|
srcs = ["semmlecode.cpp.dbscheme"],
|
||||||
prefix = "cpp",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
pkg_files(
|
pkg_files(
|
||||||
name = "dbscheme-stats",
|
name = "dbscheme-stats",
|
||||||
srcs = ["semmlecode.cpp.dbscheme.stats"],
|
srcs = ["semmlecode.cpp.dbscheme.stats"],
|
||||||
prefix = "cpp",
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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
|
## 1.0.0
|
||||||
|
|
||||||
### Breaking Changes
|
### Breaking Changes
|
||||||
|
|||||||
4
cpp/ql/lib/change-notes/2024-10-06-builtin-expect.md
Normal file
4
cpp/ql/lib/change-notes/2024-10-06-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.
|
||||||
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
|
||||||
|
|||||||
26
cpp/ql/lib/ext/Boost.Asio.model.yml
Normal file
26
cpp/ql/lib/ext/Boost.Asio.model.yml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
extensions:
|
||||||
|
# partial model of the Boost::Asio network library
|
||||||
|
extensions:
|
||||||
|
- addsTo:
|
||||||
|
pack: codeql/cpp-all
|
||||||
|
extensible: sourceModel
|
||||||
|
data: # namespace, type, subtypes, name, signature, ext, output, kind, provenance
|
||||||
|
- ["boost::asio", "", False, "read", "", "", "Argument[*1]", "remote", "manual"]
|
||||||
|
- ["boost::asio", "", False, "read_at", "", "", "Argument[*2]", "remote", "manual"]
|
||||||
|
- ["boost::asio", "", False, "read_until", "", "", "Argument[*1]", "remote", "manual"]
|
||||||
|
- ["boost::asio", "", False, "async_read", "", "", "Argument[*1]", "remote", "manual"]
|
||||||
|
- ["boost::asio", "", False, "async_read_at", "", "", "Argument[*2]", "remote", "manual"]
|
||||||
|
- ["boost::asio", "", False, "async_read_until", "", "", "Argument[*1]", "remote", "manual"]
|
||||||
|
- addsTo:
|
||||||
|
pack: codeql/cpp-all
|
||||||
|
extensible: sinkModel
|
||||||
|
data: # namespace, type, subtypes, name, signature, ext, input, kind, provenance
|
||||||
|
- ["boost::asio", "", False, "write", "", "", "Argument[*1]", "remote-sink", "manual"]
|
||||||
|
- ["boost::asio", "", False, "write_at", "", "", "Argument[*2]", "remote-sink", "manual"]
|
||||||
|
- ["boost::asio", "", False, "async_write", "", "", "Argument[*1]", "remote-sink", "manual"]
|
||||||
|
- ["boost::asio", "", False, "async_write_at", "", "", "Argument[*2]", "remote-sink", "manual"]
|
||||||
|
- addsTo:
|
||||||
|
pack: codeql/cpp-all
|
||||||
|
extensible: summaryModel
|
||||||
|
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
|
||||||
|
- ["boost::asio", "", False, "buffer", "", "", "Argument[*0]", "ReturnValue", "taint", "manual"]
|
||||||
15
cpp/ql/lib/ext/empty.model.yml
Normal file
15
cpp/ql/lib/ext/empty.model.yml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
extensions:
|
||||||
|
# Make sure that the extensible model predicates have at least one definition
|
||||||
|
# to avoid errors about undefined extensionals.
|
||||||
|
- addsTo:
|
||||||
|
pack: codeql/cpp-all
|
||||||
|
extensible: sourceModel
|
||||||
|
data: []
|
||||||
|
- addsTo:
|
||||||
|
pack: codeql/cpp-all
|
||||||
|
extensible: sinkModel
|
||||||
|
data: []
|
||||||
|
- addsTo:
|
||||||
|
pack: codeql/cpp-all
|
||||||
|
extensible: summaryModel
|
||||||
|
data: []
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/cpp-all
|
name: codeql/cpp-all
|
||||||
version: 1.0.0
|
version: 1.1.1-dev
|
||||||
groups: cpp
|
groups: cpp
|
||||||
dbscheme: semmlecode.cpp.dbscheme
|
dbscheme: semmlecode.cpp.dbscheme
|
||||||
extractor: cpp
|
extractor: cpp
|
||||||
@@ -14,4 +14,6 @@ dependencies:
|
|||||||
codeql/tutorial: ${workspace}
|
codeql/tutorial: ${workspace}
|
||||||
codeql/util: ${workspace}
|
codeql/util: ${workspace}
|
||||||
codeql/xml: ${workspace}
|
codeql/xml: ${workspace}
|
||||||
|
dataExtensions:
|
||||||
|
- ext/*.model.yml
|
||||||
warnOnImplicitThis: true
|
warnOnImplicitThis: true
|
||||||
|
|||||||
@@ -410,6 +410,10 @@ class LocalVariable extends LocalScopeVariable, @localvariable {
|
|||||||
or
|
or
|
||||||
orphaned_variables(underlyingElement(this), unresolveElement(result))
|
orphaned_variables(underlyingElement(this), unresolveElement(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override predicate isStatic() {
|
||||||
|
super.isStatic() or orphaned_variables(underlyingElement(this), _)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -375,6 +375,33 @@ cached
|
|||||||
class IRGuardCondition extends Instruction {
|
class IRGuardCondition extends Instruction {
|
||||||
Instruction branch;
|
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
|
cached
|
||||||
IRGuardCondition() { branch = getBranchForCondition(this) }
|
IRGuardCondition() { branch = getBranchForCondition(this) }
|
||||||
|
|
||||||
@@ -735,6 +762,8 @@ private predicate compares_eq(
|
|||||||
exists(AbstractValue dual | value = dual.getDualValue() |
|
exists(AbstractValue dual | value = dual.getDualValue() |
|
||||||
compares_eq(test.(LogicalNotInstruction).getUnary(), left, right, k, areEqual, dual)
|
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
|
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. */
|
/* 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
|
areEqual = true and value = v
|
||||||
or
|
or
|
||||||
areEqual = false and value = v.getDualValue()
|
areEqual = false and value = v.getDualValue()
|
||||||
@@ -802,6 +833,9 @@ private predicate unary_compares_eq(
|
|||||||
int_value(const) = k1 and
|
int_value(const) = k1 and
|
||||||
k = k1 + k2
|
k = k1 + k2
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
unary_compares_eq(test.(BuiltinExpectCallInstruction).getCondition(), op, k, areEqual,
|
||||||
|
inNonZeroCase, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Rearrange various simple comparisons into `left == right + k` form. */
|
/** Rearrange various simple comparisons into `left == right + k` form. */
|
||||||
@@ -821,45 +855,55 @@ private predicate simple_comparison_eq(
|
|||||||
value.(BooleanValue).getValue() = false
|
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.
|
* Rearrange various simple comparisons into `op == k` form.
|
||||||
*/
|
*/
|
||||||
private predicate unary_simple_comparison_eq(
|
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 |
|
exists(SwitchInstruction switch, CaseEdge case |
|
||||||
test = switch.getExpression() and
|
test = switch.getExpression() and
|
||||||
op.getDef() = test and
|
|
||||||
case = value.(MatchValue).getCase() and
|
case = value.(MatchValue).getCase() and
|
||||||
exists(switch.getSuccessor(case)) and
|
exists(switch.getSuccessor(case)) and
|
||||||
case.getValue().toInt() = k and
|
case.getValue().toInt() = k and
|
||||||
inNonZeroCase = false
|
inNonZeroCase = false
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// There's no implicit CompareInstruction in files compiled as C since C
|
// Any instruction with an integral type could potentially be part of a
|
||||||
// doesn't have implicit boolean conversions. So instead we check whether
|
// check for nullness when used in a guard. So we include all integral
|
||||||
// there's a branch on a value of pointer or integer type.
|
// typed instructions here. However, since some of these instructions are
|
||||||
relevantUnaryComparison(test) and
|
// already included as guards in other cases, we exclude those here.
|
||||||
op.getDef() = test and
|
// 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
|
k = 1 and
|
||||||
value.(BooleanValue).getValue() = true 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(
|
private predicate complex_eq(
|
||||||
CompareInstruction cmp, Operand left, Operand right, int k, boolean areEqual, AbstractValue value
|
CompareInstruction cmp, Operand left, Operand right, int k, boolean areEqual, AbstractValue value
|
||||||
) {
|
) {
|
||||||
sub_eq(cmp, left, right, k, areEqual, value)
|
sub_eq(cmp, left, right, k, areEqual, value)
|
||||||
or
|
or
|
||||||
add_eq(cmp, left, right, k, areEqual, value)
|
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(
|
private predicate unary_complex_eq(
|
||||||
@@ -885,6 +985,8 @@ private predicate unary_complex_eq(
|
|||||||
unary_sub_eq(test, op, k, areEqual, inNonZeroCase, value)
|
unary_sub_eq(test, op, k, areEqual, inNonZeroCase, value)
|
||||||
or
|
or
|
||||||
unary_add_eq(test, op, k, areEqual, inNonZeroCase, value)
|
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`. */
|
/** 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) {
|
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
|
or
|
||||||
complex_lt(test, op, k, isLt, value)
|
complex_lt(test, op, k, isLt, value)
|
||||||
or
|
or
|
||||||
@@ -960,12 +1063,11 @@ private predicate simple_comparison_lt(CompareInstruction cmp, Operand left, Ope
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Rearrange various simple comparisons into `op < k` form. */
|
/** Rearrange various simple comparisons into `op < k` form. */
|
||||||
private predicate simple_comparison_lt(
|
private predicate unary_simple_comparison_lt(
|
||||||
Instruction test, Operand op, int k, boolean isLt, AbstractValue value
|
Instruction test, int k, boolean isLt, AbstractValue value
|
||||||
) {
|
) {
|
||||||
exists(SwitchInstruction switch, CaseEdge case |
|
exists(SwitchInstruction switch, CaseEdge case |
|
||||||
test = switch.getExpression() and
|
test = switch.getExpression() and
|
||||||
op.getDef() = test and
|
|
||||||
case = value.(MatchValue).getCase() and
|
case = value.(MatchValue).getCase() and
|
||||||
exists(switch.getSuccessor(case)) and
|
exists(switch.getSuccessor(case)) and
|
||||||
case.getMaxValue() > case.getMinValue()
|
case.getMaxValue() > case.getMinValue()
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ private import internal.FlowSummaryImpl
|
|||||||
private import internal.FlowSummaryImpl::Public
|
private import internal.FlowSummaryImpl::Public
|
||||||
private import internal.FlowSummaryImpl::Private
|
private import internal.FlowSummaryImpl::Private
|
||||||
private import internal.FlowSummaryImpl::Private::External
|
private import internal.FlowSummaryImpl::Private::External
|
||||||
|
private import internal.ExternalFlowExtensions as Extensions
|
||||||
private import codeql.mad.ModelValidation as SharedModelVal
|
private import codeql.mad.ModelValidation as SharedModelVal
|
||||||
private import codeql.util.Unit
|
private import codeql.util.Unit
|
||||||
|
|
||||||
@@ -138,6 +139,9 @@ predicate sourceModel(
|
|||||||
row.splitAt(";", 7) = kind
|
row.splitAt(";", 7) = kind
|
||||||
) and
|
) and
|
||||||
provenance = "manual"
|
provenance = "manual"
|
||||||
|
or
|
||||||
|
Extensions::sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance,
|
||||||
|
_)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if a sink model exists for the given parameters. */
|
/** Holds if a sink model exists for the given parameters. */
|
||||||
@@ -158,6 +162,8 @@ predicate sinkModel(
|
|||||||
row.splitAt(";", 7) = kind
|
row.splitAt(";", 7) = kind
|
||||||
) and
|
) and
|
||||||
provenance = "manual"
|
provenance = "manual"
|
||||||
|
or
|
||||||
|
Extensions::sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, provenance, _)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if a summary model exists for the given parameters. */
|
/** Holds if a summary model exists for the given parameters. */
|
||||||
@@ -179,6 +185,9 @@ predicate summaryModel(
|
|||||||
row.splitAt(";", 8) = kind
|
row.splitAt(";", 8) = kind
|
||||||
) and
|
) and
|
||||||
provenance = "manual"
|
provenance = "manual"
|
||||||
|
or
|
||||||
|
Extensions::summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind,
|
||||||
|
provenance, _)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate relevantNamespace(string namespace) {
|
private predicate relevantNamespace(string namespace) {
|
||||||
@@ -203,8 +212,10 @@ private predicate canonicalNamespaceLink(string namespace, string subns) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if CSV framework coverage of `namespace` is `n` api endpoints of the
|
* Holds if MaD framework coverage of `namespace` is `n` api endpoints of the
|
||||||
* kind `(kind, part)`.
|
* kind `(kind, part)`, and `namespaces` is the number of subnamespaces of
|
||||||
|
* `namespace` which have MaD framework coverage (including `namespace`
|
||||||
|
* itself).
|
||||||
*/
|
*/
|
||||||
predicate modelCoverage(string namespace, int namespaces, string kind, string part, int n) {
|
predicate modelCoverage(string namespace, int namespaces, string kind, string part, int n) {
|
||||||
namespaces = strictcount(string subns | canonicalNamespaceLink(namespace, subns)) and
|
namespaces = strictcount(string subns | canonicalNamespaceLink(namespace, subns)) and
|
||||||
@@ -321,10 +332,10 @@ module CsvValidation {
|
|||||||
or
|
or
|
||||||
summaryModel(namespace, type, _, name, signature, ext, _, _, _, _) and pred = "summary"
|
summaryModel(namespace, type, _, name, signature, ext, _, _, _, _) and pred = "summary"
|
||||||
|
|
|
|
||||||
not namespace.regexpMatch("[a-zA-Z0-9_\\.]+") and
|
not namespace.regexpMatch("[a-zA-Z0-9_\\.:]*") and
|
||||||
result = "Dubious namespace \"" + namespace + "\" in " + pred + " model."
|
result = "Dubious namespace \"" + namespace + "\" in " + pred + " model."
|
||||||
or
|
or
|
||||||
not type.regexpMatch("[a-zA-Z0-9_<>,\\+]+") and
|
not type.regexpMatch("[a-zA-Z0-9_<>,\\+]*") and
|
||||||
result = "Dubious type \"" + type + "\" in " + pred + " model."
|
result = "Dubious type \"" + type + "\" in " + pred + " model."
|
||||||
or
|
or
|
||||||
not name.regexpMatch("[a-zA-Z0-9_<>,]*") and
|
not name.regexpMatch("[a-zA-Z0-9_<>,]*") and
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* This module provides extensible predicates for defining MaD models.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if an external source model exists for the given parameters.
|
||||||
|
*/
|
||||||
|
extensible predicate sourceModel(
|
||||||
|
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||||
|
string output, string kind, string provenance, QlBuiltins::ExtensionId madId
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if an external sink model exists for the given parameters.
|
||||||
|
*/
|
||||||
|
extensible predicate sinkModel(
|
||||||
|
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||||
|
string input, string kind, string provenance, QlBuiltins::ExtensionId madId
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if an external summary model exists for the given parameters.
|
||||||
|
*/
|
||||||
|
extensible predicate summaryModel(
|
||||||
|
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||||
|
string input, string output, string kind, string provenance, QlBuiltins::ExtensionId madId
|
||||||
|
);
|
||||||
@@ -1336,6 +1336,8 @@ predicate nodeIsHidden(Node n) {
|
|||||||
n instanceof FinalGlobalValue
|
n instanceof FinalGlobalValue
|
||||||
or
|
or
|
||||||
n instanceof InitialGlobalValue
|
n instanceof InitialGlobalValue
|
||||||
|
or
|
||||||
|
n instanceof SsaPhiInputNode
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate neverSkipInPathGraph(Node n) {
|
predicate neverSkipInPathGraph(Node n) {
|
||||||
@@ -1634,6 +1636,8 @@ private Instruction getAnInstruction(Node n) {
|
|||||||
or
|
or
|
||||||
result = n.(SsaPhiNode).getPhiNode().getBasicBlock().getFirstInstruction()
|
result = n.(SsaPhiNode).getPhiNode().getBasicBlock().getFirstInstruction()
|
||||||
or
|
or
|
||||||
|
result = n.(SsaPhiInputNode).getBasicBlock().getFirstInstruction()
|
||||||
|
or
|
||||||
n.(IndirectInstruction).hasInstructionAndIndirectionIndex(result, _)
|
n.(IndirectInstruction).hasInstructionAndIndirectionIndex(result, _)
|
||||||
or
|
or
|
||||||
not n instanceof IndirectInstruction and
|
not n instanceof IndirectInstruction and
|
||||||
@@ -1763,7 +1767,7 @@ module IteratorFlow {
|
|||||||
crementCall = def.getValue().asInstruction().(StoreInstruction).getSourceValue() and
|
crementCall = def.getValue().asInstruction().(StoreInstruction).getSourceValue() and
|
||||||
sv = def.getSourceVariable() and
|
sv = def.getSourceVariable() and
|
||||||
bb.getInstruction(i) = crementCall and
|
bb.getInstruction(i) = crementCall and
|
||||||
Ssa::ssaDefReachesRead(sv, result.asDef(), bb, i)
|
Ssa::ssaDefReachesReadExt(sv, result.asDef(), bb, i)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1797,7 +1801,7 @@ module IteratorFlow {
|
|||||||
isIteratorWrite(writeToDeref, address) and
|
isIteratorWrite(writeToDeref, address) and
|
||||||
operandForFullyConvertedCall(address, starCall) and
|
operandForFullyConvertedCall(address, starCall) and
|
||||||
bbStar.getInstruction(iStar) = starCall and
|
bbStar.getInstruction(iStar) = starCall and
|
||||||
Ssa::ssaDefReachesRead(_, def.asDef(), bbStar, iStar) and
|
Ssa::ssaDefReachesReadExt(_, def.asDef(), bbStar, iStar) and
|
||||||
ultimate = getAnUltimateDefinition*(def) and
|
ultimate = getAnUltimateDefinition*(def) and
|
||||||
beginStore = ultimate.getValue().asInstruction() and
|
beginStore = ultimate.getValue().asInstruction() and
|
||||||
operandForFullyConvertedCall(beginStore.getSourceValueOperand(), beginCall)
|
operandForFullyConvertedCall(beginStore.getSourceValueOperand(), beginCall)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ private import SsaInternals as Ssa
|
|||||||
private import DataFlowImplCommon as DataFlowImplCommon
|
private import DataFlowImplCommon as DataFlowImplCommon
|
||||||
private import codeql.util.Unit
|
private import codeql.util.Unit
|
||||||
private import Node0ToString
|
private import Node0ToString
|
||||||
|
import ExprNodes
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The IR dataflow graph consists of the following nodes:
|
* The IR dataflow graph consists of the following nodes:
|
||||||
@@ -45,6 +46,7 @@ private newtype TIRDataFlowNode =
|
|||||||
or
|
or
|
||||||
Ssa::isModifiableByCall(operand, indirectionIndex)
|
Ssa::isModifiableByCall(operand, indirectionIndex)
|
||||||
} or
|
} or
|
||||||
|
TSsaPhiInputNode(Ssa::PhiNode phi, IRBlock input) { phi.hasInputFromBlock(_, _, _, _, input) } or
|
||||||
TSsaPhiNode(Ssa::PhiNode phi) or
|
TSsaPhiNode(Ssa::PhiNode phi) or
|
||||||
TSsaIteratorNode(IteratorFlow::IteratorFlowNode n) or
|
TSsaIteratorNode(IteratorFlow::IteratorFlowNode n) or
|
||||||
TRawIndirectOperand0(Node0Impl node, int indirectionIndex) {
|
TRawIndirectOperand0(Node0Impl node, int indirectionIndex) {
|
||||||
@@ -114,6 +116,13 @@ predicate conversionFlow(
|
|||||||
instrTo.(CheckedConvertOrNullInstruction).getUnaryOperand() = opFrom
|
instrTo.(CheckedConvertOrNullInstruction).getUnaryOperand() = opFrom
|
||||||
or
|
or
|
||||||
instrTo.(InheritanceConversionInstruction).getUnaryOperand() = opFrom
|
instrTo.(InheritanceConversionInstruction).getUnaryOperand() = opFrom
|
||||||
|
or
|
||||||
|
exists(BuiltInInstruction builtIn |
|
||||||
|
builtIn = instrTo and
|
||||||
|
// __builtin_bit_cast
|
||||||
|
builtIn.getBuiltInOperation() instanceof BuiltInBitCast and
|
||||||
|
opFrom = builtIn.getAnOperand()
|
||||||
|
)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
additional = true and
|
additional = true and
|
||||||
@@ -158,6 +167,12 @@ class Node extends TIRDataFlowNode {
|
|||||||
/** Gets the operands corresponding to this node, if any. */
|
/** Gets the operands corresponding to this node, if any. */
|
||||||
Operand asOperand() { result = this.(OperandNode).getOperand() }
|
Operand asOperand() { result = this.(OperandNode).getOperand() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the operand that is indirectly tracked by this node behind `index`
|
||||||
|
* number of indirections.
|
||||||
|
*/
|
||||||
|
Operand asIndirectOperand(int index) { hasOperandAndIndex(this, result, index) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if this node is at index `i` in basic block `block`.
|
* Holds if this node is at index `i` in basic block `block`.
|
||||||
*
|
*
|
||||||
@@ -170,6 +185,9 @@ class Node extends TIRDataFlowNode {
|
|||||||
or
|
or
|
||||||
this.(SsaPhiNode).getPhiNode().getBasicBlock() = block and i = -1
|
this.(SsaPhiNode).getPhiNode().getBasicBlock() = block and i = -1
|
||||||
or
|
or
|
||||||
|
this.(SsaPhiInputNode).getBlock() = block and
|
||||||
|
i = block.getInstructionCount()
|
||||||
|
or
|
||||||
this.(RawIndirectOperand).getOperand().getUse() = block.getInstruction(i)
|
this.(RawIndirectOperand).getOperand().getUse() = block.getInstruction(i)
|
||||||
or
|
or
|
||||||
this.(RawIndirectInstruction).getInstruction() = block.getInstruction(i)
|
this.(RawIndirectInstruction).getInstruction() = block.getInstruction(i)
|
||||||
@@ -622,7 +640,7 @@ class SsaPhiNode extends Node, TSsaPhiNode {
|
|||||||
|
|
||||||
final override Location getLocationImpl() { result = phi.getBasicBlock().getLocation() }
|
final override Location getLocationImpl() { result = phi.getBasicBlock().getLocation() }
|
||||||
|
|
||||||
override string toStringImpl() { result = "Phi" }
|
override string toStringImpl() { result = phi.toString() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a node that is used as input to this phi node.
|
* Gets a node that is used as input to this phi node.
|
||||||
@@ -631,7 +649,7 @@ class SsaPhiNode extends Node, TSsaPhiNode {
|
|||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
final Node getAnInput(boolean fromBackEdge) {
|
final Node getAnInput(boolean fromBackEdge) {
|
||||||
localFlowStep(result, this) and
|
result.(SsaPhiInputNode).getPhiNode() = phi and
|
||||||
exists(IRBlock bPhi, IRBlock bResult |
|
exists(IRBlock bPhi, IRBlock bResult |
|
||||||
bPhi = phi.getBasicBlock() and bResult = result.getBasicBlock()
|
bPhi = phi.getBasicBlock() and bResult = result.getBasicBlock()
|
||||||
|
|
|
|
||||||
@@ -654,6 +672,58 @@ class SsaPhiNode extends Node, TSsaPhiNode {
|
|||||||
predicate isPhiRead() { phi.isPhiRead() }
|
predicate isPhiRead() { phi.isPhiRead() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* INTERNAL: Do not use.
|
||||||
|
*
|
||||||
|
* A node that is used as an input to a phi node.
|
||||||
|
*
|
||||||
|
* This class exists to allow more powerful barrier guards. Consider this
|
||||||
|
* example:
|
||||||
|
*
|
||||||
|
* ```cpp
|
||||||
|
* int x = source();
|
||||||
|
* if(!safe(x)) {
|
||||||
|
* x = clear();
|
||||||
|
* }
|
||||||
|
* // phi node for x here
|
||||||
|
* sink(x);
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* At the phi node for `x` it is neither the case that `x` is dominated by
|
||||||
|
* `safe(x)`, or is the case that the phi is dominated by a clearing of `x`.
|
||||||
|
*
|
||||||
|
* By inserting a "phi input" node as the last entry in the basic block that
|
||||||
|
* defines the inputs to the phi we can conclude that each of those inputs are
|
||||||
|
* safe to pass to `sink`.
|
||||||
|
*/
|
||||||
|
class SsaPhiInputNode extends Node, TSsaPhiInputNode {
|
||||||
|
Ssa::PhiNode phi;
|
||||||
|
IRBlock block;
|
||||||
|
|
||||||
|
SsaPhiInputNode() { this = TSsaPhiInputNode(phi, block) }
|
||||||
|
|
||||||
|
/** Gets the phi node associated with this node. */
|
||||||
|
Ssa::PhiNode getPhiNode() { result = phi }
|
||||||
|
|
||||||
|
/** Gets the basic block in which this input originates. */
|
||||||
|
IRBlock getBlock() { result = block }
|
||||||
|
|
||||||
|
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||||
|
|
||||||
|
override Declaration getFunction() { result = phi.getBasicBlock().getEnclosingFunction() }
|
||||||
|
|
||||||
|
override DataFlowType getType() { result = this.getSourceVariable().getType() }
|
||||||
|
|
||||||
|
override predicate isGLValue() { phi.getSourceVariable().isGLValue() }
|
||||||
|
|
||||||
|
final override Location getLocationImpl() { result = block.getLastInstruction().getLocation() }
|
||||||
|
|
||||||
|
override string toStringImpl() { result = "Phi input" }
|
||||||
|
|
||||||
|
/** Gets the source variable underlying this phi node. */
|
||||||
|
Ssa::SourceVariable getSourceVariable() { result = phi.getSourceVariable() }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* INTERNAL: do not use.
|
* INTERNAL: do not use.
|
||||||
*
|
*
|
||||||
@@ -1227,466 +1297,6 @@ class UninitializedNode extends Node {
|
|||||||
LocalVariable getLocalVariable() { result = v }
|
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 {
|
abstract private class AbstractParameterNode extends Node {
|
||||||
/**
|
/**
|
||||||
* Holds if this node is the parameter of `f` at the specified position. The
|
* Holds if this node is the parameter of `f` at the specified position. The
|
||||||
@@ -2176,6 +1786,9 @@ private module Cached {
|
|||||||
// Def-use/Use-use flow
|
// Def-use/Use-use flow
|
||||||
Ssa::ssaFlow(nodeFrom, nodeTo)
|
Ssa::ssaFlow(nodeFrom, nodeTo)
|
||||||
or
|
or
|
||||||
|
// Phi input -> Phi
|
||||||
|
nodeFrom.(SsaPhiInputNode).getPhiNode() = nodeTo.(SsaPhiNode).getPhiNode()
|
||||||
|
or
|
||||||
IteratorFlow::localFlowStep(nodeFrom, nodeTo)
|
IteratorFlow::localFlowStep(nodeFrom, nodeTo)
|
||||||
or
|
or
|
||||||
// Operand -> Instruction flow
|
// Operand -> Instruction flow
|
||||||
@@ -2614,6 +2227,22 @@ class ContentSet instanceof Content {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate guardControlsPhiInput(
|
||||||
|
IRGuardCondition g, boolean branch, Ssa::Definition def, IRBlock input, Ssa::PhiNode phi
|
||||||
|
) {
|
||||||
|
phi.hasInputFromBlock(def, _, _, _, input) and
|
||||||
|
(
|
||||||
|
g.controls(input, branch)
|
||||||
|
or
|
||||||
|
exists(EdgeKind kind |
|
||||||
|
g.getBlock() = input and
|
||||||
|
kind = getConditionalEdge(branch) and
|
||||||
|
input.getSuccessor(kind) = phi.getBasicBlock()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the guard `g` validates the expression `e` upon evaluating to `branch`.
|
* Holds if the guard `g` validates the expression `e` upon evaluating to `branch`.
|
||||||
*
|
*
|
||||||
@@ -2662,13 +2291,21 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
|
|||||||
*
|
*
|
||||||
* NOTE: If an indirect expression is tracked, use `getAnIndirectBarrierNode` instead.
|
* NOTE: If an indirect expression is tracked, use `getAnIndirectBarrierNode` instead.
|
||||||
*/
|
*/
|
||||||
ExprNode getABarrierNode() {
|
Node getABarrierNode() {
|
||||||
exists(IRGuardCondition g, Expr e, ValueNumber value, boolean edge |
|
exists(IRGuardCondition g, Expr e, ValueNumber value, boolean edge |
|
||||||
e = value.getAnInstruction().getConvertedResultExpression() and
|
e = value.getAnInstruction().getConvertedResultExpression() and
|
||||||
result.getConvertedExpr() = e and
|
result.asConvertedExpr() = e and
|
||||||
guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and
|
guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and
|
||||||
g.controls(result.getBasicBlock(), edge)
|
g.controls(result.getBasicBlock(), edge)
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
exists(
|
||||||
|
IRGuardCondition g, boolean branch, Ssa::DefinitionExt def, IRBlock input, Ssa::PhiNode phi
|
||||||
|
|
|
||||||
|
guardChecks(g, def.getARead().asOperand().getDef().getConvertedResultExpression(), branch) and
|
||||||
|
guardControlsPhiInput(g, branch, def, input, phi) and
|
||||||
|
result = TSsaPhiInputNode(phi, input)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2704,7 +2341,7 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
|
|||||||
*
|
*
|
||||||
* NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead.
|
* NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead.
|
||||||
*/
|
*/
|
||||||
IndirectExprNode getAnIndirectBarrierNode() { result = getAnIndirectBarrierNode(_) }
|
Node getAnIndirectBarrierNode() { result = getAnIndirectBarrierNode(_) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets an indirect expression node with indirection index `indirectionIndex` that is
|
* Gets an indirect expression node with indirection index `indirectionIndex` that is
|
||||||
@@ -2740,13 +2377,23 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
|
|||||||
*
|
*
|
||||||
* NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead.
|
* NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead.
|
||||||
*/
|
*/
|
||||||
IndirectExprNode getAnIndirectBarrierNode(int indirectionIndex) {
|
Node getAnIndirectBarrierNode(int indirectionIndex) {
|
||||||
exists(IRGuardCondition g, Expr e, ValueNumber value, boolean edge |
|
exists(IRGuardCondition g, Expr e, ValueNumber value, boolean edge |
|
||||||
e = value.getAnInstruction().getConvertedResultExpression() and
|
e = value.getAnInstruction().getConvertedResultExpression() and
|
||||||
result.getConvertedExpr(indirectionIndex) = e and
|
result.asIndirectConvertedExpr(indirectionIndex) = e and
|
||||||
guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and
|
guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and
|
||||||
g.controls(result.getBasicBlock(), edge)
|
g.controls(result.getBasicBlock(), edge)
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
exists(
|
||||||
|
IRGuardCondition g, boolean branch, Ssa::DefinitionExt def, IRBlock input, Ssa::PhiNode phi
|
||||||
|
|
|
||||||
|
guardChecks(g,
|
||||||
|
def.getARead().asIndirectOperand(indirectionIndex).getDef().getConvertedResultExpression(),
|
||||||
|
branch) and
|
||||||
|
guardControlsPhiInput(g, branch, def, input, phi) and
|
||||||
|
result = TSsaPhiInputNode(phi, input)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2755,6 +2402,14 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
|
|||||||
*/
|
*/
|
||||||
signature predicate instructionGuardChecksSig(IRGuardCondition g, Instruction instr, boolean branch);
|
signature predicate instructionGuardChecksSig(IRGuardCondition g, Instruction instr, boolean branch);
|
||||||
|
|
||||||
|
private EdgeKind getConditionalEdge(boolean branch) {
|
||||||
|
branch = true and
|
||||||
|
result instanceof TrueEdge
|
||||||
|
or
|
||||||
|
branch = false and
|
||||||
|
result instanceof FalseEdge
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a set of barrier nodes for a guard that validates an instruction.
|
* Provides a set of barrier nodes for a guard that validates an instruction.
|
||||||
*
|
*
|
||||||
@@ -2763,12 +2418,20 @@ signature predicate instructionGuardChecksSig(IRGuardCondition g, Instruction in
|
|||||||
*/
|
*/
|
||||||
module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardChecks> {
|
module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardChecks> {
|
||||||
/** Gets a node that is safely guarded by the given guard check. */
|
/** Gets a node that is safely guarded by the given guard check. */
|
||||||
ExprNode getABarrierNode() {
|
Node getABarrierNode() {
|
||||||
exists(IRGuardCondition g, ValueNumber value, boolean edge, Operand use |
|
exists(IRGuardCondition g, ValueNumber value, boolean edge, Operand use |
|
||||||
instructionGuardChecks(g, value.getAnInstruction(), edge) and
|
instructionGuardChecks(g, value.getAnInstruction(), edge) and
|
||||||
use = value.getAnInstruction().getAUse() and
|
use = value.getAnInstruction().getAUse() and
|
||||||
result.asOperand() = use and
|
result.asOperand() = use and
|
||||||
g.controls(use.getDef().getBlock(), edge)
|
g.controls(result.getBasicBlock(), edge)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
exists(
|
||||||
|
IRGuardCondition g, boolean branch, Ssa::DefinitionExt def, IRBlock input, Ssa::PhiNode phi
|
||||||
|
|
|
||||||
|
instructionGuardChecks(g, def.getARead().asOperand().getDef(), branch) and
|
||||||
|
guardControlsPhiInput(g, branch, def, input, phi) and
|
||||||
|
result = TSsaPhiInputNode(phi, input)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
479
cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ExprNodes.qll
Normal file
479
cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ExprNodes.qll
Normal file
@@ -0,0 +1,479 @@
|
|||||||
|
/**
|
||||||
|
* 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 `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`. */
|
||||||
|
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
|
||||||
@@ -657,19 +657,9 @@ class GlobalDefImpl extends DefImpl, TGlobalDefImpl {
|
|||||||
*/
|
*/
|
||||||
predicate adjacentDefRead(IRBlock bb1, int i1, SourceVariable sv, IRBlock bb2, int i2) {
|
predicate adjacentDefRead(IRBlock bb1, int i1, SourceVariable sv, IRBlock bb2, int i2) {
|
||||||
adjacentDefReadExt(_, sv, bb1, i1, bb2, i2)
|
adjacentDefReadExt(_, sv, bb1, i1, bb2, i2)
|
||||||
or
|
|
||||||
exists(PhiNode phi |
|
|
||||||
lastRefRedefExt(_, sv, bb1, i1, phi) and
|
|
||||||
phi.definesAt(sv, bb2, i2, _)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate useToNode(IRBlock bb, int i, SourceVariable sv, Node nodeTo) {
|
predicate useToNode(IRBlock bb, int i, SourceVariable sv, Node nodeTo) {
|
||||||
exists(Phi phi |
|
|
||||||
phi.asPhi().definesAt(sv, bb, i, _) and
|
|
||||||
nodeTo = phi.getNode()
|
|
||||||
)
|
|
||||||
or
|
|
||||||
exists(UseImpl use |
|
exists(UseImpl use |
|
||||||
use.hasIndexInBlock(bb, i, sv) and
|
use.hasIndexInBlock(bb, i, sv) and
|
||||||
nodeTo = use.getNode()
|
nodeTo = use.getNode()
|
||||||
@@ -723,46 +713,26 @@ predicate nodeToDefOrUse(Node node, SourceVariable sv, IRBlock bb, int i, boolea
|
|||||||
*/
|
*/
|
||||||
private predicate indirectConversionFlowStep(Node nFrom, Node nTo) {
|
private predicate indirectConversionFlowStep(Node nFrom, Node nTo) {
|
||||||
not exists(SourceVariable sv, IRBlock bb2, int i2 |
|
not exists(SourceVariable sv, IRBlock bb2, int i2 |
|
||||||
nodeToDefOrUse(nTo, sv, bb2, i2, _) and
|
useToNode(bb2, i2, sv, nTo) and
|
||||||
adjacentDefRead(bb2, i2, sv, _, _)
|
adjacentDefRead(bb2, i2, sv, _, _)
|
||||||
) and
|
) and
|
||||||
(
|
exists(Operand op1, Operand op2, int indirectionIndex, Instruction instr |
|
||||||
exists(Operand op1, Operand op2, int indirectionIndex, Instruction instr |
|
hasOperandAndIndex(nFrom, op1, pragma[only_bind_into](indirectionIndex)) and
|
||||||
hasOperandAndIndex(nFrom, op1, pragma[only_bind_into](indirectionIndex)) and
|
hasOperandAndIndex(nTo, op2, pragma[only_bind_into](indirectionIndex)) and
|
||||||
hasOperandAndIndex(nTo, op2, pragma[only_bind_into](indirectionIndex)) and
|
instr = op2.getDef() and
|
||||||
instr = op2.getDef() and
|
conversionFlow(op1, instr, _, _)
|
||||||
conversionFlow(op1, instr, _, _)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
exists(Operand op1, Operand op2, int indirectionIndex, Instruction instr |
|
|
||||||
hasOperandAndIndex(nFrom, op1, pragma[only_bind_into](indirectionIndex)) and
|
|
||||||
hasOperandAndIndex(nTo, op2, indirectionIndex - 1) and
|
|
||||||
instr = op2.getDef() and
|
|
||||||
isDereference(instr, op1, _)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The reason for this predicate is a bit annoying:
|
* Holds if `node` is a phi input node that should receive flow from the
|
||||||
* We cannot mark a `PointerArithmeticInstruction` that computes an offset based on some SSA
|
* definition to (or use of) `sv` at `(bb1, i1)`.
|
||||||
* variable `x` as a use of `x` since this creates taint-flow in the following example:
|
|
||||||
* ```c
|
|
||||||
* int x = array[source]
|
|
||||||
* sink(*array)
|
|
||||||
* ```
|
|
||||||
* This is because `source` would flow from the operand of `PointerArithmeticInstruction` to the
|
|
||||||
* result of the instruction, and into the `IndirectOperand` that represents the value of `*array`.
|
|
||||||
* Then, via use-use flow, flow will arrive at `*array` in `sink(*array)`.
|
|
||||||
*
|
|
||||||
* So this predicate recurses back along conversions and `PointerArithmeticInstruction`s to find the
|
|
||||||
* first use that has provides use-use flow, and uses that target as the target of the `nodeFrom`.
|
|
||||||
*/
|
*/
|
||||||
private predicate adjustForPointerArith(PostUpdateNode pun, SourceVariable sv, IRBlock bb2, int i2) {
|
private predicate phiToNode(SsaPhiInputNode node, SourceVariable sv, IRBlock bb1, int i1) {
|
||||||
exists(IRBlock bb1, int i1, Node adjusted |
|
exists(PhiNode phi, IRBlock input |
|
||||||
indirectConversionFlowStep*(adjusted, pun.getPreUpdateNode()) and
|
phi.hasInputFromBlock(_, sv, bb1, i1, input) and
|
||||||
nodeToDefOrUse(adjusted, sv, bb1, i1, _) and
|
node.getPhiNode() = phi and
|
||||||
adjacentDefRead(bb1, i1, sv, bb2, i2)
|
node.getBlock() = input
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -777,10 +747,14 @@ private predicate adjustForPointerArith(PostUpdateNode pun, SourceVariable sv, I
|
|||||||
private predicate ssaFlowImpl(
|
private predicate ssaFlowImpl(
|
||||||
IRBlock bb1, int i1, SourceVariable sv, Node nodeFrom, Node nodeTo, boolean uncertain
|
IRBlock bb1, int i1, SourceVariable sv, Node nodeFrom, Node nodeTo, boolean uncertain
|
||||||
) {
|
) {
|
||||||
exists(IRBlock bb2, int i2 |
|
nodeToDefOrUse(nodeFrom, sv, bb1, i1, uncertain) and
|
||||||
nodeToDefOrUse(nodeFrom, sv, bb1, i1, uncertain) and
|
(
|
||||||
adjacentDefRead(bb1, i1, sv, bb2, i2) and
|
exists(IRBlock bb2, int i2 |
|
||||||
useToNode(bb2, i2, sv, nodeTo)
|
adjacentDefRead(bb1, i1, sv, bb2, i2) and
|
||||||
|
useToNode(bb2, i2, sv, nodeTo)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
phiToNode(nodeTo, sv, bb1, i1)
|
||||||
) and
|
) and
|
||||||
nodeFrom != nodeTo
|
nodeFrom != nodeTo
|
||||||
}
|
}
|
||||||
@@ -789,7 +763,7 @@ private predicate ssaFlowImpl(
|
|||||||
private Node getAPriorDefinition(DefinitionExt next) {
|
private Node getAPriorDefinition(DefinitionExt next) {
|
||||||
exists(IRBlock bb, int i, SourceVariable sv |
|
exists(IRBlock bb, int i, SourceVariable sv |
|
||||||
lastRefRedefExt(_, pragma[only_bind_into](sv), pragma[only_bind_into](bb),
|
lastRefRedefExt(_, pragma[only_bind_into](sv), pragma[only_bind_into](bb),
|
||||||
pragma[only_bind_into](i), next) and
|
pragma[only_bind_into](i), _, next) and
|
||||||
nodeToDefOrUse(result, sv, bb, i, _)
|
nodeToDefOrUse(result, sv, bb, i, _)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -896,9 +870,31 @@ private predicate isArgumentOfCallable(DataFlowCall call, Node n) {
|
|||||||
* Holds if there is use-use flow from `pun`'s pre-update node to `n`.
|
* Holds if there is use-use flow from `pun`'s pre-update node to `n`.
|
||||||
*/
|
*/
|
||||||
private predicate postUpdateNodeToFirstUse(PostUpdateNode pun, Node n) {
|
private predicate postUpdateNodeToFirstUse(PostUpdateNode pun, Node n) {
|
||||||
exists(SourceVariable sv, IRBlock bb2, int i2 |
|
// We cannot mark a `PointerArithmeticInstruction` that computes an offset
|
||||||
adjustForPointerArith(pun, sv, bb2, i2) and
|
// based on some SSA
|
||||||
useToNode(bb2, i2, sv, n)
|
// variable `x` as a use of `x` since this creates taint-flow in the
|
||||||
|
// following example:
|
||||||
|
// ```c
|
||||||
|
// int x = array[source]
|
||||||
|
// sink(*array)
|
||||||
|
// ```
|
||||||
|
// This is because `source` would flow from the operand of `PointerArithmetic`
|
||||||
|
// instruction to the result of the instruction, and into the `IndirectOperand`
|
||||||
|
// that represents the value of `*array`. Then, via use-use flow, flow will
|
||||||
|
// arrive at `*array` in `sink(*array)`.
|
||||||
|
// So this predicate recurses back along conversions and `PointerArithmetic`
|
||||||
|
// instructions to find the first use that has provides use-use flow, and
|
||||||
|
// uses that target as the target of the `nodeFrom`.
|
||||||
|
exists(Node adjusted, IRBlock bb1, int i1, SourceVariable sv |
|
||||||
|
indirectConversionFlowStep*(adjusted, pun.getPreUpdateNode()) and
|
||||||
|
useToNode(bb1, i1, sv, adjusted)
|
||||||
|
|
|
||||||
|
exists(IRBlock bb2, int i2 |
|
||||||
|
adjacentDefRead(bb1, i1, sv, bb2, i2) and
|
||||||
|
useToNode(bb2, i2, sv, n)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
phiToNode(n, sv, bb1, i1)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -953,11 +949,16 @@ predicate postUpdateFlow(PostUpdateNode pun, Node nodeTo) {
|
|||||||
|
|
||||||
/** Holds if `nodeTo` receives flow from the phi node `nodeFrom`. */
|
/** Holds if `nodeTo` receives flow from the phi node `nodeFrom`. */
|
||||||
predicate fromPhiNode(SsaPhiNode nodeFrom, Node nodeTo) {
|
predicate fromPhiNode(SsaPhiNode nodeFrom, Node nodeTo) {
|
||||||
exists(PhiNode phi, SourceVariable sv, IRBlock bb1, int i1, IRBlock bb2, int i2 |
|
exists(PhiNode phi, SourceVariable sv, IRBlock bb1, int i1 |
|
||||||
phi = nodeFrom.getPhiNode() and
|
phi = nodeFrom.getPhiNode() and
|
||||||
phi.definesAt(sv, bb1, i1, _) and
|
phi.definesAt(sv, bb1, i1, _)
|
||||||
adjacentDefRead(bb1, i1, sv, bb2, i2) and
|
|
|
||||||
useToNode(bb2, i2, sv, nodeTo)
|
exists(IRBlock bb2, int i2 |
|
||||||
|
adjacentDefRead(bb1, i1, sv, bb2, i2) and
|
||||||
|
useToNode(bb2, i2, sv, nodeTo)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
phiToNode(nodeTo, sv, bb1, i1)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1031,22 +1032,26 @@ module SsaCached {
|
|||||||
* Holds if the node at index `i` in `bb` is a last reference to SSA definition
|
* Holds if the node at index `i` in `bb` is a last reference to SSA definition
|
||||||
* `def`. The reference is last because it can reach another write `next`,
|
* `def`. The reference is last because it can reach another write `next`,
|
||||||
* without passing through another read or write.
|
* without passing through another read or write.
|
||||||
|
*
|
||||||
|
* The path from node `i` in `bb` to `next` goes via basic block `input`,
|
||||||
|
* which is either a predecessor of the basic block of `next`, or `input` =
|
||||||
|
* `bb` in case `next` occurs in basic block `bb`.
|
||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
predicate lastRefRedefExt(
|
predicate lastRefRedefExt(
|
||||||
DefinitionExt def, SourceVariable sv, IRBlock bb, int i, DefinitionExt next
|
DefinitionExt def, SourceVariable sv, IRBlock bb, int i, IRBlock input, DefinitionExt next
|
||||||
) {
|
) {
|
||||||
SsaImpl::lastRefRedefExt(def, sv, bb, i, next)
|
SsaImpl::lastRefRedefExt(def, sv, bb, i, input, next)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
Definition phiHasInputFromBlock(PhiNode phi, IRBlock bb) {
|
Definition phiHasInputFromBlockExt(PhiNode phi, IRBlock bb) {
|
||||||
SsaImpl::phiHasInputFromBlock(phi, result, bb)
|
SsaImpl::phiHasInputFromBlockExt(phi, result, bb)
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate ssaDefReachesRead(SourceVariable v, Definition def, IRBlock bb, int i) {
|
predicate ssaDefReachesReadExt(SourceVariable v, DefinitionExt def, IRBlock bb, int i) {
|
||||||
SsaImpl::ssaDefReachesRead(v, def, bb, i)
|
SsaImpl::ssaDefReachesReadExt(v, def, bb, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate variableRead = SsaInput::variableRead/4;
|
predicate variableRead = SsaInput::variableRead/4;
|
||||||
@@ -1198,11 +1203,11 @@ class Phi extends TPhi, SsaDef {
|
|||||||
|
|
||||||
final override Location getLocation() { result = phi.getBasicBlock().getLocation() }
|
final override Location getLocation() { result = phi.getBasicBlock().getLocation() }
|
||||||
|
|
||||||
override string toString() { result = "Phi" }
|
override string toString() { result = phi.toString() }
|
||||||
|
|
||||||
SsaPhiNode getNode() { result.getPhiNode() = phi }
|
SsaPhiInputNode getNode(IRBlock block) { result.getPhiNode() = phi and result.getBlock() = block }
|
||||||
|
|
||||||
predicate hasInputFromBlock(Definition inp, IRBlock bb) { inp = phiHasInputFromBlock(phi, bb) }
|
predicate hasInputFromBlock(Definition inp, IRBlock bb) { inp = phiHasInputFromBlockExt(phi, bb) }
|
||||||
|
|
||||||
final Definition getAnInput() { this.hasInputFromBlock(result, _) }
|
final Definition getAnInput() { this.hasInputFromBlock(result, _) }
|
||||||
}
|
}
|
||||||
@@ -1228,13 +1233,21 @@ class PhiNode extends SsaImpl::DefinitionExt {
|
|||||||
*/
|
*/
|
||||||
predicate isPhiRead() { this instanceof SsaImpl::PhiReadNode }
|
predicate isPhiRead() { this instanceof SsaImpl::PhiReadNode }
|
||||||
|
|
||||||
/** Holds if `inp` is an input to this phi node along the edge originating in `bb`. */
|
/**
|
||||||
predicate hasInputFromBlock(Definition inp, IRBlock bb) {
|
* Holds if the node at index `i` in `bb` is a last reference to SSA
|
||||||
inp = SsaCached::phiHasInputFromBlock(this, bb)
|
* definition `def` of `sv`. The reference is last because it can reach
|
||||||
|
* this phi node, without passing through another read or write.
|
||||||
|
*
|
||||||
|
* The path from node `i` in `bb` to this phi node goes via basic block
|
||||||
|
* `input`, which is either a predecessor of the basic block of this phi
|
||||||
|
* node, or `input` = `bb` in case this phi node occurs in basic block `bb`.
|
||||||
|
*/
|
||||||
|
predicate hasInputFromBlock(DefinitionExt def, SourceVariable sv, IRBlock bb, int i, IRBlock input) {
|
||||||
|
SsaCached::lastRefRedefExt(def, sv, bb, i, input, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets a definition that is an input to this phi node. */
|
/** Gets a definition that is an input to this phi node. */
|
||||||
final Definition getAnInput() { this.hasInputFromBlock(result, _) }
|
final Definition getAnInput() { this.hasInputFromBlock(result, _, _, _, _) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** An static single assignment (SSA) definition. */
|
/** An static single assignment (SSA) definition. */
|
||||||
@@ -1249,6 +1262,15 @@ class DefinitionExt extends SsaImpl::DefinitionExt {
|
|||||||
result = this.getAPhiInputOrPriorDefinition*() and
|
result = this.getAPhiInputOrPriorDefinition*() and
|
||||||
not result instanceof PhiNode
|
not result instanceof PhiNode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Gets a node that represents a read of this SSA definition. */
|
||||||
|
Node getARead() {
|
||||||
|
exists(SourceVariable sv, IRBlock bb, int i | SsaCached::ssaDefReachesReadExt(sv, this, bb, i) |
|
||||||
|
useToNode(bb, i, sv, result)
|
||||||
|
or
|
||||||
|
phiToNode(result, sv, bb, i)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Definition = SsaImpl::Definition;
|
class Definition = SsaImpl::Definition;
|
||||||
|
|||||||
@@ -106,8 +106,8 @@ private predicate operandEscapesDomain(Operand operand) {
|
|||||||
not isArgumentForParameter(_, operand, _) and
|
not isArgumentForParameter(_, operand, _) and
|
||||||
not isOnlyEscapesViaReturnArgument(operand) and
|
not isOnlyEscapesViaReturnArgument(operand) and
|
||||||
not operand.getUse() instanceof ReturnValueInstruction and
|
not operand.getUse() instanceof ReturnValueInstruction and
|
||||||
not operand.getUse() instanceof ReturnIndirectionInstruction and
|
not operand.getUse() instanceof ReturnIndirectionInstruction// and
|
||||||
not operand instanceof PhiInputOperand
|
// not operand instanceof PhiInputOperand
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -211,9 +211,9 @@ private predicate operandEscapesNonReturn(Operand operand) {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
isOnlyEscapesViaReturnArgument(operand) and resultEscapesNonReturn(operand.getUse())
|
isOnlyEscapesViaReturnArgument(operand) and resultEscapesNonReturn(operand.getUse())
|
||||||
or
|
// or
|
||||||
operand instanceof PhiInputOperand and
|
// operand instanceof PhiInputOperand and
|
||||||
resultEscapesNonReturn(operand.getUse())
|
// resultEscapesNonReturn(operand.getUse())
|
||||||
or
|
or
|
||||||
operandEscapesDomain(operand)
|
operandEscapesDomain(operand)
|
||||||
}
|
}
|
||||||
@@ -454,6 +454,9 @@ module Print {
|
|||||||
|
|
|
|
||||||
value, ", "
|
value, ", "
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
key = "escapes" and
|
||||||
|
result = strictconcat(string value | operandEscapesNonReturn(operand) and value = "nonreturn" | value, ", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
string getInstructionProperty(Instruction instr, string key) {
|
string getInstructionProperty(Instruction instr, string key) {
|
||||||
|
|||||||
@@ -3208,9 +3208,20 @@ class TranslatedBuiltInOperation extends TranslatedNonConstantExpr {
|
|||||||
|
|
||||||
final override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) }
|
final override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the rnk'th (0-indexed) child for which a `TranslatedElement` exists.
|
||||||
|
*
|
||||||
|
* We use this predicate to filter out `TypeName` expressions that sometimes
|
||||||
|
* occur in builtin operations since the IR doesn't have an instruction to
|
||||||
|
* represent a reference to a type.
|
||||||
|
*/
|
||||||
|
private TranslatedElement getRankedChild(int rnk) {
|
||||||
|
result = rank[rnk + 1](int id, TranslatedElement te | te = this.getChild(id) | te order by id)
|
||||||
|
}
|
||||||
|
|
||||||
final override Instruction getFirstInstruction(EdgeKind kind) {
|
final override Instruction getFirstInstruction(EdgeKind kind) {
|
||||||
if exists(this.getChild(0))
|
if exists(this.getRankedChild(0))
|
||||||
then result = this.getChild(0).getFirstInstruction(kind)
|
then result = this.getRankedChild(0).getFirstInstruction(kind)
|
||||||
else (
|
else (
|
||||||
kind instanceof GotoEdge and result = this.getInstruction(OnlyInstructionTag())
|
kind instanceof GotoEdge and result = this.getInstruction(OnlyInstructionTag())
|
||||||
)
|
)
|
||||||
@@ -3230,11 +3241,11 @@ class TranslatedBuiltInOperation extends TranslatedNonConstantExpr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
|
final override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
|
||||||
exists(int id | child = this.getChild(id) |
|
exists(int id | child = this.getRankedChild(id) |
|
||||||
result = this.getChild(id + 1).getFirstInstruction(kind)
|
result = this.getRankedChild(id + 1).getFirstInstruction(kind)
|
||||||
or
|
or
|
||||||
kind instanceof GotoEdge and
|
kind instanceof GotoEdge and
|
||||||
not exists(this.getChild(id + 1)) and
|
not exists(this.getRankedChild(id + 1)) and
|
||||||
result = this.getInstruction(OnlyInstructionTag())
|
result = this.getInstruction(OnlyInstructionTag())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -3249,7 +3260,7 @@ class TranslatedBuiltInOperation extends TranslatedNonConstantExpr {
|
|||||||
tag = OnlyInstructionTag() and
|
tag = OnlyInstructionTag() and
|
||||||
exists(int index |
|
exists(int index |
|
||||||
operandTag = positionalArgumentOperand(index) and
|
operandTag = positionalArgumentOperand(index) and
|
||||||
result = this.getChild(index).(TranslatedExpr).getResult()
|
result = this.getRankedChild(index).(TranslatedExpr).getResult()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
## 1.0.0
|
||||||
|
|
||||||
### Breaking Changes
|
### Breaking Changes
|
||||||
|
|||||||
@@ -209,6 +209,7 @@ class LoopWithAlloca extends Stmt {
|
|||||||
DataFlow::localFlow(result, DataFlow::exprNode(va)) and
|
DataFlow::localFlow(result, DataFlow::exprNode(va)) and
|
||||||
// Phi nodes will be preceded by nodes that represent actual definitions
|
// Phi nodes will be preceded by nodes that represent actual definitions
|
||||||
not result instanceof DataFlow::SsaPhiNode and
|
not result instanceof DataFlow::SsaPhiNode and
|
||||||
|
not result instanceof DataFlow::SsaPhiInputNode and
|
||||||
// A source is outside the loop if it's not inside the loop
|
// A source is outside the loop if it's not inside the loop
|
||||||
not exists(Expr e | e = getExpr(result) | this = getAnEnclosingLoopOfExpr(e))
|
not exists(Expr e | e = getExpr(result) | this = getAnEnclosingLoopOfExpr(e))
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -17,5 +17,6 @@ import cpp
|
|||||||
from FunctionCall call, Function target
|
from FunctionCall call, Function target
|
||||||
where
|
where
|
||||||
call.getTarget() = target and
|
call.getTarget() = target and
|
||||||
target.hasGlobalOrStdName("gets")
|
target.hasGlobalOrStdName("gets") and
|
||||||
|
target.getNumberOfParameters() = 1
|
||||||
select call, "'gets' does not guard against buffer overflow."
|
select call, "'gets' does not guard against buffer overflow."
|
||||||
|
|||||||
5
cpp/ql/src/change-notes/released/1.0.1.md
Normal file
5
cpp/ql/src/change-notes/released/1.0.1.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
## 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
|
name: codeql/cpp-queries
|
||||||
version: 1.0.0
|
version: 1.0.2-dev
|
||||||
groups:
|
groups:
|
||||||
- cpp
|
- cpp
|
||||||
- queries
|
- queries
|
||||||
|
|||||||
@@ -74,6 +74,8 @@ astGuardsCompare
|
|||||||
| 34 | j >= 10+0 when ... < ... is false |
|
| 34 | j >= 10+0 when ... < ... is false |
|
||||||
| 42 | 10 < j+1 when ... < ... is false |
|
| 42 | 10 < j+1 when ... < ... is false |
|
||||||
| 42 | 10 >= j+1 when ... < ... is true |
|
| 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 true |
|
||||||
| 42 | j >= 10+0 when ... < ... is false |
|
| 42 | j >= 10+0 when ... < ... is false |
|
||||||
| 44 | 0 < z+0 when ... > ... is true |
|
| 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 | 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 | 30 | 30 |
|
||||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | -1 | 31 | 32 |
|
| 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
|
irGuards
|
||||||
| test.c:7:9:7:13 | CompareGT: ... > ... |
|
| test.c:7:9:7:13 | CompareGT: ... > ... |
|
||||||
| test.c:17:8:17:12 | CompareLT: ... < ... |
|
| test.c:17:8:17:12 | CompareLT: ... < ... |
|
||||||
@@ -613,6 +617,8 @@ irGuardsCompare
|
|||||||
| 34 | j >= 10+0 when CompareLT: ... < ... is false |
|
| 34 | j >= 10+0 when CompareLT: ... < ... is false |
|
||||||
| 42 | 10 < j+1 when CompareLT: ... < ... is false |
|
| 42 | 10 < j+1 when CompareLT: ... < ... is false |
|
||||||
| 42 | 10 >= j+1 when CompareLT: ... < ... is true |
|
| 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 when CompareLT: ... < ... is true |
|
||||||
| 42 | j < 10+0 when CompareLT: ... < ... is true |
|
| 42 | j < 10+0 when CompareLT: ... < ... is true |
|
||||||
| 42 | j >= 10 when CompareLT: ... < ... is false |
|
| 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 | 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 | 30 | 30 |
|
||||||
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | == | -1 | 32 | 32 |
|
| 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:99:6:99:6 | f |
|
||||||
| test.cpp:105:6:105:14 | ... != ... |
|
| test.cpp:105:6:105:14 | ... != ... |
|
||||||
| test.cpp:111:6:111: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 |
|
| 34 | j >= 10+0 when ... < ... is false |
|
||||||
| 42 | 10 < j+1 when ... < ... is false |
|
| 42 | 10 < j+1 when ... < ... is false |
|
||||||
| 42 | 10 >= j+1 when ... < ... is true |
|
| 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 when ... < ... is true |
|
||||||
| 42 | j < 10+0 when ... < ... is true |
|
| 42 | j < 10+0 when ... < ... is true |
|
||||||
| 42 | j >= 10 when ... < ... is false |
|
| 42 | j >= 10 when ... < ... is false |
|
||||||
@@ -149,16 +151,59 @@
|
|||||||
| 111 | 0.0 == i+0 when ... != ... is false |
|
| 111 | 0.0 == i+0 when ... != ... is false |
|
||||||
| 111 | i != 0.0+0 when ... != ... is true |
|
| 111 | i != 0.0+0 when ... != ... is true |
|
||||||
| 111 | i == 0.0+0 when ... != ... is false |
|
| 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 1 is true |
|
||||||
| 126 | 1 != 0 when ... && ... is true |
|
| 126 | 1 != 0 when ... && ... is true |
|
||||||
| 126 | 1 == 0 when 1 is false |
|
| 126 | 1 == 0 when 1 is false |
|
||||||
| 126 | call to test3_condition != 0 when ... && ... is true |
|
| 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 true |
|
||||||
| 126 | call to test3_condition == 0 when call to test3_condition is false |
|
| 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 != 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 == 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 true |
|
||||||
| 137 | 0 == 0 when 0 is false |
|
| 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 true |
|
||||||
| 146 | ! ... == 0 when ! ... is false |
|
| 146 | ! ... == 0 when ! ... is false |
|
||||||
| 146 | x != 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:99:6:99:6 | f | true | 99 | 100 |
|
||||||
| test.cpp:105:6:105:14 | ... != ... | true | 105 | 106 |
|
| test.cpp:105:6:105:14 | ... != ... | true | 105 | 106 |
|
||||||
| test.cpp:111:6:111:14 | ... != ... | true | 111 | 112 |
|
| 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: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: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: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
|
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 | 10 | 11 |
|
||||||
| test.c:7:9:7:13 | ... > ... | test.c:7:9:7:9 | x | >= | 1 | 7 | 9 |
|
| 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 | 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 | 30 | 30 |
|
||||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | -1 | 31 | 32 |
|
| 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 | == | 0 | 62 | 64 |
|
||||||
| test.cpp:61:10:61:10 | i | test.cpp:61:10:61:10 | i | == | 1 | 65 | 66 |
|
| 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 |
|
| 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 | >= | 0 | 75 | 77 |
|
||||||
| test.cpp:74:10:74:10 | i | test.cpp:74:10:74:10 | i | >= | 11 | 78 | 79 |
|
| 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: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);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -75,4 +75,54 @@ void bg_indirect_expr() {
|
|||||||
if (guarded(buf)) {
|
if (guarded(buf)) {
|
||||||
sink(buf);
|
sink(buf);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_guard_and_reassign() {
|
||||||
|
int x = source();
|
||||||
|
|
||||||
|
if(!guarded(x)) {
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
|
sink(x); // $ SPURIOUS: ast
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_phi_read_guard(bool b) {
|
||||||
|
int x = source();
|
||||||
|
|
||||||
|
if(b) {
|
||||||
|
if(!guarded(x))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(!guarded(x))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sink(x); // $ SPURIOUS: ast
|
||||||
|
}
|
||||||
|
|
||||||
|
bool unsafe(int);
|
||||||
|
|
||||||
|
void test_guard_and_reassign_2() {
|
||||||
|
int x = source();
|
||||||
|
|
||||||
|
if(unsafe(x)) {
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
|
sink(x); // $ SPURIOUS: ast
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_phi_read_guard_2(bool b) {
|
||||||
|
int x = source();
|
||||||
|
|
||||||
|
if(b) {
|
||||||
|
if(unsafe(x))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(unsafe(x))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sink(x); // $ SPURIOUS: ast
|
||||||
}
|
}
|
||||||
@@ -7,10 +7,17 @@ module AstTest {
|
|||||||
* S in `if (guarded(x)) S`.
|
* S in `if (guarded(x)) S`.
|
||||||
*/
|
*/
|
||||||
// This is tested in `BarrierGuard.cpp`.
|
// This is tested in `BarrierGuard.cpp`.
|
||||||
predicate testBarrierGuard(GuardCondition g, Expr checked, boolean isTrue) {
|
predicate testBarrierGuard(GuardCondition g, Expr checked, boolean branch) {
|
||||||
g.(FunctionCall).getTarget().getName() = "guarded" and
|
exists(Call call, boolean b |
|
||||||
checked = g.(FunctionCall).getArgument(0) and
|
checked = call.getArgument(0) and
|
||||||
isTrue = true
|
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. */
|
/** Common data flow configuration to be used by tests. */
|
||||||
@@ -102,12 +109,16 @@ module IRTest {
|
|||||||
* S in `if (guarded(x)) S`.
|
* S in `if (guarded(x)) S`.
|
||||||
*/
|
*/
|
||||||
// This is tested in `BarrierGuard.cpp`.
|
// This is tested in `BarrierGuard.cpp`.
|
||||||
predicate testBarrierGuard(IRGuardCondition g, Expr checked, boolean isTrue) {
|
predicate testBarrierGuard(IRGuardCondition g, Expr checked, boolean branch) {
|
||||||
exists(Call call |
|
exists(CallInstruction call, boolean b |
|
||||||
call = g.getUnconvertedResultExpression() and
|
checked = call.getArgument(0).getUnconvertedResultExpression() and
|
||||||
call.getTarget().hasName("guarded") and
|
g.comparesEq(call.getAUse(), 0, b, any(BooleanValue bv | bv.getValue() = branch))
|
||||||
checked = call.getArgument(0) and
|
|
|
||||||
isTrue = true
|
call.getStaticCallTarget().hasName("guarded") and
|
||||||
|
b = false
|
||||||
|
or
|
||||||
|
call.getStaticCallTarget().hasName("unsafe") and
|
||||||
|
b = true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,3 +52,9 @@ void following_pointers( // $ ast-def=sourceStruct1_ptr ir-def=*cleanArray1 ir-d
|
|||||||
sink(stackArray); // $ ast,ir
|
sink(stackArray); // $ ast,ir
|
||||||
indirect_sink(stackArray); // $ ast ir=50:25 ir=50:35 ir=51:19
|
indirect_sink(stackArray); // $ ast ir=50:25 ir=50:35 ir=51:19
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_bitcast() {
|
||||||
|
unsigned long x = source();
|
||||||
|
double d = __builtin_bit_cast(double, x);
|
||||||
|
sink(d); // $ ir MISSING: ast
|
||||||
|
}
|
||||||
@@ -69,45 +69,61 @@
|
|||||||
| test.cpp:8:8:8:9 | t1 | test.cpp:9:8:9:9 | t1 |
|
| test.cpp:8:8:8:9 | t1 | test.cpp:9:8:9:9 | t1 |
|
||||||
| test.cpp:9:8:9:9 | t1 | test.cpp:11:7:11:8 | t1 |
|
| test.cpp:9:8:9:9 | t1 | test.cpp:11:7:11:8 | t1 |
|
||||||
| test.cpp:9:8:9:9 | t1 | test.cpp:11:7:11:8 | t1 |
|
| test.cpp:9:8:9:9 | t1 | test.cpp:11:7:11:8 | t1 |
|
||||||
|
| test.cpp:10:8:10:9 | t2 | test.cpp:11:7:11:8 | Phi input |
|
||||||
|
| test.cpp:10:8:10:9 | t2 | test.cpp:11:7:11:8 | Phi input |
|
||||||
| test.cpp:10:8:10:9 | t2 | test.cpp:13:10:13:11 | t2 |
|
| test.cpp:10:8:10:9 | t2 | test.cpp:13:10:13:11 | t2 |
|
||||||
| test.cpp:10:8:10:9 | t2 | test.cpp:15:3:15:6 | Phi |
|
| test.cpp:11:7:11:8 | Phi input | test.cpp:15:3:15:6 | SSA phi read(t2) |
|
||||||
| test.cpp:10:8:10:9 | t2 | test.cpp:15:3:15:6 | Phi |
|
| test.cpp:11:7:11:8 | Phi input | test.cpp:15:3:15:6 | SSA phi(*t2) |
|
||||||
| test.cpp:11:7:11:8 | t1 | test.cpp:21:8:21:9 | t1 |
|
| test.cpp:11:7:11:8 | t1 | test.cpp:21:8:21:9 | t1 |
|
||||||
| test.cpp:12:5:12:10 | ... = ... | test.cpp:13:10:13:11 | t2 |
|
| test.cpp:12:5:12:10 | ... = ... | test.cpp:13:10:13:11 | t2 |
|
||||||
| test.cpp:12:10:12:10 | 0 | test.cpp:12:5:12:10 | ... = ... |
|
| test.cpp:12:10:12:10 | 0 | test.cpp:12:5:12:10 | ... = ... |
|
||||||
| test.cpp:13:10:13:11 | t2 | test.cpp:15:3:15:6 | Phi |
|
| test.cpp:13:5:13:8 | Phi input | test.cpp:15:3:15:6 | SSA phi read(t2) |
|
||||||
| test.cpp:13:10:13:11 | t2 | test.cpp:15:3:15:6 | Phi |
|
| test.cpp:13:5:13:8 | Phi input | test.cpp:15:3:15:6 | SSA phi(*t2) |
|
||||||
| test.cpp:15:3:15:6 | Phi | test.cpp:15:8:15:9 | t2 |
|
| test.cpp:13:10:13:11 | t2 | test.cpp:13:5:13:8 | Phi input |
|
||||||
| test.cpp:15:3:15:6 | Phi | test.cpp:15:8:15:9 | t2 |
|
| test.cpp:13:10:13:11 | t2 | test.cpp:13:5:13:8 | Phi input |
|
||||||
| test.cpp:15:8:15:9 | t2 | test.cpp:23:19:23:19 | Phi |
|
| test.cpp:15:3:15:6 | SSA phi read(t2) | test.cpp:15:8:15:9 | t2 |
|
||||||
| test.cpp:15:8:15:9 | t2 | test.cpp:23:19:23:19 | Phi |
|
| test.cpp:15:3:15:6 | SSA phi(*t2) | test.cpp:15:8:15:9 | t2 |
|
||||||
|
| test.cpp:15:8:15:9 | t2 | test.cpp:23:15:23:16 | Phi input |
|
||||||
|
| test.cpp:15:8:15:9 | t2 | test.cpp:23:15:23:16 | Phi input |
|
||||||
| test.cpp:17:3:17:8 | ... = ... | test.cpp:21:8:21:9 | t1 |
|
| test.cpp:17:3:17:8 | ... = ... | test.cpp:21:8:21:9 | t1 |
|
||||||
| test.cpp:17:8:17:8 | 0 | test.cpp:17:3:17:8 | ... = ... |
|
| test.cpp:17:8:17:8 | 0 | test.cpp:17:3:17:8 | ... = ... |
|
||||||
| test.cpp:21:8:21:9 | t1 | test.cpp:23:19:23:19 | Phi |
|
| test.cpp:21:8:21:9 | t1 | test.cpp:23:15:23:16 | Phi input |
|
||||||
| test.cpp:21:8:21:9 | t1 | test.cpp:23:19:23:19 | Phi |
|
| test.cpp:21:8:21:9 | t1 | test.cpp:23:15:23:16 | Phi input |
|
||||||
| test.cpp:23:15:23:16 | 0 | test.cpp:23:15:23:16 | 0 |
|
| test.cpp:23:15:23:16 | 0 | test.cpp:23:15:23:16 | 0 |
|
||||||
| test.cpp:23:15:23:16 | 0 | test.cpp:23:19:23:19 | Phi |
|
| test.cpp:23:15:23:16 | 0 | test.cpp:23:15:23:16 | Phi input |
|
||||||
| test.cpp:23:19:23:19 | Phi | test.cpp:23:19:23:19 | i |
|
| test.cpp:23:15:23:16 | Phi input | test.cpp:23:19:23:19 | SSA phi read(*t2) |
|
||||||
| test.cpp:23:19:23:19 | Phi | test.cpp:23:19:23:19 | i |
|
| test.cpp:23:15:23:16 | Phi input | test.cpp:23:19:23:19 | SSA phi read(i) |
|
||||||
| test.cpp:23:19:23:19 | Phi | test.cpp:23:23:23:24 | t1 |
|
| test.cpp:23:15:23:16 | Phi input | test.cpp:23:19:23:19 | SSA phi read(t1) |
|
||||||
| test.cpp:23:19:23:19 | Phi | test.cpp:23:23:23:24 | t1 |
|
| test.cpp:23:15:23:16 | Phi input | test.cpp:23:19:23:19 | SSA phi read(t2) |
|
||||||
| test.cpp:23:19:23:19 | Phi | test.cpp:24:10:24:11 | t2 |
|
| test.cpp:23:15:23:16 | Phi input | test.cpp:23:19:23:19 | SSA phi(*i) |
|
||||||
| test.cpp:23:19:23:19 | Phi | test.cpp:24:10:24:11 | t2 |
|
| test.cpp:23:15:23:16 | Phi input | test.cpp:23:19:23:19 | SSA phi(*t1) |
|
||||||
|
| test.cpp:23:19:23:19 | SSA phi read(*t2) | test.cpp:24:10:24:11 | t2 |
|
||||||
|
| test.cpp:23:19:23:19 | SSA phi read(i) | test.cpp:23:19:23:19 | i |
|
||||||
|
| test.cpp:23:19:23:19 | SSA phi read(t1) | test.cpp:23:23:23:24 | t1 |
|
||||||
|
| test.cpp:23:19:23:19 | SSA phi read(t2) | test.cpp:24:10:24:11 | t2 |
|
||||||
|
| test.cpp:23:19:23:19 | SSA phi(*i) | test.cpp:23:19:23:19 | i |
|
||||||
|
| test.cpp:23:19:23:19 | SSA phi(*t1) | test.cpp:23:23:23:24 | t1 |
|
||||||
| test.cpp:23:19:23:19 | i | test.cpp:23:27:23:27 | i |
|
| test.cpp:23:19:23:19 | i | test.cpp:23:27:23:27 | i |
|
||||||
| test.cpp:23:19:23:19 | i | test.cpp:23:27:23:27 | i |
|
| test.cpp:23:19:23:19 | i | test.cpp:23:27:23:27 | i |
|
||||||
| test.cpp:23:23:23:24 | t1 | test.cpp:23:19:23:19 | Phi |
|
| test.cpp:23:23:23:24 | t1 | test.cpp:23:27:23:29 | Phi input |
|
||||||
| test.cpp:23:23:23:24 | t1 | test.cpp:26:8:26:9 | t1 |
|
| test.cpp:23:23:23:24 | t1 | test.cpp:26:8:26:9 | t1 |
|
||||||
| test.cpp:23:23:23:24 | t1 | test.cpp:26:8:26:9 | t1 |
|
| test.cpp:23:23:23:24 | t1 | test.cpp:26:8:26:9 | t1 |
|
||||||
| test.cpp:23:27:23:27 | *i | test.cpp:23:27:23:27 | *i |
|
| test.cpp:23:27:23:27 | *i | test.cpp:23:27:23:27 | *i |
|
||||||
| test.cpp:23:27:23:27 | *i | test.cpp:23:27:23:27 | i |
|
| test.cpp:23:27:23:27 | *i | test.cpp:23:27:23:27 | i |
|
||||||
| test.cpp:23:27:23:27 | i | test.cpp:23:19:23:19 | Phi |
|
|
||||||
| test.cpp:23:27:23:27 | i | test.cpp:23:27:23:27 | i |
|
| test.cpp:23:27:23:27 | i | test.cpp:23:27:23:27 | i |
|
||||||
| test.cpp:23:27:23:27 | i | test.cpp:23:27:23:27 | i |
|
| test.cpp:23:27:23:27 | i | test.cpp:23:27:23:27 | i |
|
||||||
| test.cpp:23:27:23:29 | ... ++ | test.cpp:23:19:23:19 | Phi |
|
| test.cpp:23:27:23:27 | i | test.cpp:23:27:23:29 | Phi input |
|
||||||
| test.cpp:23:27:23:29 | ... ++ | test.cpp:23:27:23:29 | ... ++ |
|
| test.cpp:23:27:23:29 | ... ++ | test.cpp:23:27:23:29 | ... ++ |
|
||||||
| test.cpp:24:5:24:11 | ... = ... | test.cpp:23:19:23:19 | Phi |
|
| test.cpp:23:27:23:29 | ... ++ | test.cpp:23:27:23:29 | Phi input |
|
||||||
| test.cpp:24:10:24:11 | t2 | test.cpp:23:19:23:19 | Phi |
|
| test.cpp:23:27:23:29 | Phi input | test.cpp:23:19:23:19 | SSA phi read(*t2) |
|
||||||
| test.cpp:24:10:24:11 | t2 | test.cpp:23:19:23:19 | Phi |
|
| test.cpp:23:27:23:29 | Phi input | test.cpp:23:19:23:19 | SSA phi read(i) |
|
||||||
|
| test.cpp:23:27:23:29 | Phi input | test.cpp:23:19:23:19 | SSA phi read(t1) |
|
||||||
|
| test.cpp:23:27:23:29 | Phi input | test.cpp:23:19:23:19 | SSA phi read(t2) |
|
||||||
|
| test.cpp:23:27:23:29 | Phi input | test.cpp:23:19:23:19 | SSA phi(*i) |
|
||||||
|
| test.cpp:23:27:23:29 | Phi input | test.cpp:23:19:23:19 | SSA phi(*t1) |
|
||||||
|
| test.cpp:24:5:24:11 | ... = ... | test.cpp:23:27:23:29 | Phi input |
|
||||||
|
| test.cpp:24:10:24:11 | t2 | test.cpp:23:27:23:29 | Phi input |
|
||||||
|
| test.cpp:24:10:24:11 | t2 | test.cpp:23:27:23:29 | Phi input |
|
||||||
| test.cpp:24:10:24:11 | t2 | test.cpp:24:5:24:11 | ... = ... |
|
| test.cpp:24:10:24:11 | t2 | test.cpp:24:5:24:11 | ... = ... |
|
||||||
| test.cpp:382:48:382:54 | source1 | test.cpp:384:16:384:23 | *& ... |
|
| test.cpp:382:48:382:54 | source1 | test.cpp:384:16:384:23 | *& ... |
|
||||||
| test.cpp:383:12:383:13 | 0 | test.cpp:383:12:383:13 | 0 |
|
| test.cpp:383:12:383:13 | 0 | test.cpp:383:12:383:13 | 0 |
|
||||||
|
|||||||
@@ -12,6 +12,10 @@ astFlow
|
|||||||
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:62:14:62:14 | x |
|
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:62:14:62:14 | 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:64:14:64:14 | x |
|
||||||
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:66:14:66: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 |
|
||||||
|
| BarrierGuard.cpp:107:11:107:16 | call to source | BarrierGuard.cpp:112:8:112:8 | x |
|
||||||
|
| BarrierGuard.cpp:116:11:116:16 | call to source | BarrierGuard.cpp:127:8:127:8 | x |
|
||||||
| acrossLinkTargets.cpp:19:27:19:32 | call to source | acrossLinkTargets.cpp:12:8:12: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:18:8:18:19 | sourceArray1 |
|
||||||
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:22:8:22:20 | & ... |
|
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:22:8:22:20 | & ... |
|
||||||
@@ -153,6 +157,7 @@ irFlow
|
|||||||
| clang.cpp:50:25:50:30 | call to source | clang.cpp:53:17:53:26 | *stackArray |
|
| clang.cpp:50:25:50:30 | call to source | clang.cpp:53:17:53:26 | *stackArray |
|
||||||
| clang.cpp:50:35:50:40 | call to source | clang.cpp:53:17:53:26 | *stackArray |
|
| clang.cpp:50:35:50:40 | call to source | clang.cpp:53:17:53:26 | *stackArray |
|
||||||
| clang.cpp:51:19:51:24 | call to source | clang.cpp:53:17:53:26 | *stackArray |
|
| clang.cpp:51:19:51:24 | call to source | clang.cpp:53:17:53:26 | *stackArray |
|
||||||
|
| clang.cpp:57:21:57:28 | call to source | clang.cpp:59:8:59:8 | d |
|
||||||
| dispatch.cpp:9:37:9:42 | call to source | dispatch.cpp:35:16:35:25 | call to notSource1 |
|
| dispatch.cpp:9:37:9:42 | call to source | dispatch.cpp:35:16:35:25 | call to notSource1 |
|
||||||
| dispatch.cpp:9:37:9:42 | call to source | dispatch.cpp:43:15:43:24 | call to notSource1 |
|
| dispatch.cpp:9:37:9:42 | call to source | dispatch.cpp:43:15:43:24 | call to notSource1 |
|
||||||
| dispatch.cpp:10:37:10:42 | call to source | dispatch.cpp:36:16:36:25 | call to notSource2 |
|
| dispatch.cpp:10:37:10:42 | call to source | dispatch.cpp:36:16:36:25 | call to notSource2 |
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
|
||||||
|
// --- stub library headers ---
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
typedef unsigned long size_t;
|
||||||
|
#define SIZE_MAX 0xFFFFFFFF
|
||||||
|
|
||||||
|
template <class T> class allocator {
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class charT> struct char_traits {
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> >
|
||||||
|
class basic_string {
|
||||||
|
public:
|
||||||
|
basic_string(const charT* s, const Allocator& a = Allocator());
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef basic_string<char> string;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace system {
|
||||||
|
class error_code {
|
||||||
|
public:
|
||||||
|
operator bool() const;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace asio {
|
||||||
|
template<typename Protocol/*, typename Executor*/>
|
||||||
|
class basic_stream_socket /*: public basic_socket<Protocol, Executor>*/ {
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace ip {
|
||||||
|
class tcp {
|
||||||
|
public:
|
||||||
|
typedef basic_stream_socket<tcp> socket;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Allocator = std::allocator<char>> class basic_streambuf {
|
||||||
|
public:
|
||||||
|
basic_streambuf(
|
||||||
|
std::size_t maximum_size = SIZE_MAX,
|
||||||
|
const Allocator &allocator = Allocator());
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef basic_streambuf<> streambuf;
|
||||||
|
|
||||||
|
class mutable_buffer {
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Elem, typename Traits, typename Allocator>
|
||||||
|
mutable_buffer buffer(std::basic_string<Elem, Traits, Allocator> & data);
|
||||||
|
|
||||||
|
template<typename SyncReadStream, typename Allocator> std::size_t read_until(
|
||||||
|
SyncReadStream &s,
|
||||||
|
asio::basic_streambuf<Allocator> &b,
|
||||||
|
char delim,
|
||||||
|
boost::system::error_code &ec);
|
||||||
|
|
||||||
|
template<typename SyncWriteStream, typename ConstBufferSequence> std::size_t write(
|
||||||
|
SyncWriteStream &s,
|
||||||
|
const ConstBufferSequence &buffers,
|
||||||
|
boost::system::error_code &ec,
|
||||||
|
int constraint = 0); // simplified
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- test code ---
|
||||||
|
|
||||||
|
char *source();
|
||||||
|
void sink(char *);
|
||||||
|
void sink(std::string);
|
||||||
|
void sink(boost::asio::streambuf);
|
||||||
|
void sink(boost::asio::mutable_buffer);
|
||||||
|
|
||||||
|
char *getenv(const char *name);
|
||||||
|
int send(int, const void*, int, int);
|
||||||
|
|
||||||
|
void test(boost::asio::ip::tcp::socket &socket) {
|
||||||
|
boost::asio::streambuf recv_buffer;
|
||||||
|
boost::system::error_code error;
|
||||||
|
|
||||||
|
boost::asio::read_until(socket, recv_buffer, '\0', error);
|
||||||
|
if (error) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
sink(recv_buffer); // $ ir
|
||||||
|
|
||||||
|
boost::asio::write(socket, recv_buffer, error); // $ ir
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
std::string send_str = std::string(source());
|
||||||
|
sink(send_str); // $ ir
|
||||||
|
|
||||||
|
boost::asio::mutable_buffer send_buffer = boost::asio::buffer(send_str);
|
||||||
|
sink(send_buffer); // $ ir
|
||||||
|
|
||||||
|
boost::asio::write(socket, send_buffer, error); // $ ir
|
||||||
|
if (error) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
testFailures
|
||||||
|
failures
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
extensions:
|
||||||
|
- addsTo:
|
||||||
|
pack: codeql/cpp-all
|
||||||
|
extensible: sourceModel
|
||||||
|
data: # namespace, type, subtypes, name, signature, ext, output, kind, provenance
|
||||||
|
- ["", "", False, "ymlSource", "", "", "ReturnValue", "local", "manual"]
|
||||||
|
- addsTo:
|
||||||
|
pack: codeql/cpp-all
|
||||||
|
extensible: sinkModel
|
||||||
|
data: # namespace, type, subtypes, name, signature, ext, input, kind, provenance
|
||||||
|
- ["", "", False, "ymlSink", "", "", "Argument[0]", "test-sink", "manual"]
|
||||||
|
- addsTo:
|
||||||
|
pack: codeql/cpp-all
|
||||||
|
extensible: summaryModel
|
||||||
|
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
|
||||||
|
- ["", "", False, "ymlStep", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
|
||||||
34
cpp/ql/test/library-tests/dataflow/external-models/flow.ql
Normal file
34
cpp/ql/test/library-tests/dataflow/external-models/flow.ql
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import TestUtilities.dataflow.FlowTestCommon
|
||||||
|
import cpp
|
||||||
|
import semmle.code.cpp.security.FlowSources
|
||||||
|
|
||||||
|
module IRTest {
|
||||||
|
private import semmle.code.cpp.ir.IR
|
||||||
|
private import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||||
|
|
||||||
|
/** Common data flow configuration to be used by tests. */
|
||||||
|
module TestAllocationConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) {
|
||||||
|
// external flow source node
|
||||||
|
sourceNode(source, _)
|
||||||
|
or
|
||||||
|
// test source function
|
||||||
|
source.asExpr().(FunctionCall).getTarget().getName() = "source"
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) {
|
||||||
|
// external flow sink node
|
||||||
|
sinkNode(sink, _)
|
||||||
|
or
|
||||||
|
// test sink function
|
||||||
|
exists(FunctionCall call |
|
||||||
|
call.getTarget().getName() = "sink" and
|
||||||
|
sink.asExpr() = call.getAnArgument()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module IRFlow = TaintTracking::Global<TestAllocationConfig>;
|
||||||
|
}
|
||||||
|
|
||||||
|
import MakeTest<IRFlowTest<IRTest::IRFlow>>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
| asio_streams.cpp:93:29:93:39 | *recv_buffer | remote-sink |
|
||||||
|
| asio_streams.cpp:103:29:103:39 | *send_buffer | remote-sink |
|
||||||
|
| test.cpp:9:10:9:10 | 0 | test-sink |
|
||||||
|
| test.cpp:11:10:11:10 | x | test-sink |
|
||||||
|
| test.cpp:15:10:15:10 | y | test-sink |
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
extensions:
|
||||||
|
- addsTo:
|
||||||
|
pack: codeql/cpp-all
|
||||||
|
extensible: sinkModel
|
||||||
|
data: # namespace, type, subtypes, name, signature, ext, input, kind, provenance
|
||||||
|
- ["", "", False, "ymlSink", "", "", "Argument[0]", "test-sink", "manual"]
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import cpp
|
||||||
|
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||||
|
import semmle.code.cpp.dataflow.ExternalFlow
|
||||||
|
|
||||||
|
from DataFlow::Node node, string kind
|
||||||
|
where sinkNode(node, kind)
|
||||||
|
select node, kind
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
| asio_streams.cpp:87:34:87:44 | read_until output argument | remote |
|
||||||
|
| test.cpp:7:10:7:18 | call to ymlSource | local |
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
extensions:
|
||||||
|
- addsTo:
|
||||||
|
pack: codeql/cpp-all
|
||||||
|
extensible: sourceModel
|
||||||
|
data: # namespace, type, subtypes, name, signature, ext, output, kind, provenance
|
||||||
|
- ["", "", False, "ymlSource", "", "", "ReturnValue", "local", "manual"]
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import cpp
|
||||||
|
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||||
|
import semmle.code.cpp.dataflow.ExternalFlow
|
||||||
|
|
||||||
|
from DataFlow::Node node, string kind
|
||||||
|
where sourceNode(node, kind)
|
||||||
|
select node, kind
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer |
|
||||||
|
| test.cpp:13:18:13:18 | x | test.cpp:13:10:13:16 | call to ymlStep |
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
extensions:
|
||||||
|
- addsTo:
|
||||||
|
pack: codeql/cpp-all
|
||||||
|
extensible: summaryModel
|
||||||
|
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
|
||||||
|
- ["", "", False, "ymlStep", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import cpp
|
||||||
|
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||||
|
import semmle.code.cpp.dataflow.ExternalFlow
|
||||||
|
import semmle.code.cpp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
|
||||||
|
|
||||||
|
from DataFlow::Node node1, DataFlow::Node node2
|
||||||
|
where FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(node1, node2, _)
|
||||||
|
select node1, node2
|
||||||
16
cpp/ql/test/library-tests/dataflow/external-models/test.cpp
Normal file
16
cpp/ql/test/library-tests/dataflow/external-models/test.cpp
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
int ymlSource();
|
||||||
|
void ymlSink(int value);
|
||||||
|
int ymlStep(int value);
|
||||||
|
|
||||||
|
void test() {
|
||||||
|
int x = ymlSource();
|
||||||
|
|
||||||
|
ymlSink(0);
|
||||||
|
|
||||||
|
ymlSink(x); // $ ir
|
||||||
|
|
||||||
|
int y = ymlStep(x);
|
||||||
|
|
||||||
|
ymlSink(y); // $ ir
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
import cpp
|
||||||
|
import semmle.code.cpp.dataflow.ExternalFlow::CsvValidation
|
||||||
@@ -184,6 +184,7 @@ postWithInFlow
|
|||||||
| simple.cpp:65:7:65:7 | i [post update] | PostUpdateNode should not be the target of local flow. |
|
| simple.cpp:65:7:65:7 | i [post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
| simple.cpp:83:12:83:13 | f1 [post update] | PostUpdateNode should not be the target of local flow. |
|
| simple.cpp:83:12:83:13 | f1 [post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
| simple.cpp:92:7:92:7 | i [post update] | PostUpdateNode should not be the target of local flow. |
|
| simple.cpp:92:7:92:7 | i [post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
|
| simple.cpp:118:7:118:7 | i [post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
| struct_init.c:24:11:24:12 | ab [inner post update] | PostUpdateNode should not be the target of local flow. |
|
| struct_init.c:24:11:24:12 | ab [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
| struct_init.c:36:17:36:24 | nestedAB [inner post update] | PostUpdateNode should not be the target of local flow. |
|
| struct_init.c:36:17:36:24 | nestedAB [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
viableImplInCallContextTooLarge
|
viableImplInCallContextTooLarge
|
||||||
|
|||||||
@@ -842,6 +842,10 @@ edges
|
|||||||
| simple.cpp:108:17:108:26 | call to user_input | simple.cpp:108:17:108:26 | call to user_input | provenance | |
|
| simple.cpp:108:17:108:26 | call to user_input | simple.cpp:108:17:108:26 | call to user_input | provenance | |
|
||||||
| simple.cpp:108:17:108:26 | call to user_input | simple.cpp:109:43:109:43 | x | provenance | |
|
| simple.cpp:108:17:108:26 | call to user_input | simple.cpp:109:43:109:43 | x | provenance | |
|
||||||
| simple.cpp:109:43:109:43 | x | simple.cpp:103:24:103:24 | x | provenance | |
|
| simple.cpp:109:43:109:43 | x | simple.cpp:103:24:103:24 | x | provenance | |
|
||||||
|
| simple.cpp:118:5:118:5 | *a [post update] [i] | simple.cpp:120:8:120:8 | *a [i] | provenance | |
|
||||||
|
| simple.cpp:118:5:118:22 | ... = ... | simple.cpp:118:5:118:5 | *a [post update] [i] | provenance | |
|
||||||
|
| simple.cpp:118:11:118:20 | call to user_input | simple.cpp:118:5:118:22 | ... = ... | provenance | |
|
||||||
|
| simple.cpp:120:8:120:8 | *a [i] | simple.cpp:120:10:120:10 | i | provenance | |
|
||||||
| struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:14:24:14:25 | *ab [a] | provenance | |
|
| struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:14:24:14:25 | *ab [a] | provenance | |
|
||||||
| struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:15:8:15:9 | *ab [a] | provenance | |
|
| struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:15:8:15:9 | *ab [a] | provenance | |
|
||||||
| struct_init.c:15:8:15:9 | *ab [a] | struct_init.c:15:12:15:12 | a | provenance | |
|
| struct_init.c:15:8:15:9 | *ab [a] | struct_init.c:15:12:15:12 | a | provenance | |
|
||||||
@@ -1747,6 +1751,11 @@ nodes
|
|||||||
| simple.cpp:108:17:108:26 | call to user_input | semmle.label | call to user_input |
|
| simple.cpp:108:17:108:26 | call to user_input | semmle.label | call to user_input |
|
||||||
| simple.cpp:108:17:108:26 | call to user_input | semmle.label | call to user_input |
|
| simple.cpp:108:17:108:26 | call to user_input | semmle.label | call to user_input |
|
||||||
| simple.cpp:109:43:109:43 | x | semmle.label | x |
|
| simple.cpp:109:43:109:43 | x | semmle.label | x |
|
||||||
|
| simple.cpp:118:5:118:5 | *a [post update] [i] | semmle.label | *a [post update] [i] |
|
||||||
|
| simple.cpp:118:5:118:22 | ... = ... | semmle.label | ... = ... |
|
||||||
|
| simple.cpp:118:11:118:20 | call to user_input | semmle.label | call to user_input |
|
||||||
|
| simple.cpp:120:8:120:8 | *a [i] | semmle.label | *a [i] |
|
||||||
|
| simple.cpp:120:10:120:10 | i | semmle.label | i |
|
||||||
| struct_init.c:14:24:14:25 | *ab [a] | semmle.label | *ab [a] |
|
| struct_init.c:14:24:14:25 | *ab [a] | semmle.label | *ab [a] |
|
||||||
| struct_init.c:14:24:14:25 | *ab [a] | semmle.label | *ab [a] |
|
| struct_init.c:14:24:14:25 | *ab [a] | semmle.label | *ab [a] |
|
||||||
| struct_init.c:15:8:15:9 | *ab [a] | semmle.label | *ab [a] |
|
| struct_init.c:15:8:15:9 | *ab [a] | semmle.label | *ab [a] |
|
||||||
@@ -1957,6 +1966,7 @@ subpaths
|
|||||||
| simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input |
|
| simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input |
|
||||||
| simple.cpp:94:13:94:13 | i | simple.cpp:92:11:92:20 | call to user_input | simple.cpp:94:13:94:13 | i | i flows from $@ | simple.cpp:92:11:92:20 | call to user_input | call to user_input |
|
| simple.cpp:94:13:94:13 | i | simple.cpp:92:11:92:20 | call to user_input | simple.cpp:94:13:94:13 | i | i flows from $@ | simple.cpp:92:11:92:20 | call to user_input | call to user_input |
|
||||||
| simple.cpp:104:14:104:14 | x | simple.cpp:108:17:108:26 | call to user_input | simple.cpp:104:14:104:14 | x | x flows from $@ | simple.cpp:108:17:108:26 | call to user_input | call to user_input |
|
| simple.cpp:104:14:104:14 | x | simple.cpp:108:17:108:26 | call to user_input | simple.cpp:104:14:104:14 | x | x flows from $@ | simple.cpp:108:17:108:26 | call to user_input | call to user_input |
|
||||||
|
| simple.cpp:120:10:120:10 | i | simple.cpp:118:11:118:20 | call to user_input | simple.cpp:120:10:120:10 | i | i flows from $@ | simple.cpp:118:11:118:20 | call to user_input | call to user_input |
|
||||||
| struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input |
|
| struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input |
|
||||||
| struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input |
|
| struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input |
|
||||||
| struct_init.c:15:12:15:12 | a | struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:40:20:40:29 | call to user_input | call to user_input |
|
| struct_init.c:15:12:15:12 | a | struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:40:20:40:29 | call to user_input | call to user_input |
|
||||||
|
|||||||
@@ -289,3 +289,5 @@ WARNING: Module DataFlow has been deprecated and may be removed in future (parti
|
|||||||
| simple.cpp:83:12:83:13 | f1 | AST only |
|
| simple.cpp:83:12:83:13 | f1 | AST only |
|
||||||
| simple.cpp:92:7:92:7 | i | AST only |
|
| simple.cpp:92:7:92:7 | i | AST only |
|
||||||
| simple.cpp:94:10:94:11 | a2 | IR only |
|
| simple.cpp:94:10:94:11 | a2 | IR only |
|
||||||
|
| simple.cpp:118:7:118:7 | i | AST only |
|
||||||
|
| simple.cpp:120:8:120:8 | a | IR only |
|
||||||
|
|||||||
@@ -649,6 +649,8 @@
|
|||||||
| simple.cpp:84:14:84:20 | this |
|
| simple.cpp:84:14:84:20 | this |
|
||||||
| simple.cpp:92:5:92:5 | a |
|
| simple.cpp:92:5:92:5 | a |
|
||||||
| simple.cpp:94:10:94:11 | a2 |
|
| simple.cpp:94:10:94:11 | a2 |
|
||||||
|
| simple.cpp:118:5:118:5 | a |
|
||||||
|
| simple.cpp:120:8:120:8 | a |
|
||||||
| struct_init.c:15:8:15:9 | ab |
|
| struct_init.c:15:8:15:9 | ab |
|
||||||
| struct_init.c:15:12:15:12 | a |
|
| struct_init.c:15:12:15:12 | a |
|
||||||
| struct_init.c:16:8:16:9 | ab |
|
| struct_init.c:16:8:16:9 | ab |
|
||||||
|
|||||||
@@ -579,6 +579,8 @@ WARNING: Module DataFlow has been deprecated and may be removed in future (parti
|
|||||||
| simple.cpp:84:14:84:20 | this |
|
| simple.cpp:84:14:84:20 | this |
|
||||||
| simple.cpp:92:5:92:5 | a |
|
| simple.cpp:92:5:92:5 | a |
|
||||||
| simple.cpp:92:7:92:7 | i |
|
| simple.cpp:92:7:92:7 | i |
|
||||||
|
| simple.cpp:118:5:118:5 | a |
|
||||||
|
| simple.cpp:118:7:118:7 | i |
|
||||||
| struct_init.c:15:8:15:9 | ab |
|
| struct_init.c:15:8:15:9 | ab |
|
||||||
| struct_init.c:15:12:15:12 | a |
|
| struct_init.c:15:12:15:12 | a |
|
||||||
| struct_init.c:16:8:16:9 | ab |
|
| struct_init.c:16:8:16:9 | ab |
|
||||||
|
|||||||
@@ -731,6 +731,10 @@ edges
|
|||||||
| simple.cpp:92:5:92:22 | ... = ... | simple.cpp:92:5:92:5 | a [post update] [i] | provenance | |
|
| simple.cpp:92:5:92:22 | ... = ... | simple.cpp:92:5:92:5 | a [post update] [i] | provenance | |
|
||||||
| simple.cpp:92:11:92:20 | call to user_input | simple.cpp:92:5:92:22 | ... = ... | provenance | |
|
| simple.cpp:92:11:92:20 | call to user_input | simple.cpp:92:5:92:22 | ... = ... | provenance | |
|
||||||
| simple.cpp:94:10:94:11 | a2 [i] | simple.cpp:94:13:94:13 | i | provenance | |
|
| simple.cpp:94:10:94:11 | a2 [i] | simple.cpp:94:13:94:13 | i | provenance | |
|
||||||
|
| simple.cpp:118:5:118:5 | a [post update] [i] | simple.cpp:120:8:120:8 | a [i] | provenance | |
|
||||||
|
| simple.cpp:118:5:118:22 | ... = ... | simple.cpp:118:5:118:5 | a [post update] [i] | provenance | |
|
||||||
|
| simple.cpp:118:11:118:20 | call to user_input | simple.cpp:118:5:118:22 | ... = ... | provenance | |
|
||||||
|
| simple.cpp:120:8:120:8 | a [i] | simple.cpp:120:10:120:10 | i | provenance | |
|
||||||
| struct_init.c:14:24:14:25 | ab [a] | struct_init.c:14:24:14:25 | ab [a] | provenance | |
|
| struct_init.c:14:24:14:25 | ab [a] | struct_init.c:14:24:14:25 | ab [a] | provenance | |
|
||||||
| struct_init.c:14:24:14:25 | ab [a] | struct_init.c:15:8:15:9 | ab [a] | provenance | |
|
| struct_init.c:14:24:14:25 | ab [a] | struct_init.c:15:8:15:9 | ab [a] | provenance | |
|
||||||
| struct_init.c:15:8:15:9 | ab [a] | struct_init.c:15:12:15:12 | a | provenance | |
|
| struct_init.c:15:8:15:9 | ab [a] | struct_init.c:15:12:15:12 | a | provenance | |
|
||||||
@@ -1538,6 +1542,11 @@ nodes
|
|||||||
| simple.cpp:92:11:92:20 | call to user_input | semmle.label | call to user_input |
|
| simple.cpp:92:11:92:20 | call to user_input | semmle.label | call to user_input |
|
||||||
| simple.cpp:94:10:94:11 | a2 [i] | semmle.label | a2 [i] |
|
| simple.cpp:94:10:94:11 | a2 [i] | semmle.label | a2 [i] |
|
||||||
| simple.cpp:94:13:94:13 | i | semmle.label | i |
|
| simple.cpp:94:13:94:13 | i | semmle.label | i |
|
||||||
|
| simple.cpp:118:5:118:5 | a [post update] [i] | semmle.label | a [post update] [i] |
|
||||||
|
| simple.cpp:118:5:118:22 | ... = ... | semmle.label | ... = ... |
|
||||||
|
| simple.cpp:118:11:118:20 | call to user_input | semmle.label | call to user_input |
|
||||||
|
| simple.cpp:120:8:120:8 | a [i] | semmle.label | a [i] |
|
||||||
|
| simple.cpp:120:10:120:10 | i | semmle.label | i |
|
||||||
| struct_init.c:14:24:14:25 | ab [a] | semmle.label | ab [a] |
|
| struct_init.c:14:24:14:25 | ab [a] | semmle.label | ab [a] |
|
||||||
| struct_init.c:14:24:14:25 | ab [a] | semmle.label | ab [a] |
|
| struct_init.c:14:24:14:25 | ab [a] | semmle.label | ab [a] |
|
||||||
| struct_init.c:15:8:15:9 | ab [a] | semmle.label | ab [a] |
|
| struct_init.c:15:8:15:9 | ab [a] | semmle.label | ab [a] |
|
||||||
@@ -1751,6 +1760,7 @@ subpaths
|
|||||||
| simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input |
|
| simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input |
|
||||||
| simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input |
|
| simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input |
|
||||||
| simple.cpp:94:13:94:13 | i | simple.cpp:92:11:92:20 | call to user_input | simple.cpp:94:13:94:13 | i | i flows from $@ | simple.cpp:92:11:92:20 | call to user_input | call to user_input |
|
| simple.cpp:94:13:94:13 | i | simple.cpp:92:11:92:20 | call to user_input | simple.cpp:94:13:94:13 | i | i flows from $@ | simple.cpp:92:11:92:20 | call to user_input | call to user_input |
|
||||||
|
| simple.cpp:120:10:120:10 | i | simple.cpp:118:11:118:20 | call to user_input | simple.cpp:120:10:120:10 | i | i flows from $@ | simple.cpp:118:11:118:20 | call to user_input | call to user_input |
|
||||||
| struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input |
|
| struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input |
|
||||||
| struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input |
|
| struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input |
|
||||||
| struct_init.c:15:12:15:12 | a | struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:40:20:40:29 | call to user_input | call to user_input |
|
| struct_init.c:15:12:15:12 | a | struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:40:20:40:29 | call to user_input | call to user_input |
|
||||||
|
|||||||
@@ -111,4 +111,13 @@ namespace TestAdditionalCallTargets {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void post_update_to_phi_input(bool b)
|
||||||
|
{
|
||||||
|
A a;
|
||||||
|
if(b) {
|
||||||
|
a.i = user_input();
|
||||||
|
}
|
||||||
|
sink(a.i); // $ ast,ir
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Simple
|
} // namespace Simple
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
|
||||||
|
// --- stub library headers ---
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
typedef unsigned long size_t;
|
||||||
|
#define SIZE_MAX 0xFFFFFFFF
|
||||||
|
|
||||||
|
template <class T> class allocator {
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class charT> struct char_traits {
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> >
|
||||||
|
class basic_string {
|
||||||
|
public:
|
||||||
|
basic_string(const charT* s, const Allocator& a = Allocator());
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef basic_string<char> string;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace system {
|
||||||
|
class error_code {
|
||||||
|
public:
|
||||||
|
operator bool() const;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace asio {
|
||||||
|
template<typename Protocol/*, typename Executor*/>
|
||||||
|
class basic_stream_socket /*: public basic_socket<Protocol, Executor>*/ {
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace ip {
|
||||||
|
class tcp {
|
||||||
|
public:
|
||||||
|
typedef basic_stream_socket<tcp> socket;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Allocator = std::allocator<char>> class basic_streambuf {
|
||||||
|
public:
|
||||||
|
basic_streambuf(
|
||||||
|
std::size_t maximum_size = SIZE_MAX,
|
||||||
|
const Allocator &allocator = Allocator());
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef basic_streambuf<> streambuf;
|
||||||
|
|
||||||
|
class mutable_buffer {
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Elem, typename Traits, typename Allocator>
|
||||||
|
mutable_buffer buffer(std::basic_string<Elem, Traits, Allocator> & data);
|
||||||
|
|
||||||
|
template<typename SyncReadStream, typename Allocator> std::size_t read_until(
|
||||||
|
SyncReadStream &s,
|
||||||
|
asio::basic_streambuf<Allocator> &b,
|
||||||
|
char delim,
|
||||||
|
boost::system::error_code &ec);
|
||||||
|
|
||||||
|
template<typename SyncWriteStream, typename ConstBufferSequence> std::size_t write(
|
||||||
|
SyncWriteStream &s,
|
||||||
|
const ConstBufferSequence &buffers,
|
||||||
|
boost::system::error_code &ec,
|
||||||
|
int constraint = 0); // simplified
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- test code ---
|
||||||
|
|
||||||
|
void test(boost::asio::ip::tcp::socket &socket) {
|
||||||
|
boost::asio::streambuf recv_buffer;
|
||||||
|
boost::system::error_code error;
|
||||||
|
|
||||||
|
boost::asio::read_until(socket, recv_buffer, '\0', error); // $ remote_source
|
||||||
|
if (error) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string send_str = std::string("message");
|
||||||
|
boost::asio::mutable_buffer send_buffer = boost::asio::buffer(send_str);
|
||||||
|
boost::asio::write(socket, send_buffer, error); // $ remote_sink
|
||||||
|
if (error) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -193,10 +193,11 @@ void Escape()
|
|||||||
int passByRef3;
|
int passByRef3;
|
||||||
CallByReferenceParamEscape(ReturnReference(passByRef3));
|
CallByReferenceParamEscape(ReturnReference(passByRef3));
|
||||||
|
|
||||||
int no_ssa_passByPtr4;
|
int ssa_passByPtr4;
|
||||||
int no_ssa_passByPtr5;
|
int ssa_passByPtr5;
|
||||||
bool no_b2 = false;
|
bool no_b2 = false;
|
||||||
MaybeReturn(&no_ssa_passByPtr4, &no_ssa_passByPtr5, no_b2);
|
// Treated as escaped because we don't know _which_ address will be returned.
|
||||||
|
MaybeReturn(&ssa_passByPtr4, &ssa_passByPtr5, no_b2);
|
||||||
|
|
||||||
int passByRef6;
|
int passByRef6;
|
||||||
EscapeAndReturn(passByRef6);
|
EscapeAndReturn(passByRef6);
|
||||||
@@ -251,3 +252,19 @@ void Escape()
|
|||||||
CallByPointer(no_condTemp);
|
CallByPointer(no_condTemp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool getBool();
|
||||||
|
|
||||||
|
void use(int);
|
||||||
|
|
||||||
|
void test_while() {
|
||||||
|
int r;
|
||||||
|
int *no_rP = &r;
|
||||||
|
|
||||||
|
while(getBool()) {
|
||||||
|
int s = 0;
|
||||||
|
*no_rP = s;
|
||||||
|
no_rP = &s;
|
||||||
|
}
|
||||||
|
|
||||||
|
use(r);
|
||||||
|
}
|
||||||
|
|||||||
@@ -22734,6 +22734,25 @@ ir.cpp:
|
|||||||
# 2552| Type = [Class] ClassWithDestructor
|
# 2552| Type = [Class] ClassWithDestructor
|
||||||
# 2552| ValueCategory = xvalue
|
# 2552| ValueCategory = xvalue
|
||||||
# 2553| getStmt(1): [ReturnStmt] return ...
|
# 2553| getStmt(1): [ReturnStmt] return ...
|
||||||
|
# 2555| [TopLevelFunction] void builtin_bitcast(unsigned long)
|
||||||
|
# 2555| <params>:
|
||||||
|
# 2555| getParameter(0): [Parameter] ul
|
||||||
|
# 2555| Type = [LongType] unsigned long
|
||||||
|
# 2555| getEntryPoint(): [BlockStmt] { ... }
|
||||||
|
# 2556| getStmt(0): [DeclStmt] declaration
|
||||||
|
# 2556| getDeclarationEntry(0): [VariableDeclarationEntry] definition of d
|
||||||
|
# 2556| Type = [DoubleType] double
|
||||||
|
# 2556| getVariable().getInitializer(): [Initializer] initializer for d
|
||||||
|
# 2556| getExpr(): [BuiltInBitCast] __builtin_bit_cast
|
||||||
|
# 2556| Type = [DoubleType] double
|
||||||
|
# 2556| ValueCategory = prvalue
|
||||||
|
# 2556| getChild(0): [TypeName] double
|
||||||
|
# 2556| Type = [DoubleType] double
|
||||||
|
# 2556| ValueCategory = prvalue
|
||||||
|
# 2556| getChild(1): [VariableAccess] ul
|
||||||
|
# 2556| Type = [LongType] unsigned long
|
||||||
|
# 2556| ValueCategory = prvalue(load)
|
||||||
|
# 2557| getStmt(1): [ReturnStmt] return ...
|
||||||
perf-regression.cpp:
|
perf-regression.cpp:
|
||||||
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
|
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
|
||||||
# 4| <params>:
|
# 4| <params>:
|
||||||
|
|||||||
@@ -13430,6 +13430,32 @@ ir.cpp:
|
|||||||
# 1898| v1898_6(void) = AliasedUse : m1898_3
|
# 1898| v1898_6(void) = AliasedUse : m1898_3
|
||||||
# 1898| v1898_7(void) = ExitFunction :
|
# 1898| v1898_7(void) = ExitFunction :
|
||||||
|
|
||||||
|
# 1899| const char[17] __PRETTY_FUNCTION__
|
||||||
|
# 1899| Block 0
|
||||||
|
# 1899| v1899_1(void) = EnterFunction :
|
||||||
|
# 1899| m1899_2(unknown) = AliasedDefinition :
|
||||||
|
# 1899| r1899_3(glval<char[17]>) = VariableAddress[__PRETTY_FUNCTION__] :
|
||||||
|
# 1899| r1899_4(glval<char[17]>) = StringConstant[__PRETTY_FUNCTION__] :
|
||||||
|
# 1899| r1899_5(char[17]) = Load[?] : &:r1899_4, ~m?
|
||||||
|
# 1899| m1899_6(char[17]) = Store[__PRETTY_FUNCTION__] : &:r1899_3, r1899_5
|
||||||
|
# 1899| m1899_7(unknown) = Chi : total:m1899_2, partial:m1899_6
|
||||||
|
# 1899| v1899_8(void) = ReturnVoid :
|
||||||
|
# 1899| v1899_9(void) = AliasedUse : ~m1899_7
|
||||||
|
# 1899| v1899_10(void) = ExitFunction :
|
||||||
|
|
||||||
|
# 1900| const char[10] __func__
|
||||||
|
# 1900| Block 0
|
||||||
|
# 1900| v1900_1(void) = EnterFunction :
|
||||||
|
# 1900| m1900_2(unknown) = AliasedDefinition :
|
||||||
|
# 1900| r1900_3(glval<char[10]>) = VariableAddress[__func__] :
|
||||||
|
# 1900| r1900_4(glval<char[10]>) = StringConstant[__func__] :
|
||||||
|
# 1900| r1900_5(char[10]) = Load[?] : &:r1900_4, ~m?
|
||||||
|
# 1900| m1900_6(char[10]) = Store[__func__] : &:r1900_3, r1900_5
|
||||||
|
# 1900| m1900_7(unknown) = Chi : total:m1900_2, partial:m1900_6
|
||||||
|
# 1900| v1900_8(void) = ReturnVoid :
|
||||||
|
# 1900| v1900_9(void) = AliasedUse : ~m1900_7
|
||||||
|
# 1900| v1900_10(void) = ExitFunction :
|
||||||
|
|
||||||
# 1911| void* missing_declaration_entries::Bar1<int>::missing_type_decl_entry(missing_declaration_entries::Bar1<int>::pointer)
|
# 1911| void* missing_declaration_entries::Bar1<int>::missing_type_decl_entry(missing_declaration_entries::Bar1<int>::pointer)
|
||||||
# 1911| Block 0
|
# 1911| Block 0
|
||||||
# 1911| v1911_1(void) = EnterFunction :
|
# 1911| v1911_1(void) = EnterFunction :
|
||||||
@@ -18351,6 +18377,24 @@ ir.cpp:
|
|||||||
# 2550| Block 2
|
# 2550| Block 2
|
||||||
# 2550| v2550_10(void) = Unreached :
|
# 2550| v2550_10(void) = Unreached :
|
||||||
|
|
||||||
|
# 2555| void builtin_bitcast(unsigned long)
|
||||||
|
# 2555| Block 0
|
||||||
|
# 2555| v2555_1(void) = EnterFunction :
|
||||||
|
# 2555| m2555_2(unknown) = AliasedDefinition :
|
||||||
|
# 2555| m2555_3(unknown) = InitializeNonLocal :
|
||||||
|
# 2555| m2555_4(unknown) = Chi : total:m2555_2, partial:m2555_3
|
||||||
|
# 2555| r2555_5(glval<unsigned long>) = VariableAddress[ul] :
|
||||||
|
# 2555| m2555_6(unsigned long) = InitializeParameter[ul] : &:r2555_5
|
||||||
|
# 2556| r2556_1(glval<double>) = VariableAddress[d] :
|
||||||
|
# 2556| r2556_2(glval<unsigned long>) = VariableAddress[ul] :
|
||||||
|
# 2556| r2556_3(unsigned long) = Load[ul] : &:r2556_2, m2555_6
|
||||||
|
# 2556| r2556_4(double) = BuiltIn[__builtin_bit_cast] : 0:r2556_3
|
||||||
|
# 2556| m2556_5(double) = Store[d] : &:r2556_1, r2556_4
|
||||||
|
# 2557| v2557_1(void) = NoOp :
|
||||||
|
# 2555| v2555_7(void) = ReturnVoid :
|
||||||
|
# 2555| v2555_8(void) = AliasedUse : m2555_3
|
||||||
|
# 2555| v2555_9(void) = ExitFunction :
|
||||||
|
|
||||||
perf-regression.cpp:
|
perf-regression.cpp:
|
||||||
# 6| void Big::Big()
|
# 6| void Big::Big()
|
||||||
# 6| Block 0
|
# 6| Block 0
|
||||||
|
|||||||
@@ -2552,4 +2552,8 @@ void constexpr_inconsistency(bool b) {
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void builtin_bitcast(unsigned long ul) {
|
||||||
|
double d = __builtin_bit_cast(double, ul);
|
||||||
|
}
|
||||||
|
|
||||||
// semmle-extractor-options: -std=c++20 --clang
|
// semmle-extractor-options: -std=c++20 --clang
|
||||||
|
|||||||
@@ -12384,6 +12384,30 @@ ir.cpp:
|
|||||||
# 1898| v1898_5(void) = AliasedUse : ~m?
|
# 1898| v1898_5(void) = AliasedUse : ~m?
|
||||||
# 1898| v1898_6(void) = ExitFunction :
|
# 1898| v1898_6(void) = ExitFunction :
|
||||||
|
|
||||||
|
# 1899| const char[17] __PRETTY_FUNCTION__
|
||||||
|
# 1899| Block 0
|
||||||
|
# 1899| v1899_1(void) = EnterFunction :
|
||||||
|
# 1899| mu1899_2(unknown) = AliasedDefinition :
|
||||||
|
# 1899| r1899_3(glval<char[17]>) = VariableAddress[__PRETTY_FUNCTION__] :
|
||||||
|
# 1899| r1899_4(glval<char[17]>) = StringConstant[__PRETTY_FUNCTION__] :
|
||||||
|
# 1899| r1899_5(char[17]) = Load[?] : &:r1899_4, ~m?
|
||||||
|
# 1899| mu1899_6(char[17]) = Store[__PRETTY_FUNCTION__] : &:r1899_3, r1899_5
|
||||||
|
# 1899| v1899_7(void) = ReturnVoid :
|
||||||
|
# 1899| v1899_8(void) = AliasedUse : ~m?
|
||||||
|
# 1899| v1899_9(void) = ExitFunction :
|
||||||
|
|
||||||
|
# 1900| const char[10] __func__
|
||||||
|
# 1900| Block 0
|
||||||
|
# 1900| v1900_1(void) = EnterFunction :
|
||||||
|
# 1900| mu1900_2(unknown) = AliasedDefinition :
|
||||||
|
# 1900| r1900_3(glval<char[10]>) = VariableAddress[__func__] :
|
||||||
|
# 1900| r1900_4(glval<char[10]>) = StringConstant[__func__] :
|
||||||
|
# 1900| r1900_5(char[10]) = Load[?] : &:r1900_4, ~m?
|
||||||
|
# 1900| mu1900_6(char[10]) = Store[__func__] : &:r1900_3, r1900_5
|
||||||
|
# 1900| v1900_7(void) = ReturnVoid :
|
||||||
|
# 1900| v1900_8(void) = AliasedUse : ~m?
|
||||||
|
# 1900| v1900_9(void) = ExitFunction :
|
||||||
|
|
||||||
# 1911| void* missing_declaration_entries::Bar1<int>::missing_type_decl_entry(missing_declaration_entries::Bar1<int>::pointer)
|
# 1911| void* missing_declaration_entries::Bar1<int>::missing_type_decl_entry(missing_declaration_entries::Bar1<int>::pointer)
|
||||||
# 1911| Block 0
|
# 1911| Block 0
|
||||||
# 1911| v1911_1(void) = EnterFunction :
|
# 1911| v1911_1(void) = EnterFunction :
|
||||||
@@ -16693,6 +16717,23 @@ ir.cpp:
|
|||||||
# 2550| v2550_7(void) = AliasedUse : ~m?
|
# 2550| v2550_7(void) = AliasedUse : ~m?
|
||||||
# 2550| v2550_8(void) = ExitFunction :
|
# 2550| v2550_8(void) = ExitFunction :
|
||||||
|
|
||||||
|
# 2555| void builtin_bitcast(unsigned long)
|
||||||
|
# 2555| Block 0
|
||||||
|
# 2555| v2555_1(void) = EnterFunction :
|
||||||
|
# 2555| mu2555_2(unknown) = AliasedDefinition :
|
||||||
|
# 2555| mu2555_3(unknown) = InitializeNonLocal :
|
||||||
|
# 2555| r2555_4(glval<unsigned long>) = VariableAddress[ul] :
|
||||||
|
# 2555| mu2555_5(unsigned long) = InitializeParameter[ul] : &:r2555_4
|
||||||
|
# 2556| r2556_1(glval<double>) = VariableAddress[d] :
|
||||||
|
# 2556| r2556_2(glval<unsigned long>) = VariableAddress[ul] :
|
||||||
|
# 2556| r2556_3(unsigned long) = Load[ul] : &:r2556_2, ~m?
|
||||||
|
# 2556| r2556_4(double) = BuiltIn[__builtin_bit_cast] : 0:r2556_3
|
||||||
|
# 2556| mu2556_5(double) = Store[d] : &:r2556_1, r2556_4
|
||||||
|
# 2557| v2557_1(void) = NoOp :
|
||||||
|
# 2555| v2555_6(void) = ReturnVoid :
|
||||||
|
# 2555| v2555_7(void) = AliasedUse : ~m?
|
||||||
|
# 2555| v2555_8(void) = ExitFunction :
|
||||||
|
|
||||||
perf-regression.cpp:
|
perf-regression.cpp:
|
||||||
# 6| void Big::Big()
|
# 6| void Big::Big()
|
||||||
# 6| Block 0
|
# 6| Block 0
|
||||||
|
|||||||
@@ -39,3 +39,4 @@
|
|||||||
| variables.cpp:51:9:51:12 | town | file://:0:0:0:0 | char * | Field | | |
|
| variables.cpp:51:9:51:12 | town | file://:0:0:0:0 | char * | Field | | |
|
||||||
| variables.cpp:52:16:52:22 | country | file://:0:0:0:0 | char * | MemberVariable, StaticStorageDurationVariable | | static |
|
| variables.cpp:52:16:52:22 | country | file://:0:0:0:0 | char * | MemberVariable, StaticStorageDurationVariable | | static |
|
||||||
| variables.cpp:56:14:56:29 | externInFunction | file://:0:0:0:0 | int | GlobalLikeVariable, GlobalVariable, StaticStorageDurationVariable | | |
|
| variables.cpp:56:14:56:29 | externInFunction | file://:0:0:0:0 | int | GlobalLikeVariable, GlobalVariable, StaticStorageDurationVariable | | |
|
||||||
|
| variables.cpp:60:10:60:17 | __func__ | file://:0:0:0:0 | const char[9] | GlobalLikeVariable, StaticInitializedStaticLocalVariable | | static |
|
||||||
|
|||||||
@@ -55,3 +55,7 @@ struct address {
|
|||||||
void hasExtern() {
|
void hasExtern() {
|
||||||
extern int externInFunction;
|
extern int externInFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* isStatic() {
|
||||||
|
return __func__;
|
||||||
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ char *gets(char *s);
|
|||||||
|
|
||||||
void testGets() {
|
void testGets() {
|
||||||
char buf1[1024];
|
char buf1[1024];
|
||||||
char buf2 = malloc(1024);
|
char *buf2 = malloc(1024);
|
||||||
char *s;
|
char *s;
|
||||||
|
|
||||||
gets(buf1); // BAD: use of gets
|
gets(buf1); // BAD: use of gets
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
char *gets();
|
||||||
|
|
||||||
|
void testOtherGets() {
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
s = gets(); // GOOD: this is not the gets from stdio.h
|
||||||
|
}
|
||||||
1
csharp/.gitignore
vendored
1
csharp/.gitignore
vendored
@@ -14,5 +14,4 @@ csharp.log
|
|||||||
.vscode/launch.json
|
.vscode/launch.json
|
||||||
|
|
||||||
extractor/Semmle.Extraction.CSharp.Driver/Properties/launchSettings.json
|
extractor/Semmle.Extraction.CSharp.Driver/Properties/launchSettings.json
|
||||||
extractor-pack
|
|
||||||
paket-files/
|
paket-files/
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
load("@rules_pkg//pkg:mappings.bzl", "pkg_filegroup", "pkg_files")
|
load("@rules_pkg//pkg:mappings.bzl", "pkg_filegroup", "pkg_files")
|
||||||
load("@semmle_code//:dist.bzl", "dist")
|
load("//misc/bazel:pkg.bzl", "codeql_pack", "codeql_pkg_files_overlay")
|
||||||
load("//misc/bazel:pkg.bzl", "codeql_pkg_files_overlay")
|
|
||||||
|
|
||||||
package(default_visibility = ["//visibility:public"])
|
package(default_visibility = ["//visibility:public"])
|
||||||
|
|
||||||
@@ -59,22 +58,16 @@ codeql_pkg_files_overlay(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
dist(
|
codeql_pack(
|
||||||
name = "extractor-arch",
|
name = "csharp",
|
||||||
srcs = [":extractor-arch-overlay"],
|
|
||||||
)
|
|
||||||
|
|
||||||
dist(
|
|
||||||
name = "extractor-generic",
|
|
||||||
srcs = [
|
srcs = [
|
||||||
":dbscheme-group",
|
":dbscheme-group",
|
||||||
":extra-files",
|
":extra-files",
|
||||||
|
":extractor-arch-overlay",
|
||||||
":extractor-asp",
|
":extractor-asp",
|
||||||
"//csharp/downgrades",
|
"//csharp/downgrades",
|
||||||
"//csharp/tools",
|
"//csharp/tools",
|
||||||
],
|
],
|
||||||
prefix = "csharp",
|
|
||||||
visibility = ["//visibility:public"],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
test_suite(
|
test_suite(
|
||||||
|
|||||||
@@ -7,10 +7,11 @@
|
|||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
|
||||||
<Company>GitHub</Company>
|
<Company>GitHub</Company>
|
||||||
|
<Product>CodeQL</Product>
|
||||||
<Copyright>Copyright © $([System.DateTime]::Now.Year) $(Company)</Copyright>
|
<Copyright>Copyright © $([System.DateTime]::Now.Year) $(Company)</Copyright>
|
||||||
<Version>1.0.0.0</Version>
|
<Version>1.0.0.0</Version>
|
||||||
<AssemblyVersion>1.0.0.0</AssemblyVersion>
|
<AssemblyVersion>$(Version)</AssemblyVersion>
|
||||||
<FileVersion>1.0.0.0</FileVersion>
|
<FileVersion>$(Version)</FileVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ codeql_xunit_test(
|
|||||||
name = "Semmle.Autobuild.CSharp.Tests",
|
name = "Semmle.Autobuild.CSharp.Tests",
|
||||||
srcs = glob([
|
srcs = glob([
|
||||||
"*.cs",
|
"*.cs",
|
||||||
"Properties/*.cs",
|
|
||||||
]),
|
]),
|
||||||
deps = [
|
deps = [
|
||||||
"//csharp/autobuilder/Semmle.Autobuild.CSharp:bin/Semmle.Autobuild.CSharp",
|
"//csharp/autobuilder/Semmle.Autobuild.CSharp:bin/Semmle.Autobuild.CSharp",
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ codeql_csharp_binary(
|
|||||||
name = "Semmle.Autobuild.CSharp",
|
name = "Semmle.Autobuild.CSharp",
|
||||||
srcs = glob([
|
srcs = glob([
|
||||||
"*.cs",
|
"*.cs",
|
||||||
"Properties/*.cs",
|
|
||||||
]),
|
]),
|
||||||
visibility = ["//csharp:__subpackages__"],
|
visibility = ["//csharp:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace Semmle.Autobuild.CSharp
|
|||||||
public class CSharpAutobuildOptions : AutobuildOptionsShared
|
public class CSharpAutobuildOptions : AutobuildOptionsShared
|
||||||
{
|
{
|
||||||
private const string buildModeEnvironmentVariable = "CODEQL_EXTRACTOR_CSHARP_BUILD_MODE";
|
private const string buildModeEnvironmentVariable = "CODEQL_EXTRACTOR_CSHARP_BUILD_MODE";
|
||||||
private const string extractorOptionPrefix = "CODEQL_EXTRACTOR_CSHARP_OPTION_";
|
internal const string ExtractorOptionBuildless = "CODEQL_EXTRACTOR_CSHARP_OPTION_BUILDLESS";
|
||||||
|
|
||||||
public bool Buildless { get; }
|
public bool Buildless { get; }
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ namespace Semmle.Autobuild.CSharp
|
|||||||
public CSharpAutobuildOptions(IBuildActions actions) : base(actions)
|
public CSharpAutobuildOptions(IBuildActions actions) : base(actions)
|
||||||
{
|
{
|
||||||
Buildless =
|
Buildless =
|
||||||
actions.GetEnvironmentVariable(extractorOptionPrefix + "BUILDLESS").AsBool("buildless", false) ||
|
actions.GetEnvironmentVariable(ExtractorOptionBuildless).AsBool("buildless", false) ||
|
||||||
actions.GetEnvironmentVariable(buildModeEnvironmentVariable)?.ToLower() == "none";
|
actions.GetEnvironmentVariable(buildModeEnvironmentVariable)?.ToLower() == "none";
|
||||||
|
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ namespace Semmle.Autobuild.CSharp
|
|||||||
case CSharpBuildStrategy.Buildless:
|
case CSharpBuildStrategy.Buildless:
|
||||||
// No need to check that the extractor has been executed in buildless mode
|
// No need to check that the extractor has been executed in buildless mode
|
||||||
attempt = BuildScript.Bind(
|
attempt = BuildScript.Bind(
|
||||||
AddBuildlessStartedDiagnostic() & new StandaloneBuildRule().Analyse(this, false),
|
AddBuildlessWronglyConfiguredWarning() & AddBuildlessStartedDiagnostic() & new StandaloneBuildRule().Analyse(this, false),
|
||||||
AddBuildlessEndedDiagnostic);
|
AddBuildlessEndedDiagnostic);
|
||||||
break;
|
break;
|
||||||
case CSharpBuildStrategy.Auto:
|
case CSharpBuildStrategy.Auto:
|
||||||
@@ -81,6 +81,27 @@ namespace Semmle.Autobuild.CSharp
|
|||||||
return 1;
|
return 1;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
private BuildScript AddBuildlessWronglyConfiguredWarning()
|
||||||
|
{
|
||||||
|
return BuildScript.Create(actions =>
|
||||||
|
{
|
||||||
|
if (actions.GetEnvironmentVariable(CSharpAutobuildOptions.ExtractorOptionBuildless) is null)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddDiagnostic(new DiagnosticMessage(
|
||||||
|
Options.Language,
|
||||||
|
"buildless/use-build-mode",
|
||||||
|
"C# was extracted with the deprecated 'buildless' option, use build-mode instead",
|
||||||
|
visibility: new DiagnosticMessage.TspVisibility(statusPage: true, cliSummaryTable: true, telemetry: true),
|
||||||
|
markdownMessage: "C# was extracted with the deprecated 'buildless' option, use build-mode instead.",
|
||||||
|
severity: DiagnosticMessage.TspSeverity.Warning
|
||||||
|
));
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private BuildScript AddBuildlessStartedDiagnostic()
|
private BuildScript AddBuildlessStartedDiagnostic()
|
||||||
{
|
{
|
||||||
return BuildScript.Create(actions =>
|
return BuildScript.Create(actions =>
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ codeql_xunit_test(
|
|||||||
name = "Semmle.Autobuild.Cpp.Tests",
|
name = "Semmle.Autobuild.Cpp.Tests",
|
||||||
srcs = glob([
|
srcs = glob([
|
||||||
"*.cs",
|
"*.cs",
|
||||||
"Properties/*.cs",
|
|
||||||
]),
|
]),
|
||||||
deps = [
|
deps = [
|
||||||
"//csharp/autobuilder/Semmle.Autobuild.Cpp:bin/Semmle.Autobuild.Cpp",
|
"//csharp/autobuilder/Semmle.Autobuild.Cpp:bin/Semmle.Autobuild.Cpp",
|
||||||
|
|||||||
@@ -7,9 +7,7 @@ codeql_csharp_binary(
|
|||||||
name = "Semmle.Autobuild.Cpp",
|
name = "Semmle.Autobuild.Cpp",
|
||||||
srcs = glob([
|
srcs = glob([
|
||||||
"*.cs",
|
"*.cs",
|
||||||
"Properties/*.cs",
|
|
||||||
]),
|
]),
|
||||||
language_prefix = "cpp",
|
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
deps = [
|
deps = [
|
||||||
"//csharp/autobuilder/Semmle.Autobuild.Shared",
|
"//csharp/autobuilder/Semmle.Autobuild.Shared",
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ codeql_csharp_library(
|
|||||||
name = "Semmle.Autobuild.Shared",
|
name = "Semmle.Autobuild.Shared",
|
||||||
srcs = glob([
|
srcs = glob([
|
||||||
"*.cs",
|
"*.cs",
|
||||||
"Properties/*.cs",
|
|
||||||
]),
|
]),
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
deps = [
|
deps = [
|
||||||
|
|||||||
@@ -4,41 +4,41 @@ Amazon.Lambda.Core,10,,,,,,,,,,,10,,,,,,,,,,,
|
|||||||
Dapper,55,42,1,,,,,,,,,,55,,42,,,,,,,,1
|
Dapper,55,42,1,,,,,,,,,,55,,42,,,,,,,,1
|
||||||
ILCompiler,,,81,,,,,,,,,,,,,,,,,,,81,
|
ILCompiler,,,81,,,,,,,,,,,,,,,,,,,81,
|
||||||
ILLink.RoslynAnalyzer,,,63,,,,,,,,,,,,,,,,,,,63,
|
ILLink.RoslynAnalyzer,,,63,,,,,,,,,,,,,,,,,,,63,
|
||||||
ILLink.Shared,,,32,,,,,,,,,,,,,,,,,,,29,3
|
ILLink.Shared,,,32,,,,,,,,,,,,,,,,,,,30,2
|
||||||
ILLink.Tasks,,,3,,,,,,,,,,,,,,,,,,,3,
|
ILLink.Tasks,,,3,,,,,,,,,,,,,,,,,,,3,
|
||||||
Internal.IL,,,69,,,,,,,,,,,,,,,,,,,67,2
|
Internal.IL,,,46,,,,,,,,,,,,,,,,,,,44,2
|
||||||
Internal.Pgo,,,9,,,,,,,,,,,,,,,,,,,8,1
|
Internal.Pgo,,,9,,,,,,,,,,,,,,,,,,,8,1
|
||||||
Internal.TypeSystem,,,367,,,,,,,,,,,,,,,,,,,331,36
|
Internal.TypeSystem,,,291,,,,,,,,,,,,,,,,,,,275,16
|
||||||
JsonToItemsTaskFactory,,,5,,,,,,,,,,,,,,,,,,,5,
|
JsonToItemsTaskFactory,,,5,,,,,,,,,,,,,,,,,,,5,
|
||||||
Microsoft.Android.Build,,,14,,,,,,,,,,,,,,,,,,,14,
|
Microsoft.Android.Build,,,14,,,,,,,,,,,,,,,,,,,14,
|
||||||
Microsoft.Apple.Build,,,5,,,,,,,,,,,,,,,,,,,5,
|
Microsoft.Apple.Build,,,5,,,,,,,,,,,,,,,,,,,5,
|
||||||
Microsoft.ApplicationBlocks.Data,28,,,,,,,,,,,,28,,,,,,,,,,
|
Microsoft.ApplicationBlocks.Data,28,,,,,,,,,,,,28,,,,,,,,,,
|
||||||
Microsoft.CSharp,,,24,,,,,,,,,,,,,,,,,,,24,
|
Microsoft.CSharp,,,10,,,,,,,,,,,,,,,,,,,10,
|
||||||
Microsoft.Diagnostics.Tools.Pgo,,,13,,,,,,,,,,,,,,,,,,,13,
|
Microsoft.Diagnostics.Tools.Pgo,,,12,,,,,,,,,,,,,,,,,,,12,
|
||||||
Microsoft.EntityFrameworkCore,6,,12,,,,,,,,,,6,,,,,,,,,,12
|
Microsoft.EntityFrameworkCore,6,,12,,,,,,,,,,6,,,,,,,,,,12
|
||||||
Microsoft.Extensions.Caching.Distributed,,,9,,,,,,,,,,,,,,,,,,,9,
|
Microsoft.Extensions.Caching.Distributed,,,9,,,,,,,,,,,,,,,,,,,9,
|
||||||
Microsoft.Extensions.Caching.Memory,,,30,,,,,,,,,,,,,,,,,,,29,1
|
Microsoft.Extensions.Caching.Memory,,,30,,,,,,,,,,,,,,,,,,,29,1
|
||||||
Microsoft.Extensions.Configuration,,2,83,,,,,,,,,,,,,2,,,,,,81,2
|
Microsoft.Extensions.Configuration,,2,77,,,,,,,,,,,,,2,,,,,,76,1
|
||||||
Microsoft.Extensions.DependencyInjection,,,120,,,,,,,,,,,,,,,,,,,120,
|
Microsoft.Extensions.DependencyInjection,,,96,,,,,,,,,,,,,,,,,,,95,1
|
||||||
Microsoft.Extensions.DependencyModel,,,12,,,,,,,,,,,,,,,,,,,12,
|
Microsoft.Extensions.DependencyModel,,,9,,,,,,,,,,,,,,,,,,,9,
|
||||||
Microsoft.Extensions.Diagnostics.Metrics,,,13,,,,,,,,,,,,,,,,,,,13,
|
Microsoft.Extensions.Diagnostics.Metrics,,,15,,,,,,,,,,,,,,,,,,,15,
|
||||||
Microsoft.Extensions.FileProviders,,,15,,,,,,,,,,,,,,,,,,,15,
|
Microsoft.Extensions.FileProviders,,,15,,,,,,,,,,,,,,,,,,,15,
|
||||||
Microsoft.Extensions.FileSystemGlobbing,,,16,,,,,,,,,,,,,,,,,,,14,2
|
Microsoft.Extensions.FileSystemGlobbing,,,16,,,,,,,,,,,,,,,,,,,14,2
|
||||||
Microsoft.Extensions.Hosting,,,23,,,,,,,,,,,,,,,,,,,22,1
|
Microsoft.Extensions.Hosting,,,26,,,,,,,,,,,,,,,,,,,25,1
|
||||||
Microsoft.Extensions.Http,,,8,,,,,,,,,,,,,,,,,,,8,
|
Microsoft.Extensions.Http,,,8,,,,,,,,,,,,,,,,,,,8,
|
||||||
Microsoft.Extensions.Logging,,,60,,,,,,,,,,,,,,,,,,,59,1
|
Microsoft.Extensions.Logging,,,53,,,,,,,,,,,,,,,,,,,52,1
|
||||||
Microsoft.Extensions.Options,,,8,,,,,,,,,,,,,,,,,,,8,
|
Microsoft.Extensions.Options,,,8,,,,,,,,,,,,,,,,,,,8,
|
||||||
Microsoft.Extensions.Primitives,,,64,,,,,,,,,,,,,,,,,,,64,
|
Microsoft.Extensions.Primitives,,,64,,,,,,,,,,,,,,,,,,,64,
|
||||||
Microsoft.Interop,,,78,,,,,,,,,,,,,,,,,,,78,
|
Microsoft.Interop,,,73,,,,,,,,,,,,,,,,,,,73,
|
||||||
Microsoft.NET.Build.Tasks,,,1,,,,,,,,,,,,,,,,,,,1,
|
Microsoft.NET.Build.Tasks,,,1,,,,,,,,,,,,,,,,,,,1,
|
||||||
Microsoft.NET.WebAssembly.Webcil,,,7,,,,,,,,,,,,,,,,,,,7,
|
Microsoft.NET.WebAssembly.Webcil,,,7,,,,,,,,,,,,,,,,,,,7,
|
||||||
Microsoft.VisualBasic,,,10,,,,,,,,,,,,,,,,,,,5,5
|
Microsoft.VisualBasic,,,6,,,,,,,,,,,,,,,,,,,1,5
|
||||||
Microsoft.WebAssembly.Build.Tasks,,,3,,,,,,,,,,,,,,,,,,,3,
|
Microsoft.WebAssembly.Build.Tasks,,,3,,,,,,,,,,,,,,,,,,,3,
|
||||||
Microsoft.Win32,,4,4,,,,,,,,,,,,,,,,,,4,4,
|
Microsoft.Win32,,4,4,,,,,,,,,,,,,,,,,,4,4,
|
||||||
Mono.Linker,,,161,,,,,,,,,,,,,,,,,,,161,
|
Mono.Linker,,,158,,,,,,,,,,,,,,,,,,,158,
|
||||||
MySql.Data.MySqlClient,48,,,,,,,,,,,,48,,,,,,,,,,
|
MySql.Data.MySqlClient,48,,,,,,,,,,,,48,,,,,,,,,,
|
||||||
Newtonsoft.Json,,,91,,,,,,,,,,,,,,,,,,,73,18
|
Newtonsoft.Json,,,91,,,,,,,,,,,,,,,,,,,73,18
|
||||||
ServiceStack,194,,7,27,,,,,75,,,,92,,,,,,,,,7,
|
ServiceStack,194,,7,27,,,,,75,,,,92,,,,,,,,,7,
|
||||||
SourceGenerators,,,4,,,,,,,,,,,,,,,,,,,4,
|
SourceGenerators,,,4,,,,,,,,,,,,,,,,,,,4,
|
||||||
System,59,44,10429,,8,8,1,,,4,5,,33,2,,3,15,17,3,4,,8460,1969
|
System,49,44,9873,,3,3,1,,,4,5,,33,2,,3,15,17,3,4,,7968,1905
|
||||||
Windows.Security.Cryptography.Core,1,,,,,,,1,,,,,,,,,,,,,,,
|
Windows.Security.Cryptography.Core,1,,,,,,,1,,,,,,,,,,,,,,,
|
||||||
|
|||||||
|
@@ -8,7 +8,7 @@ C# framework & library support
|
|||||||
|
|
||||||
Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE-079` :sub:`Cross-site scripting`
|
Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE-079` :sub:`Cross-site scripting`
|
||||||
`ServiceStack <https://servicestack.net/>`_,"``ServiceStack.*``, ``ServiceStack``",,7,194,
|
`ServiceStack <https://servicestack.net/>`_,"``ServiceStack.*``, ``ServiceStack``",,7,194,
|
||||||
System,"``System.*``, ``System``",44,10429,59,9
|
System,"``System.*``, ``System``",44,9873,49,9
|
||||||
Others,"``Amazon.Lambda.APIGatewayEvents``, ``Amazon.Lambda.Core``, ``Dapper``, ``ILCompiler``, ``ILLink.RoslynAnalyzer``, ``ILLink.Shared``, ``ILLink.Tasks``, ``Internal.IL``, ``Internal.Pgo``, ``Internal.TypeSystem``, ``JsonToItemsTaskFactory``, ``Microsoft.Android.Build``, ``Microsoft.Apple.Build``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.CSharp``, ``Microsoft.Diagnostics.Tools.Pgo``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.Diagnostics.Metrics``, ``Microsoft.Extensions.FileProviders``, ``Microsoft.Extensions.FileSystemGlobbing``, ``Microsoft.Extensions.Hosting``, ``Microsoft.Extensions.Http``, ``Microsoft.Extensions.Logging``, ``Microsoft.Extensions.Options``, ``Microsoft.Extensions.Primitives``, ``Microsoft.Interop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.NET.WebAssembly.Webcil``, ``Microsoft.VisualBasic``, ``Microsoft.WebAssembly.Build.Tasks``, ``Microsoft.Win32``, ``Mono.Linker``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``, ``SourceGenerators``, ``Windows.Security.Cryptography.Core``",54,1518,148,
|
Others,"``Amazon.Lambda.APIGatewayEvents``, ``Amazon.Lambda.Core``, ``Dapper``, ``ILCompiler``, ``ILLink.RoslynAnalyzer``, ``ILLink.Shared``, ``ILLink.Tasks``, ``Internal.IL``, ``Internal.Pgo``, ``Internal.TypeSystem``, ``JsonToItemsTaskFactory``, ``Microsoft.Android.Build``, ``Microsoft.Apple.Build``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.CSharp``, ``Microsoft.Diagnostics.Tools.Pgo``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.Diagnostics.Metrics``, ``Microsoft.Extensions.FileProviders``, ``Microsoft.Extensions.FileSystemGlobbing``, ``Microsoft.Extensions.Hosting``, ``Microsoft.Extensions.Http``, ``Microsoft.Extensions.Logging``, ``Microsoft.Extensions.Options``, ``Microsoft.Extensions.Primitives``, ``Microsoft.Interop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.NET.WebAssembly.Webcil``, ``Microsoft.VisualBasic``, ``Microsoft.WebAssembly.Build.Tasks``, ``Microsoft.Win32``, ``Mono.Linker``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``, ``SourceGenerators``, ``Windows.Security.Cryptography.Core``",54,1357,148,
|
||||||
Totals,,98,11954,401,9
|
Totals,,98,11237,391,9
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ codeql_csharp_library(
|
|||||||
name = "Semmle.Extraction.CSharp.DependencyFetching",
|
name = "Semmle.Extraction.CSharp.DependencyFetching",
|
||||||
srcs = glob([
|
srcs = glob([
|
||||||
"*.cs",
|
"*.cs",
|
||||||
"Properties/*.cs",
|
|
||||||
"SourceGenerators/**/*.cs",
|
"SourceGenerators/**/*.cs",
|
||||||
]),
|
]),
|
||||||
allow_unsafe_blocks = True,
|
allow_unsafe_blocks = True,
|
||||||
|
|||||||
@@ -97,6 +97,15 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
|||||||
return envVarPath;
|
return envVarPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return DownloadNugetExe(fileProvider.SourceDir.FullName);
|
||||||
|
}
|
||||||
|
catch (Exception exc)
|
||||||
|
{
|
||||||
|
logger.LogInfo($"Download of nuget.exe failed: {exc.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
var nugetExesInRepo = fileProvider.NugetExes;
|
var nugetExesInRepo = fileProvider.NugetExes;
|
||||||
if (nugetExesInRepo.Count > 1)
|
if (nugetExesInRepo.Count > 1)
|
||||||
{
|
{
|
||||||
@@ -119,7 +128,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
|||||||
return nugetPath;
|
return nugetPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
return DownloadNugetExe(fileProvider.SourceDir.FullName);
|
throw new Exception("Could not find or download nuget.exe.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private string DownloadNugetExe(string sourceDir)
|
private string DownloadNugetExe(string sourceDir)
|
||||||
@@ -136,28 +145,20 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
|||||||
|
|
||||||
Directory.CreateDirectory(directory);
|
Directory.CreateDirectory(directory);
|
||||||
logger.LogInfo("Attempting to download nuget.exe");
|
logger.LogInfo("Attempting to download nuget.exe");
|
||||||
try
|
FileUtils.DownloadFile(FileUtils.NugetExeUrl, nuget);
|
||||||
{
|
logger.LogInfo($"Downloaded nuget.exe to {nuget}");
|
||||||
FileUtils.DownloadFile(FileUtils.NugetExeUrl, nuget);
|
return nuget;
|
||||||
logger.LogInfo($"Downloaded nuget.exe to {nuget}");
|
|
||||||
return nuget;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// Download failed.
|
|
||||||
throw new FileNotFoundException("Download of nuget.exe failed.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool RunWithMono => !Win32.IsWindows() && !string.IsNullOrEmpty(Path.GetExtension(nugetExe));
|
private bool RunWithMono => !Win32.IsWindows() && !string.IsNullOrEmpty(Path.GetExtension(nugetExe));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Restore all files in a specified package.
|
/// Restore all packages in the specified packages.config file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="package">The package file.</param>
|
/// <param name="packagesConfig">The packages.config file.</param>
|
||||||
private bool TryRestoreNugetPackage(string package)
|
private bool TryRestoreNugetPackage(string packagesConfig)
|
||||||
{
|
{
|
||||||
logger.LogInfo($"Restoring file {package}...");
|
logger.LogInfo($"Restoring file \"{packagesConfig}\"...");
|
||||||
|
|
||||||
/* Use nuget.exe to install a package.
|
/* Use nuget.exe to install a package.
|
||||||
* Note that there is a clutch of NuGet assemblies which could be used to
|
* Note that there is a clutch of NuGet assemblies which could be used to
|
||||||
@@ -169,12 +170,12 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
|||||||
if (RunWithMono)
|
if (RunWithMono)
|
||||||
{
|
{
|
||||||
exe = "mono";
|
exe = "mono";
|
||||||
args = $"{nugetExe} install -OutputDirectory {packageDirectory} {package}";
|
args = $"\"{nugetExe}\" install -OutputDirectory \"{packageDirectory}\" \"{packagesConfig}\"";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
exe = nugetExe!;
|
exe = nugetExe!;
|
||||||
args = $"install -OutputDirectory {packageDirectory} {package}";
|
args = $"install -OutputDirectory \"{packageDirectory}\" \"{packagesConfig}\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
var pi = new ProcessStartInfo(exe, args)
|
var pi = new ProcessStartInfo(exe, args)
|
||||||
@@ -195,7 +196,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logger.LogInfo($"Restored file {package}");
|
logger.LogInfo($"Restored file \"{packagesConfig}\"");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -205,7 +206,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int InstallPackages()
|
public int InstallPackages()
|
||||||
{
|
{
|
||||||
return fileProvider.PackagesConfigs.Count(package => TryRestoreNugetPackage(package));
|
return fileProvider.PackagesConfigs.Count(TryRestoreNugetPackage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool HasNoPackageSource()
|
private bool HasNoPackageSource()
|
||||||
@@ -239,7 +240,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
|||||||
if (RunWithMono)
|
if (RunWithMono)
|
||||||
{
|
{
|
||||||
exe = "mono";
|
exe = "mono";
|
||||||
args = $"{nugetExe} {command}";
|
args = $"\"{nugetExe}\" {command}";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user