mirror of
https://github.com/github/codeql.git
synced 2026-07-06 03:55:30 +02:00
Compare commits
764 Commits
codeql-cli
...
rdmarsh2/c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ddacf55a5 | ||
|
|
ba1005f875 | ||
|
|
99b21b3d79 | ||
|
|
5b51fcbd3d | ||
|
|
e13ae70eeb | ||
|
|
9f17bd0d89 | ||
|
|
86bb9c38ce | ||
|
|
dc105b404b | ||
|
|
fac28ccbe0 | ||
|
|
06afe9c0f4 | ||
|
|
2e2621adad | ||
|
|
ba1ad00d2a | ||
|
|
c7aa58252a | ||
|
|
12eab3d7f0 | ||
|
|
b0ae12850d | ||
|
|
bf6d9f8c23 | ||
|
|
c6f89aac0a | ||
|
|
3fcfd32eb1 | ||
|
|
5d97bb35d0 | ||
|
|
237b3670b4 | ||
|
|
b9a4b5ab9a | ||
|
|
4cd618f81c | ||
|
|
d9c078060a | ||
|
|
344863d896 | ||
|
|
bb73767042 | ||
|
|
5f8d8cdf40 | ||
|
|
501a9b3c6b | ||
|
|
b3e88f8234 | ||
|
|
014dcd1454 | ||
|
|
5d9b25c75d | ||
|
|
b485706fde | ||
|
|
eb7091a6d3 | ||
|
|
e4f66b8aa7 | ||
|
|
610c788e34 | ||
|
|
3af330dce9 | ||
|
|
613c13c2bf | ||
|
|
436fe65c7b | ||
|
|
1c0f2251e2 | ||
|
|
2ee8d1a9d3 | ||
|
|
06a39d2b93 | ||
|
|
7873f07fac | ||
|
|
edb29b498d | ||
|
|
31e1230c64 | ||
|
|
20ac15d549 | ||
|
|
4cd90a15d0 | ||
|
|
28d95f4d99 | ||
|
|
f1799ae3d2 | ||
|
|
28d58be1b6 | ||
|
|
cee15277ce | ||
|
|
b5f20e40fc | ||
|
|
8fe59e7ebc | ||
|
|
01f27ea331 | ||
|
|
c514c8838d | ||
|
|
940f18f5ae | ||
|
|
44501f5318 | ||
|
|
da7b7ce9f5 | ||
|
|
623d87aaca | ||
|
|
8b4cf295bc | ||
|
|
acff279e8d | ||
|
|
1d50dd54ce | ||
|
|
f570cc1916 | ||
|
|
de03fbdc49 | ||
|
|
997d9e8559 | ||
|
|
09427af2a2 | ||
|
|
ca31984040 | ||
|
|
273053c92a | ||
|
|
a412c955e7 | ||
|
|
e446eaba68 | ||
|
|
51e7b0880a | ||
|
|
761ed283b6 | ||
|
|
f728ddf823 | ||
|
|
fbc36800aa | ||
|
|
2e273f2273 | ||
|
|
30d554503a | ||
|
|
592b60d6ab | ||
|
|
160ae934af | ||
|
|
c3e21e8555 | ||
|
|
37976d56bc | ||
|
|
d2087ec748 | ||
|
|
581824a9b4 | ||
|
|
8949f71250 | ||
|
|
ad671f7fb4 | ||
|
|
00d1b8665d | ||
|
|
9b16192a7f | ||
|
|
54e85ff903 | ||
|
|
2c2e09b20b | ||
|
|
37f01fe10e | ||
|
|
9f9129d3c9 | ||
|
|
4939439982 | ||
|
|
053460ffeb | ||
|
|
3315d768f8 | ||
|
|
4c59cfb296 | ||
|
|
19469a26d7 | ||
|
|
8db454aa15 | ||
|
|
fbc0e6a1ec | ||
|
|
120fb25702 | ||
|
|
5255e16816 | ||
|
|
15c05e201d | ||
|
|
0578d3e6c4 | ||
|
|
929f1b324b | ||
|
|
7d46d15f2b | ||
|
|
136bdeb8e6 | ||
|
|
9c6bcec500 | ||
|
|
87c7dd90c0 | ||
|
|
0cf4e64655 | ||
|
|
cc44e89065 | ||
|
|
50d9a2e9cd | ||
|
|
4df2e5d937 | ||
|
|
27fcc90a97 | ||
|
|
18ed9ed2ee | ||
|
|
f0e5ef68c2 | ||
|
|
ecde0abc04 | ||
|
|
03faddd7eb | ||
|
|
8996c54b8e | ||
|
|
6e148a4c3f | ||
|
|
2fc88d5f8e | ||
|
|
910372bfb7 | ||
|
|
b83e851ac6 | ||
|
|
0ea55a9581 | ||
|
|
844e0129b6 | ||
|
|
a50234adb0 | ||
|
|
dbefe73b62 | ||
|
|
cddcea5d56 | ||
|
|
d3a8060e34 | ||
|
|
98dd2448ff | ||
|
|
5e3cb08ed2 | ||
|
|
1a7d3ee831 | ||
|
|
0a7350f3bf | ||
|
|
51ada5c2af | ||
|
|
085c12a51f | ||
|
|
afadcd9b45 | ||
|
|
d96d6721ba | ||
|
|
de8384d904 | ||
|
|
e3c1101b79 | ||
|
|
305a23b952 | ||
|
|
131d6043c1 | ||
|
|
82a5b7838c | ||
|
|
82d9180892 | ||
|
|
7704a9eeac | ||
|
|
a57981ea69 | ||
|
|
ac79866799 | ||
|
|
45e78a355f | ||
|
|
6b4cfbbacd | ||
|
|
cd10f559ca | ||
|
|
a3f27d4abe | ||
|
|
da3288fced | ||
|
|
5fb3119fea | ||
|
|
b5f9012033 | ||
|
|
f7846a598e | ||
|
|
78ba7650b3 | ||
|
|
94ec0b8a52 | ||
|
|
e88d7d5027 | ||
|
|
7e0bd5bde4 | ||
|
|
df9a9f4a56 | ||
|
|
9b257bfa9e | ||
|
|
ca299b9dc1 | ||
|
|
31e15e27fc | ||
|
|
778879908e | ||
|
|
60908de089 | ||
|
|
20625ae60d | ||
|
|
b5458b2125 | ||
|
|
9cdd8cc8f5 | ||
|
|
9395f156de | ||
|
|
684a987abf | ||
|
|
54268f4424 | ||
|
|
8899c1be04 | ||
|
|
280b101caa | ||
|
|
034d197e01 | ||
|
|
2d0a4c3d83 | ||
|
|
5a0183f1e2 | ||
|
|
151529d08f | ||
|
|
b5f3cd7a55 | ||
|
|
49a3e208d7 | ||
|
|
52171d6733 | ||
|
|
ea11f744e1 | ||
|
|
064c9a6938 | ||
|
|
678e433013 | ||
|
|
ea2777fa3e | ||
|
|
55c8863e92 | ||
|
|
3553f3d9b8 | ||
|
|
39c1832995 | ||
|
|
cc41a83a8d | ||
|
|
b471a401cc | ||
|
|
698ccd8850 | ||
|
|
5a312cd0da | ||
|
|
b1c9843d15 | ||
|
|
594fbc678e | ||
|
|
e52fa9a469 | ||
|
|
28083ebe09 | ||
|
|
a593a52b5e | ||
|
|
e89e0eb7fb | ||
|
|
0136c7542b | ||
|
|
733078183e | ||
|
|
f34e23bdba | ||
|
|
ac07544d70 | ||
|
|
efac4b197d | ||
|
|
e003e2c809 | ||
|
|
eee12264c3 | ||
|
|
c5526ffef8 | ||
|
|
fba9ffd49a | ||
|
|
eacce03073 | ||
|
|
0934c1d184 | ||
|
|
9968d5d816 | ||
|
|
115f76ac5a | ||
|
|
b88d545c49 | ||
|
|
58d3d89b2e | ||
|
|
825df218a3 | ||
|
|
084b9830bc | ||
|
|
55bd9f943f | ||
|
|
a99d7ffaaf | ||
|
|
33c48ec685 | ||
|
|
10fa687e26 | ||
|
|
eea1089ee0 | ||
|
|
60921a0355 | ||
|
|
a6ecac6e00 | ||
|
|
8d5bbc458f | ||
|
|
3e09d86a4f | ||
|
|
0ac8b7ce65 | ||
|
|
25195bb0ba | ||
|
|
422abc1a18 | ||
|
|
eadd85bce9 | ||
|
|
aa0ff2b53f | ||
|
|
ee6ac744c5 | ||
|
|
d5b414f163 | ||
|
|
cede617840 | ||
|
|
9c95dcc126 | ||
|
|
2ac5441aec | ||
|
|
1a89ddae5d | ||
|
|
ce9f69a639 | ||
|
|
831f143fe6 | ||
|
|
5e815fb359 | ||
|
|
c35fbf9abc | ||
|
|
72c204063d | ||
|
|
25098ef2d8 | ||
|
|
4c8926d880 | ||
|
|
65abb54a73 | ||
|
|
584037737e | ||
|
|
284c8dd448 | ||
|
|
3314b56ffe | ||
|
|
c904ba1d16 | ||
|
|
f00a9ac8fc | ||
|
|
f3ef8510d3 | ||
|
|
04564b4323 | ||
|
|
642c9929e6 | ||
|
|
2fd09d34de | ||
|
|
2f11f3760e | ||
|
|
11b039c1f1 | ||
|
|
31c09ba678 | ||
|
|
d86b7f6c54 | ||
|
|
7b1ef7473e | ||
|
|
049af68bc2 | ||
|
|
0aebc90b61 | ||
|
|
d209231ff9 | ||
|
|
b944005046 | ||
|
|
2adf5662a2 | ||
|
|
02c8e316d3 | ||
|
|
4a7ad84d02 | ||
|
|
e5370a0caa | ||
|
|
584a0189a8 | ||
|
|
259b942fac | ||
|
|
8d20b9cf52 | ||
|
|
3266f1f35f | ||
|
|
6ac6a81bfa | ||
|
|
678ecffea8 | ||
|
|
bcf4c57060 | ||
|
|
d052b1e3c9 | ||
|
|
1ea7caf559 | ||
|
|
e39475d778 | ||
|
|
6f4fbac412 | ||
|
|
90aa7d8be5 | ||
|
|
a0a3dfb93d | ||
|
|
3c6c09b0f8 | ||
|
|
794fd976a9 | ||
|
|
75f62098e0 | ||
|
|
631d234026 | ||
|
|
5d670c6186 | ||
|
|
812b6bddcf | ||
|
|
f0ec43b04c | ||
|
|
66459b81da | ||
|
|
99c049c09e | ||
|
|
309fecac92 | ||
|
|
6706ba6ded | ||
|
|
3b81f4860e | ||
|
|
e3f86a9eb0 | ||
|
|
e23d36909d | ||
|
|
e30a488dab | ||
|
|
e668bf631a | ||
|
|
b34cae6bdd | ||
|
|
1c08ac1d7a | ||
|
|
9b50336e47 | ||
|
|
18fb4a87af | ||
|
|
a6cee9edf9 | ||
|
|
1b29bddb73 | ||
|
|
663096fe3a | ||
|
|
62779944e8 | ||
|
|
949de2a8dd | ||
|
|
e2afc80aff | ||
|
|
45f922b3f2 | ||
|
|
6068f63e9e | ||
|
|
c86c9ec2c3 | ||
|
|
93fc952ef1 | ||
|
|
50a53008cd | ||
|
|
c3e0388a75 | ||
|
|
058541c0d6 | ||
|
|
bbb6ba088b | ||
|
|
424d909201 | ||
|
|
d2c5266139 | ||
|
|
aaf14b0184 | ||
|
|
6e5a412150 | ||
|
|
bd6d3c7347 | ||
|
|
c8afb1bb94 | ||
|
|
328e47834e | ||
|
|
d2055283de | ||
|
|
8eb5d001f7 | ||
|
|
38b4c02508 | ||
|
|
c953b05cc2 | ||
|
|
ec1cc72669 | ||
|
|
4f93f2b9ba | ||
|
|
17dd1f64ec | ||
|
|
f275885258 | ||
|
|
61a2c0dab5 | ||
|
|
e8f027dab2 | ||
|
|
2afb4abaa2 | ||
|
|
d68f817e53 | ||
|
|
26fcf6b25b | ||
|
|
e5911df697 | ||
|
|
5704995b62 | ||
|
|
72009f8614 | ||
|
|
ece37d80f0 | ||
|
|
ad1cb8f8c7 | ||
|
|
08a5b5dc73 | ||
|
|
e949458add | ||
|
|
349331d6ca | ||
|
|
a46e2b3f2f | ||
|
|
682986c0a2 | ||
|
|
9e7c0c6ab9 | ||
|
|
07e0bd3ce1 | ||
|
|
de3e1c39e4 | ||
|
|
473bc92e2d | ||
|
|
93830f43cc | ||
|
|
baa646e102 | ||
|
|
37e5f0438c | ||
|
|
fb9a34851a | ||
|
|
4bc10f9b5c | ||
|
|
8f370b2457 | ||
|
|
70ec70940a | ||
|
|
d96dca4f5e | ||
|
|
7850ab2dcc | ||
|
|
cb110ba266 | ||
|
|
f738567f96 | ||
|
|
e93ff8672c | ||
|
|
78756bdc6a | ||
|
|
3802deab70 | ||
|
|
e33ddbdcfd | ||
|
|
ed2ec1acc0 | ||
|
|
c307a12c20 | ||
|
|
d4d6657cb7 | ||
|
|
1c15fc5600 | ||
|
|
6b9f01535b | ||
|
|
077bae55fe | ||
|
|
f6eccd390e | ||
|
|
5d01653371 | ||
|
|
1eb0f6a12e | ||
|
|
c3ba632a32 | ||
|
|
bd4947fdbd | ||
|
|
6e495ba6e5 | ||
|
|
2622c78766 | ||
|
|
14d83ab1b5 | ||
|
|
8066e39d07 | ||
|
|
355c1f5959 | ||
|
|
dbbba32579 | ||
|
|
b7b80fe176 | ||
|
|
ffb65d054e | ||
|
|
2e44fba67d | ||
|
|
b9823cf335 | ||
|
|
b2e3d8bb86 | ||
|
|
6ac898bad4 | ||
|
|
0d4419dd8c | ||
|
|
5d00b871d4 | ||
|
|
2bc2649204 | ||
|
|
61db581512 | ||
|
|
c034a1e268 | ||
|
|
27f76330be | ||
|
|
857b473503 | ||
|
|
94a51142d0 | ||
|
|
abc4405221 | ||
|
|
f12c73f472 | ||
|
|
d8f7861ab1 | ||
|
|
47353f6c28 | ||
|
|
de69827711 | ||
|
|
fe5a61bdde | ||
|
|
c77b17574a | ||
|
|
08b77493d2 | ||
|
|
9ae652dd6a | ||
|
|
41bdd6d4cc | ||
|
|
7c188a6b96 | ||
|
|
7989ba3391 | ||
|
|
5afc0b0c15 | ||
|
|
bf32b5a8fd | ||
|
|
a62bb8e115 | ||
|
|
960a4e58a0 | ||
|
|
c152a27a68 | ||
|
|
4d0957711b | ||
|
|
c0a1300955 | ||
|
|
f8f21c7ee6 | ||
|
|
44e1ecdf94 | ||
|
|
979706903a | ||
|
|
1f4dad4167 | ||
|
|
f1a546c4d6 | ||
|
|
e48158b9ad | ||
|
|
f2384a6a8f | ||
|
|
025e34d8e1 | ||
|
|
ab6287aebd | ||
|
|
b7d9bf4066 | ||
|
|
3179c60a1e | ||
|
|
6bb24f9d7c | ||
|
|
3fba4a5fa7 | ||
|
|
c234bd94d1 | ||
|
|
6e289a9db3 | ||
|
|
17dfb4e7b8 | ||
|
|
c9fc43a4ba | ||
|
|
478e0bf5a3 | ||
|
|
04173b7e93 | ||
|
|
2c71c46282 | ||
|
|
e69f4cd1b3 | ||
|
|
42049b1c0e | ||
|
|
507e0aa164 | ||
|
|
1568763eec | ||
|
|
4b7f63a0f3 | ||
|
|
514f98cd44 | ||
|
|
5586c9a17e | ||
|
|
7406915616 | ||
|
|
7b33aebe1f | ||
|
|
9e0c82eabb | ||
|
|
9232b282d8 | ||
|
|
8fb57149fb | ||
|
|
f17fed7c9a | ||
|
|
818bdcf3ab | ||
|
|
9cd2ae2fd1 | ||
|
|
31aa6692cb | ||
|
|
243dda79d2 | ||
|
|
dd23d48ad2 | ||
|
|
4901deb796 | ||
|
|
0e4066b6a8 | ||
|
|
1e1e2318b7 | ||
|
|
e7c6c04076 | ||
|
|
3006fa60c6 | ||
|
|
7395587244 | ||
|
|
611a6807bc | ||
|
|
9a61f24e16 | ||
|
|
6be6d26cb5 | ||
|
|
98819f64da | ||
|
|
1f5176d623 | ||
|
|
37f6fecf51 | ||
|
|
3a373c508d | ||
|
|
b17e74dfe8 | ||
|
|
df40ccd129 | ||
|
|
232952519a | ||
|
|
fd5b8896df | ||
|
|
e4c257db74 | ||
|
|
367752222f | ||
|
|
d02ad51d74 | ||
|
|
cbb1108f6e | ||
|
|
c927ac9b33 | ||
|
|
19c2ca8d40 | ||
|
|
449e697761 | ||
|
|
9f5b215d49 | ||
|
|
2fbae81356 | ||
|
|
8e6a36256c | ||
|
|
7a47551027 | ||
|
|
aa93986d1a | ||
|
|
007d98e3b4 | ||
|
|
28e4224ab1 | ||
|
|
6e57e45309 | ||
|
|
f106e064fa | ||
|
|
14cfe2e250 | ||
|
|
3355a7a046 | ||
|
|
5bad696b41 | ||
|
|
7ef6ffbc54 | ||
|
|
ab9079a838 | ||
|
|
b3adb62adb | ||
|
|
d38d810677 | ||
|
|
ae08130451 | ||
|
|
427a607843 | ||
|
|
847934078c | ||
|
|
5e53124217 | ||
|
|
d816f7f390 | ||
|
|
07e141c5be | ||
|
|
4986cc8458 | ||
|
|
f529cc43bc | ||
|
|
29acce1e93 | ||
|
|
4c2b05ce8c | ||
|
|
b779f9f935 | ||
|
|
c010f92811 | ||
|
|
6e10fcf519 | ||
|
|
229324fde0 | ||
|
|
3714a98403 | ||
|
|
ead36822be | ||
|
|
f961540979 | ||
|
|
af0a663ee8 | ||
|
|
d1a23ad78c | ||
|
|
15df392fd8 | ||
|
|
d8dbdfcd70 | ||
|
|
8c4b98c04f | ||
|
|
475d67a4df | ||
|
|
e2374f816a | ||
|
|
54470c794d | ||
|
|
54acd0e330 | ||
|
|
fdb437552c | ||
|
|
cf39cc0909 | ||
|
|
6720dba8e7 | ||
|
|
639af0a9a3 | ||
|
|
79a4ddd2ee | ||
|
|
68d1c2d3e8 | ||
|
|
02cd7bc7d2 | ||
|
|
ffbb158570 | ||
|
|
69de832f76 | ||
|
|
9de5985218 | ||
|
|
79bae0caeb | ||
|
|
1365d0911d | ||
|
|
d06b3a17bb | ||
|
|
48e6b4c01b | ||
|
|
10463e12a7 | ||
|
|
eaf3aa7075 | ||
|
|
d4517f1266 | ||
|
|
16451654db | ||
|
|
8ba330a886 | ||
|
|
ace92d0958 | ||
|
|
9347030611 | ||
|
|
459c2a21b4 | ||
|
|
c652f3e3dd | ||
|
|
6b94cdbd8d | ||
|
|
774e379eb1 | ||
|
|
0adb588fe8 | ||
|
|
15906338dc | ||
|
|
e27d62b0b4 | ||
|
|
c40ec728c6 | ||
|
|
38c0557d90 | ||
|
|
3c41f28519 | ||
|
|
671573633b | ||
|
|
9f82088f5d | ||
|
|
1a3dc1d6eb | ||
|
|
79a716488b | ||
|
|
80a37c5863 | ||
|
|
6c4685e538 | ||
|
|
51a724315f | ||
|
|
09d249e5d8 | ||
|
|
6dc90bc46c | ||
|
|
5677e38994 | ||
|
|
3cf871e9e5 | ||
|
|
dfde5712a3 | ||
|
|
a28948e836 | ||
|
|
a3fb54c9de | ||
|
|
176009ca88 | ||
|
|
ca4ef6578d | ||
|
|
c5e46f78ec | ||
|
|
8bea2a5f6c | ||
|
|
40334a21ce | ||
|
|
b62e9dc92c | ||
|
|
ddb0846e06 | ||
|
|
0a6ccbca45 | ||
|
|
60e0f09586 | ||
|
|
cac6bd57ab | ||
|
|
3a4a3437b5 | ||
|
|
b54f037424 | ||
|
|
b9e96fb078 | ||
|
|
97681ea219 | ||
|
|
3403e2f325 | ||
|
|
5450681ade | ||
|
|
0449d914c4 | ||
|
|
4d76fd198e | ||
|
|
5c905b76b4 | ||
|
|
ebf8161f1b | ||
|
|
e1b1657cdd | ||
|
|
de142b276d | ||
|
|
af2c96f344 | ||
|
|
65643515ba | ||
|
|
3bbd333336 | ||
|
|
e6aa2de977 | ||
|
|
254c166f93 | ||
|
|
ccef2f7646 | ||
|
|
af473db067 | ||
|
|
1d56330baa | ||
|
|
451be6c32c | ||
|
|
e9b184fa4c | ||
|
|
eb9057918c | ||
|
|
0bd00ce1db | ||
|
|
b4f7e07cc1 | ||
|
|
0c58764643 | ||
|
|
d3047f6293 | ||
|
|
9ae17f93da | ||
|
|
e2882f0706 | ||
|
|
7c7c335b0e | ||
|
|
b052fbf41c | ||
|
|
f71d684a08 | ||
|
|
9ff94120d8 | ||
|
|
284d88d906 | ||
|
|
d023f840de | ||
|
|
50fb6621a9 | ||
|
|
21d0c78376 | ||
|
|
a3fc463d0a | ||
|
|
740265dc38 | ||
|
|
73df8e4c7d | ||
|
|
2a9af11727 | ||
|
|
2feb9db96c | ||
|
|
9b1842b18e | ||
|
|
160208188e | ||
|
|
77277a9e1b | ||
|
|
ad09386c5e | ||
|
|
79a8f96139 | ||
|
|
fcdba7ce57 | ||
|
|
3005b4bfcc | ||
|
|
c97001ede7 | ||
|
|
641c6b0300 | ||
|
|
82beca6787 | ||
|
|
98f49e08b6 | ||
|
|
774ae0e5da | ||
|
|
1e3306d341 | ||
|
|
41003231b0 | ||
|
|
a83bd4292a | ||
|
|
66a191e4b5 | ||
|
|
395414c3cf | ||
|
|
495576c438 | ||
|
|
2ee1979546 | ||
|
|
1dcc44ff2f | ||
|
|
ff23f8ef86 | ||
|
|
5259025c67 | ||
|
|
c89592cda7 | ||
|
|
faaf1ec30d | ||
|
|
7a406d8e41 | ||
|
|
6e6bd208b1 | ||
|
|
e9df675f88 | ||
|
|
548d7ac37d | ||
|
|
a5239bc1e8 | ||
|
|
eb6c2882f9 | ||
|
|
e7f009e879 | ||
|
|
9cb4e4a61c | ||
|
|
803e079dab | ||
|
|
a66229ee9d | ||
|
|
887f6557ed | ||
|
|
db614bda29 | ||
|
|
d16a7754e1 | ||
|
|
d7f50eafae | ||
|
|
11f45cf20c | ||
|
|
c2ee5fe258 | ||
|
|
bf24d7886a | ||
|
|
7a61f59b1e | ||
|
|
44c4b9ba5c | ||
|
|
00e290e1f1 | ||
|
|
c31995764b | ||
|
|
abad133ab5 | ||
|
|
0d83b7cbd0 | ||
|
|
da30436c44 | ||
|
|
c3adb990a3 | ||
|
|
36a713510c | ||
|
|
504160fee4 | ||
|
|
5c47ae3f98 | ||
|
|
1355931b50 | ||
|
|
ced9ee5f5d | ||
|
|
2abd1f77f4 | ||
|
|
09e4c6b66b | ||
|
|
2ca0b0c6b5 | ||
|
|
f1cc7bb60c | ||
|
|
2b51e03223 | ||
|
|
1e7e49a528 | ||
|
|
344770f06a | ||
|
|
fd67c34ee4 | ||
|
|
78cfb226a3 | ||
|
|
86000f32e7 | ||
|
|
aa13ab31e1 | ||
|
|
1fb209990e | ||
|
|
ce9baaa1f3 | ||
|
|
6f9f771f58 | ||
|
|
d42752714c | ||
|
|
cf68a11267 | ||
|
|
4d80fd0b00 | ||
|
|
7da07400ea | ||
|
|
c2b670eff8 | ||
|
|
da4da229b1 | ||
|
|
49276b1f38 | ||
|
|
0abbd50ca1 | ||
|
|
af92fc389b | ||
|
|
50b4df52f0 | ||
|
|
9d3e8ec475 | ||
|
|
4f1bc3022c | ||
|
|
76cecc170e | ||
|
|
7c4d3800b6 | ||
|
|
5c11062d21 | ||
|
|
83af49c72f | ||
|
|
e0cfbb53dc | ||
|
|
844aabe3d6 | ||
|
|
c09c38c9a8 | ||
|
|
d324969d68 | ||
|
|
457ce3d884 | ||
|
|
f81abe40c4 | ||
|
|
18b9a2fa6e | ||
|
|
95df751425 | ||
|
|
954047c6ab | ||
|
|
60795fc652 | ||
|
|
8b13adbb93 | ||
|
|
6abd4a6a29 | ||
|
|
c578505ae0 | ||
|
|
a16d5f72d1 | ||
|
|
ef09031cf9 | ||
|
|
47f26e6029 | ||
|
|
10976bbbab | ||
|
|
ea0725525b | ||
|
|
4ae218729a | ||
|
|
cc8e65f811 | ||
|
|
76b292da6a | ||
|
|
0b691dd46c | ||
|
|
09ec37943c | ||
|
|
b7e522749f | ||
|
|
2436b060f1 | ||
|
|
b5cac9285e | ||
|
|
cfacd015b9 | ||
|
|
87960b6e42 | ||
|
|
bde47836d0 | ||
|
|
a6970638cb | ||
|
|
01cec0490b | ||
|
|
595875ff98 | ||
|
|
a4262f8d91 | ||
|
|
8e52fc97fc | ||
|
|
220ff3cb2e | ||
|
|
712805f3bf | ||
|
|
592464d98b | ||
|
|
aae3e2ddde | ||
|
|
ff25451699 | ||
|
|
65b9947428 | ||
|
|
781a2a73d3 | ||
|
|
39f885413f | ||
|
|
391dd5b38d | ||
|
|
ebe48ec30a | ||
|
|
48e16e52b5 | ||
|
|
1a41d4c379 | ||
|
|
300a14c35c | ||
|
|
209a21655a | ||
|
|
c6f2f61bfb | ||
|
|
16814071df | ||
|
|
7ab8f0262c | ||
|
|
955e614563 | ||
|
|
9ecc3a2671 | ||
|
|
2e295e4a04 | ||
|
|
b5ca2c3d9d | ||
|
|
7122f29296 | ||
|
|
4c7d476280 | ||
|
|
a343ceaf8b | ||
|
|
9bc12ed8fd | ||
|
|
28ac47689f | ||
|
|
554888b884 | ||
|
|
724721c5c8 | ||
|
|
22871138c6 | ||
|
|
be37763125 | ||
|
|
bf20b7dfc5 | ||
|
|
14204be2f9 | ||
|
|
3bea7df45d | ||
|
|
2e4c2df67e | ||
|
|
13482fc97b | ||
|
|
bbc8cb32be | ||
|
|
6b0df9bdfb | ||
|
|
dbeae9aefb | ||
|
|
7fb3d81d2f | ||
|
|
3be4a86acd | ||
|
|
dc06e9df02 |
1
.github/labeler.yml
vendored
1
.github/labeler.yml
vendored
@@ -42,3 +42,4 @@ documentation:
|
|||||||
|
|
||||||
"QL-for-QL":
|
"QL-for-QL":
|
||||||
- ql/**/*
|
- ql/**/*
|
||||||
|
- .github/workflows/ql-for-ql*
|
||||||
|
|||||||
12
.github/workflows/go-tests.yml
vendored
12
.github/workflows/go-tests.yml
vendored
@@ -11,10 +11,10 @@ jobs:
|
|||||||
name: Test Linux (Ubuntu)
|
name: Test Linux (Ubuntu)
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Set up Go 1.18.1
|
- name: Set up Go 1.19
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: 1.18.1
|
go-version: 1.19
|
||||||
id: go
|
id: go
|
||||||
|
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
@@ -57,10 +57,10 @@ jobs:
|
|||||||
name: Test MacOS
|
name: Test MacOS
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Set up Go 1.18.1
|
- name: Set up Go 1.19
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: 1.18.1
|
go-version: 1.19
|
||||||
id: go
|
id: go
|
||||||
|
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
@@ -87,10 +87,10 @@ jobs:
|
|||||||
name: Test Windows
|
name: Test Windows
|
||||||
runs-on: windows-2019
|
runs-on: windows-2019
|
||||||
steps:
|
steps:
|
||||||
- name: Set up Go 1.18.1
|
- name: Set up Go 1.19
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: 1.18.1
|
go-version: 1.19
|
||||||
id: go
|
id: go
|
||||||
|
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
|
|||||||
119
.github/workflows/ql-for-ql-build.yml
vendored
119
.github/workflows/ql-for-ql-build.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Find codeql
|
- name: Find codeql
|
||||||
id: find-codeql
|
id: find-codeql
|
||||||
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
|
uses: github/codeql-action/init@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
|
||||||
with:
|
with:
|
||||||
languages: javascript # does not matter
|
languages: javascript # does not matter
|
||||||
- name: Get CodeQL version
|
- name: Get CodeQL version
|
||||||
@@ -27,30 +27,37 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||||
|
- name: Cache entire pack
|
||||||
|
id: cache-pack
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: ${{ runner.temp }}/pack
|
||||||
|
key: ${{ runner.os }}-pack-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }}-${{ hashFiles('ql/**/*.ql*') }}-${{ hashFiles('ql/**/qlpack.yml') }}-${{ hashFiles('ql/ql/src/ql.dbscheme*') }}-${{ steps.get-codeql-version.outputs.version }}--${{ hashFiles('.github/workflows/ql-for-ql-build.yml') }}
|
||||||
- name: Cache queries
|
- name: Cache queries
|
||||||
|
if: steps.cache-pack.outputs.cache-hit != 'true'
|
||||||
id: cache-queries
|
id: cache-queries
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: ${{ runner.temp }}/query-pack.zip
|
path: ${{ runner.temp }}/queries
|
||||||
key: queries-${{ hashFiles('ql/**/*.ql*') }}-${{ hashFiles('ql/**/qlpack.yml') }}-${{ hashFiles('ql/ql/src/ql.dbscheme*') }}-${{ steps.get-codeql-version.outputs.version }}
|
key: queries-${{ hashFiles('ql/**/*.ql*') }}-${{ hashFiles('ql/**/qlpack.yml') }}-${{ hashFiles('ql/ql/src/ql.dbscheme*') }}-${{ steps.get-codeql-version.outputs.version }}--${{ hashFiles('.github/workflows/ql-for-ql-build.yml') }}
|
||||||
- name: Build query pack
|
- name: Build query pack
|
||||||
if: steps.cache-queries.outputs.cache-hit != 'true'
|
if: steps.cache-queries.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
|
||||||
run: |
|
run: |
|
||||||
cd ql/ql/src
|
cd ql/ql/src
|
||||||
"${CODEQL}" pack create
|
"${CODEQL}" pack create -j 16
|
||||||
cd .codeql/pack/codeql/ql/0.0.0
|
mv .codeql/pack/codeql/ql/0.0.0 ${{ runner.temp }}/queries
|
||||||
zip "${PACKZIP}" -r .
|
|
||||||
env:
|
env:
|
||||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||||
PACKZIP: ${{ runner.temp }}/query-pack.zip
|
- name: Move cache queries to pack
|
||||||
- name: Upload query pack
|
if: steps.cache-pack.outputs.cache-hit != 'true'
|
||||||
uses: actions/upload-artifact@v3
|
run: |
|
||||||
with:
|
cp -r ${{ runner.temp }}/queries ${{ runner.temp }}/pack
|
||||||
name: query-pack-zip
|
env:
|
||||||
path: ${{ runner.temp }}/query-pack.zip
|
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||||
|
|
||||||
### Build the extractor ###
|
### Build the extractor ###
|
||||||
- name: Cache entire extractor
|
- name: Cache entire extractor
|
||||||
|
if: steps.cache-pack.outputs.cache-hit != 'true'
|
||||||
id: cache-extractor
|
id: cache-extractor
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
@@ -61,7 +68,7 @@ jobs:
|
|||||||
ql/target/release/ql-extractor.exe
|
ql/target/release/ql-extractor.exe
|
||||||
key: ${{ runner.os }}-extractor-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }}
|
key: ${{ runner.os }}-extractor-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }}
|
||||||
- name: Cache cargo
|
- name: Cache cargo
|
||||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
if: steps.cache-extractor.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
@@ -70,72 +77,35 @@ jobs:
|
|||||||
ql/target
|
ql/target
|
||||||
key: ${{ runner.os }}-rust-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
|
key: ${{ runner.os }}-rust-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
|
||||||
- name: Check formatting
|
- name: Check formatting
|
||||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
if: steps.cache-extractor.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
|
||||||
run: cd ql; cargo fmt --all -- --check
|
run: cd ql; cargo fmt --all -- --check
|
||||||
- name: Build
|
- name: Build
|
||||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
if: steps.cache-extractor.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
|
||||||
run: cd ql; cargo build --verbose
|
run: cd ql; cargo build --verbose
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
if: steps.cache-extractor.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
|
||||||
run: cd ql; cargo test --verbose
|
run: cd ql; cargo test --verbose
|
||||||
- name: Release build
|
- name: Release build
|
||||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
if: steps.cache-extractor.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
|
||||||
run: cd ql; cargo build --release
|
run: cd ql; cargo build --release
|
||||||
- name: Generate dbscheme
|
- name: Generate dbscheme
|
||||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
if: steps.cache-extractor.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
|
||||||
run: ql/target/release/ql-generator --dbscheme ql/ql/src/ql.dbscheme --library ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll
|
run: ql/target/release/ql-generator --dbscheme ql/ql/src/ql.dbscheme --library ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll
|
||||||
- uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: extractor-ubuntu-latest
|
|
||||||
path: |
|
|
||||||
ql/target/release/ql-autobuilder
|
|
||||||
ql/target/release/ql-autobuilder.exe
|
|
||||||
ql/target/release/ql-extractor
|
|
||||||
ql/target/release/ql-extractor.exe
|
|
||||||
retention-days: 1
|
|
||||||
|
|
||||||
### Package the queries and extractor ###
|
### Package the queries and extractor ###
|
||||||
- uses: actions/download-artifact@v3
|
- name: Package pack
|
||||||
with:
|
if: steps.cache-pack.outputs.cache-hit != 'true'
|
||||||
name: query-pack-zip
|
run: |
|
||||||
path: query-pack-zip
|
cp -r ql/codeql-extractor.yml ql/tools ql/ql/src/ql.dbscheme.stats ${PACK}/
|
||||||
- uses: actions/download-artifact@v3
|
mkdir -p ${PACK}/tools/linux64
|
||||||
with:
|
cp ql/target/release/ql-autobuilder ${PACK}/tools/linux64/autobuilder
|
||||||
name: extractor-ubuntu-latest
|
cp ql/target/release/ql-extractor ${PACK}/tools/linux64/extractor
|
||||||
path: linux64
|
chmod +x ${PACK}/tools/linux64/autobuilder
|
||||||
- run: |
|
chmod +x ${PACK}/tools/linux64/extractor
|
||||||
unzip query-pack-zip/*.zip -d pack
|
env:
|
||||||
cp -r ql/codeql-extractor.yml ql/tools ql/ql/src/ql.dbscheme.stats pack/
|
PACK: ${{ runner.temp }}/pack
|
||||||
mkdir -p pack/tools/linux64
|
|
||||||
if [[ -f linux64/ql-autobuilder ]]; then
|
|
||||||
cp linux64/ql-autobuilder pack/tools/linux64/autobuilder
|
|
||||||
chmod +x pack/tools/linux64/autobuilder
|
|
||||||
fi
|
|
||||||
if [[ -f linux64/ql-extractor ]]; then
|
|
||||||
cp linux64/ql-extractor pack/tools/linux64/extractor
|
|
||||||
chmod +x pack/tools/linux64/extractor
|
|
||||||
fi
|
|
||||||
cd pack
|
|
||||||
zip -rq ../codeql-ql.zip .
|
|
||||||
- uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: codeql-ql-pack
|
|
||||||
path: codeql-ql.zip
|
|
||||||
retention-days: 1
|
|
||||||
|
|
||||||
### Run the analysis ###
|
### Run the analysis ###
|
||||||
- name: Download pack
|
|
||||||
uses: actions/download-artifact@v3
|
|
||||||
with:
|
|
||||||
name: codeql-ql-pack
|
|
||||||
path: ${{ runner.temp }}/codeql-ql-pack-artifact
|
|
||||||
|
|
||||||
- name: Prepare pack
|
|
||||||
run: |
|
|
||||||
unzip "${PACK_ARTIFACT}/*.zip" -d "${PACK}"
|
|
||||||
env:
|
|
||||||
PACK_ARTIFACT: ${{ runner.temp }}/codeql-ql-pack-artifact
|
|
||||||
PACK: ${{ runner.temp }}/pack
|
|
||||||
- name: Hack codeql-action options
|
- name: Hack codeql-action options
|
||||||
run: |
|
run: |
|
||||||
JSON=$(jq -nc --arg pack "${PACK}" '.database."run-queries"=["--search-path", $pack] | .resolve.queries=["--search-path", $pack] | .resolve.extractor=["--search-path", $pack] | .database.init=["--search-path", $pack]')
|
JSON=$(jq -nc --arg pack "${PACK}" '.database."run-queries"=["--search-path", $pack] | .resolve.queries=["--search-path", $pack] | .resolve.extractor=["--search-path", $pack] | .database.init=["--search-path", $pack]')
|
||||||
@@ -149,21 +119,26 @@ jobs:
|
|||||||
echo " - ql/ql/test" >> ${CONF}
|
echo " - ql/ql/test" >> ${CONF}
|
||||||
echo " - \"*/ql/lib/upgrades/\"" >> ${CONF}
|
echo " - \"*/ql/lib/upgrades/\"" >> ${CONF}
|
||||||
echo "disable-default-queries: true" >> ${CONF}
|
echo "disable-default-queries: true" >> ${CONF}
|
||||||
echo "packs:" >> ${CONF}
|
echo "queries:" >> ${CONF}
|
||||||
echo " - codeql/ql" >> ${CONF}
|
echo " - uses: ./ql/ql/src/codeql-suites/ql-code-scanning.qls" >> ${CONF}
|
||||||
echo "Config file: "
|
echo "Config file: "
|
||||||
cat ${CONF}
|
cat ${CONF}
|
||||||
env:
|
env:
|
||||||
CONF: ./ql-for-ql-config.yml
|
CONF: ./ql-for-ql-config.yml
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
|
uses: github/codeql-action/init@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
|
||||||
with:
|
with:
|
||||||
languages: ql
|
languages: ql
|
||||||
db-location: ${{ runner.temp }}/db
|
db-location: ${{ runner.temp }}/db
|
||||||
config-file: ./ql-for-ql-config.yml
|
config-file: ./ql-for-ql-config.yml
|
||||||
|
- name: Move pack cache
|
||||||
|
run: |
|
||||||
|
cp -r ${PACK}/.cache ql/ql/src/.cache
|
||||||
|
env:
|
||||||
|
PACK: ${{ runner.temp }}/pack
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@aa93aea877e5fb8841bcb1193f672abf6e9f2980
|
uses: github/codeql-action/analyze@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
|
||||||
with:
|
with:
|
||||||
category: "ql-for-ql"
|
category: "ql-for-ql"
|
||||||
- name: Copy sarif file to CWD
|
- name: Copy sarif file to CWD
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Find codeql
|
- name: Find codeql
|
||||||
id: find-codeql
|
id: find-codeql
|
||||||
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
|
uses: github/codeql-action/init@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
|
||||||
with:
|
with:
|
||||||
languages: javascript # does not matter
|
languages: javascript # does not matter
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v3
|
||||||
|
|||||||
4
.github/workflows/ql-for-ql-tests.yml
vendored
4
.github/workflows/ql-for-ql-tests.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Find codeql
|
- name: Find codeql
|
||||||
id: find-codeql
|
id: find-codeql
|
||||||
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
|
uses: github/codeql-action/init@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
|
||||||
with:
|
with:
|
||||||
languages: javascript # does not matter
|
languages: javascript # does not matter
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v3
|
||||||
@@ -44,7 +44,7 @@ jobs:
|
|||||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||||
- name: Check QL formatting
|
- name: Check QL formatting
|
||||||
run: |
|
run: |
|
||||||
find ql/ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 "${CODEQL}" query format --check-only
|
find ql/ql/src "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 "${CODEQL}" query format --check-only
|
||||||
env:
|
env:
|
||||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||||
- name: Check QL compilation
|
- name: Check QL compilation
|
||||||
|
|||||||
@@ -485,28 +485,39 @@
|
|||||||
"ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll"
|
"ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll"
|
||||||
],
|
],
|
||||||
"ReDoS Util Python/JS/Ruby/Java": [
|
"ReDoS Util Python/JS/Ruby/Java": [
|
||||||
"javascript/ql/lib/semmle/javascript/security/performance/ReDoSUtil.qll",
|
"javascript/ql/lib/semmle/javascript/security/regexp/NfaUtils.qll",
|
||||||
"python/ql/lib/semmle/python/security/performance/ReDoSUtil.qll",
|
"python/ql/lib/semmle/python/security/regexp/NfaUtils.qll",
|
||||||
"ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtil.qll",
|
"ruby/ql/lib/codeql/ruby/security/regexp/NfaUtils.qll",
|
||||||
"java/ql/lib/semmle/code/java/security/performance/ReDoSUtil.qll"
|
"java/ql/lib/semmle/code/java/security/regexp/NfaUtils.qll"
|
||||||
],
|
],
|
||||||
"ReDoS Exponential Python/JS/Ruby/Java": [
|
"ReDoS Exponential Python/JS/Ruby/Java": [
|
||||||
"javascript/ql/lib/semmle/javascript/security/performance/ExponentialBackTracking.qll",
|
"javascript/ql/lib/semmle/javascript/security/regexp/ExponentialBackTracking.qll",
|
||||||
"python/ql/lib/semmle/python/security/performance/ExponentialBackTracking.qll",
|
"python/ql/lib/semmle/python/security/regexp/ExponentialBackTracking.qll",
|
||||||
"ruby/ql/lib/codeql/ruby/security/performance/ExponentialBackTracking.qll",
|
"ruby/ql/lib/codeql/ruby/security/regexp/ExponentialBackTracking.qll",
|
||||||
"java/ql/lib/semmle/code/java/security/performance/ExponentialBackTracking.qll"
|
"java/ql/lib/semmle/code/java/security/regexp/ExponentialBackTracking.qll"
|
||||||
],
|
],
|
||||||
"ReDoS Polynomial Python/JS/Ruby/Java": [
|
"ReDoS Polynomial Python/JS/Ruby/Java": [
|
||||||
"javascript/ql/lib/semmle/javascript/security/performance/SuperlinearBackTracking.qll",
|
"javascript/ql/lib/semmle/javascript/security/regexp/SuperlinearBackTracking.qll",
|
||||||
"python/ql/lib/semmle/python/security/performance/SuperlinearBackTracking.qll",
|
"python/ql/lib/semmle/python/security/regexp/SuperlinearBackTracking.qll",
|
||||||
"ruby/ql/lib/codeql/ruby/security/performance/SuperlinearBackTracking.qll",
|
"ruby/ql/lib/codeql/ruby/security/regexp/SuperlinearBackTracking.qll",
|
||||||
"java/ql/lib/semmle/code/java/security/performance/SuperlinearBackTracking.qll"
|
"java/ql/lib/semmle/code/java/security/regexp/SuperlinearBackTracking.qll"
|
||||||
|
],
|
||||||
|
"RegexpMatching Python/JS/Ruby": [
|
||||||
|
"javascript/ql/lib/semmle/javascript/security/regexp/RegexpMatching.qll",
|
||||||
|
"python/ql/lib/semmle/python/security/regexp/RegexpMatching.qll",
|
||||||
|
"ruby/ql/lib/codeql/ruby/security/regexp/RegexpMatching.qll"
|
||||||
],
|
],
|
||||||
"BadTagFilterQuery Python/JS/Ruby": [
|
"BadTagFilterQuery Python/JS/Ruby": [
|
||||||
"javascript/ql/lib/semmle/javascript/security/BadTagFilterQuery.qll",
|
"javascript/ql/lib/semmle/javascript/security/BadTagFilterQuery.qll",
|
||||||
"python/ql/lib/semmle/python/security/BadTagFilterQuery.qll",
|
"python/ql/lib/semmle/python/security/BadTagFilterQuery.qll",
|
||||||
"ruby/ql/lib/codeql/ruby/security/BadTagFilterQuery.qll"
|
"ruby/ql/lib/codeql/ruby/security/BadTagFilterQuery.qll"
|
||||||
],
|
],
|
||||||
|
"OverlyLargeRange Python/JS/Ruby/Java": [
|
||||||
|
"javascript/ql/lib/semmle/javascript/security/OverlyLargeRangeQuery.qll",
|
||||||
|
"python/ql/lib/semmle/python/security/OverlyLargeRangeQuery.qll",
|
||||||
|
"ruby/ql/lib/codeql/ruby/security/OverlyLargeRangeQuery.qll",
|
||||||
|
"java/ql/lib/semmle/code/java/security/OverlyLargeRangeQuery.qll"
|
||||||
|
],
|
||||||
"CFG": [
|
"CFG": [
|
||||||
"csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll",
|
"csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll",
|
||||||
"ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImplShared.qll",
|
"ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImplShared.qll",
|
||||||
@@ -586,5 +597,9 @@
|
|||||||
"Swift patterns test file": [
|
"Swift patterns test file": [
|
||||||
"swift/ql/test/extractor-tests/patterns/patterns.swift",
|
"swift/ql/test/extractor-tests/patterns/patterns.swift",
|
||||||
"swift/ql/test/library-tests/parent/patterns.swift"
|
"swift/ql/test/library-tests/parent/patterns.swift"
|
||||||
|
],
|
||||||
|
"IncompleteMultiCharacterSanitization JS/Ruby": [
|
||||||
|
"javascript/ql/lib/semmle/javascript/security/IncompleteMultiCharacterSanitizationQuery.qll",
|
||||||
|
"ruby/ql/lib/codeql/ruby/security/IncompleteMultiCharacterSanitizationQuery.qll"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
class Expr extends @expr {
|
||||||
|
string toString() { none() }
|
||||||
|
}
|
||||||
|
|
||||||
|
class Location extends @location_expr {
|
||||||
|
string toString() { none() }
|
||||||
|
}
|
||||||
|
|
||||||
|
from Expr expr, int kind, int kind_new, Location location
|
||||||
|
where
|
||||||
|
exprs(expr, kind, location) and
|
||||||
|
if expr instanceof @blockassignexpr then kind_new = 0 else kind_new = kind
|
||||||
|
select expr, kind_new, location
|
||||||
2131
cpp/downgrades/73af5058c6899dcdb05754c27ca966aeb3a68c94/old.dbscheme
Normal file
2131
cpp/downgrades/73af5058c6899dcdb05754c27ca966aeb3a68c94/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
|||||||
|
description: Support block assignment
|
||||||
|
compatibility: partial
|
||||||
|
exprs.rel: run exprs.qlo
|
||||||
2136
cpp/downgrades/f96ad9b2da43bbc9e55a72a165febd270ae07981/old.dbscheme
Normal file
2136
cpp/downgrades/f96ad9b2da43bbc9e55a72a165febd270ae07981/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
|||||||
|
description: Add relation for orphaned local variables
|
||||||
|
compatibility: full
|
||||||
|
orphaned_variables.rel: delete
|
||||||
4
cpp/ql/lib/change-notes/2022-08-01-gvn-functions.md
Normal file
4
cpp/ql/lib/change-notes/2022-08-01-gvn-functions.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: minorAnalysis
|
||||||
|
---
|
||||||
|
* Multiple function calls made in the same function may now receive the same global value number when the analysis can show they produce the same results.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: feature
|
||||||
|
---
|
||||||
|
* Added a `BlockAssignExpr` class, which models a `memcpy`-like operation used in compiler generated copy/move constructors and assignment operations.
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
category: minorAnalysis
|
||||||
|
---
|
||||||
|
* All deprecated predicates/classes/modules that have been deprecated for over a year have been
|
||||||
|
deleted.
|
||||||
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: feature
|
||||||
|
---
|
||||||
|
* Added support for getting the link targets of global and namespace variables.
|
||||||
5
cpp/ql/lib/change-notes/2022-08-22-xml-rename.md
Normal file
5
cpp/ql/lib/change-notes/2022-08-22-xml-rename.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
category: deprecated
|
||||||
|
---
|
||||||
|
* Many classes/predicates/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
|
||||||
|
The old name still exists as a deprecated alias.
|
||||||
@@ -119,27 +119,67 @@ module SemanticExprConfig {
|
|||||||
result = block.getDisplayIndex()
|
result = block.getDisplayIndex()
|
||||||
}
|
}
|
||||||
|
|
||||||
class SsaVariable instanceof IR::Instruction {
|
newtype TSsaVariable =
|
||||||
SsaVariable() { super.hasMemoryResult() }
|
TSsaInstruction(IR::Instruction instr) { instr.hasMemoryResult() } or
|
||||||
|
TSsaOperand(IR::Operand op) { op.isDefinitionInexact() }
|
||||||
|
|
||||||
final string toString() { result = super.toString() }
|
class SsaVariable extends TSsaVariable {
|
||||||
|
string toString() { none() }
|
||||||
|
|
||||||
final Location getLocation() { result = super.getLocation() }
|
Location getLocation() { none() }
|
||||||
|
|
||||||
|
IR::Instruction asInstruction() { none() }
|
||||||
|
|
||||||
|
IR::Operand asOperand() { none() }
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate explicitUpdate(SsaVariable v, Expr sourceExpr) { v = sourceExpr }
|
class SsaInstructionVariable extends SsaVariable, TSsaInstruction {
|
||||||
|
IR::Instruction instr;
|
||||||
|
|
||||||
predicate phi(SsaVariable v) { v instanceof IR::PhiInstruction }
|
SsaInstructionVariable() { this = TSsaInstruction(instr) }
|
||||||
|
|
||||||
SsaVariable getAPhiInput(SsaVariable v) { result = v.(IR::PhiInstruction).getAnInput() }
|
final override string toString() { result = instr.toString() }
|
||||||
|
|
||||||
Expr getAUse(SsaVariable v) { result.(IR::LoadInstruction).getSourceValue() = v }
|
final override Location getLocation() { result = instr.getLocation() }
|
||||||
|
|
||||||
|
final override IR::Instruction asInstruction() { result = instr }
|
||||||
|
}
|
||||||
|
|
||||||
|
class SsaOperand extends SsaVariable, TSsaOperand {
|
||||||
|
IR::Operand op;
|
||||||
|
|
||||||
|
SsaOperand() { this = TSsaOperand(op) }
|
||||||
|
|
||||||
|
final override string toString() { result = op.toString() }
|
||||||
|
|
||||||
|
final override Location getLocation() { result = op.getLocation() }
|
||||||
|
|
||||||
|
final override IR::Operand asOperand() { result = op }
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate explicitUpdate(SsaVariable v, Expr sourceExpr) { v.asInstruction() = sourceExpr }
|
||||||
|
|
||||||
|
predicate phi(SsaVariable v) { v.asInstruction() instanceof IR::PhiInstruction }
|
||||||
|
|
||||||
|
SsaVariable getAPhiInput(SsaVariable v) {
|
||||||
|
exists(IR::PhiInstruction instr |
|
||||||
|
result.asInstruction() = instr.getAnInput()
|
||||||
|
or
|
||||||
|
result.asOperand() = instr.getAnInputOperand()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Expr getAUse(SsaVariable v) { result.(IR::LoadInstruction).getSourceValue() = v.asInstruction() }
|
||||||
|
|
||||||
SemType getSsaVariableType(SsaVariable v) {
|
SemType getSsaVariableType(SsaVariable v) {
|
||||||
result = getSemanticType(v.(IR::Instruction).getResultIRType())
|
result = getSemanticType(v.asInstruction().getResultIRType())
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicBlock getSsaVariableBasicBlock(SsaVariable v) { result = v.(IR::Instruction).getBlock() }
|
BasicBlock getSsaVariableBasicBlock(SsaVariable v) {
|
||||||
|
result = v.asInstruction().getBlock()
|
||||||
|
or
|
||||||
|
result = v.asOperand().getUse().getBlock()
|
||||||
|
}
|
||||||
|
|
||||||
private newtype TReadPosition =
|
private newtype TReadPosition =
|
||||||
TReadPositionBlock(IR::IRBlock block) or
|
TReadPositionBlock(IR::IRBlock block) or
|
||||||
@@ -169,7 +209,9 @@ module SemanticExprConfig {
|
|||||||
|
|
||||||
final override predicate hasRead(SsaVariable v) {
|
final override predicate hasRead(SsaVariable v) {
|
||||||
exists(IR::Operand operand |
|
exists(IR::Operand operand |
|
||||||
operand.getDef() = v and not operand instanceof IR::PhiInputOperand
|
operand.getDef() = v.asInstruction() and
|
||||||
|
not operand instanceof IR::PhiInputOperand and
|
||||||
|
operand.getUse().getBlock() = block
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -186,7 +228,7 @@ module SemanticExprConfig {
|
|||||||
|
|
||||||
final override predicate hasRead(SsaVariable v) {
|
final override predicate hasRead(SsaVariable v) {
|
||||||
exists(IR::PhiInputOperand operand |
|
exists(IR::PhiInputOperand operand |
|
||||||
operand.getDef() = v and
|
operand.getDef() = v.asInstruction() and
|
||||||
operand.getPredecessorBlock() = pred and
|
operand.getPredecessorBlock() = pred and
|
||||||
operand.getUse().getBlock() = succ
|
operand.getUse().getBlock() = succ
|
||||||
)
|
)
|
||||||
@@ -205,17 +247,16 @@ module SemanticExprConfig {
|
|||||||
exists(IR::PhiInputOperand operand |
|
exists(IR::PhiInputOperand operand |
|
||||||
pos = TReadPositionPhiInputEdge(operand.getPredecessorBlock(), operand.getUse().getBlock())
|
pos = TReadPositionPhiInputEdge(operand.getPredecessorBlock(), operand.getUse().getBlock())
|
||||||
|
|
|
|
||||||
phi = operand.getUse() and input = operand.getDef()
|
phi.asInstruction() = operand.getUse() and
|
||||||
|
(
|
||||||
|
input.asInstruction() = operand.getDef()
|
||||||
|
or
|
||||||
|
input.asOperand() = operand
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
class Bound instanceof IRBound::Bound {
|
class Bound instanceof IRBound::Bound {
|
||||||
Bound() {
|
|
||||||
this instanceof IRBound::ZeroBound
|
|
||||||
or
|
|
||||||
this.(IRBound::ValueNumberBound).getValueNumber().getAnInstruction() instanceof SsaVariable
|
|
||||||
}
|
|
||||||
|
|
||||||
string toString() { result = super.toString() }
|
string toString() { result = super.toString() }
|
||||||
|
|
||||||
final Location getLocation() { result = super.getLocation() }
|
final Location getLocation() { result = super.getLocation() }
|
||||||
@@ -228,13 +269,13 @@ module SemanticExprConfig {
|
|||||||
|
|
||||||
override string toString() {
|
override string toString() {
|
||||||
result =
|
result =
|
||||||
min(SsaVariable instr |
|
min(SsaVariable v |
|
||||||
instr = bound.getValueNumber().getAnInstruction()
|
v.asInstruction() = bound.getValueNumber().getAnInstruction()
|
||||||
|
|
|
|
||||||
instr
|
v
|
||||||
order by
|
order by
|
||||||
instr.(IR::Instruction).getBlock().getDisplayIndex(),
|
v.asInstruction().getBlock().getDisplayIndex(),
|
||||||
instr.(IR::Instruction).getDisplayIndexInBlock()
|
v.asInstruction().getDisplayIndexInBlock()
|
||||||
).toString()
|
).toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -242,7 +283,7 @@ module SemanticExprConfig {
|
|||||||
predicate zeroBound(Bound bound) { bound instanceof IRBound::ZeroBound }
|
predicate zeroBound(Bound bound) { bound instanceof IRBound::ZeroBound }
|
||||||
|
|
||||||
predicate ssaBound(Bound bound, SsaVariable v) {
|
predicate ssaBound(Bound bound, SsaVariable v) {
|
||||||
v = bound.(IRBound::ValueNumberBound).getValueNumber().getAnInstruction()
|
v.asInstruction() = bound.(IRBound::ValueNumberBound).getValueNumber().getAnInstruction()
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr getBoundExpr(Bound bound, int delta) {
|
Expr getBoundExpr(Bound bound, int delta) {
|
||||||
@@ -251,22 +292,20 @@ module SemanticExprConfig {
|
|||||||
|
|
||||||
class Guard = IRGuards::IRGuardCondition;
|
class Guard = IRGuards::IRGuardCondition;
|
||||||
|
|
||||||
predicate guard(Guard guard, BasicBlock block) {
|
predicate guard(Guard guard, BasicBlock block) { block = guard.getBlock() }
|
||||||
block = guard.(IRGuards::IRGuardCondition).getBlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
Expr getGuardAsExpr(Guard guard) { result = guard }
|
Expr getGuardAsExpr(Guard guard) { result = guard }
|
||||||
|
|
||||||
predicate equalityGuard(Guard guard, Expr e1, Expr e2, boolean polarity) {
|
predicate equalityGuard(Guard guard, Expr e1, Expr e2, boolean polarity) {
|
||||||
guard.(IRGuards::IRGuardCondition).comparesEq(e1.getAUse(), e2.getAUse(), 0, true, polarity)
|
guard.comparesEq(e1.getAUse(), e2.getAUse(), 0, true, polarity)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate guardDirectlyControlsBlock(Guard guard, BasicBlock controlled, boolean branch) {
|
predicate guardDirectlyControlsBlock(Guard guard, BasicBlock controlled, boolean branch) {
|
||||||
guard.(IRGuards::IRGuardCondition).controls(controlled, branch)
|
guard.controls(controlled, branch)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate guardHasBranchEdge(Guard guard, BasicBlock bb1, BasicBlock bb2, boolean branch) {
|
predicate guardHasBranchEdge(Guard guard, BasicBlock bb1, BasicBlock bb2, boolean branch) {
|
||||||
guard.(IRGuards::IRGuardCondition).controlsEdge(bb1, bb2, branch)
|
guard.controlsEdge(bb1, bb2, branch)
|
||||||
}
|
}
|
||||||
|
|
||||||
Guard comparisonGuard(Expr e) { result = e }
|
Guard comparisonGuard(Expr e) { result = e }
|
||||||
@@ -284,9 +323,13 @@ SemBasicBlock getSemanticBasicBlock(IR::IRBlock block) { result = block }
|
|||||||
|
|
||||||
IR::IRBlock getCppBasicBlock(SemBasicBlock block) { block = result }
|
IR::IRBlock getCppBasicBlock(SemBasicBlock block) { block = result }
|
||||||
|
|
||||||
SemSsaVariable getSemanticSsaVariable(IR::Instruction instr) { result = instr }
|
SemSsaVariable getSemanticSsaVariable(IR::Instruction instr) {
|
||||||
|
result.(SemanticExprConfig::SsaVariable).asInstruction() = instr
|
||||||
|
}
|
||||||
|
|
||||||
IR::Instruction getCppSsaVariableInstruction(SemSsaVariable v) { v = result }
|
IR::Instruction getCppSsaVariableInstruction(SemSsaVariable var) {
|
||||||
|
var.(SemanticExprConfig::SsaVariable).asInstruction() = result
|
||||||
|
}
|
||||||
|
|
||||||
SemBound getSemanticBound(IRBound::Bound bound) { result = bound }
|
SemBound getSemanticBound(IRBound::Bound bound) { result = bound }
|
||||||
|
|
||||||
|
|||||||
@@ -160,6 +160,7 @@ private predicate phiModulusInit(SemSsaPhiNode phi, SemBound b, int val, int mod
|
|||||||
/**
|
/**
|
||||||
* Holds if all inputs to `phi` numbered `1` to `rix` are equal to `b + val` modulo `mod`.
|
* Holds if all inputs to `phi` numbered `1` to `rix` are equal to `b + val` modulo `mod`.
|
||||||
*/
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
private predicate phiModulusRankStep(SemSsaPhiNode phi, SemBound b, int val, int mod, int rix) {
|
private predicate phiModulusRankStep(SemSsaPhiNode phi, SemBound b, int val, int mod, int rix) {
|
||||||
rix = 0 and
|
rix = 0 and
|
||||||
phiModulusInit(phi, b, val, mod)
|
phiModulusInit(phi, b, val, mod)
|
||||||
@@ -169,7 +170,7 @@ private predicate phiModulusRankStep(SemSsaPhiNode phi, SemBound b, int val, int
|
|||||||
val = remainder(v1, mod)
|
val = remainder(v1, mod)
|
||||||
|
|
|
|
||||||
exists(int v2, int m2 |
|
exists(int v2, int m2 |
|
||||||
rankedPhiInput(phi, inp, edge, rix) and
|
rankedPhiInput(pragma[only_bind_out](phi), inp, edge, rix) and
|
||||||
phiModulusRankStep(phi, b, v1, m1, rix - 1) and
|
phiModulusRankStep(phi, b, v1, m1, rix - 1) and
|
||||||
ssaModulus(inp, edge, b, v2, m2) and
|
ssaModulus(inp, edge, b, v2, m2) and
|
||||||
mod = m1.gcd(m2).gcd(v1 - v2)
|
mod = m1.gcd(m2).gcd(v1 - v2)
|
||||||
|
|||||||
@@ -342,7 +342,10 @@ private class ConvertOrBoxExpr extends SemUnaryExpr {
|
|||||||
* A cast that can be ignored for the purpose of range analysis.
|
* A cast that can be ignored for the purpose of range analysis.
|
||||||
*/
|
*/
|
||||||
private class SafeCastExpr extends ConvertOrBoxExpr {
|
private class SafeCastExpr extends ConvertOrBoxExpr {
|
||||||
SafeCastExpr() { conversionCannotOverflow(getTrackedType(getOperand()), getTrackedType(this)) }
|
SafeCastExpr() {
|
||||||
|
conversionCannotOverflow(getTrackedType(pragma[only_bind_into](getOperand())),
|
||||||
|
getTrackedType(this))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -189,9 +189,12 @@ private class BinarySignExpr extends FlowSignExpr {
|
|||||||
BinarySignExpr() { binary = this }
|
BinarySignExpr() { binary = this }
|
||||||
|
|
||||||
override Sign getSignRestriction() {
|
override Sign getSignRestriction() {
|
||||||
result =
|
exists(SemExpr left, SemExpr right |
|
||||||
semExprSign(binary.getLeftOperand())
|
binaryExprOperands(binary, left, right) and
|
||||||
.applyBinaryOp(semExprSign(binary.getRightOperand()), binary.getOpcode())
|
result =
|
||||||
|
semExprSign(pragma[only_bind_out](left))
|
||||||
|
.applyBinaryOp(semExprSign(pragma[only_bind_out](right)), binary.getOpcode())
|
||||||
|
)
|
||||||
or
|
or
|
||||||
exists(SemDivExpr div | div = binary |
|
exists(SemDivExpr div | div = binary |
|
||||||
result = semExprSign(div.getLeftOperand()) and
|
result = semExprSign(div.getLeftOperand()) and
|
||||||
@@ -201,6 +204,10 @@ private class BinarySignExpr extends FlowSignExpr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate binaryExprOperands(SemBinaryExpr binary, SemExpr left, SemExpr right) {
|
||||||
|
binary.getLeftOperand() = left and binary.getRightOperand() = right
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A `Convert`, `Box`, or `Unbox` expression.
|
* A `Convert`, `Box`, or `Unbox` expression.
|
||||||
*/
|
*/
|
||||||
@@ -221,7 +228,7 @@ private class UnarySignExpr extends FlowSignExpr {
|
|||||||
UnarySignExpr() { unary = this and not this instanceof SemCastExpr }
|
UnarySignExpr() { unary = this and not this instanceof SemCastExpr }
|
||||||
|
|
||||||
override Sign getSignRestriction() {
|
override Sign getSignRestriction() {
|
||||||
result = semExprSign(unary.getOperand()).applyUnaryOp(unary.getOpcode())
|
result = semExprSign(pragma[only_bind_out](unary.getOperand())).applyUnaryOp(unary.getOpcode())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/cpp-all
|
name: codeql/cpp-all
|
||||||
version: 0.3.3
|
version: 0.3.4-dev
|
||||||
groups: cpp
|
groups: cpp
|
||||||
dbscheme: semmlecode.cpp.dbscheme
|
dbscheme: semmlecode.cpp.dbscheme
|
||||||
extractor: cpp
|
extractor: cpp
|
||||||
|
|||||||
@@ -218,8 +218,6 @@ class Folder extends Container, @folder {
|
|||||||
class File extends Container, @file {
|
class File extends Container, @file {
|
||||||
override string getAbsolutePath() { files(underlyingElement(this), result) }
|
override string getAbsolutePath() { files(underlyingElement(this), result) }
|
||||||
|
|
||||||
override string toString() { result = Container.super.toString() }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "File" }
|
override string getAPrimaryQlClass() { result = "File" }
|
||||||
|
|
||||||
override Location getLocation() {
|
override Location getLocation() {
|
||||||
|
|||||||
@@ -41,6 +41,15 @@ class LinkTarget extends @link_target {
|
|||||||
* translation units which contributed to this link target.
|
* translation units which contributed to this link target.
|
||||||
*/
|
*/
|
||||||
Class getAClass() { link_parent(unresolveElement(result), this) }
|
Class getAClass() { link_parent(unresolveElement(result), this) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a global or namespace variable which was compiled into this
|
||||||
|
* link target, or had its declaration included by one of the translation
|
||||||
|
* units which contributed to this link target.
|
||||||
|
*/
|
||||||
|
GlobalOrNamespaceVariable getAGlobalOrNamespaceVariable() {
|
||||||
|
link_parent(unresolveElement(result), this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -256,7 +256,7 @@ class AttributeArgument extends Element, @attribute_arg {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the text for the value of this argument, if its value is
|
* Gets the text for the value of this argument, if its value is
|
||||||
* a constant or token.
|
* a constant or a token.
|
||||||
*/
|
*/
|
||||||
string getValueText() {
|
string getValueText() {
|
||||||
if underlyingElement(this) instanceof @attribute_arg_constant_expr
|
if underlyingElement(this) instanceof @attribute_arg_constant_expr
|
||||||
|
|||||||
@@ -398,6 +398,8 @@ class LocalVariable extends LocalScopeVariable, @localvariable {
|
|||||||
exists(DeclStmt s | s.getADeclaration() = this and s.getEnclosingFunction() = result)
|
exists(DeclStmt s | s.getADeclaration() = this and s.getEnclosingFunction() = result)
|
||||||
or
|
or
|
||||||
exists(ConditionDeclExpr e | e.getVariable() = this and e.getEnclosingFunction() = result)
|
exists(ConditionDeclExpr e | e.getVariable() = this and e.getEnclosingFunction() = result)
|
||||||
|
or
|
||||||
|
orphaned_variables(underlyingElement(this), unresolveElement(result))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -471,6 +473,9 @@ class GlobalOrNamespaceVariable extends Variable, @globalvariable {
|
|||||||
override Type getType() { globalvariables(underlyingElement(this), unresolveElement(result), _) }
|
override Type getType() { globalvariables(underlyingElement(this), unresolveElement(result), _) }
|
||||||
|
|
||||||
override Element getEnclosingElement() { none() }
|
override Element getEnclosingElement() { none() }
|
||||||
|
|
||||||
|
/** Gets a link target which compiled or referenced this global or namespace variable. */
|
||||||
|
LinkTarget getALinkTarget() { this = result.getAGlobalOrNamespaceVariable() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
107
cpp/ql/lib/semmle/code/cpp/XML.qll
Executable file → Normal file
107
cpp/ql/lib/semmle/code/cpp/XML.qll
Executable file → Normal file
@@ -8,7 +8,7 @@ private class TXmlLocatable =
|
|||||||
@xmldtd or @xmlelement or @xmlattribute or @xmlnamespace or @xmlcomment or @xmlcharacters;
|
@xmldtd or @xmlelement or @xmlattribute or @xmlnamespace or @xmlcomment or @xmlcharacters;
|
||||||
|
|
||||||
/** An XML element that has a location. */
|
/** An XML element that has a location. */
|
||||||
class XMLLocatable extends @xmllocatable, TXmlLocatable {
|
class XmlLocatable extends @xmllocatable, TXmlLocatable {
|
||||||
/** Gets the source location for this element. */
|
/** Gets the source location for this element. */
|
||||||
Location getLocation() { xmllocations(this, result) }
|
Location getLocation() { xmllocations(this, result) }
|
||||||
|
|
||||||
@@ -32,13 +32,16 @@ class XMLLocatable extends @xmllocatable, TXmlLocatable {
|
|||||||
string toString() { none() } // overridden in subclasses
|
string toString() { none() } // overridden in subclasses
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for XmlLocatable */
|
||||||
|
deprecated class XMLLocatable = XmlLocatable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An `XMLParent` is either an `XMLElement` or an `XMLFile`,
|
* An `XmlParent` is either an `XmlElement` or an `XmlFile`,
|
||||||
* both of which can contain other elements.
|
* both of which can contain other elements.
|
||||||
*/
|
*/
|
||||||
class XMLParent extends @xmlparent {
|
class XmlParent extends @xmlparent {
|
||||||
XMLParent() {
|
XmlParent() {
|
||||||
// explicitly restrict `this` to be either an `XMLElement` or an `XMLFile`;
|
// explicitly restrict `this` to be either an `XmlElement` or an `XmlFile`;
|
||||||
// the type `@xmlparent` currently also includes non-XML files
|
// the type `@xmlparent` currently also includes non-XML files
|
||||||
this instanceof @xmlelement or xmlEncoding(this, _)
|
this instanceof @xmlelement or xmlEncoding(this, _)
|
||||||
}
|
}
|
||||||
@@ -50,28 +53,28 @@ class XMLParent extends @xmlparent {
|
|||||||
string getName() { none() } // overridden in subclasses
|
string getName() { none() } // overridden in subclasses
|
||||||
|
|
||||||
/** Gets the file to which this XML parent belongs. */
|
/** Gets the file to which this XML parent belongs. */
|
||||||
XMLFile getFile() { result = this or xmlElements(this, _, _, _, result) }
|
XmlFile getFile() { result = this or xmlElements(this, _, _, _, result) }
|
||||||
|
|
||||||
/** Gets the child element at a specified index of this XML parent. */
|
/** Gets the child element at a specified index of this XML parent. */
|
||||||
XMLElement getChild(int index) { xmlElements(result, _, this, index, _) }
|
XmlElement getChild(int index) { xmlElements(result, _, this, index, _) }
|
||||||
|
|
||||||
/** Gets a child element of this XML parent. */
|
/** Gets a child element of this XML parent. */
|
||||||
XMLElement getAChild() { xmlElements(result, _, this, _, _) }
|
XmlElement getAChild() { xmlElements(result, _, this, _, _) }
|
||||||
|
|
||||||
/** Gets a child element of this XML parent with the given `name`. */
|
/** Gets a child element of this XML parent with the given `name`. */
|
||||||
XMLElement getAChild(string name) { xmlElements(result, _, this, _, _) and result.hasName(name) }
|
XmlElement getAChild(string name) { xmlElements(result, _, this, _, _) and result.hasName(name) }
|
||||||
|
|
||||||
/** Gets a comment that is a child of this XML parent. */
|
/** Gets a comment that is a child of this XML parent. */
|
||||||
XMLComment getAComment() { xmlComments(result, _, this, _) }
|
XmlComment getAComment() { xmlComments(result, _, this, _) }
|
||||||
|
|
||||||
/** Gets a character sequence that is a child of this XML parent. */
|
/** Gets a character sequence that is a child of this XML parent. */
|
||||||
XMLCharacters getACharactersSet() { xmlChars(result, _, this, _, _, _) }
|
XmlCharacters getACharactersSet() { xmlChars(result, _, this, _, _, _) }
|
||||||
|
|
||||||
/** Gets the depth in the tree. (Overridden in XMLElement.) */
|
/** Gets the depth in the tree. (Overridden in XmlElement.) */
|
||||||
int getDepth() { result = 0 }
|
int getDepth() { result = 0 }
|
||||||
|
|
||||||
/** Gets the number of child XML elements of this XML parent. */
|
/** Gets the number of child XML elements of this XML parent. */
|
||||||
int getNumberOfChildren() { result = count(XMLElement e | xmlElements(e, _, this, _, _)) }
|
int getNumberOfChildren() { result = count(XmlElement e | xmlElements(e, _, this, _, _)) }
|
||||||
|
|
||||||
/** Gets the number of places in the body of this XML parent where text occurs. */
|
/** Gets the number of places in the body of this XML parent where text occurs. */
|
||||||
int getNumberOfCharacterSets() { result = count(int pos | xmlChars(_, _, this, pos, _, _)) }
|
int getNumberOfCharacterSets() { result = count(int pos | xmlChars(_, _, this, pos, _, _)) }
|
||||||
@@ -92,9 +95,12 @@ class XMLParent extends @xmlparent {
|
|||||||
string toString() { result = this.getName() }
|
string toString() { result = this.getName() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for XmlParent */
|
||||||
|
deprecated class XMLParent = XmlParent;
|
||||||
|
|
||||||
/** An XML file. */
|
/** An XML file. */
|
||||||
class XMLFile extends XMLParent, File {
|
class XmlFile extends XmlParent, File {
|
||||||
XMLFile() { xmlEncoding(this, _) }
|
XmlFile() { xmlEncoding(this, _) }
|
||||||
|
|
||||||
/** Gets a printable representation of this XML file. */
|
/** Gets a printable representation of this XML file. */
|
||||||
override string toString() { result = this.getName() }
|
override string toString() { result = this.getName() }
|
||||||
@@ -120,15 +126,21 @@ class XMLFile extends XMLParent, File {
|
|||||||
string getEncoding() { xmlEncoding(this, result) }
|
string getEncoding() { xmlEncoding(this, result) }
|
||||||
|
|
||||||
/** Gets the XML file itself. */
|
/** Gets the XML file itself. */
|
||||||
override XMLFile getFile() { result = this }
|
override XmlFile getFile() { result = this }
|
||||||
|
|
||||||
/** Gets a top-most element in an XML file. */
|
/** Gets a top-most element in an XML file. */
|
||||||
XMLElement getARootElement() { result = this.getAChild() }
|
XmlElement getARootElement() { result = this.getAChild() }
|
||||||
|
|
||||||
/** Gets a DTD associated with this XML file. */
|
/** Gets a DTD associated with this XML file. */
|
||||||
XMLDTD getADTD() { xmlDTDs(result, _, _, _, this) }
|
XmlDtd getADtd() { xmlDTDs(result, _, _, _, this) }
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for getADtd */
|
||||||
|
deprecated XmlDtd getADTD() { result = this.getADtd() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for XmlFile */
|
||||||
|
deprecated class XMLFile = XmlFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An XML document type definition (DTD).
|
* An XML document type definition (DTD).
|
||||||
*
|
*
|
||||||
@@ -140,7 +152,7 @@ class XMLFile extends XMLParent, File {
|
|||||||
* <!ELEMENT lastName (#PCDATA)>
|
* <!ELEMENT lastName (#PCDATA)>
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
class XMLDTD extends XMLLocatable, @xmldtd {
|
class XmlDtd extends XmlLocatable, @xmldtd {
|
||||||
/** Gets the name of the root element of this DTD. */
|
/** Gets the name of the root element of this DTD. */
|
||||||
string getRoot() { xmlDTDs(this, result, _, _, _) }
|
string getRoot() { xmlDTDs(this, result, _, _, _) }
|
||||||
|
|
||||||
@@ -154,7 +166,7 @@ class XMLDTD extends XMLLocatable, @xmldtd {
|
|||||||
predicate isPublic() { not xmlDTDs(this, _, "", _, _) }
|
predicate isPublic() { not xmlDTDs(this, _, "", _, _) }
|
||||||
|
|
||||||
/** Gets the parent of this DTD. */
|
/** Gets the parent of this DTD. */
|
||||||
XMLParent getParent() { xmlDTDs(this, _, _, _, result) }
|
XmlParent getParent() { xmlDTDs(this, _, _, _, result) }
|
||||||
|
|
||||||
override string toString() {
|
override string toString() {
|
||||||
this.isPublic() and
|
this.isPublic() and
|
||||||
@@ -165,6 +177,9 @@ class XMLDTD extends XMLLocatable, @xmldtd {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for XmlDtd */
|
||||||
|
deprecated class XMLDTD = XmlDtd;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An XML element in an XML file.
|
* An XML element in an XML file.
|
||||||
*
|
*
|
||||||
@@ -176,7 +191,7 @@ class XMLDTD extends XMLLocatable, @xmldtd {
|
|||||||
* </manifest>
|
* </manifest>
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
|
class XmlElement extends @xmlelement, XmlParent, XmlLocatable {
|
||||||
/** Holds if this XML element has the given `name`. */
|
/** Holds if this XML element has the given `name`. */
|
||||||
predicate hasName(string name) { name = this.getName() }
|
predicate hasName(string name) { name = this.getName() }
|
||||||
|
|
||||||
@@ -184,10 +199,10 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
|
|||||||
override string getName() { xmlElements(this, result, _, _, _) }
|
override string getName() { xmlElements(this, result, _, _, _) }
|
||||||
|
|
||||||
/** Gets the XML file in which this XML element occurs. */
|
/** Gets the XML file in which this XML element occurs. */
|
||||||
override XMLFile getFile() { xmlElements(this, _, _, _, result) }
|
override XmlFile getFile() { xmlElements(this, _, _, _, result) }
|
||||||
|
|
||||||
/** Gets the parent of this XML element. */
|
/** Gets the parent of this XML element. */
|
||||||
XMLParent getParent() { xmlElements(this, _, result, _, _) }
|
XmlParent getParent() { xmlElements(this, _, result, _, _) }
|
||||||
|
|
||||||
/** Gets the index of this XML element among its parent's children. */
|
/** Gets the index of this XML element among its parent's children. */
|
||||||
int getIndex() { xmlElements(this, _, _, result, _) }
|
int getIndex() { xmlElements(this, _, _, result, _) }
|
||||||
@@ -196,7 +211,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
|
|||||||
predicate hasNamespace() { xmlHasNs(this, _, _) }
|
predicate hasNamespace() { xmlHasNs(this, _, _) }
|
||||||
|
|
||||||
/** Gets the namespace of this XML element, if any. */
|
/** Gets the namespace of this XML element, if any. */
|
||||||
XMLNamespace getNamespace() { xmlHasNs(this, result, _) }
|
XmlNamespace getNamespace() { xmlHasNs(this, result, _) }
|
||||||
|
|
||||||
/** Gets the index of this XML element among its parent's children. */
|
/** Gets the index of this XML element among its parent's children. */
|
||||||
int getElementPositionIndex() { xmlElements(this, _, _, result, _) }
|
int getElementPositionIndex() { xmlElements(this, _, _, result, _) }
|
||||||
@@ -205,10 +220,10 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
|
|||||||
override int getDepth() { result = this.getParent().getDepth() + 1 }
|
override int getDepth() { result = this.getParent().getDepth() + 1 }
|
||||||
|
|
||||||
/** Gets an XML attribute of this XML element. */
|
/** Gets an XML attribute of this XML element. */
|
||||||
XMLAttribute getAnAttribute() { result.getElement() = this }
|
XmlAttribute getAnAttribute() { result.getElement() = this }
|
||||||
|
|
||||||
/** Gets the attribute with the specified `name`, if any. */
|
/** Gets the attribute with the specified `name`, if any. */
|
||||||
XMLAttribute getAttribute(string name) { result.getElement() = this and result.getName() = name }
|
XmlAttribute getAttribute(string name) { result.getElement() = this and result.getName() = name }
|
||||||
|
|
||||||
/** Holds if this XML element has an attribute with the specified `name`. */
|
/** Holds if this XML element has an attribute with the specified `name`. */
|
||||||
predicate hasAttribute(string name) { exists(this.getAttribute(name)) }
|
predicate hasAttribute(string name) { exists(this.getAttribute(name)) }
|
||||||
@@ -220,6 +235,9 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
|
|||||||
override string toString() { result = this.getName() }
|
override string toString() { result = this.getName() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for XmlElement */
|
||||||
|
deprecated class XMLElement = XmlElement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An attribute that occurs inside an XML element.
|
* An attribute that occurs inside an XML element.
|
||||||
*
|
*
|
||||||
@@ -230,18 +248,18 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
|
|||||||
* android:versionCode="1"
|
* android:versionCode="1"
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
class XMLAttribute extends @xmlattribute, XMLLocatable {
|
class XmlAttribute extends @xmlattribute, XmlLocatable {
|
||||||
/** Gets the name of this attribute. */
|
/** Gets the name of this attribute. */
|
||||||
string getName() { xmlAttrs(this, _, result, _, _, _) }
|
string getName() { xmlAttrs(this, _, result, _, _, _) }
|
||||||
|
|
||||||
/** Gets the XML element to which this attribute belongs. */
|
/** Gets the XML element to which this attribute belongs. */
|
||||||
XMLElement getElement() { xmlAttrs(this, result, _, _, _, _) }
|
XmlElement getElement() { xmlAttrs(this, result, _, _, _, _) }
|
||||||
|
|
||||||
/** Holds if this attribute has a namespace. */
|
/** Holds if this attribute has a namespace. */
|
||||||
predicate hasNamespace() { xmlHasNs(this, _, _) }
|
predicate hasNamespace() { xmlHasNs(this, _, _) }
|
||||||
|
|
||||||
/** Gets the namespace of this attribute, if any. */
|
/** Gets the namespace of this attribute, if any. */
|
||||||
XMLNamespace getNamespace() { xmlHasNs(this, result, _) }
|
XmlNamespace getNamespace() { xmlHasNs(this, result, _) }
|
||||||
|
|
||||||
/** Gets the value of this attribute. */
|
/** Gets the value of this attribute. */
|
||||||
string getValue() { xmlAttrs(this, _, _, result, _, _) }
|
string getValue() { xmlAttrs(this, _, _, result, _, _) }
|
||||||
@@ -250,6 +268,9 @@ class XMLAttribute extends @xmlattribute, XMLLocatable {
|
|||||||
override string toString() { result = this.getName() + "=" + this.getValue() }
|
override string toString() { result = this.getName() + "=" + this.getValue() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for XmlAttribute */
|
||||||
|
deprecated class XMLAttribute = XmlAttribute;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A namespace used in an XML file.
|
* A namespace used in an XML file.
|
||||||
*
|
*
|
||||||
@@ -259,23 +280,29 @@ class XMLAttribute extends @xmlattribute, XMLLocatable {
|
|||||||
* xmlns:android="http://schemas.android.com/apk/res/android"
|
* xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
class XMLNamespace extends XMLLocatable, @xmlnamespace {
|
class XmlNamespace extends XmlLocatable, @xmlnamespace {
|
||||||
/** Gets the prefix of this namespace. */
|
/** Gets the prefix of this namespace. */
|
||||||
string getPrefix() { xmlNs(this, result, _, _) }
|
string getPrefix() { xmlNs(this, result, _, _) }
|
||||||
|
|
||||||
/** Gets the URI of this namespace. */
|
/** Gets the URI of this namespace. */
|
||||||
string getURI() { xmlNs(this, _, result, _) }
|
string getUri() { xmlNs(this, _, result, _) }
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for getUri */
|
||||||
|
deprecated string getURI() { result = this.getUri() }
|
||||||
|
|
||||||
/** Holds if this namespace has no prefix. */
|
/** Holds if this namespace has no prefix. */
|
||||||
predicate isDefault() { this.getPrefix() = "" }
|
predicate isDefault() { this.getPrefix() = "" }
|
||||||
|
|
||||||
override string toString() {
|
override string toString() {
|
||||||
this.isDefault() and result = this.getURI()
|
this.isDefault() and result = this.getUri()
|
||||||
or
|
or
|
||||||
not this.isDefault() and result = this.getPrefix() + ":" + this.getURI()
|
not this.isDefault() and result = this.getPrefix() + ":" + this.getUri()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for XmlNamespace */
|
||||||
|
deprecated class XMLNamespace = XmlNamespace;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A comment in an XML file.
|
* A comment in an XML file.
|
||||||
*
|
*
|
||||||
@@ -285,17 +312,20 @@ class XMLNamespace extends XMLLocatable, @xmlnamespace {
|
|||||||
* <!-- This is a comment. -->
|
* <!-- This is a comment. -->
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
class XMLComment extends @xmlcomment, XMLLocatable {
|
class XmlComment extends @xmlcomment, XmlLocatable {
|
||||||
/** Gets the text content of this XML comment. */
|
/** Gets the text content of this XML comment. */
|
||||||
string getText() { xmlComments(this, result, _, _) }
|
string getText() { xmlComments(this, result, _, _) }
|
||||||
|
|
||||||
/** Gets the parent of this XML comment. */
|
/** Gets the parent of this XML comment. */
|
||||||
XMLParent getParent() { xmlComments(this, _, result, _) }
|
XmlParent getParent() { xmlComments(this, _, result, _) }
|
||||||
|
|
||||||
/** Gets a printable representation of this XML comment. */
|
/** Gets a printable representation of this XML comment. */
|
||||||
override string toString() { result = this.getText() }
|
override string toString() { result = this.getText() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for XmlComment */
|
||||||
|
deprecated class XMLComment = XmlComment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A sequence of characters that occurs between opening and
|
* A sequence of characters that occurs between opening and
|
||||||
* closing tags of an XML element, excluding other elements.
|
* closing tags of an XML element, excluding other elements.
|
||||||
@@ -306,12 +336,12 @@ class XMLComment extends @xmlcomment, XMLLocatable {
|
|||||||
* <content>This is a sequence of characters.</content>
|
* <content>This is a sequence of characters.</content>
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
class XMLCharacters extends @xmlcharacters, XMLLocatable {
|
class XmlCharacters extends @xmlcharacters, XmlLocatable {
|
||||||
/** Gets the content of this character sequence. */
|
/** Gets the content of this character sequence. */
|
||||||
string getCharacters() { xmlChars(this, result, _, _, _, _) }
|
string getCharacters() { xmlChars(this, result, _, _, _, _) }
|
||||||
|
|
||||||
/** Gets the parent of this character sequence. */
|
/** Gets the parent of this character sequence. */
|
||||||
XMLParent getParent() { xmlChars(this, _, result, _, _, _) }
|
XmlParent getParent() { xmlChars(this, _, result, _, _, _) }
|
||||||
|
|
||||||
/** Holds if this character sequence is CDATA. */
|
/** Holds if this character sequence is CDATA. */
|
||||||
predicate isCDATA() { xmlChars(this, _, _, _, 1, _) }
|
predicate isCDATA() { xmlChars(this, _, _, _, 1, _) }
|
||||||
@@ -319,3 +349,6 @@ class XMLCharacters extends @xmlcharacters, XMLLocatable {
|
|||||||
/** Gets a printable representation of this XML character sequence. */
|
/** Gets a printable representation of this XML character sequence. */
|
||||||
override string toString() { result = this.getCharacters() }
|
override string toString() { result = this.getCharacters() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for XmlCharacters */
|
||||||
|
deprecated class XMLCharacters = XmlCharacters;
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ class BasicBlock extends ControlFlowNodeBase {
|
|||||||
exists(Function f | f.getBlock() = this)
|
exists(Function f | f.getBlock() = this)
|
||||||
or
|
or
|
||||||
exists(TryStmt t, BasicBlock tryblock |
|
exists(TryStmt t, BasicBlock tryblock |
|
||||||
// a `Handler` preceeds the `CatchBlock`, and is always the beginning
|
// a `Handler` precedes the `CatchBlock`, and is always the beginning
|
||||||
// of a new `BasicBlock` (see `primitive_basic_block_entry_node`).
|
// of a new `BasicBlock` (see `primitive_basic_block_entry_node`).
|
||||||
this.(Handler).getTryStmt() = t and
|
this.(Handler).getTryStmt() = t and
|
||||||
tryblock.isReachable() and
|
tryblock.isReachable() and
|
||||||
|
|||||||
@@ -3061,7 +3061,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
|||||||
else cc instanceof CallContextAny
|
else cc instanceof CallContextAny
|
||||||
) and
|
) and
|
||||||
sc instanceof SummaryCtxNone and
|
sc instanceof SummaryCtxNone and
|
||||||
ap instanceof AccessPathNil
|
ap = TAccessPathNil(node.getDataFlowType())
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate isAtSink() {
|
predicate isAtSink() {
|
||||||
|
|||||||
@@ -3061,7 +3061,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
|||||||
else cc instanceof CallContextAny
|
else cc instanceof CallContextAny
|
||||||
) and
|
) and
|
||||||
sc instanceof SummaryCtxNone and
|
sc instanceof SummaryCtxNone and
|
||||||
ap instanceof AccessPathNil
|
ap = TAccessPathNil(node.getDataFlowType())
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate isAtSink() {
|
predicate isAtSink() {
|
||||||
|
|||||||
@@ -3061,7 +3061,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
|||||||
else cc instanceof CallContextAny
|
else cc instanceof CallContextAny
|
||||||
) and
|
) and
|
||||||
sc instanceof SummaryCtxNone and
|
sc instanceof SummaryCtxNone and
|
||||||
ap instanceof AccessPathNil
|
ap = TAccessPathNil(node.getDataFlowType())
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate isAtSink() {
|
predicate isAtSink() {
|
||||||
|
|||||||
@@ -3061,7 +3061,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
|||||||
else cc instanceof CallContextAny
|
else cc instanceof CallContextAny
|
||||||
) and
|
) and
|
||||||
sc instanceof SummaryCtxNone and
|
sc instanceof SummaryCtxNone and
|
||||||
ap instanceof AccessPathNil
|
ap = TAccessPathNil(node.getDataFlowType())
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate isAtSink() {
|
predicate isAtSink() {
|
||||||
|
|||||||
@@ -3061,7 +3061,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
|||||||
else cc instanceof CallContextAny
|
else cc instanceof CallContextAny
|
||||||
) and
|
) and
|
||||||
sc instanceof SummaryCtxNone and
|
sc instanceof SummaryCtxNone and
|
||||||
ap instanceof AccessPathNil
|
ap = TAccessPathNil(node.getDataFlowType())
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate isAtSink() {
|
predicate isAtSink() {
|
||||||
|
|||||||
@@ -47,6 +47,20 @@ class AssignExpr extends Assignment, @assignexpr {
|
|||||||
override string toString() { result = "... = ..." }
|
override string toString() { result = "... = ..." }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A compiler generated assignment operation that may occur in a compiler generated
|
||||||
|
* copy/move constructor or assignment operator, and which functions like `memcpy`
|
||||||
|
* where the size argument is based on the type of the rvalue of the assignment.
|
||||||
|
*/
|
||||||
|
class BlockAssignExpr extends Assignment, @blockassignexpr {
|
||||||
|
override string getOperator() { result = "=" }
|
||||||
|
|
||||||
|
override string getAPrimaryQlClass() { result = "BlockAssignExpr" }
|
||||||
|
|
||||||
|
/** Gets a textual representation of this assignment. */
|
||||||
|
override string toString() { result = "... = ..." }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A non-overloaded binary assignment operation other than `=`.
|
* A non-overloaded binary assignment operation other than `=`.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -3061,7 +3061,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
|||||||
else cc instanceof CallContextAny
|
else cc instanceof CallContextAny
|
||||||
) and
|
) and
|
||||||
sc instanceof SummaryCtxNone and
|
sc instanceof SummaryCtxNone and
|
||||||
ap instanceof AccessPathNil
|
ap = TAccessPathNil(node.getDataFlowType())
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate isAtSink() {
|
predicate isAtSink() {
|
||||||
|
|||||||
@@ -3061,7 +3061,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
|||||||
else cc instanceof CallContextAny
|
else cc instanceof CallContextAny
|
||||||
) and
|
) and
|
||||||
sc instanceof SummaryCtxNone and
|
sc instanceof SummaryCtxNone and
|
||||||
ap instanceof AccessPathNil
|
ap = TAccessPathNil(node.getDataFlowType())
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate isAtSink() {
|
predicate isAtSink() {
|
||||||
|
|||||||
@@ -3061,7 +3061,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
|||||||
else cc instanceof CallContextAny
|
else cc instanceof CallContextAny
|
||||||
) and
|
) and
|
||||||
sc instanceof SummaryCtxNone and
|
sc instanceof SummaryCtxNone and
|
||||||
ap instanceof AccessPathNil
|
ap = TAccessPathNil(node.getDataFlowType())
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate isAtSink() {
|
predicate isAtSink() {
|
||||||
|
|||||||
@@ -3061,7 +3061,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
|||||||
else cc instanceof CallContextAny
|
else cc instanceof CallContextAny
|
||||||
) and
|
) and
|
||||||
sc instanceof SummaryCtxNone and
|
sc instanceof SummaryCtxNone and
|
||||||
ap instanceof AccessPathNil
|
ap = TAccessPathNil(node.getDataFlowType())
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate isAtSink() {
|
predicate isAtSink() {
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ private module Liveness {
|
|||||||
/**
|
/**
|
||||||
* Holds if the `i`th node of basic block `bb` is a reference to `v` of kind `k`.
|
* Holds if the `i`th node of basic block `bb` is a reference to `v` of kind `k`.
|
||||||
*/
|
*/
|
||||||
private predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) {
|
predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) {
|
||||||
exists(boolean certain | variableRead(bb, i, v, certain) | k = Read(certain))
|
exists(boolean certain | variableRead(bb, i, v, certain) | k = Read(certain))
|
||||||
or
|
or
|
||||||
exists(boolean certain | variableWrite(bb, i, v, certain) | k = Write(certain))
|
exists(boolean certain | variableWrite(bb, i, v, certain) | k = Write(certain))
|
||||||
@@ -76,6 +76,10 @@ private module Liveness {
|
|||||||
not result + 1 = refRank(bb, _, v, _)
|
not result + 1 = refRank(bb, _, v, _)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
predicate lastRefIsRead(BasicBlock bb, SourceVariable v) {
|
||||||
|
maxRefRank(bb, v) = refRank(bb, _, v, Read(_))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the (1-based) rank of the first reference to `v` inside basic block `bb`
|
* Gets the (1-based) rank of the first reference to `v` inside basic block `bb`
|
||||||
* that is either a read or a certain write.
|
* that is either a read or a certain write.
|
||||||
@@ -185,23 +189,29 @@ newtype TDefinition =
|
|||||||
|
|
||||||
private module SsaDefReaches {
|
private module SsaDefReaches {
|
||||||
newtype TSsaRefKind =
|
newtype TSsaRefKind =
|
||||||
SsaRead() or
|
SsaActualRead() or
|
||||||
|
SsaPhiRead() or
|
||||||
SsaDef()
|
SsaDef()
|
||||||
|
|
||||||
|
class SsaRead = SsaActualRead or SsaPhiRead;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A classification of SSA variable references into reads and definitions.
|
* A classification of SSA variable references into reads and definitions.
|
||||||
*/
|
*/
|
||||||
class SsaRefKind extends TSsaRefKind {
|
class SsaRefKind extends TSsaRefKind {
|
||||||
string toString() {
|
string toString() {
|
||||||
this = SsaRead() and
|
this = SsaActualRead() and
|
||||||
result = "SsaRead"
|
result = "SsaActualRead"
|
||||||
|
or
|
||||||
|
this = SsaPhiRead() and
|
||||||
|
result = "SsaPhiRead"
|
||||||
or
|
or
|
||||||
this = SsaDef() and
|
this = SsaDef() and
|
||||||
result = "SsaDef"
|
result = "SsaDef"
|
||||||
}
|
}
|
||||||
|
|
||||||
int getOrder() {
|
int getOrder() {
|
||||||
this = SsaRead() and
|
this instanceof SsaRead and
|
||||||
result = 0
|
result = 0
|
||||||
or
|
or
|
||||||
this = SsaDef() and
|
this = SsaDef() and
|
||||||
@@ -209,6 +219,80 @@ private module SsaDefReaches {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `bb` is in the dominance frontier of a block containing a
|
||||||
|
* read of `v`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate inReadDominanceFrontier(BasicBlock bb, SourceVariable v) {
|
||||||
|
exists(BasicBlock readbb | inDominanceFrontier(readbb, bb) |
|
||||||
|
lastRefIsRead(readbb, v)
|
||||||
|
or
|
||||||
|
phiRead(readbb, v)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if a phi-read node should be inserted for variable `v` at the beginning
|
||||||
|
* of basic block `bb`.
|
||||||
|
*
|
||||||
|
* Phi-read nodes are like normal phi nodes, but they are inserted based on reads
|
||||||
|
* instead of writes, and only if the dominance-frontier block does not already
|
||||||
|
* contain a reference (read or write) to `v`. Unlike normal phi nodes, this is
|
||||||
|
* an internal implementation detail that is not exposed.
|
||||||
|
*
|
||||||
|
* The motivation for adding phi-reads is to improve performance of the use-use
|
||||||
|
* calculation in cases where there is a large number of reads that can reach the
|
||||||
|
* same join-point, and from there reach a large number of basic blocks. Example:
|
||||||
|
*
|
||||||
|
* ```cs
|
||||||
|
* if (a)
|
||||||
|
* use(x);
|
||||||
|
* else if (b)
|
||||||
|
* use(x);
|
||||||
|
* else if (c)
|
||||||
|
* use(x);
|
||||||
|
* else if (d)
|
||||||
|
* use(x);
|
||||||
|
* // many more ifs ...
|
||||||
|
*
|
||||||
|
* // phi-read for `x` inserted here
|
||||||
|
*
|
||||||
|
* // program not mentioning `x`, with large basic block graph
|
||||||
|
*
|
||||||
|
* use(x);
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Without phi-reads, the analysis has to replicate reachability for each of
|
||||||
|
* the guarded uses of `x`. However, with phi-reads, the analysis will limit
|
||||||
|
* each conditional use of `x` to reach the basic block containing the phi-read
|
||||||
|
* node for `x`, and only that basic block will have to compute reachability
|
||||||
|
* through the remainder of the large program.
|
||||||
|
*
|
||||||
|
* Like normal reads, each phi-read node `phi-read` can be reached from exactly
|
||||||
|
* one SSA definition (without passing through another definition): Assume, for
|
||||||
|
* the sake of contradiction, that there are two reaching definitions `def1` and
|
||||||
|
* `def2`. Now, if both `def1` and `def2` dominate `phi-read`, then the nearest
|
||||||
|
* dominating definition will prevent the other from reaching `phi-read`. So, at
|
||||||
|
* least one of `def1` and `def2` cannot dominate `phi-read`; assume it is `def1`.
|
||||||
|
* Then `def1` must go through one of its dominance-frontier blocks in order to
|
||||||
|
* reach `phi-read`. However, such a block will always start with a (normal) phi
|
||||||
|
* node, which contradicts reachability.
|
||||||
|
*
|
||||||
|
* Also, like normal reads, the unique SSA definition `def` that reaches `phi-read`,
|
||||||
|
* will dominate `phi-read`. Assuming it doesn't means that the path from `def`
|
||||||
|
* to `phi-read` goes through a dominance-frontier block, and hence a phi node,
|
||||||
|
* which contradicts reachability.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate phiRead(BasicBlock bb, SourceVariable v) {
|
||||||
|
inReadDominanceFrontier(bb, v) and
|
||||||
|
liveAtEntry(bb, v) and
|
||||||
|
// only if there are no other references to `v` inside `bb`
|
||||||
|
not ref(bb, _, v, _) and
|
||||||
|
not exists(Definition def | def.definesAt(v, bb, _))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the `i`th node of basic block `bb` is a reference to `v`,
|
* Holds if the `i`th node of basic block `bb` is a reference to `v`,
|
||||||
* either a read (when `k` is `SsaRead()`) or an SSA definition (when `k`
|
* either a read (when `k` is `SsaRead()`) or an SSA definition (when `k`
|
||||||
@@ -216,11 +300,16 @@ private module SsaDefReaches {
|
|||||||
*
|
*
|
||||||
* Unlike `Liveness::ref`, this includes `phi` nodes.
|
* Unlike `Liveness::ref`, this includes `phi` nodes.
|
||||||
*/
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
predicate ssaRef(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) {
|
predicate ssaRef(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) {
|
||||||
variableRead(bb, i, v, _) and
|
variableRead(bb, i, v, _) and
|
||||||
k = SsaRead()
|
k = SsaActualRead()
|
||||||
or
|
or
|
||||||
exists(Definition def | def.definesAt(v, bb, i)) and
|
phiRead(bb, v) and
|
||||||
|
i = -1 and
|
||||||
|
k = SsaPhiRead()
|
||||||
|
or
|
||||||
|
any(Definition def).definesAt(v, bb, i) and
|
||||||
k = SsaDef()
|
k = SsaDef()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,7 +362,7 @@ private module SsaDefReaches {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
ssaDefReachesRank(bb, def, rnk - 1, v) and
|
ssaDefReachesRank(bb, def, rnk - 1, v) and
|
||||||
rnk = ssaRefRank(bb, _, v, SsaRead())
|
rnk = ssaRefRank(bb, _, v, any(SsaRead k))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -283,7 +372,7 @@ private module SsaDefReaches {
|
|||||||
predicate ssaDefReachesReadWithinBlock(SourceVariable v, Definition def, BasicBlock bb, int i) {
|
predicate ssaDefReachesReadWithinBlock(SourceVariable v, Definition def, BasicBlock bb, int i) {
|
||||||
exists(int rnk |
|
exists(int rnk |
|
||||||
ssaDefReachesRank(bb, def, rnk, v) and
|
ssaDefReachesRank(bb, def, rnk, v) and
|
||||||
rnk = ssaRefRank(bb, i, v, SsaRead())
|
rnk = ssaRefRank(bb, i, v, any(SsaRead k))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,45 +398,94 @@ private module SsaDefReaches {
|
|||||||
ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v)
|
ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v) {
|
predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v, SsaRefKind k) {
|
||||||
exists(ssaDefRank(def, v, bb, _, _))
|
exists(ssaDefRank(def, v, bb, _, k))
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate ssaDefReachesThroughBlock(Definition def, BasicBlock bb) {
|
private predicate ssaDefReachesThroughBlock(Definition def, BasicBlock bb) {
|
||||||
ssaDefReachesEndOfBlock(bb, def, _) and
|
ssaDefReachesEndOfBlock(bb, def, _) and
|
||||||
not defOccursInBlock(_, bb, def.getSourceVariable())
|
not defOccursInBlock(_, bb, def.getSourceVariable(), _)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `def` is accessed in basic block `bb1` (either a read or a write),
|
* Holds if `def` is accessed in basic block `bb1` (either a read or a write),
|
||||||
* `bb2` is a transitive successor of `bb1`, `def` is live at the end of `bb1`,
|
* `bb2` is a transitive successor of `bb1`, `def` is live at the end of _some_
|
||||||
* and the underlying variable for `def` is neither read nor written in any block
|
* predecessor of `bb2`, and the underlying variable for `def` is neither read
|
||||||
* on the path between `bb1` and `bb2`.
|
* nor written in any block on the path between `bb1` and `bb2`.
|
||||||
|
*
|
||||||
|
* Phi reads are considered as normal reads for this predicate.
|
||||||
*/
|
*/
|
||||||
predicate varBlockReaches(Definition def, BasicBlock bb1, BasicBlock bb2) {
|
pragma[nomagic]
|
||||||
defOccursInBlock(def, bb1, _) and
|
private predicate varBlockReachesInclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) {
|
||||||
|
defOccursInBlock(def, bb1, _, _) and
|
||||||
bb2 = getABasicBlockSuccessor(bb1)
|
bb2 = getABasicBlockSuccessor(bb1)
|
||||||
or
|
or
|
||||||
exists(BasicBlock mid |
|
exists(BasicBlock mid |
|
||||||
varBlockReaches(def, bb1, mid) and
|
varBlockReachesInclPhiRead(def, bb1, mid) and
|
||||||
ssaDefReachesThroughBlock(def, mid) and
|
ssaDefReachesThroughBlock(def, mid) and
|
||||||
bb2 = getABasicBlockSuccessor(mid)
|
bb2 = getABasicBlockSuccessor(mid)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate phiReadStep(Definition def, SourceVariable v, BasicBlock bb1, BasicBlock bb2) {
|
||||||
|
varBlockReachesInclPhiRead(def, bb1, bb2) and
|
||||||
|
defOccursInBlock(def, bb2, v, SsaPhiRead())
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate varBlockReachesExclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) {
|
||||||
|
varBlockReachesInclPhiRead(pragma[only_bind_into](def), bb1, pragma[only_bind_into](bb2)) and
|
||||||
|
ssaRef(bb2, _, def.getSourceVariable(), [SsaActualRead().(TSsaRefKind), SsaDef()])
|
||||||
|
or
|
||||||
|
exists(BasicBlock mid |
|
||||||
|
varBlockReachesExclPhiRead(def, mid, bb2) and
|
||||||
|
phiReadStep(def, _, bb1, mid)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `def` is accessed in basic block `bb1` (either a read or a write),
|
* Holds if `def` is accessed in basic block `bb1` (either a read or a write),
|
||||||
* `def` is read at index `i2` in basic block `bb2`, `bb2` is in a transitive
|
* the underlying variable `v` of `def` is accessed in basic block `bb2`
|
||||||
* successor block of `bb1`, and `def` is neither read nor written in any block
|
* (either a read or a write), `bb2` is a transitive successor of `bb1`, and
|
||||||
* on a path between `bb1` and `bb2`.
|
* `v` is neither read nor written in any block on the path between `bb1`
|
||||||
|
* and `bb2`.
|
||||||
*/
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate varBlockReaches(Definition def, BasicBlock bb1, BasicBlock bb2) {
|
||||||
|
varBlockReachesExclPhiRead(def, bb1, bb2) and
|
||||||
|
not defOccursInBlock(def, bb1, _, SsaPhiRead())
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) {
|
predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) {
|
||||||
varBlockReaches(def, bb1, bb2) and
|
varBlockReaches(def, bb1, bb2) and
|
||||||
ssaRefRank(bb2, i2, def.getSourceVariable(), SsaRead()) = 1
|
ssaRefRank(bb2, i2, def.getSourceVariable(), SsaActualRead()) = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `def` is accessed in basic block `bb` (either a read or a write),
|
||||||
|
* `bb1` can reach a transitive successor `bb2` where `def` is no longer live,
|
||||||
|
* and `v` is neither read nor written in any block on the path between `bb`
|
||||||
|
* and `bb2`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate varBlockReachesExit(Definition def, BasicBlock bb) {
|
||||||
|
exists(BasicBlock bb2 | varBlockReachesInclPhiRead(def, bb, bb2) |
|
||||||
|
not defOccursInBlock(def, bb2, _, _) and
|
||||||
|
not ssaDefReachesEndOfBlock(bb2, def, _)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
exists(BasicBlock mid |
|
||||||
|
varBlockReachesExit(def, mid) and
|
||||||
|
phiReadStep(def, _, bb, mid)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
predicate phiReadExposedForTesting = phiRead/2;
|
||||||
|
|
||||||
private import SsaDefReaches
|
private import SsaDefReaches
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -365,7 +503,8 @@ predicate liveThrough(BasicBlock bb, SourceVariable v) {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) {
|
predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) {
|
||||||
exists(int last | last = maxSsaRefRank(bb, v) |
|
exists(int last |
|
||||||
|
last = maxSsaRefRank(pragma[only_bind_into](bb), pragma[only_bind_into](v)) and
|
||||||
ssaDefReachesRank(bb, def, last, v) and
|
ssaDefReachesRank(bb, def, last, v) and
|
||||||
liveAtExit(bb, v)
|
liveAtExit(bb, v)
|
||||||
)
|
)
|
||||||
@@ -405,7 +544,7 @@ pragma[nomagic]
|
|||||||
predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int i) {
|
predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int i) {
|
||||||
ssaDefReachesReadWithinBlock(v, def, bb, i)
|
ssaDefReachesReadWithinBlock(v, def, bb, i)
|
||||||
or
|
or
|
||||||
variableRead(bb, i, v, _) and
|
ssaRef(bb, i, v, any(SsaRead k)) and
|
||||||
ssaDefReachesEndOfBlock(getABasicBlockPredecessor(bb), def, v) and
|
ssaDefReachesEndOfBlock(getABasicBlockPredecessor(bb), def, v) and
|
||||||
not ssaDefReachesReadWithinBlock(v, _, bb, i)
|
not ssaDefReachesReadWithinBlock(v, _, bb, i)
|
||||||
}
|
}
|
||||||
@@ -421,7 +560,7 @@ pragma[nomagic]
|
|||||||
predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) {
|
predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) {
|
||||||
exists(int rnk |
|
exists(int rnk |
|
||||||
rnk = ssaDefRank(def, _, bb1, i1, _) and
|
rnk = ssaDefRank(def, _, bb1, i1, _) and
|
||||||
rnk + 1 = ssaDefRank(def, _, bb1, i2, SsaRead()) and
|
rnk + 1 = ssaDefRank(def, _, bb1, i2, SsaActualRead()) and
|
||||||
variableRead(bb1, i2, _, _) and
|
variableRead(bb1, i2, _, _) and
|
||||||
bb2 = bb1
|
bb2 = bb1
|
||||||
)
|
)
|
||||||
@@ -538,18 +677,15 @@ predicate lastRefRedefNoUncertainReads(Definition def, BasicBlock bb, int i, Def
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate lastRef(Definition def, BasicBlock bb, int i) {
|
predicate lastRef(Definition def, BasicBlock bb, int i) {
|
||||||
|
// Can reach another definition
|
||||||
lastRefRedef(def, bb, i, _)
|
lastRefRedef(def, bb, i, _)
|
||||||
or
|
or
|
||||||
lastSsaRef(def, _, bb, i) and
|
exists(SourceVariable v | lastSsaRef(def, v, bb, i) |
|
||||||
(
|
|
||||||
// Can reach exit directly
|
// Can reach exit directly
|
||||||
bb instanceof ExitBasicBlock
|
bb instanceof ExitBasicBlock
|
||||||
or
|
or
|
||||||
// Can reach a block using one or more steps, where `def` is no longer live
|
// Can reach a block using one or more steps, where `def` is no longer live
|
||||||
exists(BasicBlock bb2 | varBlockReaches(def, bb, bb2) |
|
varBlockReachesExit(def, bb)
|
||||||
not defOccursInBlock(def, bb2, _) and
|
|
||||||
not ssaDefReachesEndOfBlock(bb2, def, _)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ module InstructionConsistency {
|
|||||||
abstract Language::Location getLocation();
|
abstract Language::Location getLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
|
class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
|
||||||
private IRFunction irFunc;
|
private IRFunction irFunc;
|
||||||
|
|
||||||
PresentIRFunction() { this = TPresentIRFunction(irFunc) }
|
PresentIRFunction() { this = TPresentIRFunction(irFunc) }
|
||||||
@@ -37,6 +37,8 @@ module InstructionConsistency {
|
|||||||
result =
|
result =
|
||||||
min(Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString())
|
min(Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IRFunction getIRFunction() { result = irFunc }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction {
|
private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction {
|
||||||
|
|||||||
@@ -1712,6 +1712,11 @@ class SideEffectInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class CallSideEffectInstruction extends SideEffectInstruction {
|
class CallSideEffectInstruction extends SideEffectInstruction {
|
||||||
CallSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallSideEffect }
|
CallSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallSideEffect }
|
||||||
|
|
||||||
|
/** Gets the operand for the value that will be read by this instruction */
|
||||||
|
final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() }
|
||||||
|
|
||||||
|
final Instruction getSideEffect() { result = this.getAnOperand().getDef() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1723,6 +1728,11 @@ class CallSideEffectInstruction extends SideEffectInstruction {
|
|||||||
*/
|
*/
|
||||||
class CallReadSideEffectInstruction extends SideEffectInstruction {
|
class CallReadSideEffectInstruction extends SideEffectInstruction {
|
||||||
CallReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallReadSideEffect }
|
CallReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallReadSideEffect }
|
||||||
|
|
||||||
|
/** Gets the operand for the value that will be read by this instruction */
|
||||||
|
final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() }
|
||||||
|
|
||||||
|
final Instruction getSideEffect() { result = this.getAnOperand().getDef() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
import semmle.code.cpp.ir.implementation.aliased_ssa.IR
|
import semmle.code.cpp.ir.implementation.aliased_ssa.IR
|
||||||
import semmle.code.cpp.ir.internal.Overlap
|
import semmle.code.cpp.ir.internal.Overlap
|
||||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||||
|
import semmle.code.cpp.models.interfaces.SideEffect as SideEffect
|
||||||
|
|||||||
@@ -41,8 +41,92 @@ newtype TValueNumber =
|
|||||||
) {
|
) {
|
||||||
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
|
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
|
||||||
} or
|
} or
|
||||||
|
TCallValueNumber(TCallPartialValueNumber vn) { callValueNumber(_, _, vn) } or
|
||||||
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
||||||
|
|
||||||
|
private class NumberableCallInstruction extends CallInstruction {
|
||||||
|
NumberableCallInstruction() {
|
||||||
|
not this.getResultIRType() instanceof IRVoidType and
|
||||||
|
exists(SideEffect::SideEffectFunction sideEffectFunc |
|
||||||
|
sideEffectFunc = this.getStaticCallTarget()
|
||||||
|
|
|
||||||
|
sideEffectFunc.hasOnlySpecificReadSideEffects() and
|
||||||
|
sideEffectFunc.hasOnlySpecificWriteSideEffects()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private newtype TCallPartialValueNumber =
|
||||||
|
TNilArgument() or
|
||||||
|
TArgument(TCallPartialValueNumber head, TValueNumber arg) {
|
||||||
|
exists(NumberableCallInstruction call, int index |
|
||||||
|
callArgValueNumber(call, index, arg) and
|
||||||
|
callPartialValueNumber(call, index, head)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate callValueNumber(
|
||||||
|
NumberableCallInstruction call, int index, TCallPartialValueNumber vn
|
||||||
|
) {
|
||||||
|
index = max(int n | callArgRank(call, n, _) | n) and
|
||||||
|
exists(TCallPartialValueNumber head, TValueNumber arg |
|
||||||
|
callPartialValueNumber(call, index, pragma[only_bind_out](head)) and
|
||||||
|
callArgValueNumber(call, index, pragma[only_bind_into](arg)) and
|
||||||
|
vn = TArgument(head, arg)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
not exists(int n | callArgRank(call, n, _)) and
|
||||||
|
index = -1 and
|
||||||
|
vn = TNilArgument()
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate callPartialValueNumber(
|
||||||
|
NumberableCallInstruction call, int index, TCallPartialValueNumber head
|
||||||
|
) {
|
||||||
|
exists(call) and
|
||||||
|
index = 1 and
|
||||||
|
head = TNilArgument()
|
||||||
|
or
|
||||||
|
exists(TCallPartialValueNumber prev, TValueNumber prevVN |
|
||||||
|
callPartialValueNumber(call, index - 1, pragma[only_bind_out](prev)) and
|
||||||
|
callArgValueNumber(call, index - 1, pragma[only_bind_into](prevVN)) and
|
||||||
|
head = TArgument(prev, prevVN)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
private predicate callArgValueNumber(NumberableCallInstruction call, int index, TValueNumber arg) {
|
||||||
|
exists(Instruction instr |
|
||||||
|
callArgRank(call, index, instr) and
|
||||||
|
arg = tvalueNumber(instr)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `arg` is the `index`th element in `call`'s extended argument list, including the `this`
|
||||||
|
* argument and side-effect reads.
|
||||||
|
*/
|
||||||
|
private predicate callArgRank(NumberableCallInstruction call, int index, Instruction arg) {
|
||||||
|
arg =
|
||||||
|
rank[index](int argIndex, boolean isEffect, Instruction instr |
|
||||||
|
// There is no need to include the call's read and write side effects on
|
||||||
|
// all-aliased-memory as `NumberableCallInstruction`s do not read or write
|
||||||
|
// to all-aliased-memory.
|
||||||
|
instr = call.getArgument(argIndex) and
|
||||||
|
isEffect = false
|
||||||
|
or
|
||||||
|
exists(ReadSideEffectInstruction read |
|
||||||
|
read.getPrimaryInstruction() = call and
|
||||||
|
read.getSideEffectOperand().getAnyDef() = instr and
|
||||||
|
read.getIndex() = argIndex and
|
||||||
|
isEffect = true
|
||||||
|
)
|
||||||
|
|
|
||||||
|
instr order by argIndex, isEffect
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
|
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
|
||||||
* operand.
|
* operand.
|
||||||
@@ -93,6 +177,8 @@ private predicate numberableInstruction(Instruction instr) {
|
|||||||
instr instanceof CongruentCopyInstruction
|
instr instanceof CongruentCopyInstruction
|
||||||
or
|
or
|
||||||
instr instanceof LoadTotalOverlapInstruction
|
instr instanceof LoadTotalOverlapInstruction
|
||||||
|
or
|
||||||
|
instr instanceof NumberableCallInstruction
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate filteredNumberableInstruction(Instruction instr) {
|
private predicate filteredNumberableInstruction(Instruction instr) {
|
||||||
@@ -309,6 +395,11 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
|||||||
or
|
or
|
||||||
// The value number of a copy is just the value number of its source value.
|
// The value number of a copy is just the value number of its source value.
|
||||||
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||||
|
or
|
||||||
|
exists(TCallPartialValueNumber pvn |
|
||||||
|
callValueNumber(instr, _, pvn) and
|
||||||
|
result = TCallValueNumber(pvn)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import semmle.code.cpp.ir.internal.Overlap
|
|||||||
private import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
private import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||||
private import semmle.code.cpp.Print
|
private import semmle.code.cpp.Print
|
||||||
private import semmle.code.cpp.ir.implementation.unaliased_ssa.IR
|
private import semmle.code.cpp.ir.implementation.unaliased_ssa.IR
|
||||||
private import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConstruction as OldSSA
|
private import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConstruction as OldSsa
|
||||||
private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
|
private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
|
||||||
private import semmle.code.cpp.ir.internal.IntegerInterval as Interval
|
private import semmle.code.cpp.ir.internal.IntegerInterval as Interval
|
||||||
private import semmle.code.cpp.ir.implementation.internal.OperandTag
|
private import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||||
@@ -572,7 +572,7 @@ private Overlap getVariableMemoryLocationOverlap(
|
|||||||
* Holds if the def/use information for the result of `instr` can be reused from the previous
|
* Holds if the def/use information for the result of `instr` can be reused from the previous
|
||||||
* iteration of the IR.
|
* iteration of the IR.
|
||||||
*/
|
*/
|
||||||
predicate canReuseSsaForOldResult(Instruction instr) { OldSSA::canReuseSsaForMemoryResult(instr) }
|
predicate canReuseSsaForOldResult(Instruction instr) { OldSsa::canReuseSsaForMemoryResult(instr) }
|
||||||
|
|
||||||
/** DEPRECATED: Alias for canReuseSsaForOldResult */
|
/** DEPRECATED: Alias for canReuseSsaForOldResult */
|
||||||
deprecated predicate canReuseSSAForOldResult = canReuseSsaForOldResult/1;
|
deprecated predicate canReuseSSAForOldResult = canReuseSsaForOldResult/1;
|
||||||
|
|||||||
@@ -5,14 +5,9 @@ private import Imports::OperandTag
|
|||||||
private import Imports::Overlap
|
private import Imports::Overlap
|
||||||
private import Imports::TInstruction
|
private import Imports::TInstruction
|
||||||
private import Imports::RawIR as RawIR
|
private import Imports::RawIR as RawIR
|
||||||
private import SSAInstructions
|
private import SsaInstructions
|
||||||
private import SSAOperands
|
private import SsaOperands
|
||||||
private import NewIR
|
private import NewIR
|
||||||
|
|
||||||
private class OldBlock = Reachability::ReachableBlock;
|
|
||||||
|
|
||||||
private class OldInstruction = Reachability::ReachableInstruction;
|
|
||||||
|
|
||||||
import Cached
|
import Cached
|
||||||
|
|
||||||
cached
|
cached
|
||||||
@@ -58,7 +53,9 @@ private module Cached {
|
|||||||
|
|
||||||
cached
|
cached
|
||||||
predicate hasInstruction(TStageInstruction instr) {
|
predicate hasInstruction(TStageInstruction instr) {
|
||||||
instr instanceof TRawInstruction and instr instanceof OldInstruction
|
instr instanceof TRawInstruction and
|
||||||
|
instr instanceof OldInstruction and
|
||||||
|
not removedInstruction(instr)
|
||||||
or
|
or
|
||||||
instr = phiInstruction(_, _)
|
instr = phiInstruction(_, _)
|
||||||
or
|
or
|
||||||
@@ -382,7 +379,14 @@ private module Cached {
|
|||||||
(
|
(
|
||||||
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
|
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
|
||||||
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
|
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
|
||||||
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
else
|
||||||
|
if removedInstruction(oldInstruction.getSuccessor(kind))
|
||||||
|
then
|
||||||
|
// the only removed nodes are side-effect writes, but those may have Chi nodes
|
||||||
|
// skip to the following instruction in the old IR, which won't be removed
|
||||||
|
// if we start skipping specific side effects, this may no longer hold
|
||||||
|
result = getNewInstruction(oldInstruction.getSuccessor(kind).getSuccessor(kind))
|
||||||
|
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
|||||||
@@ -2,7 +2,26 @@ import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as OldIR
|
|||||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.ReachableBlock as Reachability
|
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.ReachableBlock as Reachability
|
||||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.Dominance as Dominance
|
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.Dominance as Dominance
|
||||||
import semmle.code.cpp.ir.implementation.aliased_ssa.IR as NewIR
|
import semmle.code.cpp.ir.implementation.aliased_ssa.IR as NewIR
|
||||||
import semmle.code.cpp.ir.implementation.internal.TInstruction::AliasedSsaInstructions as SSAInstructions
|
import semmle.code.cpp.ir.implementation.internal.TInstruction::AliasedSsaInstructions as SsaInstructions
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for SsaInstructions */
|
||||||
|
deprecated module SSAInstructions = SsaInstructions;
|
||||||
|
|
||||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||||
import AliasedSSA as Alias
|
import AliasedSSA as Alias
|
||||||
import semmle.code.cpp.ir.implementation.internal.TOperand::AliasedSsaOperands as SSAOperands
|
import semmle.code.cpp.ir.implementation.internal.TOperand::AliasedSsaOperands as SsaOperands
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for SsaOperands */
|
||||||
|
deprecated module SSAOperands = SsaOperands;
|
||||||
|
|
||||||
|
private import SideEffectElimination as Elim
|
||||||
|
|
||||||
|
predicate removedInstruction(Reachability::ReachableInstruction instr) {
|
||||||
|
Elim::removeableSideEffect(instr)
|
||||||
|
}
|
||||||
|
|
||||||
|
class OldBlock = Reachability::ReachableBlock;
|
||||||
|
|
||||||
|
class OldInstruction extends Reachability::ReachableInstruction {
|
||||||
|
OldInstruction() { not Elim::removeableSideEffect(this) }
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import cpp as CPP
|
||||||
|
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as Unaliased
|
||||||
|
import AliasAnalysis as Alias
|
||||||
|
import AliasConfiguration as Conf
|
||||||
|
import semmle.code.cpp.models.interfaces.SideEffect as SideEffect
|
||||||
|
|
||||||
|
private predicate noLocalSideEffectWrite(CPP::Function func) {
|
||||||
|
forall(Unaliased::AddressOperand addr | addr.getUse().getEnclosingFunction() = func |
|
||||||
|
not (
|
||||||
|
Alias::getAddressOperandAllocation(addr) instanceof Conf::VariableAllocation and
|
||||||
|
Alias::getAddressOperandAllocation(addr).(Conf::VariableAllocation).alwaysEscapes()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
language[monotonicAggregates]
|
||||||
|
private predicate noTransitiveSideEffectWrite(CPP::Function func) {
|
||||||
|
exists(Unaliased::IRFunction irFunc | irFunc.getFunction() = func) and
|
||||||
|
noLocalSideEffectWrite(func) and
|
||||||
|
forall(Unaliased::CallInstruction call | call.getEnclosingFunction() = func |
|
||||||
|
exists(call.getStaticCallTarget())
|
||||||
|
) and
|
||||||
|
forall(Unaliased::CallInstruction call, CPP::Function callee |
|
||||||
|
call.getStaticCallTarget() = callee and
|
||||||
|
call.getEnclosingFunction() = func
|
||||||
|
|
|
||||||
|
noTransitiveSideEffectWrite(callee)
|
||||||
|
or
|
||||||
|
callee.(SideEffect::SideEffectFunction).hasOnlySpecificWriteSideEffects()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate removeableSideEffect(Unaliased::SideEffectInstruction instr) {
|
||||||
|
(
|
||||||
|
instr instanceof Unaliased::CallSideEffectInstruction or
|
||||||
|
instr instanceof Unaliased::CallReadSideEffectInstruction
|
||||||
|
) and
|
||||||
|
noTransitiveSideEffectWrite(instr
|
||||||
|
.getPrimaryInstruction()
|
||||||
|
.(Unaliased::CallInstruction)
|
||||||
|
.getStaticCallTarget())
|
||||||
|
}
|
||||||
@@ -29,15 +29,16 @@ newtype TInstruction =
|
|||||||
UnaliasedSsa::SSA::hasUnreachedInstruction(irFunc)
|
UnaliasedSsa::SSA::hasUnreachedInstruction(irFunc)
|
||||||
} or
|
} or
|
||||||
TAliasedSsaPhiInstruction(
|
TAliasedSsaPhiInstruction(
|
||||||
TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation
|
TRawInstruction blockStartInstr, AliasedSsa::SSA::MemoryLocation memoryLocation
|
||||||
) {
|
) {
|
||||||
AliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation)
|
AliasedSsa::SSA::hasPhiInstruction(blockStartInstr, memoryLocation)
|
||||||
} or
|
} or
|
||||||
TAliasedSsaChiInstruction(TRawInstruction primaryInstruction) {
|
TAliasedSsaChiInstruction(TRawInstruction primaryInstruction) {
|
||||||
AliasedSSA::SSA::hasChiInstruction(primaryInstruction)
|
not AliasedSsa::removedInstruction(primaryInstruction) and
|
||||||
|
AliasedSsa::SSA::hasChiInstruction(primaryInstruction)
|
||||||
} or
|
} or
|
||||||
TAliasedSsaUnreachedInstruction(IRFunctionBase irFunc) {
|
TAliasedSsaUnreachedInstruction(IRFunctionBase irFunc) {
|
||||||
AliasedSSA::SSA::hasUnreachedInstruction(irFunc)
|
AliasedSsa::SSA::hasUnreachedInstruction(irFunc)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -83,7 +84,7 @@ module AliasedSsaInstructions {
|
|||||||
class TPhiInstruction = TAliasedSsaPhiInstruction or TUnaliasedSsaPhiInstruction;
|
class TPhiInstruction = TAliasedSsaPhiInstruction or TUnaliasedSsaPhiInstruction;
|
||||||
|
|
||||||
TPhiInstruction phiInstruction(
|
TPhiInstruction phiInstruction(
|
||||||
TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation
|
TRawInstruction blockStartInstr, AliasedSsa::SSA::MemoryLocation memoryLocation
|
||||||
) {
|
) {
|
||||||
result = TAliasedSsaPhiInstruction(blockStartInstr, memoryLocation)
|
result = TAliasedSsaPhiInstruction(blockStartInstr, memoryLocation)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||||
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
|
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
|
||||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedSsa
|
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedSsa
|
||||||
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSAConstruction as AliasedSSA
|
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSAConstruction as AliasedSsa
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for AliasedSsa */
|
||||||
|
deprecated module AliasedSSA = AliasedSsa;
|
||||||
|
|
||||||
|
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SideEffectElimination as Elim
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ module InstructionConsistency {
|
|||||||
abstract Language::Location getLocation();
|
abstract Language::Location getLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
|
class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
|
||||||
private IRFunction irFunc;
|
private IRFunction irFunc;
|
||||||
|
|
||||||
PresentIRFunction() { this = TPresentIRFunction(irFunc) }
|
PresentIRFunction() { this = TPresentIRFunction(irFunc) }
|
||||||
@@ -37,6 +37,8 @@ module InstructionConsistency {
|
|||||||
result =
|
result =
|
||||||
min(Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString())
|
min(Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IRFunction getIRFunction() { result = irFunc }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction {
|
private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction {
|
||||||
|
|||||||
@@ -1712,6 +1712,11 @@ class SideEffectInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class CallSideEffectInstruction extends SideEffectInstruction {
|
class CallSideEffectInstruction extends SideEffectInstruction {
|
||||||
CallSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallSideEffect }
|
CallSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallSideEffect }
|
||||||
|
|
||||||
|
/** Gets the operand for the value that will be read by this instruction */
|
||||||
|
final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() }
|
||||||
|
|
||||||
|
final Instruction getSideEffect() { result = this.getAnOperand().getDef() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1723,6 +1728,11 @@ class CallSideEffectInstruction extends SideEffectInstruction {
|
|||||||
*/
|
*/
|
||||||
class CallReadSideEffectInstruction extends SideEffectInstruction {
|
class CallReadSideEffectInstruction extends SideEffectInstruction {
|
||||||
CallReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallReadSideEffect }
|
CallReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallReadSideEffect }
|
||||||
|
|
||||||
|
/** Gets the operand for the value that will be read by this instruction */
|
||||||
|
final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() }
|
||||||
|
|
||||||
|
final Instruction getSideEffect() { result = this.getAnOperand().getDef() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
import semmle.code.cpp.ir.implementation.aliased_ssa.IR
|
import semmle.code.cpp.ir.implementation.aliased_ssa.IR
|
||||||
import semmle.code.cpp.ir.internal.Overlap
|
import semmle.code.cpp.ir.internal.Overlap
|
||||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||||
|
import semmle.code.cpp.models.interfaces.SideEffect as SideEffect
|
||||||
|
|||||||
@@ -41,8 +41,92 @@ newtype TValueNumber =
|
|||||||
) {
|
) {
|
||||||
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
|
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
|
||||||
} or
|
} or
|
||||||
|
TCallValueNumber(TCallPartialValueNumber vn) { callValueNumber(_, _, vn) } or
|
||||||
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
||||||
|
|
||||||
|
private class NumberableCallInstruction extends CallInstruction {
|
||||||
|
NumberableCallInstruction() {
|
||||||
|
not this.getResultIRType() instanceof IRVoidType and
|
||||||
|
exists(SideEffect::SideEffectFunction sideEffectFunc |
|
||||||
|
sideEffectFunc = this.getStaticCallTarget()
|
||||||
|
|
|
||||||
|
sideEffectFunc.hasOnlySpecificReadSideEffects() and
|
||||||
|
sideEffectFunc.hasOnlySpecificWriteSideEffects()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private newtype TCallPartialValueNumber =
|
||||||
|
TNilArgument() or
|
||||||
|
TArgument(TCallPartialValueNumber head, TValueNumber arg) {
|
||||||
|
exists(NumberableCallInstruction call, int index |
|
||||||
|
callArgValueNumber(call, index, arg) and
|
||||||
|
callPartialValueNumber(call, index, head)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate callValueNumber(
|
||||||
|
NumberableCallInstruction call, int index, TCallPartialValueNumber vn
|
||||||
|
) {
|
||||||
|
index = max(int n | callArgRank(call, n, _) | n) and
|
||||||
|
exists(TCallPartialValueNumber head, TValueNumber arg |
|
||||||
|
callPartialValueNumber(call, index, pragma[only_bind_out](head)) and
|
||||||
|
callArgValueNumber(call, index, pragma[only_bind_into](arg)) and
|
||||||
|
vn = TArgument(head, arg)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
not exists(int n | callArgRank(call, n, _)) and
|
||||||
|
index = -1 and
|
||||||
|
vn = TNilArgument()
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate callPartialValueNumber(
|
||||||
|
NumberableCallInstruction call, int index, TCallPartialValueNumber head
|
||||||
|
) {
|
||||||
|
exists(call) and
|
||||||
|
index = 1 and
|
||||||
|
head = TNilArgument()
|
||||||
|
or
|
||||||
|
exists(TCallPartialValueNumber prev, TValueNumber prevVN |
|
||||||
|
callPartialValueNumber(call, index - 1, pragma[only_bind_out](prev)) and
|
||||||
|
callArgValueNumber(call, index - 1, pragma[only_bind_into](prevVN)) and
|
||||||
|
head = TArgument(prev, prevVN)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
private predicate callArgValueNumber(NumberableCallInstruction call, int index, TValueNumber arg) {
|
||||||
|
exists(Instruction instr |
|
||||||
|
callArgRank(call, index, instr) and
|
||||||
|
arg = tvalueNumber(instr)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `arg` is the `index`th element in `call`'s extended argument list, including the `this`
|
||||||
|
* argument and side-effect reads.
|
||||||
|
*/
|
||||||
|
private predicate callArgRank(NumberableCallInstruction call, int index, Instruction arg) {
|
||||||
|
arg =
|
||||||
|
rank[index](int argIndex, boolean isEffect, Instruction instr |
|
||||||
|
// There is no need to include the call's read and write side effects on
|
||||||
|
// all-aliased-memory as `NumberableCallInstruction`s do not read or write
|
||||||
|
// to all-aliased-memory.
|
||||||
|
instr = call.getArgument(argIndex) and
|
||||||
|
isEffect = false
|
||||||
|
or
|
||||||
|
exists(ReadSideEffectInstruction read |
|
||||||
|
read.getPrimaryInstruction() = call and
|
||||||
|
read.getSideEffectOperand().getAnyDef() = instr and
|
||||||
|
read.getIndex() = argIndex and
|
||||||
|
isEffect = true
|
||||||
|
)
|
||||||
|
|
|
||||||
|
instr order by argIndex, isEffect
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
|
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
|
||||||
* operand.
|
* operand.
|
||||||
@@ -93,6 +177,8 @@ private predicate numberableInstruction(Instruction instr) {
|
|||||||
instr instanceof CongruentCopyInstruction
|
instr instanceof CongruentCopyInstruction
|
||||||
or
|
or
|
||||||
instr instanceof LoadTotalOverlapInstruction
|
instr instanceof LoadTotalOverlapInstruction
|
||||||
|
or
|
||||||
|
instr instanceof NumberableCallInstruction
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate filteredNumberableInstruction(Instruction instr) {
|
private predicate filteredNumberableInstruction(Instruction instr) {
|
||||||
@@ -309,6 +395,11 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
|||||||
or
|
or
|
||||||
// The value number of a copy is just the value number of its source value.
|
// The value number of a copy is just the value number of its source value.
|
||||||
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||||
|
or
|
||||||
|
exists(TCallPartialValueNumber pvn |
|
||||||
|
callValueNumber(instr, _, pvn) and
|
||||||
|
result = TCallValueNumber(pvn)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1450,8 +1450,6 @@ class TranslatedAssignExpr extends TranslatedNonConstantExpr {
|
|||||||
result = this.getLeftOperand().getResult()
|
result = this.getLeftOperand().getResult()
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract Instruction getStoredValue();
|
|
||||||
|
|
||||||
final TranslatedExpr getLeftOperand() {
|
final TranslatedExpr getLeftOperand() {
|
||||||
result = getTranslatedExpr(expr.getLValue().getFullyConverted())
|
result = getTranslatedExpr(expr.getLValue().getFullyConverted())
|
||||||
}
|
}
|
||||||
@@ -1493,6 +1491,75 @@ class TranslatedAssignExpr extends TranslatedNonConstantExpr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TranslatedBlockAssignExpr extends TranslatedNonConstantExpr {
|
||||||
|
override BlockAssignExpr expr;
|
||||||
|
|
||||||
|
final override TranslatedElement getChild(int id) {
|
||||||
|
id = 0 and result = this.getLeftOperand()
|
||||||
|
or
|
||||||
|
id = 1 and result = this.getRightOperand()
|
||||||
|
}
|
||||||
|
|
||||||
|
final override Instruction getFirstInstruction() {
|
||||||
|
// The operand evaluation order should not matter since block assignments behave like memcpy.
|
||||||
|
result = this.getLeftOperand().getFirstInstruction()
|
||||||
|
}
|
||||||
|
|
||||||
|
final override Instruction getResult() { result = this.getInstruction(AssignmentStoreTag()) }
|
||||||
|
|
||||||
|
final TranslatedExpr getLeftOperand() {
|
||||||
|
result = getTranslatedExpr(expr.getLValue().getFullyConverted())
|
||||||
|
}
|
||||||
|
|
||||||
|
final TranslatedExpr getRightOperand() {
|
||||||
|
result = getTranslatedExpr(expr.getRValue().getFullyConverted())
|
||||||
|
}
|
||||||
|
|
||||||
|
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||||
|
tag = LoadTag() and
|
||||||
|
result = this.getInstruction(AssignmentStoreTag()) and
|
||||||
|
kind instanceof GotoEdge
|
||||||
|
or
|
||||||
|
tag = AssignmentStoreTag() and
|
||||||
|
result = this.getParent().getChildSuccessor(this) and
|
||||||
|
kind instanceof GotoEdge
|
||||||
|
}
|
||||||
|
|
||||||
|
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||||
|
child = this.getLeftOperand() and
|
||||||
|
result = this.getRightOperand().getFirstInstruction()
|
||||||
|
or
|
||||||
|
child = this.getRightOperand() and
|
||||||
|
result = this.getInstruction(LoadTag())
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||||
|
tag = LoadTag() and
|
||||||
|
opcode instanceof Opcode::Load and
|
||||||
|
resultType = getTypeForPRValue(expr.getRValue().getType())
|
||||||
|
or
|
||||||
|
tag = AssignmentStoreTag() and
|
||||||
|
opcode instanceof Opcode::Store and
|
||||||
|
// The frontend specifies that the relevant type is the one of the source.
|
||||||
|
resultType = getTypeForPRValue(expr.getRValue().getType())
|
||||||
|
}
|
||||||
|
|
||||||
|
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
|
||||||
|
tag = LoadTag() and
|
||||||
|
operandTag instanceof AddressOperandTag and
|
||||||
|
result = this.getRightOperand().getResult()
|
||||||
|
or
|
||||||
|
tag = AssignmentStoreTag() and
|
||||||
|
(
|
||||||
|
operandTag instanceof AddressOperandTag and
|
||||||
|
result = this.getLeftOperand().getResult()
|
||||||
|
or
|
||||||
|
operandTag instanceof StoreValueOperandTag and
|
||||||
|
result = this.getInstruction(LoadTag())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class TranslatedAssignOperation extends TranslatedNonConstantExpr {
|
class TranslatedAssignOperation extends TranslatedNonConstantExpr {
|
||||||
override AssignOperation expr;
|
override AssignOperation expr;
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ module InstructionConsistency {
|
|||||||
abstract Language::Location getLocation();
|
abstract Language::Location getLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
|
class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
|
||||||
private IRFunction irFunc;
|
private IRFunction irFunc;
|
||||||
|
|
||||||
PresentIRFunction() { this = TPresentIRFunction(irFunc) }
|
PresentIRFunction() { this = TPresentIRFunction(irFunc) }
|
||||||
@@ -37,6 +37,8 @@ module InstructionConsistency {
|
|||||||
result =
|
result =
|
||||||
min(Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString())
|
min(Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IRFunction getIRFunction() { result = irFunc }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction {
|
private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction {
|
||||||
|
|||||||
@@ -1712,6 +1712,11 @@ class SideEffectInstruction extends Instruction {
|
|||||||
*/
|
*/
|
||||||
class CallSideEffectInstruction extends SideEffectInstruction {
|
class CallSideEffectInstruction extends SideEffectInstruction {
|
||||||
CallSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallSideEffect }
|
CallSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallSideEffect }
|
||||||
|
|
||||||
|
/** Gets the operand for the value that will be read by this instruction */
|
||||||
|
final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() }
|
||||||
|
|
||||||
|
final Instruction getSideEffect() { result = this.getAnOperand().getDef() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1723,6 +1728,11 @@ class CallSideEffectInstruction extends SideEffectInstruction {
|
|||||||
*/
|
*/
|
||||||
class CallReadSideEffectInstruction extends SideEffectInstruction {
|
class CallReadSideEffectInstruction extends SideEffectInstruction {
|
||||||
CallReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallReadSideEffect }
|
CallReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallReadSideEffect }
|
||||||
|
|
||||||
|
/** Gets the operand for the value that will be read by this instruction */
|
||||||
|
final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() }
|
||||||
|
|
||||||
|
final Instruction getSideEffect() { result = this.getAnOperand().getDef() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
import semmle.code.cpp.ir.implementation.aliased_ssa.IR
|
import semmle.code.cpp.ir.implementation.aliased_ssa.IR
|
||||||
import semmle.code.cpp.ir.internal.Overlap
|
import semmle.code.cpp.ir.internal.Overlap
|
||||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||||
|
import semmle.code.cpp.models.interfaces.SideEffect as SideEffect
|
||||||
|
|||||||
@@ -41,8 +41,92 @@ newtype TValueNumber =
|
|||||||
) {
|
) {
|
||||||
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
|
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
|
||||||
} or
|
} or
|
||||||
|
TCallValueNumber(TCallPartialValueNumber vn) { callValueNumber(_, _, vn) } or
|
||||||
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
||||||
|
|
||||||
|
private class NumberableCallInstruction extends CallInstruction {
|
||||||
|
NumberableCallInstruction() {
|
||||||
|
not this.getResultIRType() instanceof IRVoidType and
|
||||||
|
exists(SideEffect::SideEffectFunction sideEffectFunc |
|
||||||
|
sideEffectFunc = this.getStaticCallTarget()
|
||||||
|
|
|
||||||
|
sideEffectFunc.hasOnlySpecificReadSideEffects() and
|
||||||
|
sideEffectFunc.hasOnlySpecificWriteSideEffects()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private newtype TCallPartialValueNumber =
|
||||||
|
TNilArgument() or
|
||||||
|
TArgument(TCallPartialValueNumber head, TValueNumber arg) {
|
||||||
|
exists(NumberableCallInstruction call, int index |
|
||||||
|
callArgValueNumber(call, index, arg) and
|
||||||
|
callPartialValueNumber(call, index, head)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate callValueNumber(
|
||||||
|
NumberableCallInstruction call, int index, TCallPartialValueNumber vn
|
||||||
|
) {
|
||||||
|
index = max(int n | callArgRank(call, n, _) | n) and
|
||||||
|
exists(TCallPartialValueNumber head, TValueNumber arg |
|
||||||
|
callPartialValueNumber(call, index, pragma[only_bind_out](head)) and
|
||||||
|
callArgValueNumber(call, index, pragma[only_bind_into](arg)) and
|
||||||
|
vn = TArgument(head, arg)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
not exists(int n | callArgRank(call, n, _)) and
|
||||||
|
index = -1 and
|
||||||
|
vn = TNilArgument()
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate callPartialValueNumber(
|
||||||
|
NumberableCallInstruction call, int index, TCallPartialValueNumber head
|
||||||
|
) {
|
||||||
|
exists(call) and
|
||||||
|
index = 1 and
|
||||||
|
head = TNilArgument()
|
||||||
|
or
|
||||||
|
exists(TCallPartialValueNumber prev, TValueNumber prevVN |
|
||||||
|
callPartialValueNumber(call, index - 1, pragma[only_bind_out](prev)) and
|
||||||
|
callArgValueNumber(call, index - 1, pragma[only_bind_into](prevVN)) and
|
||||||
|
head = TArgument(prev, prevVN)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
private predicate callArgValueNumber(NumberableCallInstruction call, int index, TValueNumber arg) {
|
||||||
|
exists(Instruction instr |
|
||||||
|
callArgRank(call, index, instr) and
|
||||||
|
arg = tvalueNumber(instr)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `arg` is the `index`th element in `call`'s extended argument list, including the `this`
|
||||||
|
* argument and side-effect reads.
|
||||||
|
*/
|
||||||
|
private predicate callArgRank(NumberableCallInstruction call, int index, Instruction arg) {
|
||||||
|
arg =
|
||||||
|
rank[index](int argIndex, boolean isEffect, Instruction instr |
|
||||||
|
// There is no need to include the call's read and write side effects on
|
||||||
|
// all-aliased-memory as `NumberableCallInstruction`s do not read or write
|
||||||
|
// to all-aliased-memory.
|
||||||
|
instr = call.getArgument(argIndex) and
|
||||||
|
isEffect = false
|
||||||
|
or
|
||||||
|
exists(ReadSideEffectInstruction read |
|
||||||
|
read.getPrimaryInstruction() = call and
|
||||||
|
read.getSideEffectOperand().getAnyDef() = instr and
|
||||||
|
read.getIndex() = argIndex and
|
||||||
|
isEffect = true
|
||||||
|
)
|
||||||
|
|
|
||||||
|
instr order by argIndex, isEffect
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
|
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
|
||||||
* operand.
|
* operand.
|
||||||
@@ -93,6 +177,8 @@ private predicate numberableInstruction(Instruction instr) {
|
|||||||
instr instanceof CongruentCopyInstruction
|
instr instanceof CongruentCopyInstruction
|
||||||
or
|
or
|
||||||
instr instanceof LoadTotalOverlapInstruction
|
instr instanceof LoadTotalOverlapInstruction
|
||||||
|
or
|
||||||
|
instr instanceof NumberableCallInstruction
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate filteredNumberableInstruction(Instruction instr) {
|
private predicate filteredNumberableInstruction(Instruction instr) {
|
||||||
@@ -309,6 +395,11 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
|||||||
or
|
or
|
||||||
// The value number of a copy is just the value number of its source value.
|
// The value number of a copy is just the value number of its source value.
|
||||||
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||||
|
or
|
||||||
|
exists(TCallPartialValueNumber pvn |
|
||||||
|
callValueNumber(instr, _, pvn) and
|
||||||
|
result = TCallValueNumber(pvn)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,14 +5,9 @@ private import Imports::OperandTag
|
|||||||
private import Imports::Overlap
|
private import Imports::Overlap
|
||||||
private import Imports::TInstruction
|
private import Imports::TInstruction
|
||||||
private import Imports::RawIR as RawIR
|
private import Imports::RawIR as RawIR
|
||||||
private import SSAInstructions
|
private import SsaInstructions
|
||||||
private import SSAOperands
|
private import SsaOperands
|
||||||
private import NewIR
|
private import NewIR
|
||||||
|
|
||||||
private class OldBlock = Reachability::ReachableBlock;
|
|
||||||
|
|
||||||
private class OldInstruction = Reachability::ReachableInstruction;
|
|
||||||
|
|
||||||
import Cached
|
import Cached
|
||||||
|
|
||||||
cached
|
cached
|
||||||
@@ -58,7 +53,9 @@ private module Cached {
|
|||||||
|
|
||||||
cached
|
cached
|
||||||
predicate hasInstruction(TStageInstruction instr) {
|
predicate hasInstruction(TStageInstruction instr) {
|
||||||
instr instanceof TRawInstruction and instr instanceof OldInstruction
|
instr instanceof TRawInstruction and
|
||||||
|
instr instanceof OldInstruction and
|
||||||
|
not removedInstruction(instr)
|
||||||
or
|
or
|
||||||
instr = phiInstruction(_, _)
|
instr = phiInstruction(_, _)
|
||||||
or
|
or
|
||||||
@@ -382,7 +379,14 @@ private module Cached {
|
|||||||
(
|
(
|
||||||
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
|
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
|
||||||
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
|
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
|
||||||
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
else
|
||||||
|
if removedInstruction(oldInstruction.getSuccessor(kind))
|
||||||
|
then
|
||||||
|
// the only removed nodes are side-effect writes, but those may have Chi nodes
|
||||||
|
// skip to the following instruction in the old IR, which won't be removed
|
||||||
|
// if we start skipping specific side effects, this may no longer hold
|
||||||
|
result = getNewInstruction(oldInstruction.getSuccessor(kind).getSuccessor(kind))
|
||||||
|
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
|||||||
@@ -3,7 +3,20 @@ import semmle.code.cpp.ir.implementation.raw.internal.reachability.ReachableBloc
|
|||||||
import semmle.code.cpp.ir.implementation.raw.internal.reachability.Dominance as Dominance
|
import semmle.code.cpp.ir.implementation.raw.internal.reachability.Dominance as Dominance
|
||||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as NewIR
|
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as NewIR
|
||||||
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as RawStage
|
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as RawStage
|
||||||
import semmle.code.cpp.ir.implementation.internal.TInstruction::UnaliasedSsaInstructions as SSAInstructions
|
import semmle.code.cpp.ir.implementation.internal.TInstruction::UnaliasedSsaInstructions as SsaInstructions
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for SsaInstructions */
|
||||||
|
deprecated module SSAInstructions = SsaInstructions;
|
||||||
|
|
||||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||||
import SimpleSSA as Alias
|
import SimpleSSA as Alias
|
||||||
import semmle.code.cpp.ir.implementation.internal.TOperand::UnaliasedSsaOperands as SSAOperands
|
import semmle.code.cpp.ir.implementation.internal.TOperand::UnaliasedSsaOperands as SsaOperands
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for SsaOperands */
|
||||||
|
deprecated module SSAOperands = SsaOperands;
|
||||||
|
|
||||||
|
predicate removedInstruction(Reachability::ReachableInstruction instr) { none() }
|
||||||
|
|
||||||
|
class OldBlock = Reachability::ReachableBlock;
|
||||||
|
|
||||||
|
class OldInstruction = Reachability::ReachableInstruction;
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ private class CallAllocationExpr extends AllocationExpr, FunctionCall {
|
|||||||
exists(target.getReallocPtrArg()) and
|
exists(target.getReallocPtrArg()) and
|
||||||
this.getArgument(target.getSizeArg()).getValue().toInt() = 0
|
this.getArgument(target.getSizeArg()).getValue().toInt() = 0
|
||||||
) and
|
) and
|
||||||
// these are modelled directly (and more accurately), avoid duplication
|
// these are modeled directly (and more accurately), avoid duplication
|
||||||
not exists(NewOrNewArrayExpr new | new.getAllocatorCall() = this)
|
not exists(NewOrNewArrayExpr new | new.getAllocatorCall() = this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,12 +11,6 @@ private class StdPair extends ClassTemplateInstantiation {
|
|||||||
StdPair() { this.hasQualifiedName(["std", "bsl"], "pair") }
|
StdPair() { this.hasQualifiedName(["std", "bsl"], "pair") }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: This is now called `StdPair` and is a private part of the
|
|
||||||
* library implementation.
|
|
||||||
*/
|
|
||||||
deprecated class StdPairClass = StdPair;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Any of the single-parameter constructors of `std::pair` that takes a reference to an
|
* Any of the single-parameter constructors of `std::pair` that takes a reference to an
|
||||||
* instantiation of `std::pair`. These constructors allow conversion between pair types when the
|
* instantiation of `std::pair`. These constructors allow conversion between pair types when the
|
||||||
|
|||||||
@@ -27,13 +27,6 @@ abstract class RemoteFlowSourceFunction extends Function {
|
|||||||
predicate hasSocketInput(FunctionInput input) { none() }
|
predicate hasSocketInput(FunctionInput input) { none() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `RemoteFlowSourceFunction` instead.
|
|
||||||
*
|
|
||||||
* A library function that returns data that may be read from a network connection.
|
|
||||||
*/
|
|
||||||
deprecated class RemoteFlowFunction = RemoteFlowSourceFunction;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A library function that returns data that is directly controlled by a user.
|
* A library function that returns data that is directly controlled by a user.
|
||||||
*/
|
*/
|
||||||
@@ -44,13 +37,6 @@ abstract class LocalFlowSourceFunction extends Function {
|
|||||||
abstract predicate hasLocalFlowSource(FunctionOutput output, string description);
|
abstract predicate hasLocalFlowSource(FunctionOutput output, string description);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* DEPRECATED: Use `LocalFlowSourceFunction` instead.
|
|
||||||
*
|
|
||||||
* A library function that returns data that is directly controlled by a user.
|
|
||||||
*/
|
|
||||||
deprecated class LocalFlowFunction = LocalFlowSourceFunction;
|
|
||||||
|
|
||||||
/** A library function that sends data over a network connection. */
|
/** A library function that sends data over a network connection. */
|
||||||
abstract class RemoteFlowSinkFunction extends Function {
|
abstract class RemoteFlowSinkFunction extends Function {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ VariableAccess varUse(LocalScopeVariable v) { result = v.getAnAccess() }
|
|||||||
* Holds if `e` potentially overflows and `use` is an operand of `e` that is not guarded.
|
* Holds if `e` potentially overflows and `use` is an operand of `e` that is not guarded.
|
||||||
*/
|
*/
|
||||||
predicate missingGuardAgainstOverflow(Operation e, VariableAccess use) {
|
predicate missingGuardAgainstOverflow(Operation e, VariableAccess use) {
|
||||||
// Since `e` is guarenteed to be a `BinaryArithmeticOperation`, a `UnaryArithmeticOperation` or
|
// Since `e` is guaranteed to be a `BinaryArithmeticOperation`, a `UnaryArithmeticOperation` or
|
||||||
// an `AssignArithmeticOperation` by the other constraints in this predicate, we know that
|
// an `AssignArithmeticOperation` by the other constraints in this predicate, we know that
|
||||||
// `convertedExprMightOverflowPositively` will have a result even when `e` is not analyzable
|
// `convertedExprMightOverflowPositively` will have a result even when `e` is not analyzable
|
||||||
// by `SimpleRangeAnalysis`.
|
// by `SimpleRangeAnalysis`.
|
||||||
@@ -80,7 +80,7 @@ predicate missingGuardAgainstOverflow(Operation e, VariableAccess use) {
|
|||||||
* Holds if `e` potentially underflows and `use` is an operand of `e` that is not guarded.
|
* Holds if `e` potentially underflows and `use` is an operand of `e` that is not guarded.
|
||||||
*/
|
*/
|
||||||
predicate missingGuardAgainstUnderflow(Operation e, VariableAccess use) {
|
predicate missingGuardAgainstUnderflow(Operation e, VariableAccess use) {
|
||||||
// Since `e` is guarenteed to be a `BinaryArithmeticOperation`, a `UnaryArithmeticOperation` or
|
// Since `e` is guaranteed to be a `BinaryArithmeticOperation`, a `UnaryArithmeticOperation` or
|
||||||
// an `AssignArithmeticOperation` by the other constraints in this predicate, we know that
|
// an `AssignArithmeticOperation` by the other constraints in this predicate, we know that
|
||||||
// `convertedExprMightOverflowNegatively` will have a result even when `e` is not analyzable
|
// `convertedExprMightOverflowNegatively` will have a result even when `e` is not analyzable
|
||||||
// by `SimpleRangeAnalysis`.
|
// by `SimpleRangeAnalysis`.
|
||||||
|
|||||||
@@ -523,6 +523,11 @@ autoderivation(
|
|||||||
int derivation_type: @type ref
|
int derivation_type: @type ref
|
||||||
);
|
);
|
||||||
|
|
||||||
|
orphaned_variables(
|
||||||
|
int var: @localvariable ref,
|
||||||
|
int function: @function ref
|
||||||
|
)
|
||||||
|
|
||||||
enumconstants(
|
enumconstants(
|
||||||
unique int id: @enumconstant,
|
unique int id: @enumconstant,
|
||||||
int parent: @usertype ref,
|
int parent: @usertype ref,
|
||||||
@@ -1302,7 +1307,7 @@ funbind(
|
|||||||
|
|
||||||
@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr
|
@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr
|
||||||
|
|
||||||
@assign_expr = @assignexpr | @assign_op_expr
|
@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr
|
||||||
|
|
||||||
/*
|
/*
|
||||||
case @allocator.form of
|
case @allocator.form of
|
||||||
@@ -1660,6 +1665,7 @@ case @expr.kind of
|
|||||||
| 332 = @hasuniqueobjectrepresentations
|
| 332 = @hasuniqueobjectrepresentations
|
||||||
| 333 = @builtinbitcast
|
| 333 = @builtinbitcast
|
||||||
| 334 = @builtinshuffle
|
| 334 = @builtinshuffle
|
||||||
|
| 335 = @blockassignexpr
|
||||||
;
|
;
|
||||||
|
|
||||||
@var_args_expr = @vastartexpr
|
@var_args_expr = @vastartexpr
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
|||||||
|
description: Support block assignment
|
||||||
|
compatibility: backwards
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
|||||||
|
description: Add relation for orphaned local variables
|
||||||
|
compatibility: partial
|
||||||
@@ -29,7 +29,4 @@ where
|
|||||||
n = strictcount(ComplexStmt s | s = b.getAStmt()) and
|
n = strictcount(ComplexStmt s | s = b.getAStmt()) and
|
||||||
n > 3 and
|
n > 3 and
|
||||||
complexStmt = b.getAStmt()
|
complexStmt = b.getAStmt()
|
||||||
select b,
|
select b, "Block with too many statements (" + n.toString() + " complex statements in the block)."
|
||||||
"Block with too many statements (" + n.toString() +
|
|
||||||
" complex statements in the block). Complex statements at: $@", complexStmt,
|
|
||||||
complexStmt.toString()
|
|
||||||
|
|||||||
@@ -110,4 +110,4 @@ where
|
|||||||
emptyBlock(s, eb) and
|
emptyBlock(s, eb) and
|
||||||
not emptyBlockContainsNonchild(eb) and
|
not emptyBlockContainsNonchild(eb) and
|
||||||
not lineComment(eb)
|
not lineComment(eb)
|
||||||
select eb, "Empty block without comment"
|
select eb, "Empty block without comment."
|
||||||
|
|||||||
@@ -12,4 +12,4 @@
|
|||||||
import CommentedOutCode
|
import CommentedOutCode
|
||||||
|
|
||||||
from CommentedOutCode comment
|
from CommentedOutCode comment
|
||||||
select comment, "This comment appears to contain commented-out code"
|
select comment, "This comment appears to contain commented-out code."
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* @name Sign check of bitwise operation
|
* @name Sign check of bitwise operation
|
||||||
* @description Checking the sign of a bitwise operation often has surprising
|
* @description Checking the sign of the result of a bitwise operation may yield unexpected results.
|
||||||
* edge cases.
|
|
||||||
* @kind problem
|
* @kind problem
|
||||||
* @problem.severity warning
|
* @problem.severity warning
|
||||||
* @precision high
|
* @precision high
|
||||||
@@ -26,4 +25,4 @@ where
|
|||||||
forall(int op | op = lhs.(BitwiseAndExpr).getAnOperand().getValue().toInt() | op < 0) and
|
forall(int op | op = lhs.(BitwiseAndExpr).getAnOperand().getValue().toInt() | op < 0) and
|
||||||
// exception for cases involving macros
|
// exception for cases involving macros
|
||||||
not e.isAffectedByMacro()
|
not e.isAffectedByMacro()
|
||||||
select e, "Potential unsafe sign check of a bitwise operation."
|
select e, "Potentially unsafe sign check of a bitwise operation."
|
||||||
|
|||||||
@@ -21,4 +21,4 @@ where
|
|||||||
FloatingPointType and
|
FloatingPointType and
|
||||||
not ro.getAnOperand().isConstant() and // comparisons to constants generate too many false positives
|
not ro.getAnOperand().isConstant() and // comparisons to constants generate too many false positives
|
||||||
not left.(VariableAccess).getTarget() = right.(VariableAccess).getTarget() // skip self comparison
|
not left.(VariableAccess).getTarget() = right.(VariableAccess).getTarget() // skip self comparison
|
||||||
select ro, "Equality test on floating point values may not behave as expected."
|
select ro, "Equality checks on floating point values can yield unexpected results."
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ class BooleanControllingAssignmentInExpr extends BooleanControllingAssignment {
|
|||||||
// if((a = b) && use_value(a)) { ... }
|
// if((a = b) && use_value(a)) { ... }
|
||||||
// ```
|
// ```
|
||||||
// where the assignment is meant to update the value of `a` before it's used in some other boolean
|
// where the assignment is meant to update the value of `a` before it's used in some other boolean
|
||||||
// subexpression that is guarenteed to be evaluate _after_ the assignment.
|
// subexpression that is guaranteed to be evaluate _after_ the assignment.
|
||||||
this.isParenthesised() and
|
this.isParenthesised() and
|
||||||
exists(LogicalAndExpr parent, Variable var, VariableAccess access |
|
exists(LogicalAndExpr parent, Variable var, VariableAccess access |
|
||||||
var = this.getLValue().(VariableAccess).getTarget() and
|
var = this.getLValue().(VariableAccess).getTarget() and
|
||||||
|
|||||||
@@ -13,10 +13,11 @@
|
|||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
|
|
||||||
from EnumSwitch es, float missing, float total
|
from EnumSwitch es, float missing, float total, EnumConstant case
|
||||||
where
|
where
|
||||||
not es.hasDefaultCase() and
|
not es.hasDefaultCase() and
|
||||||
missing = count(es.getAMissingCase()) and
|
missing = count(es.getAMissingCase()) and
|
||||||
total = missing + count(es.getASwitchCase()) and
|
total = missing + count(es.getASwitchCase()) and
|
||||||
missing / total < 0.3
|
missing / total < 0.3 and
|
||||||
select es, "Switch statement is missing case for " + es.getAMissingCase().getName()
|
case = es.getAMissingCase()
|
||||||
|
select es, "Switch statement does not have a case for $@.", case, case.getName()
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ predicate illDefinedDecrForStmt(
|
|||||||
(
|
(
|
||||||
upperBound(initialCondition) < lowerBound(terminalCondition) and
|
upperBound(initialCondition) < lowerBound(terminalCondition) and
|
||||||
(
|
(
|
||||||
// exclude cases where the loop counter is `unsigned` (where wrapping behaviour can be used deliberately)
|
// exclude cases where the loop counter is `unsigned` (where wrapping behavior can be used deliberately)
|
||||||
v.getUnspecifiedType().(IntegralType).isSigned() or
|
v.getUnspecifiedType().(IntegralType).isSigned() or
|
||||||
initialCondition.getValue().toInt() = 0
|
initialCondition.getValue().toInt() = 0
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -106,6 +106,26 @@ predicate inheritanceConversionTypes(
|
|||||||
toType = convert.getResultType()
|
toType = convert.getResultType()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private signature class ConversionInstruction extends UnaryInstruction;
|
||||||
|
|
||||||
|
module Conversion<ConversionInstruction I> {
|
||||||
|
signature predicate hasTypes(I instr, Type fromType, Type toType);
|
||||||
|
|
||||||
|
module Using<hasTypes/3 project> {
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate hasOperandAndTypes(I convert, Instruction unary, Type fromType, Type toType) {
|
||||||
|
project(convert, fromType, toType) and
|
||||||
|
unary = convert.getUnary()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate hasObjectAndField(FieldAddressInstruction fai, Instruction object, Field f) {
|
||||||
|
fai.getObjectAddress() = object and
|
||||||
|
fai.getField() = f
|
||||||
|
}
|
||||||
|
|
||||||
/** Gets the HashCons value of an address computed by `instr`, if any. */
|
/** Gets the HashCons value of an address computed by `instr`, if any. */
|
||||||
TGlobalAddress globalAddress(Instruction instr) {
|
TGlobalAddress globalAddress(Instruction instr) {
|
||||||
result = TGlobalVariable(instr.(VariableAddressInstruction).getAstVariable())
|
result = TGlobalVariable(instr.(VariableAddressInstruction).getAstVariable())
|
||||||
@@ -117,25 +137,27 @@ TGlobalAddress globalAddress(Instruction instr) {
|
|||||||
result = TLoad(globalAddress(load.getSourceAddress()))
|
result = TLoad(globalAddress(load.getSourceAddress()))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(ConvertInstruction convert, Type fromType, Type toType | instr = convert |
|
exists(Type fromType, Type toType, Instruction unary |
|
||||||
uncheckedConversionTypes(convert, fromType, toType) and
|
Conversion<ConvertInstruction>::Using<uncheckedConversionTypes/3>::hasOperandAndTypes(instr,
|
||||||
result = TConversion("unchecked", globalAddress(convert.getUnary()), fromType, toType)
|
unary, fromType, toType) and
|
||||||
|
result = TConversion("unchecked", globalAddress(unary), fromType, toType)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(CheckedConvertOrNullInstruction convert, Type fromType, Type toType | instr = convert |
|
exists(Type fromType, Type toType, Instruction unary |
|
||||||
checkedConversionTypes(convert, fromType, toType) and
|
Conversion<CheckedConvertOrNullInstruction>::Using<checkedConversionTypes/3>::hasOperandAndTypes(instr,
|
||||||
result = TConversion("checked", globalAddress(convert.getUnary()), fromType, toType)
|
unary, fromType, toType) and
|
||||||
|
result = TConversion("checked", globalAddress(unary), fromType, toType)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(InheritanceConversionInstruction convert, Type fromType, Type toType | instr = convert |
|
exists(Type fromType, Type toType, Instruction unary |
|
||||||
inheritanceConversionTypes(convert, fromType, toType) and
|
Conversion<InheritanceConversionInstruction>::Using<inheritanceConversionTypes/3>::hasOperandAndTypes(instr,
|
||||||
result = TConversion("inheritance", globalAddress(convert.getUnary()), fromType, toType)
|
unary, fromType, toType) and
|
||||||
|
result = TConversion("inheritance", globalAddress(unary), fromType, toType)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(FieldAddressInstruction fai | instr = fai |
|
exists(FieldAddressInstruction fai, Instruction object, Field f | instr = fai |
|
||||||
result =
|
hasObjectAndField(fai, object, f) and
|
||||||
TFieldAddress(globalAddress(pragma[only_bind_into](fai.getObjectAddress())),
|
result = TFieldAddress(globalAddress(object), f)
|
||||||
pragma[only_bind_out](fai.getField()))
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
result = globalAddress(instr.(PointerOffsetInstruction).getLeft())
|
result = globalAddress(instr.(PointerOffsetInstruction).getLeft())
|
||||||
@@ -268,7 +290,11 @@ class PathElement extends TPathElement {
|
|||||||
predicate isSink(IRBlock block) { exists(this.asSink(block)) }
|
predicate isSink(IRBlock block) { exists(this.asSink(block)) }
|
||||||
|
|
||||||
string toString() {
|
string toString() {
|
||||||
result = [asStore().toString(), asCall(_).toString(), asMid().toString(), asSink(_).toString()]
|
result =
|
||||||
|
[
|
||||||
|
this.asStore().toString(), this.asCall(_).toString(), this.asMid().toString(),
|
||||||
|
this.asSink(_).toString()
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ Make sure that all classes with virtual functions also have a virtual destructor
|
|||||||
S. Meyers. <em>Effective C++ 3d ed.</em> pp 40-44. Addison-Wesley Professional, 2005.
|
S. Meyers. <em>Effective C++ 3d ed.</em> pp 40-44. Addison-Wesley Professional, 2005.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="http://blogs.msdn.com/b/oldnewthing/archive/2004/05/07/127826.aspx">When should your destructor be virtual?</a>
|
<a href="https://devblogs.microsoft.com/oldnewthing/20040507-00/?p=39443">When should your destructor be virtual?</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
43
cpp/ql/src/Metrics/Internal/IRConsistency.ql
Normal file
43
cpp/ql/src/Metrics/Internal/IRConsistency.ql
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
/**
|
||||||
|
* @name Count IR inconsistencies
|
||||||
|
* @description Counts the various IR inconsistencies that may occur.
|
||||||
|
* This query is for internal use only and may change without notice.
|
||||||
|
* @kind table
|
||||||
|
* @id cpp/count-ir-inconsistencies
|
||||||
|
*/
|
||||||
|
|
||||||
|
import cpp
|
||||||
|
import semmle.code.cpp.ir.implementation.aliased_ssa.IR
|
||||||
|
import semmle.code.cpp.ir.implementation.aliased_ssa.IRConsistency as IRConsistency
|
||||||
|
|
||||||
|
class PresentIRFunction extends IRConsistency::PresentIRFunction {
|
||||||
|
override string toString() {
|
||||||
|
result = min(string name | name = this.getIRFunction().getFunction().getQualifiedName() | name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
select count(Instruction i | IRConsistency::missingOperand(i, _, _, _) | i) as missingOperand,
|
||||||
|
count(Instruction i | IRConsistency::unexpectedOperand(i, _, _, _) | i) as unexpectedOperand,
|
||||||
|
count(Instruction i | IRConsistency::duplicateOperand(i, _, _, _) | i) as duplicateOperand,
|
||||||
|
count(PhiInstruction i | IRConsistency::missingPhiOperand(i, _, _, _) | i) as missingPhiOperand,
|
||||||
|
count(Operand o | IRConsistency::missingOperandType(o, _, _, _) | o) as missingOperandType,
|
||||||
|
count(ChiInstruction i | IRConsistency::duplicateChiOperand(i, _, _, _) | i) as duplicateChiOperand,
|
||||||
|
count(Instruction i | IRConsistency::sideEffectWithoutPrimary(i, _, _, _) | i) as sideEffectWithoutPrimary,
|
||||||
|
count(Instruction i | IRConsistency::instructionWithoutSuccessor(i, _, _, _) | i) as instructionWithoutSuccessor,
|
||||||
|
count(Instruction i | IRConsistency::ambiguousSuccessors(i, _, _, _) | i) as ambiguousSuccessors,
|
||||||
|
count(Instruction i | IRConsistency::unexplainedLoop(i, _, _, _) | i) as unexplainedLoop,
|
||||||
|
count(PhiInstruction i | IRConsistency::unnecessaryPhiInstruction(i, _, _, _) | i) as unnecessaryPhiInstruction,
|
||||||
|
count(Instruction i | IRConsistency::memoryOperandDefinitionIsUnmodeled(i, _, _, _) | i) as memoryOperandDefinitionIsUnmodeled,
|
||||||
|
count(Operand o | IRConsistency::operandAcrossFunctions(o, _, _, _, _, _) | o) as operandAcrossFunctions,
|
||||||
|
count(IRFunction f | IRConsistency::containsLoopOfForwardEdges(f, _) | f) as containsLoopOfForwardEdges,
|
||||||
|
count(IRBlock i | IRConsistency::lostReachability(i, _, _, _) | i) as lostReachability,
|
||||||
|
count(string m | IRConsistency::backEdgeCountMismatch(_, m) | m) as backEdgeCountMismatch,
|
||||||
|
count(Operand o | IRConsistency::useNotDominatedByDefinition(o, _, _, _) | o) as useNotDominatedByDefinition,
|
||||||
|
count(SwitchInstruction i | IRConsistency::switchInstructionWithoutDefaultEdge(i, _, _, _) | i) as switchInstructionWithoutDefaultEdge,
|
||||||
|
count(Instruction i | IRConsistency::notMarkedAsConflated(i, _, _, _) | i) as notMarkedAsConflated,
|
||||||
|
count(Instruction i | IRConsistency::wronglyMarkedAsConflated(i, _, _, _) | i) as wronglyMarkedAsConflated,
|
||||||
|
count(MemoryOperand o | IRConsistency::invalidOverlap(o, _, _, _) | o) as invalidOverlap,
|
||||||
|
count(Instruction i | IRConsistency::nonUniqueEnclosingIRFunction(i, _, _, _) | i) as nonUniqueEnclosingIRFunction,
|
||||||
|
count(FieldAddressInstruction i | IRConsistency::fieldAddressOnNonPointer(i, _, _, _) | i) as fieldAddressOnNonPointer,
|
||||||
|
count(Instruction i | IRConsistency::thisArgumentIsNonPointer(i, _, _, _) | i) as thisArgumentIsNonPointer,
|
||||||
|
count(Instruction i | IRConsistency::nonUniqueIRVariable(i, _, _, _) | i) as nonUniqueIRVariable
|
||||||
@@ -21,7 +21,9 @@ class UntrustedExternalApiDataNode extends ExternalApiDataNode {
|
|||||||
/** DEPRECATED: Alias for UntrustedExternalApiDataNode */
|
/** DEPRECATED: Alias for UntrustedExternalApiDataNode */
|
||||||
deprecated class UntrustedExternalAPIDataNode = UntrustedExternalApiDataNode;
|
deprecated class UntrustedExternalAPIDataNode = UntrustedExternalApiDataNode;
|
||||||
|
|
||||||
|
/** An external API which is used with untrusted data. */
|
||||||
private newtype TExternalApi =
|
private newtype TExternalApi =
|
||||||
|
/** An untrusted API method `m` where untrusted data is passed at `index`. */
|
||||||
TExternalApiParameter(Function f, int index) {
|
TExternalApiParameter(Function f, int index) {
|
||||||
exists(UntrustedExternalApiDataNode n |
|
exists(UntrustedExternalApiDataNode n |
|
||||||
f = n.getExternalFunction() and
|
f = n.getExternalFunction() and
|
||||||
|
|||||||
@@ -21,7 +21,9 @@ class UntrustedExternalApiDataNode extends ExternalApiDataNode {
|
|||||||
/** DEPRECATED: Alias for UntrustedExternalApiDataNode */
|
/** DEPRECATED: Alias for UntrustedExternalApiDataNode */
|
||||||
deprecated class UntrustedExternalAPIDataNode = UntrustedExternalApiDataNode;
|
deprecated class UntrustedExternalAPIDataNode = UntrustedExternalApiDataNode;
|
||||||
|
|
||||||
|
/** An external API which is used with untrusted data. */
|
||||||
private newtype TExternalApi =
|
private newtype TExternalApi =
|
||||||
|
/** An untrusted API method `m` where untrusted data is passed at `index`. */
|
||||||
TExternalApiParameter(Function f, int index) {
|
TExternalApiParameter(Function f, int index) {
|
||||||
exists(UntrustedExternalApiDataNode n |
|
exists(UntrustedExternalApiDataNode n |
|
||||||
f = n.getExternalFunction() and
|
f = n.getExternalFunction() and
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import semmle.code.cpp.security.Security
|
|||||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||||
import semmle.code.cpp.ir.IR
|
import semmle.code.cpp.ir.IR
|
||||||
import semmle.code.cpp.ir.dataflow.TaintTracking
|
import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||||
|
import semmle.code.cpp.ir.dataflow.TaintTracking2
|
||||||
import semmle.code.cpp.security.FlowSources
|
import semmle.code.cpp.security.FlowSources
|
||||||
import semmle.code.cpp.models.implementations.Strcat
|
import semmle.code.cpp.models.implementations.Strcat
|
||||||
import DataFlow::PathGraph
|
import DataFlow::PathGraph
|
||||||
@@ -83,6 +84,32 @@ class ExecState extends DataFlow::FlowState {
|
|||||||
DataFlow::Node getFstNode() { result = fst }
|
DataFlow::Node getFstNode() { result = fst }
|
||||||
|
|
||||||
DataFlow::Node getSndNode() { result = snd }
|
DataFlow::Node getSndNode() { result = snd }
|
||||||
|
|
||||||
|
/** Holds if this is a possible `ExecState` for `sink`. */
|
||||||
|
predicate isFeasibleForSink(DataFlow::Node sink) {
|
||||||
|
any(ExecStateConfiguration conf).hasFlow(snd, sink)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A `TaintTracking` configuration that's used to find the relevant `ExecState`s for a
|
||||||
|
* given sink. This avoids a cartesian product between all sinks and all `ExecState`s in
|
||||||
|
* `ExecTaintConfiguration::isSink`.
|
||||||
|
*/
|
||||||
|
class ExecStateConfiguration extends TaintTracking2::Configuration {
|
||||||
|
ExecStateConfiguration() { this = "ExecStateConfiguration" }
|
||||||
|
|
||||||
|
override predicate isSource(DataFlow::Node source) {
|
||||||
|
exists(ExecState state | state.getSndNode() = source)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate isSink(DataFlow::Node sink) {
|
||||||
|
shellCommand(sinkAsArgumentIndirection(sink), _)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate isSanitizerOut(DataFlow::Node node) {
|
||||||
|
isSink(node, _) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExecTaintConfiguration extends TaintTracking::Configuration {
|
class ExecTaintConfiguration extends TaintTracking::Configuration {
|
||||||
@@ -94,8 +121,8 @@ class ExecTaintConfiguration extends TaintTracking::Configuration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
|
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
|
||||||
shellCommand(sinkAsArgumentIndirection(sink), _) and
|
any(ExecStateConfiguration conf).isSink(sink) and
|
||||||
state instanceof ExecState
|
state.(ExecState).isFeasibleForSink(sink)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isAdditionalTaintStep(
|
override predicate isAdditionalTaintStep(
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ import semmle.code.cpp.dataflow.DataFlow
|
|||||||
/**
|
/**
|
||||||
* A call to `SSL_get_verify_result`.
|
* A call to `SSL_get_verify_result`.
|
||||||
*/
|
*/
|
||||||
class SSLGetVerifyResultCall extends FunctionCall {
|
class SslGetVerifyResultCall extends FunctionCall {
|
||||||
SSLGetVerifyResultCall() { getTarget().getName() = "SSL_get_verify_result" }
|
SslGetVerifyResultCall() { getTarget().getName() = "SSL_get_verify_result" }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -29,7 +29,7 @@ class VerifyResultConfig extends DataFlow::Configuration {
|
|||||||
VerifyResultConfig() { this = "VerifyResultConfig" }
|
VerifyResultConfig() { this = "VerifyResultConfig" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) {
|
override predicate isSource(DataFlow::Node source) {
|
||||||
source.asExpr() instanceof SSLGetVerifyResultCall
|
source.asExpr() instanceof SslGetVerifyResultCall
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
override predicate isSink(DataFlow::Node sink) {
|
||||||
|
|||||||
@@ -17,33 +17,33 @@ import semmle.code.cpp.controlflow.IRGuards
|
|||||||
/**
|
/**
|
||||||
* A call to `SSL_get_peer_certificate`.
|
* A call to `SSL_get_peer_certificate`.
|
||||||
*/
|
*/
|
||||||
class SSLGetPeerCertificateCall extends FunctionCall {
|
class SslGetPeerCertificateCall extends FunctionCall {
|
||||||
SSLGetPeerCertificateCall() {
|
SslGetPeerCertificateCall() {
|
||||||
getTarget().getName() = "SSL_get_peer_certificate" // SSL_get_peer_certificate(ssl)
|
getTarget().getName() = "SSL_get_peer_certificate" // SSL_get_peer_certificate(ssl)
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr getSSLArgument() { result = getArgument(0) }
|
Expr getSslArgument() { result = getArgument(0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A call to `SSL_get_verify_result`.
|
* A call to `SSL_get_verify_result`.
|
||||||
*/
|
*/
|
||||||
class SSLGetVerifyResultCall extends FunctionCall {
|
class SslGetVerifyResultCall extends FunctionCall {
|
||||||
SSLGetVerifyResultCall() {
|
SslGetVerifyResultCall() {
|
||||||
getTarget().getName() = "SSL_get_verify_result" // SSL_get_peer_certificate(ssl)
|
getTarget().getName() = "SSL_get_verify_result" // SSL_get_peer_certificate(ssl)
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr getSSLArgument() { result = getArgument(0) }
|
Expr getSslArgument() { result = getArgument(0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the SSL object passed into `SSL_get_peer_certificate` is checked with
|
* Holds if the SSL object passed into `SSL_get_peer_certificate` is checked with
|
||||||
* `SSL_get_verify_result` entering `node`.
|
* `SSL_get_verify_result` entering `node`.
|
||||||
*/
|
*/
|
||||||
predicate resultIsChecked(SSLGetPeerCertificateCall getCertCall, ControlFlowNode node) {
|
predicate resultIsChecked(SslGetPeerCertificateCall getCertCall, ControlFlowNode node) {
|
||||||
exists(Expr ssl, SSLGetVerifyResultCall check |
|
exists(Expr ssl, SslGetVerifyResultCall check |
|
||||||
ssl = globalValueNumber(getCertCall.getSSLArgument()).getAnExpr() and
|
ssl = globalValueNumber(getCertCall.getSslArgument()).getAnExpr() and
|
||||||
ssl = check.getSSLArgument() and
|
ssl = check.getSslArgument() and
|
||||||
node = check
|
node = check
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -53,7 +53,7 @@ predicate resultIsChecked(SSLGetPeerCertificateCall getCertCall, ControlFlowNode
|
|||||||
* `0` on the edge `node1` to `node2`.
|
* `0` on the edge `node1` to `node2`.
|
||||||
*/
|
*/
|
||||||
predicate certIsZero(
|
predicate certIsZero(
|
||||||
SSLGetPeerCertificateCall getCertCall, ControlFlowNode node1, ControlFlowNode node2
|
SslGetPeerCertificateCall getCertCall, ControlFlowNode node1, ControlFlowNode node2
|
||||||
) {
|
) {
|
||||||
exists(Expr cert | cert = globalValueNumber(getCertCall).getAnExpr() |
|
exists(Expr cert | cert = globalValueNumber(getCertCall).getAnExpr() |
|
||||||
exists(GuardCondition guard, Expr zero |
|
exists(GuardCondition guard, Expr zero |
|
||||||
@@ -87,7 +87,7 @@ predicate certIsZero(
|
|||||||
* `SSL_get_verify_result` at `node`. Note that this is only computed at the call to
|
* `SSL_get_verify_result` at `node`. Note that this is only computed at the call to
|
||||||
* `SSL_get_peer_certificate` and at the start and end of `BasicBlock`s.
|
* `SSL_get_peer_certificate` and at the start and end of `BasicBlock`s.
|
||||||
*/
|
*/
|
||||||
predicate certNotChecked(SSLGetPeerCertificateCall getCertCall, ControlFlowNode node) {
|
predicate certNotChecked(SslGetPeerCertificateCall getCertCall, ControlFlowNode node) {
|
||||||
// cert is not checked at the call to `SSL_get_peer_certificate`
|
// cert is not checked at the call to `SSL_get_peer_certificate`
|
||||||
node = getCertCall
|
node = getCertCall
|
||||||
or
|
or
|
||||||
@@ -112,7 +112,7 @@ predicate certNotChecked(SSLGetPeerCertificateCall getCertCall, ControlFlowNode
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
from SSLGetPeerCertificateCall getCertCall, ControlFlowNode node
|
from SslGetPeerCertificateCall getCertCall, ControlFlowNode node
|
||||||
where
|
where
|
||||||
certNotChecked(getCertCall, node) and
|
certNotChecked(getCertCall, node) and
|
||||||
node instanceof Function // (function exit)
|
node instanceof Function // (function exit)
|
||||||
|
|||||||
@@ -26,6 +26,10 @@ class ToBufferConfiguration extends TaintTracking::Configuration {
|
|||||||
|
|
||||||
override predicate isSource(DataFlow::Node source) { source instanceof FlowSource }
|
override predicate isSource(DataFlow::Node source) { source instanceof FlowSource }
|
||||||
|
|
||||||
|
override predicate isSanitizer(DataFlow::Node node) {
|
||||||
|
node.asExpr().getUnspecifiedType() instanceof IntegralType
|
||||||
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
override predicate isSink(DataFlow::Node sink) {
|
||||||
exists(BufferWrite::BufferWrite w | w.getASource() = sink.asExpr())
|
exists(BufferWrite::BufferWrite w | w.getASource() = sink.asExpr())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,14 +47,17 @@ class EnvData extends SystemData {
|
|||||||
/**
|
/**
|
||||||
* Data originating from a call to `mysql_get_client_info()`.
|
* Data originating from a call to `mysql_get_client_info()`.
|
||||||
*/
|
*/
|
||||||
class SQLClientInfo extends SystemData {
|
class SqlClientInfo extends SystemData {
|
||||||
SQLClientInfo() { this.(FunctionCall).getTarget().hasName("mysql_get_client_info") }
|
SqlClientInfo() { this.(FunctionCall).getTarget().hasName("mysql_get_client_info") }
|
||||||
|
|
||||||
override DataFlow::Node getAnExpr() { result.asConvertedExpr() = this }
|
override DataFlow::Node getAnExpr() { result.asConvertedExpr() = this }
|
||||||
|
|
||||||
override predicate isSensitive() { any() }
|
override predicate isSensitive() { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for SqlClientInfo */
|
||||||
|
deprecated class SQLClientInfo = SqlClientInfo;
|
||||||
|
|
||||||
private predicate sqlConnectInfo(FunctionCall source, Expr use) {
|
private predicate sqlConnectInfo(FunctionCall source, Expr use) {
|
||||||
(
|
(
|
||||||
source.getTarget().hasName("mysql_connect") or
|
source.getTarget().hasName("mysql_connect") or
|
||||||
@@ -66,14 +69,17 @@ private predicate sqlConnectInfo(FunctionCall source, Expr use) {
|
|||||||
/**
|
/**
|
||||||
* Data passed into an SQL connect function.
|
* Data passed into an SQL connect function.
|
||||||
*/
|
*/
|
||||||
class SQLConnectInfo extends SystemData {
|
class SqlConnectInfo extends SystemData {
|
||||||
SQLConnectInfo() { sqlConnectInfo(this, _) }
|
SqlConnectInfo() { sqlConnectInfo(this, _) }
|
||||||
|
|
||||||
override DataFlow::Node getAnExpr() { sqlConnectInfo(this, result.asConvertedExpr()) }
|
override DataFlow::Node getAnExpr() { sqlConnectInfo(this, result.asConvertedExpr()) }
|
||||||
|
|
||||||
override predicate isSensitive() { any() }
|
override predicate isSensitive() { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** DEPRECATED: Alias for SqlConnectInfo */
|
||||||
|
deprecated class SQLConnectInfo = SqlConnectInfo;
|
||||||
|
|
||||||
private predicate posixSystemInfo(FunctionCall source, DataFlow::Node use) {
|
private predicate posixSystemInfo(FunctionCall source, DataFlow::Node use) {
|
||||||
// size_t confstr(int name, char *buf, size_t len)
|
// size_t confstr(int name, char *buf, size_t len)
|
||||||
// - various OS / system strings, such as the libc version
|
// - various OS / system strings, such as the libc version
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: minorAnalysis
|
||||||
|
---
|
||||||
|
* The "Cleartext storage of sensitive information in buffer" (`cpp/cleartext-storage-buffer`) query has been improved to produce fewer false positives.
|
||||||
4
cpp/ql/src/change-notes/2022-08-23-alert-messages.md
Normal file
4
cpp/ql/src/change-notes/2022-08-23-alert-messages.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: minorAnalysis
|
||||||
|
---
|
||||||
|
* The alert message of many queries have been changed to make the message consistent with other languages.
|
||||||
@@ -67,7 +67,7 @@ predicate findUseCharacterConversion(Expr exp, string msg) {
|
|||||||
exists(FunctionCall fc |
|
exists(FunctionCall fc |
|
||||||
fc = exp and
|
fc = exp and
|
||||||
(
|
(
|
||||||
exists(Loop lptmp | lptmp = fc.getEnclosingStmt().getParentStmt*()) and
|
fc.getEnclosingStmt().getParentStmt*() instanceof Loop and
|
||||||
fc.getTarget().hasName(["mbtowc", "mbrtowc", "_mbtowc_l"]) and
|
fc.getTarget().hasName(["mbtowc", "mbrtowc", "_mbtowc_l"]) and
|
||||||
not fc.getArgument(0).isConstant() and
|
not fc.getArgument(0).isConstant() and
|
||||||
not fc.getArgument(1).isConstant() and
|
not fc.getArgument(1).isConstant() and
|
||||||
|
|||||||
@@ -44,11 +44,8 @@ predicate conversionDoneLate(MulExpr mexp) {
|
|||||||
mexp.getEnclosingElement().(ComparisonOperation).hasOperands(mexp, e0) and
|
mexp.getEnclosingElement().(ComparisonOperation).hasOperands(mexp, e0) and
|
||||||
e0.getType().getSize() = mexp.getConversion().getConversion().getType().getSize()
|
e0.getType().getSize() = mexp.getConversion().getConversion().getType().getSize()
|
||||||
or
|
or
|
||||||
e0.(FunctionCall)
|
e0.(FunctionCall).getTarget().getParameter(argumentPosition(e0, mexp, _)).getType().getSize() =
|
||||||
.getTarget()
|
mexp.getConversion().getConversion().getType().getSize()
|
||||||
.getParameter(argumentPosition(e0.(FunctionCall), mexp, _))
|
|
||||||
.getType()
|
|
||||||
.getSize() = mexp.getConversion().getConversion().getType().getSize()
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -75,7 +72,7 @@ predicate signSmallerWithEqualSizes(MulExpr mexp) {
|
|||||||
ae.getRValue().getUnderlyingType().(IntegralType).isUnsigned() and
|
ae.getRValue().getUnderlyingType().(IntegralType).isUnsigned() and
|
||||||
ae.getLValue().getUnderlyingType().(IntegralType).isSigned() and
|
ae.getLValue().getUnderlyingType().(IntegralType).isSigned() and
|
||||||
(
|
(
|
||||||
not exists(DivExpr de | mexp.getParent*() = de)
|
not mexp.getParent*() instanceof DivExpr
|
||||||
or
|
or
|
||||||
exists(DivExpr de, Expr ec |
|
exists(DivExpr de, Expr ec |
|
||||||
e2.isConstant() and
|
e2.isConstant() and
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ Make sure that all classes with virtual functions also have a virtual destructor
|
|||||||
S. Meyers. <em>Effective C++ 3d ed.</em> pp 40-44. Addison-Wesley Professional, 2005.
|
S. Meyers. <em>Effective C++ 3d ed.</em> pp 40-44. Addison-Wesley Professional, 2005.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="http://blogs.msdn.com/b/oldnewthing/archive/2004/05/07/127826.aspx">When should your destructor be virtual?</a>
|
<a href="https://devblogs.microsoft.com/oldnewthing/20040507-00/?p=39443">When should your destructor be virtual?</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/cpp-queries
|
name: codeql/cpp-queries
|
||||||
version: 0.3.2
|
version: 0.3.3-dev
|
||||||
groups:
|
groups:
|
||||||
- cpp
|
- cpp
|
||||||
- queries
|
- queries
|
||||||
|
|||||||
@@ -330,6 +330,19 @@ abstract private class Expectation extends FailureLocatable {
|
|||||||
override Location getLocation() { result = comment.getLocation() }
|
override Location getLocation() { result = comment.getLocation() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate onSameLine(ValidExpectation a, ActualResult b) {
|
||||||
|
exists(string fname, int line, Location la, Location lb |
|
||||||
|
// Join order intent:
|
||||||
|
// Take the locations of ActualResults,
|
||||||
|
// join with locations in the same file / on the same line,
|
||||||
|
// then match those against ValidExpectations.
|
||||||
|
la = a.getLocation() and
|
||||||
|
pragma[only_bind_into](lb) = b.getLocation() and
|
||||||
|
pragma[only_bind_into](la).hasLocationInfo(fname, line, _, _, _) and
|
||||||
|
lb.hasLocationInfo(fname, line, _, _, _)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private class ValidExpectation extends Expectation, TValidExpectation {
|
private class ValidExpectation extends Expectation, TValidExpectation {
|
||||||
string tag;
|
string tag;
|
||||||
string value;
|
string value;
|
||||||
@@ -344,8 +357,7 @@ private class ValidExpectation extends Expectation, TValidExpectation {
|
|||||||
string getKnownFailure() { result = knownFailure }
|
string getKnownFailure() { result = knownFailure }
|
||||||
|
|
||||||
predicate matchesActualResult(ActualResult actualResult) {
|
predicate matchesActualResult(ActualResult actualResult) {
|
||||||
getLocation().getStartLine() = actualResult.getLocation().getStartLine() and
|
onSameLine(pragma[only_bind_into](this), actualResult) and
|
||||||
getLocation().getFile() = actualResult.getLocation().getFile() and
|
|
||||||
getTag() = actualResult.getTag() and
|
getTag() = actualResult.getTag() and
|
||||||
getValue() = actualResult.getValue()
|
getValue() = actualResult.getValue()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
private import semmle.code.cpp.ir.dataflow.DataFlow::DataFlow as IRDataFlow
|
private import semmle.code.cpp.ir.dataflow.DataFlow::DataFlow as IRDataFlow
|
||||||
private import semmle.code.cpp.dataflow.DataFlow::DataFlow as ASTDataFlow
|
private import semmle.code.cpp.dataflow.DataFlow::DataFlow as AstDataFlow
|
||||||
import TestUtilities.InlineExpectationsTest
|
import TestUtilities.InlineExpectationsTest
|
||||||
|
|
||||||
class IRFlowTest extends InlineExpectationsTest {
|
class IRFlowTest extends InlineExpectationsTest {
|
||||||
@@ -49,11 +49,11 @@ class AstFlowTest extends InlineExpectationsTest {
|
|||||||
|
|
||||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||||
exists(
|
exists(
|
||||||
ASTDataFlow::Node source, ASTDataFlow::Node sink, ASTDataFlow::Configuration conf, int n
|
AstDataFlow::Node source, AstDataFlow::Node sink, AstDataFlow::Configuration conf, int n
|
||||||
|
|
|
|
||||||
tag = "ast" and
|
tag = "ast" and
|
||||||
conf.hasFlow(source, sink) and
|
conf.hasFlow(source, sink) and
|
||||||
n = strictcount(ASTDataFlow::Node otherSource | conf.hasFlow(otherSource, sink)) and
|
n = strictcount(AstDataFlow::Node otherSource | conf.hasFlow(otherSource, sink)) and
|
||||||
(
|
(
|
||||||
n = 1 and value = ""
|
n = 1 and value = ""
|
||||||
or
|
or
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
import semmle.code.cpp.security.TaintTrackingImpl as ASTTaintTracking
|
import semmle.code.cpp.security.TaintTrackingImpl as AstTaintTracking
|
||||||
import semmle.code.cpp.ir.dataflow.DefaultTaintTracking as IRDefaultTaintTracking
|
import semmle.code.cpp.ir.dataflow.DefaultTaintTracking as IRDefaultTaintTracking
|
||||||
import IRDefaultTaintTracking::TaintedWithPath as TaintedWithPath
|
import IRDefaultTaintTracking::TaintedWithPath as TaintedWithPath
|
||||||
import TaintedWithPath::Private
|
import TaintedWithPath::Private
|
||||||
@@ -17,7 +17,7 @@ predicate isSinkArgument(Element sink) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate astTaint(Expr source, Element sink) { ASTTaintTracking::tainted(source, sink) }
|
predicate astTaint(Expr source, Element sink) { AstTaintTracking::tainted(source, sink) }
|
||||||
|
|
||||||
class SourceConfiguration extends TaintedWithPath::TaintTrackingConfiguration {
|
class SourceConfiguration extends TaintedWithPath::TaintTrackingConfiguration {
|
||||||
override predicate isSink(Element e) { isSinkArgument(e) }
|
override predicate isSink(Element e) { isSinkArgument(e) }
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user