mirror of
https://github.com/github/codeql.git
synced 2026-05-16 20:27:06 +02:00
Compare commits
611 Commits
codeql-cli
...
dbartol/ja
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85cfb83f32 | ||
|
|
f7db47b771 | ||
|
|
0b6ec4624e | ||
|
|
d6848f5c5d | ||
|
|
01abcf8537 | ||
|
|
8c87b66bea | ||
|
|
d6415cd0c8 | ||
|
|
3a1f6efce4 | ||
|
|
8243f87179 | ||
|
|
fb9ec2423c | ||
|
|
3fa52ad680 | ||
|
|
9c7216fe4f | ||
|
|
69e0ad0181 | ||
|
|
8b536f54fd | ||
|
|
d3695dce4d | ||
|
|
8f0b7f0969 | ||
|
|
c4eafb2cf3 | ||
|
|
8b66dc16ad | ||
|
|
e8cb3490e6 | ||
|
|
85957767c9 | ||
|
|
071076875c | ||
|
|
26c69b8f8a | ||
|
|
bbd0aa929f | ||
|
|
17770af491 | ||
|
|
a507854288 | ||
|
|
8c1fd8fa7a | ||
|
|
f3e3734424 | ||
|
|
5444a5bf8a | ||
|
|
3a54c10f36 | ||
|
|
5fb61b0304 | ||
|
|
6af5afc184 | ||
|
|
cd1f10cdea | ||
|
|
74826032ef | ||
|
|
a9b3c0d91b | ||
|
|
323b7cb96f | ||
|
|
901f756c69 | ||
|
|
01c9509741 | ||
|
|
6081ba5902 | ||
|
|
91e26d0f44 | ||
|
|
a172063e6a | ||
|
|
fe00c8819d | ||
|
|
cb0b388345 | ||
|
|
4712ae1cfc | ||
|
|
59a77d70c0 | ||
|
|
4b5aa1497b | ||
|
|
d689db23d8 | ||
|
|
60abea17e6 | ||
|
|
66d156d386 | ||
|
|
b0efffd8f0 | ||
|
|
a282efc43e | ||
|
|
1d6626c821 | ||
|
|
2427227b84 | ||
|
|
204e4c5bb0 | ||
|
|
e97878ed63 | ||
|
|
be389b4c19 | ||
|
|
7dcdd7429f | ||
|
|
455c8c5953 | ||
|
|
c9d6c80913 | ||
|
|
684aedf6aa | ||
|
|
c496503053 | ||
|
|
eeddb176f8 | ||
|
|
162519185d | ||
|
|
9e9469f3ca | ||
|
|
318e75c094 | ||
|
|
c91f7f4918 | ||
|
|
31324fc778 | ||
|
|
51e787b316 | ||
|
|
c4737c7fbb | ||
|
|
70b4ecf0a5 | ||
|
|
338ab96593 | ||
|
|
938e962d79 | ||
|
|
d0831ebd5a | ||
|
|
5c4b4d644a | ||
|
|
52894f5b6a | ||
|
|
222ae6ad2d | ||
|
|
fcb677e84d | ||
|
|
38818f3cd2 | ||
|
|
2018b6361d | ||
|
|
d3c50727ed | ||
|
|
45d3d381f5 | ||
|
|
ef3f730d32 | ||
|
|
fd459be165 | ||
|
|
3a210b77f9 | ||
|
|
c3311e52a6 | ||
|
|
a8f55d93cb | ||
|
|
0459d136d3 | ||
|
|
2e7e26b638 | ||
|
|
1f95fa10fb | ||
|
|
5ae669937c | ||
|
|
752502ba76 | ||
|
|
ec0bd4494c | ||
|
|
29948e4c0b | ||
|
|
6f74387600 | ||
|
|
4513643a0f | ||
|
|
3e77dd8b6b | ||
|
|
bafef791f7 | ||
|
|
a017f92b78 | ||
|
|
8a1b4501dd | ||
|
|
b0ed47c277 | ||
|
|
baae8d0bb2 | ||
|
|
e73d1c7b76 | ||
|
|
654d97013f | ||
|
|
ca68aaa0de | ||
|
|
b73fe0ba0a | ||
|
|
92c8d39ba3 | ||
|
|
cc24f1ed9f | ||
|
|
26e58532ee | ||
|
|
796db77104 | ||
|
|
fb630d266e | ||
|
|
90a8bef64c | ||
|
|
7de1182f92 | ||
|
|
dc4160b24a | ||
|
|
bf58bdd2bd | ||
|
|
431b33a274 | ||
|
|
97ead6f462 | ||
|
|
2a5b48930a | ||
|
|
08be35fc2c | ||
|
|
0b39c5b982 | ||
|
|
80497f551e | ||
|
|
3d1a403655 | ||
|
|
ccadfa134e | ||
|
|
8310faa2e9 | ||
|
|
fdff209938 | ||
|
|
8e85f24c95 | ||
|
|
8967989c7b | ||
|
|
7c473c38c0 | ||
|
|
dcb75f490f | ||
|
|
8045440d00 | ||
|
|
7c32efc218 | ||
|
|
381ea93ec3 | ||
|
|
a128383760 | ||
|
|
2a5dc204fb | ||
|
|
9a923d62ad | ||
|
|
e70297a7bc | ||
|
|
d7fb7ab551 | ||
|
|
53c20ccaeb | ||
|
|
0cd4ccb790 | ||
|
|
b041829569 | ||
|
|
6777a34dfb | ||
|
|
caca4950e6 | ||
|
|
7b3960844d | ||
|
|
aae8660acc | ||
|
|
58513cadbf | ||
|
|
6cd548f410 | ||
|
|
431a1af628 | ||
|
|
76914c40c9 | ||
|
|
f389a889ad | ||
|
|
24f39ccae2 | ||
|
|
a3ad6f5697 | ||
|
|
dd993c3900 | ||
|
|
9b5c9af489 | ||
|
|
7f2d485ae9 | ||
|
|
c2871f4def | ||
|
|
4a14a3cacb | ||
|
|
0ad2e193e5 | ||
|
|
31684d2548 | ||
|
|
6a0212ea44 | ||
|
|
297d32180c | ||
|
|
ba5be80814 | ||
|
|
2c9488e475 | ||
|
|
f8ce11b3a7 | ||
|
|
7da2845cad | ||
|
|
a9ecb26885 | ||
|
|
bc83106dd8 | ||
|
|
6a184e0c2e | ||
|
|
1dcc6ac2b1 | ||
|
|
1bd504bf61 | ||
|
|
ce2d959b7e | ||
|
|
8f1c1a8399 | ||
|
|
0520fc2d9f | ||
|
|
a6fce19b0c | ||
|
|
5a03c35e9c | ||
|
|
f193084f9f | ||
|
|
a8cad4963e | ||
|
|
e8c68fff7f | ||
|
|
85cc596041 | ||
|
|
7289476c80 | ||
|
|
53e33d3ef3 | ||
|
|
0baa9e9ac1 | ||
|
|
90869ec96a | ||
|
|
79620c1a89 | ||
|
|
af80797eda | ||
|
|
e89a47f2f5 | ||
|
|
d00e27916d | ||
|
|
28c48fb471 | ||
|
|
0ee1383732 | ||
|
|
cc63abf0af | ||
|
|
f57dd0a596 | ||
|
|
329c3c7c56 | ||
|
|
0ae10ece39 | ||
|
|
cbc2389493 | ||
|
|
d299380a5a | ||
|
|
f428fdc57c | ||
|
|
8c956e8276 | ||
|
|
3bd5c6e445 | ||
|
|
1fb9835f23 | ||
|
|
aaecb9bb7a | ||
|
|
3a1b618a74 | ||
|
|
29061a08ad | ||
|
|
6e493f2baa | ||
|
|
a9e07a88af | ||
|
|
ea4f9cad3c | ||
|
|
590e93d8ed | ||
|
|
bcb718ac77 | ||
|
|
5714811071 | ||
|
|
d673d24ca6 | ||
|
|
11755482e4 | ||
|
|
40035a0b62 | ||
|
|
4d3a140dd7 | ||
|
|
73209638e3 | ||
|
|
1953e4f971 | ||
|
|
37f264df74 | ||
|
|
ca2b8ef6c0 | ||
|
|
9b8cbdad49 | ||
|
|
c596205416 | ||
|
|
bdb4d89f9f | ||
|
|
b04abc09f0 | ||
|
|
b0caabac86 | ||
|
|
6e428d5083 | ||
|
|
0255edf524 | ||
|
|
afa4b6dd4a | ||
|
|
5490f3a957 | ||
|
|
279800ea62 | ||
|
|
4dbb15ddda | ||
|
|
8c015b0784 | ||
|
|
47953339db | ||
|
|
e6085759ae | ||
|
|
fd45d2dcbb | ||
|
|
22c2522aac | ||
|
|
9b8152a44b | ||
|
|
76662a6002 | ||
|
|
bda779a58d | ||
|
|
0be52f9660 | ||
|
|
300864a38b | ||
|
|
5b45d36610 | ||
|
|
d3368be94a | ||
|
|
c1f3e7389f | ||
|
|
062127b42e | ||
|
|
300fdc344d | ||
|
|
6a11120e50 | ||
|
|
16925355a8 | ||
|
|
f287216060 | ||
|
|
37490de4a2 | ||
|
|
6a67bd52a9 | ||
|
|
d14e77ba48 | ||
|
|
8d8bbd5b12 | ||
|
|
5f3663018e | ||
|
|
3b753da74e | ||
|
|
d7614a71f4 | ||
|
|
6ae03e67e6 | ||
|
|
15bb670b3f | ||
|
|
01aa63e170 | ||
|
|
7e8da94d9a | ||
|
|
1cd8af54f2 | ||
|
|
209f9ec93d | ||
|
|
e7bc71f2da | ||
|
|
48f9e0efe5 | ||
|
|
04e3b39ffb | ||
|
|
05173fa7ac | ||
|
|
535db98823 | ||
|
|
4a21a85e73 | ||
|
|
63c3a71d95 | ||
|
|
e528a08794 | ||
|
|
bb44a2fc8c | ||
|
|
7b4137fbc8 | ||
|
|
e48e18af20 | ||
|
|
45d9d8a25a | ||
|
|
1f21d75399 | ||
|
|
75ec8ce58e | ||
|
|
7aa2816570 | ||
|
|
3a1e50dcf9 | ||
|
|
c74b6be136 | ||
|
|
81e99bf1bb | ||
|
|
69a172c7ba | ||
|
|
db06ad2ac3 | ||
|
|
2ee61f9aaa | ||
|
|
e6e0e6eb66 | ||
|
|
a9423f4bdb | ||
|
|
57458d8f38 | ||
|
|
2fdc529ac9 | ||
|
|
b2bddd3415 | ||
|
|
3001a570b2 | ||
|
|
f4071ddb28 | ||
|
|
d290591187 | ||
|
|
2a95068a0a | ||
|
|
d7aa5f1022 | ||
|
|
bcb84a84e1 | ||
|
|
164cf27e67 | ||
|
|
4e59fa9035 | ||
|
|
f7afcd038a | ||
|
|
d2ebe00492 | ||
|
|
2533f18a6e | ||
|
|
8d291ab938 | ||
|
|
3e2f886595 | ||
|
|
1bffc2a7d7 | ||
|
|
db00cb6827 | ||
|
|
9d6ee09f65 | ||
|
|
70997e8189 | ||
|
|
9f1d50ebd1 | ||
|
|
f5ff822681 | ||
|
|
94cb99e51d | ||
|
|
9d79feb4d3 | ||
|
|
eb6918f88f | ||
|
|
fd592fa18f | ||
|
|
c3dffc955b | ||
|
|
76e6942594 | ||
|
|
594045b634 | ||
|
|
f2e943f9ba | ||
|
|
74c0fa7154 | ||
|
|
cc5882a3c3 | ||
|
|
cf5d56addf | ||
|
|
a065434dd7 | ||
|
|
ee41e65e90 | ||
|
|
16813240ae | ||
|
|
ec74595671 | ||
|
|
95c18ce431 | ||
|
|
97cca76970 | ||
|
|
6a540d833e | ||
|
|
fe1081e880 | ||
|
|
0deefaddc5 | ||
|
|
0e828bb5da | ||
|
|
bb82dc1b18 | ||
|
|
bc9eb993b8 | ||
|
|
a5e3fbf367 | ||
|
|
19697b9a77 | ||
|
|
f38f818578 | ||
|
|
682f08ceb9 | ||
|
|
db9f5fdf81 | ||
|
|
3c09f70e0d | ||
|
|
2511986324 | ||
|
|
919a9002bc | ||
|
|
3aa47a3950 | ||
|
|
1c0f60fa2e | ||
|
|
24f24855f0 | ||
|
|
e19bca0de8 | ||
|
|
c3b10bf90b | ||
|
|
80d32a2333 | ||
|
|
9104c3fc81 | ||
|
|
1f30d5f41b | ||
|
|
c117a53fb0 | ||
|
|
f2fbe64137 | ||
|
|
f142af50b7 | ||
|
|
de4a7da286 | ||
|
|
2033818e39 | ||
|
|
1f3b28a555 | ||
|
|
3b9f3c2c29 | ||
|
|
ec9bb1da56 | ||
|
|
4baa4ae2aa | ||
|
|
a5ab5d9236 | ||
|
|
ded52ccb8e | ||
|
|
54632b289e | ||
|
|
61ac8d66f5 | ||
|
|
fabdb3c841 | ||
|
|
5ccb45e7d3 | ||
|
|
d5c0d41f98 | ||
|
|
4a9e3ee3aa | ||
|
|
cfa4cb432a | ||
|
|
67fa9738e6 | ||
|
|
9a8d9f857f | ||
|
|
57d1035acd | ||
|
|
cab35a25a5 | ||
|
|
5ae51f0b56 | ||
|
|
cfa14ad5eb | ||
|
|
e43d39a0fe | ||
|
|
485dc9619d | ||
|
|
7c2b149728 | ||
|
|
2769bd6f35 | ||
|
|
3632a76eaf | ||
|
|
d79aa073ea | ||
|
|
463a1254d3 | ||
|
|
ed9008a064 | ||
|
|
bbf5902b18 | ||
|
|
43c0bd36be | ||
|
|
5554c0f28f | ||
|
|
98b5ef5e01 | ||
|
|
6f555f3ad7 | ||
|
|
2972a4eace | ||
|
|
24a101297c | ||
|
|
cfd281b319 | ||
|
|
0516d75c44 | ||
|
|
db351bdb05 | ||
|
|
18ae8b14e9 | ||
|
|
c53179f742 | ||
|
|
c5cbf82dbf | ||
|
|
dd25b3ecbe | ||
|
|
c18c35d737 | ||
|
|
6a5a50521b | ||
|
|
2837d2551a | ||
|
|
295861d577 | ||
|
|
db812df06f | ||
|
|
8c0d2e910c | ||
|
|
9ea63fe716 | ||
|
|
1433363523 | ||
|
|
83376afd15 | ||
|
|
07fccf8064 | ||
|
|
6ebc615fd4 | ||
|
|
0d0c94375d | ||
|
|
2d5cbfd4c9 | ||
|
|
41726924e0 | ||
|
|
a803d3fb26 | ||
|
|
09015df8a4 | ||
|
|
992b3c74fc | ||
|
|
a2bf2c7edb | ||
|
|
7a369f8734 | ||
|
|
73a430bd18 | ||
|
|
1c7d5217a0 | ||
|
|
f93fd7cd6b | ||
|
|
68f8e17186 | ||
|
|
b7ad331b75 | ||
|
|
1fc6a0e103 | ||
|
|
6e868c2a6d | ||
|
|
9f8c3c5778 | ||
|
|
26d2e355bb | ||
|
|
68165bbce4 | ||
|
|
3e91f0f53f | ||
|
|
349268cbf7 | ||
|
|
66f48f767e | ||
|
|
56f2732bbb | ||
|
|
5432493945 | ||
|
|
c7e3682597 | ||
|
|
d680a549bd | ||
|
|
581d0c59c4 | ||
|
|
0675ba0fa4 | ||
|
|
9a398aa9a8 | ||
|
|
9f1c251809 | ||
|
|
baace41488 | ||
|
|
b1f5f9a5cd | ||
|
|
c5569cf5ad | ||
|
|
6968d7c17c | ||
|
|
6166d061f2 | ||
|
|
7c99d9c648 | ||
|
|
9a62561336 | ||
|
|
89a8cbc536 | ||
|
|
40fdd00e16 | ||
|
|
7d49624e1c | ||
|
|
a1a885efeb | ||
|
|
22edece201 | ||
|
|
aae33db137 | ||
|
|
afb9ffa50e | ||
|
|
20e968751c | ||
|
|
20661a3c56 | ||
|
|
8d0cb07ba2 | ||
|
|
6618906380 | ||
|
|
fc9c4a8e14 | ||
|
|
efa52acf73 | ||
|
|
0d8d9a3447 | ||
|
|
9b8ba41c44 | ||
|
|
961b077954 | ||
|
|
8b4114c422 | ||
|
|
27dca746ea | ||
|
|
01b47573b3 | ||
|
|
f949ca919a | ||
|
|
41ed6e6695 | ||
|
|
b907100d82 | ||
|
|
f60879bfb5 | ||
|
|
8090619117 | ||
|
|
a935bded36 | ||
|
|
de4ab44e06 | ||
|
|
cbc390ebe5 | ||
|
|
30be6803c3 | ||
|
|
d24d933ad7 | ||
|
|
37f3ea137b | ||
|
|
cf603108d4 | ||
|
|
3eaee1249c | ||
|
|
1ce4707ff9 | ||
|
|
d1704cfb14 | ||
|
|
3748365729 | ||
|
|
79be301984 | ||
|
|
64f77051bd | ||
|
|
a4399a184a | ||
|
|
964e97c842 | ||
|
|
bdc00841c0 | ||
|
|
0b579c0a1a | ||
|
|
308aca632e | ||
|
|
368ba1c5e2 | ||
|
|
367bbc4039 | ||
|
|
3c97bcb790 | ||
|
|
5de9e7c3ad | ||
|
|
add033249f | ||
|
|
63a635c89c | ||
|
|
10e42237f3 | ||
|
|
d0eae97bcf | ||
|
|
7a21b3ba46 | ||
|
|
4656b3a43d | ||
|
|
e280e1ebee | ||
|
|
8953ad6b76 | ||
|
|
8d68bdf4d6 | ||
|
|
03ee7b99d2 | ||
|
|
b76613901c | ||
|
|
0104f96f4a | ||
|
|
a6f95c577a | ||
|
|
982208cd81 | ||
|
|
21b3daa2c0 | ||
|
|
2cafa3c228 | ||
|
|
95b32fb541 | ||
|
|
aed44ba5f3 | ||
|
|
575023f212 | ||
|
|
d2f633b3b4 | ||
|
|
c785cd9d7b | ||
|
|
4ab5a1a060 | ||
|
|
5fc762d811 | ||
|
|
683ecc39d8 | ||
|
|
4dd3059f16 | ||
|
|
9c0cafeeb8 | ||
|
|
73e9b46853 | ||
|
|
04aa7b471b | ||
|
|
d72f8b2e46 | ||
|
|
fb6fbf6d21 | ||
|
|
00b9647aa1 | ||
|
|
c61970d8fe | ||
|
|
f2360542e0 | ||
|
|
7db73c8771 | ||
|
|
1eff6fdf73 | ||
|
|
5c5da3791e | ||
|
|
ece815750e | ||
|
|
cc0d99a141 | ||
|
|
c62c397cda | ||
|
|
f1233b14e8 | ||
|
|
ab4788a2ce | ||
|
|
762bf87663 | ||
|
|
cb53911224 | ||
|
|
d74dd2161a | ||
|
|
e768e2e5fe | ||
|
|
36f54cc6c9 | ||
|
|
551c4e83f4 | ||
|
|
0d5c25b400 | ||
|
|
d21cbe57aa | ||
|
|
57eafb81c7 | ||
|
|
81aeb3b755 | ||
|
|
8f93f5e34b | ||
|
|
afa4e79756 | ||
|
|
9061536cca | ||
|
|
a3de3a1c51 | ||
|
|
af7cd238e5 | ||
|
|
2894653421 | ||
|
|
13a4df9b68 | ||
|
|
6e01270fec | ||
|
|
fdf079265d | ||
|
|
c124820256 | ||
|
|
6e9f2a3b61 | ||
|
|
2f98c5ba47 | ||
|
|
faf1eeeb0d | ||
|
|
23dd572d5e | ||
|
|
61aad2ec68 | ||
|
|
1a85dfd9ce | ||
|
|
b979df61ea | ||
|
|
194c2fa9c4 | ||
|
|
549b294a05 | ||
|
|
c30332818f | ||
|
|
03f375e436 | ||
|
|
403cc3df90 | ||
|
|
7657b3e115 | ||
|
|
831d522025 | ||
|
|
f73680ba21 | ||
|
|
c821ec21bb | ||
|
|
e1f2fa8c7e | ||
|
|
3dc517c82b | ||
|
|
66b61ee25a | ||
|
|
8c10155eb7 | ||
|
|
67a06cb772 | ||
|
|
5ae8824303 | ||
|
|
6adf88542e | ||
|
|
0a8c0f5ab4 | ||
|
|
ff78bebf19 | ||
|
|
5bfe2a9e18 | ||
|
|
1b3a5cdab1 | ||
|
|
e11bfc27bd | ||
|
|
e35c2b243a | ||
|
|
0abc08c773 | ||
|
|
b94940b6d9 | ||
|
|
da012a7a44 | ||
|
|
e94890280a | ||
|
|
0fbeca14ad | ||
|
|
9149a17d79 | ||
|
|
d7e61d07d1 | ||
|
|
d2c98c86dc | ||
|
|
7c0101ad06 | ||
|
|
038bc832a7 | ||
|
|
5ff7b6557f | ||
|
|
cbebf7b392 | ||
|
|
333367c07d | ||
|
|
7d3793e718 | ||
|
|
0ccb5b198a | ||
|
|
a0b24d6194 | ||
|
|
8d8cd05b94 | ||
|
|
7483075b7e | ||
|
|
d245db54a1 | ||
|
|
66f389a4b6 | ||
|
|
e1801f3a29 | ||
|
|
56c85ffe54 | ||
|
|
b9239d7101 | ||
|
|
528f08fb83 | ||
|
|
967367bba6 | ||
|
|
529bee4d73 | ||
|
|
4cdef853d2 | ||
|
|
e58bb88ee8 | ||
|
|
68cbe35d96 | ||
|
|
44ca530087 | ||
|
|
f44905324e | ||
|
|
5f1e62aefe | ||
|
|
c60f459530 | ||
|
|
812abea0de | ||
|
|
0420d25c13 | ||
|
|
1db7865d49 | ||
|
|
8bf8893307 | ||
|
|
8f7dec07b8 | ||
|
|
617ab27c75 | ||
|
|
766dcc4dd6 | ||
|
|
5ec8e5dd30 | ||
|
|
89a2381165 | ||
|
|
a7cdf0e2fd |
2
.github/workflows/go-tests.yml
vendored
2
.github/workflows/go-tests.yml
vendored
@@ -3,6 +3,7 @@ on:
|
||||
push:
|
||||
paths:
|
||||
- "go/**"
|
||||
- "shared/**"
|
||||
- .github/workflows/go-tests.yml
|
||||
- .github/actions/**
|
||||
- codeql-workspace.yml
|
||||
@@ -12,6 +13,7 @@ on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "go/**"
|
||||
- "shared/**"
|
||||
- .github/workflows/go-tests.yml
|
||||
- .github/actions/**
|
||||
- codeql-workspace.yml
|
||||
|
||||
@@ -15,7 +15,7 @@ repos:
|
||||
- id: clang-format
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-autopep8
|
||||
rev: v1.6.0
|
||||
rev: v2.0.4
|
||||
hooks:
|
||||
- id: autopep8
|
||||
files: ^misc/codegen/.*\.py
|
||||
|
||||
98
Cargo.lock
generated
98
Cargo.lock
generated
@@ -96,6 +96,16 @@ version = "1.0.87"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10f00e1f6e58a40e807377c75c6a7f97bf9044fab57816f2414e6f5f4499d7b8"
|
||||
|
||||
[[package]]
|
||||
name = "argfile"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a1cc0ba69de57db40674c66f7cf2caee3981ddef084388482c95c0e2133e5e8"
|
||||
dependencies = [
|
||||
"fs-err",
|
||||
"os_str_bytes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.6"
|
||||
@@ -255,7 +265,7 @@ dependencies = [
|
||||
"chalk-ir",
|
||||
"ena",
|
||||
"indexmap 2.5.0",
|
||||
"itertools",
|
||||
"itertools 0.12.1",
|
||||
"petgraph",
|
||||
"rustc-hash",
|
||||
"tracing",
|
||||
@@ -360,9 +370,11 @@ name = "codeql-rust"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argfile",
|
||||
"clap",
|
||||
"codeql-extractor",
|
||||
"figment",
|
||||
"itertools 0.13.0",
|
||||
"log",
|
||||
"num-traits",
|
||||
"ra_ap_base_db",
|
||||
@@ -370,10 +382,12 @@ dependencies = [
|
||||
"ra_ap_hir_def",
|
||||
"ra_ap_ide_db",
|
||||
"ra_ap_load-cargo",
|
||||
"ra_ap_parser",
|
||||
"ra_ap_paths",
|
||||
"ra_ap_project_model",
|
||||
"ra_ap_syntax",
|
||||
"ra_ap_vfs",
|
||||
"rust-extractor-macros",
|
||||
"serde",
|
||||
"serde_with",
|
||||
"stderrlog",
|
||||
@@ -643,6 +657,15 @@ version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "fs-err"
|
||||
version = "2.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fsevent-sys"
|
||||
version = "4.1.0"
|
||||
@@ -658,6 +681,16 @@ version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a"
|
||||
|
||||
[[package]]
|
||||
name = "generate-schema"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"itertools 0.10.5",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"ungrammar",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.15"
|
||||
@@ -827,6 +860,15 @@ version = "1.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.1"
|
||||
@@ -836,6 +878,15 @@ dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
@@ -1064,6 +1115,15 @@ version = "11.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9"
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "7.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ac44c994af577c799b1b4bd80dc214701e349873ad894d6cdf96f4f7526e0b9"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "overload"
|
||||
version = "0.1.1"
|
||||
@@ -1303,7 +1363,7 @@ checksum = "c7c38520eb4770af561c34b908431f4e548c3282093cf3daf3c6e566d99a2937"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"either",
|
||||
"itertools",
|
||||
"itertools 0.12.1",
|
||||
"ra_ap_base_db",
|
||||
"ra_ap_cfg",
|
||||
"ra_ap_hir_def",
|
||||
@@ -1335,7 +1395,7 @@ dependencies = [
|
||||
"fst",
|
||||
"hashbrown 0.14.5",
|
||||
"indexmap 2.5.0",
|
||||
"itertools",
|
||||
"itertools 0.12.1",
|
||||
"la-arena",
|
||||
"ra-ap-rustc_abi",
|
||||
"ra-ap-rustc_parse_format",
|
||||
@@ -1365,7 +1425,7 @@ dependencies = [
|
||||
"cov-mark",
|
||||
"either",
|
||||
"hashbrown 0.14.5",
|
||||
"itertools",
|
||||
"itertools 0.12.1",
|
||||
"la-arena",
|
||||
"ra_ap_base_db",
|
||||
"ra_ap_cfg",
|
||||
@@ -1400,7 +1460,7 @@ dependencies = [
|
||||
"either",
|
||||
"ena",
|
||||
"indexmap 2.5.0",
|
||||
"itertools",
|
||||
"itertools 0.12.1",
|
||||
"la-arena",
|
||||
"nohash-hasher",
|
||||
"oorandom",
|
||||
@@ -1437,7 +1497,7 @@ dependencies = [
|
||||
"either",
|
||||
"fst",
|
||||
"indexmap 2.5.0",
|
||||
"itertools",
|
||||
"itertools 0.12.1",
|
||||
"line-index",
|
||||
"memchr",
|
||||
"nohash-hasher",
|
||||
@@ -1483,7 +1543,7 @@ checksum = "82e6f24b61f1ef1f3a756493d1fb7e711b69b2e4d5f4746fcb959313dfd41471"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"crossbeam-channel",
|
||||
"itertools",
|
||||
"itertools 0.12.1",
|
||||
"ra_ap_hir_expand",
|
||||
"ra_ap_ide_db",
|
||||
"ra_ap_intern",
|
||||
@@ -1578,7 +1638,7 @@ checksum = "db83d1844c74b22c110c4b8e8f2519be2b1723964008527281a11c3398749756"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cargo_metadata",
|
||||
"itertools",
|
||||
"itertools 0.12.1",
|
||||
"la-arena",
|
||||
"ra_ap_base_db",
|
||||
"ra_ap_cfg",
|
||||
@@ -1602,7 +1662,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "370b302873eeafd07ccc6a714fc9395cae11e385955ccb78081093ee3b86f94e"
|
||||
dependencies = [
|
||||
"indexmap 2.5.0",
|
||||
"itertools",
|
||||
"itertools 0.12.1",
|
||||
"lock_api",
|
||||
"oorandom",
|
||||
"parking_lot",
|
||||
@@ -1649,7 +1709,7 @@ checksum = "bb63ff9d6b11b4553fc0835f16705975258905e3b1230fcf1ddbf24c46aff69d"
|
||||
dependencies = [
|
||||
"always-assert",
|
||||
"crossbeam-channel",
|
||||
"itertools",
|
||||
"itertools 0.12.1",
|
||||
"jod-thread",
|
||||
"libc",
|
||||
"miow",
|
||||
@@ -1665,7 +1725,7 @@ dependencies = [
|
||||
"cov-mark",
|
||||
"either",
|
||||
"indexmap 2.5.0",
|
||||
"itertools",
|
||||
"itertools 0.12.1",
|
||||
"ra-ap-rustc_lexer",
|
||||
"ra_ap_parser",
|
||||
"ra_ap_stdx",
|
||||
@@ -1699,7 +1759,7 @@ version = "0.0.232"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7cb72ee1901baec556f4f2ef77e287d749ac0e973f063990672d6207b076aeac"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"itertools 0.12.1",
|
||||
"text-size",
|
||||
]
|
||||
|
||||
@@ -1875,6 +1935,14 @@ dependencies = [
|
||||
"text-size",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-extractor-macros"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
@@ -2287,6 +2355,12 @@ dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ungrammar"
|
||||
version = "1.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3e5df347f0bf3ec1d670aad6ca5c6a1859cd9ea61d2113125794654ccced68f"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.13"
|
||||
|
||||
@@ -6,6 +6,8 @@ members = [
|
||||
"shared/tree-sitter-extractor",
|
||||
"ruby/extractor",
|
||||
"rust/extractor",
|
||||
"rust/extractor/macros",
|
||||
"rust/generate-schema",
|
||||
]
|
||||
|
||||
[patch.crates-io]
|
||||
|
||||
@@ -60,6 +60,8 @@ r.from_cargo(
|
||||
"//:Cargo.toml",
|
||||
"//ruby/extractor:Cargo.toml",
|
||||
"//rust/extractor:Cargo.toml",
|
||||
"//rust/extractor/macros:Cargo.toml",
|
||||
"//rust/generate-schema:Cargo.toml",
|
||||
"//shared/tree-sitter-extractor:Cargo.toml",
|
||||
],
|
||||
)
|
||||
@@ -126,6 +128,7 @@ use_repo(
|
||||
"kotlin-compiler-1.9.20-Beta",
|
||||
"kotlin-compiler-2.0.0-RC1",
|
||||
"kotlin-compiler-2.0.20-Beta2",
|
||||
"kotlin-compiler-2.1.0-Beta1",
|
||||
"kotlin-compiler-embeddable-1.5.0",
|
||||
"kotlin-compiler-embeddable-1.5.10",
|
||||
"kotlin-compiler-embeddable-1.5.20",
|
||||
@@ -139,6 +142,7 @@ use_repo(
|
||||
"kotlin-compiler-embeddable-1.9.20-Beta",
|
||||
"kotlin-compiler-embeddable-2.0.0-RC1",
|
||||
"kotlin-compiler-embeddable-2.0.20-Beta2",
|
||||
"kotlin-compiler-embeddable-2.1.0-Beta1",
|
||||
"kotlin-stdlib-1.5.0",
|
||||
"kotlin-stdlib-1.5.10",
|
||||
"kotlin-stdlib-1.5.20",
|
||||
@@ -152,6 +156,7 @@ use_repo(
|
||||
"kotlin-stdlib-1.9.20-Beta",
|
||||
"kotlin-stdlib-2.0.0-RC1",
|
||||
"kotlin-stdlib-2.0.20-Beta2",
|
||||
"kotlin-stdlib-2.1.0-Beta1",
|
||||
)
|
||||
|
||||
go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
provide:
|
||||
- "*/ql/base/qlpack.yml"
|
||||
- "*/ql/src/qlpack.yml"
|
||||
- "*/ql/lib/qlpack.yml"
|
||||
- "*/ql/test*/qlpack.yml"
|
||||
|
||||
@@ -57,10 +57,6 @@
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll"
|
||||
],
|
||||
"Model as Data Generation Java/C# - CaptureModels": [
|
||||
"java/ql/src/utils/modelgenerator/internal/CaptureModels.qll",
|
||||
"csharp/ql/src/utils/modelgenerator/internal/CaptureModels.qll"
|
||||
],
|
||||
"Sign Java/C#": [
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/Sign.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/Sign.qll"
|
||||
@@ -355,5 +351,9 @@
|
||||
"Python model summaries test extension": [
|
||||
"python/ql/test/library-tests/dataflow/model-summaries/InlineTaintTest.ext.yml",
|
||||
"python/ql/test/library-tests/dataflow/model-summaries/NormalDataflowTest.ext.yml"
|
||||
],
|
||||
"Diagnostics.qll": [
|
||||
"ruby/ql/lib/codeql/ruby/Diagnostics.qll",
|
||||
"rust/ql/lib/codeql/rust/Diagnostics.qll"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 2.0.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 2.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
3
cpp/ql/lib/change-notes/released/2.0.1.md
Normal file
3
cpp/ql/lib/change-notes/released/2.0.1.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 2.0.1
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 2.0.0
|
||||
lastReleaseVersion: 2.0.1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 2.0.0
|
||||
version: 2.0.2-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -500,6 +500,17 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
|
||||
* Gets the nearest enclosing AccessHolder.
|
||||
*/
|
||||
override AccessHolder getEnclosingAccessHolder() { result = this.getDeclaringType() }
|
||||
|
||||
/**
|
||||
* Holds if this function has extraction errors that create an `ErrorExpr`.
|
||||
*/
|
||||
predicate hasErrors() {
|
||||
exists(ErrorExpr e |
|
||||
e.getEnclosingFunction() = this and
|
||||
// Exclude the first allocator call argument because it is always extracted as `ErrorExpr`.
|
||||
not exists(NewOrNewArrayExpr new | e = new.getAllocatorCall().getArgument(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -651,7 +662,8 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl {
|
||||
|
||||
/**
|
||||
* Holds if this declaration is an implicit function declaration, that is,
|
||||
* where a function is used before it is declared (under older C standards).
|
||||
* where a function is used before it is declared (under older C standards,
|
||||
* or when there were parse errors).
|
||||
*/
|
||||
predicate isImplicit() { fun_implicit(underlyingElement(this)) }
|
||||
|
||||
|
||||
@@ -39,8 +39,8 @@ class Type extends Locatable, @type {
|
||||
|
||||
/**
|
||||
* Gets a specifier of this type, recursively looking through `typedef` and
|
||||
* `decltype`. For example, in the context of `typedef const int *restrict
|
||||
* t`, the type `volatile t` has specifiers `volatile` and `restrict` but not
|
||||
* `decltype`. For example, in the context of `typedef const int *restrict t`,
|
||||
* the type `volatile t` has specifiers `volatile` and `restrict` but not
|
||||
* `const` since the `const` is attached to the type being pointed to rather
|
||||
* than the pointer itself.
|
||||
*/
|
||||
|
||||
@@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { none() }
|
||||
}
|
||||
|
||||
deprecated private import Impl<Config> as I
|
||||
|
||||
@@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { none() }
|
||||
}
|
||||
|
||||
deprecated private import Impl<Config> as I
|
||||
|
||||
@@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { none() }
|
||||
}
|
||||
|
||||
deprecated private import Impl<Config> as I
|
||||
|
||||
@@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { none() }
|
||||
}
|
||||
|
||||
deprecated private import Impl<Config> as I
|
||||
|
||||
@@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { none() }
|
||||
}
|
||||
|
||||
deprecated private import Impl<Config> as I
|
||||
|
||||
@@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { none() }
|
||||
}
|
||||
|
||||
deprecated private import Impl<Config> as I
|
||||
|
||||
@@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { none() }
|
||||
}
|
||||
|
||||
deprecated private import Impl<Config> as I
|
||||
|
||||
@@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { none() }
|
||||
}
|
||||
|
||||
deprecated private import Impl<Config> as I
|
||||
|
||||
@@ -283,6 +283,8 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { none() }
|
||||
}
|
||||
|
||||
deprecated private import Impl<Config> as I
|
||||
|
||||
@@ -546,7 +546,7 @@ module ProductFlow {
|
||||
Flow1::PathGraph::edges(pred1, succ1, _, _) and
|
||||
exists(ReturnKindExt returnKind |
|
||||
succ1.getNode() = returnKind.getAnOutNode(call) and
|
||||
paramReturnNode(_, pred1.asParameterReturnNode(), _, returnKind)
|
||||
returnKind = getParamReturnPosition(_, pred1.asParameterReturnNode()).getKind()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -574,7 +574,7 @@ module ProductFlow {
|
||||
Flow2::PathGraph::edges(pred2, succ2, _, _) and
|
||||
exists(ReturnKindExt returnKind |
|
||||
succ2.getNode() = returnKind.getAnOutNode(call) and
|
||||
paramReturnNode(_, pred2.asParameterReturnNode(), _, returnKind)
|
||||
returnKind = getParamReturnPosition(_, pred2.asParameterReturnNode()).getKind()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -118,19 +118,34 @@ abstract class FormattingFunction extends ArrayFunction, TaintFunction {
|
||||
|
||||
/**
|
||||
* Gets the position of the first format argument, corresponding with
|
||||
* the first format specifier in the format string.
|
||||
* the first format specifier in the format string. We ignore all
|
||||
* implicit function definitions.
|
||||
*/
|
||||
int getFirstFormatArgumentIndex() {
|
||||
result = this.getNumberOfParameters() and
|
||||
// the formatting function either has a definition in the snapshot, or all
|
||||
// The formatting function either has a definition in the snapshot, or all
|
||||
// `DeclarationEntry`s agree on the number of parameters (otherwise we don't
|
||||
// really know the correct number)
|
||||
(
|
||||
this.hasDefinition()
|
||||
or
|
||||
forall(FunctionDeclarationEntry fde | fde = this.getADeclarationEntry() |
|
||||
result = fde.getNumberOfParameters()
|
||||
)
|
||||
if this.hasDefinition()
|
||||
then result = this.getDefinition().getNumberOfParameters()
|
||||
else result = this.getNumberOfExplicitParameters()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a non-implicit function declaration entry.
|
||||
*/
|
||||
private FunctionDeclarationEntry getAnExplicitDeclarationEntry() {
|
||||
result = this.getADeclarationEntry() and
|
||||
not result.isImplicit()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of parameters, excluding any parameters that have been defined
|
||||
* from implicit function declarations. If there is some inconsistency in the number
|
||||
* of parameters, then don't return anything.
|
||||
*/
|
||||
private int getNumberOfExplicitParameters() {
|
||||
forex(FunctionDeclarationEntry fde | fde = this.getAnExplicitDeclarationEntry() |
|
||||
result = fde.getNumberOfParameters()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -160,6 +160,26 @@ private module InvalidPointerToDerefBarrier {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* BEWARE: This configuration uses an unrestricted sink, so accessing its full
|
||||
* flow computation or any stages beyond the first 2 will likely diverge.
|
||||
* Stage 1 will still be fast and we use it to restrict the subsequent sink
|
||||
* computation.
|
||||
*/
|
||||
private module InvalidPointerReachesConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { invalidPointerToDerefSource(_, _, source) }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { any() }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { InvalidPointerToDerefConfig::isBarrier(node) }
|
||||
|
||||
int fieldFlowBranchLimit() { result = invalidPointerToDereferenceFieldFlowBranchLimit() }
|
||||
}
|
||||
|
||||
private module InvalidPointerReachesFlow = DataFlow::Global<InvalidPointerReachesConfig>;
|
||||
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
|
||||
|
||||
/**
|
||||
* A configuration to track flow from a pointer-arithmetic operation found
|
||||
* by `AllocToInvalidPointerConfig` to a dereference of the pointer.
|
||||
@@ -173,8 +193,13 @@ private module InvalidPointerToDerefConfig implements DataFlow::StateConfigSig {
|
||||
invalidPointerToDerefSource(_, pai, source)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
predicate isSink(DataFlow::Node sink) { isInvalidPointerDerefSink(sink, _, _, _, _) }
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(DataFlowImplCommon::NodeEx n |
|
||||
InvalidPointerReachesFlow::Stages::Stage1::sinkNode(n, _) and
|
||||
n.asNode() = sink and
|
||||
isInvalidPointerDerefSink(sink, _, _, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink, FlowState pai) { none() }
|
||||
|
||||
|
||||
@@ -72,7 +72,6 @@ module FlowFromFree<FlowFromFreeParamSig P> {
|
||||
|
||||
predicate isSource(DataFlow::Node node, FlowState state) { isFree(node, _, state, _) }
|
||||
|
||||
pragma[inline]
|
||||
predicate isSink(DataFlow::Node sink, FlowState state) {
|
||||
exists(Expr e, DataFlow::Node source, DeallocationExpr dealloc |
|
||||
P::isSink(sink, e) and
|
||||
|
||||
@@ -57,5 +57,5 @@ where
|
||||
not declarationHasSideEffects(v) and
|
||||
not exists(AsmStmt s | f = s.getEnclosingFunction()) and
|
||||
not v.getAnAttribute().getName() = "unused" and
|
||||
not any(ErrorExpr e).getEnclosingFunction() = f // unextracted expr may use `v`
|
||||
not f.hasErrors() // Unextracted expressions may use `v`
|
||||
select v, "Variable " + v.getName() + " is not used."
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
## 1.2.4
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Fixed false positives in the `cpp/wrong-number-format-arguments` ("Too few arguments to formatting function") query when the formatting function has been declared implicitly.
|
||||
|
||||
## 1.2.3
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Removed false positives caused by buffer accesses in unreachable code.
|
||||
* Removed false positives caused by inconsistent type checking.
|
||||
* Removed false positives caused by buffer accesses in unreachable code
|
||||
* Removed false positives caused by inconsistent type checking
|
||||
* Add modeling of C functions that don't throw, thereby increasing the precision of the `cpp/incorrect-allocation-error-handling` ("Incorrect allocation-error handling") query. The query now produces additional true positives.
|
||||
|
||||
## 1.2.2
|
||||
|
||||
@@ -29,7 +29,7 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
|
||||
override predicate isSource(Instruction source) {
|
||||
exists(Function func |
|
||||
// Rule out FPs caused by extraction errors.
|
||||
not any(ErrorExpr e).getEnclosingFunction() = func and
|
||||
not func.hasErrors() and
|
||||
not intentionallyReturnsStackPointer(func) and
|
||||
func = source.getEnclosingFunction()
|
||||
|
|
||||
|
||||
@@ -65,6 +65,7 @@ predicate isSinkImpl(Instruction sink, VariableAccess va) {
|
||||
exists(LoadInstruction load |
|
||||
va = load.getUnconvertedResultExpression() and
|
||||
not va = commonException() and
|
||||
not va.getTarget().(LocalVariable).getFunction().hasErrors() and
|
||||
sink = load.getSourceValue()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ predicate instructionHasVariable(VariableAddressInstruction vai, StackVariable v
|
||||
// Pointer-to-member types aren't properly handled in the dbscheme.
|
||||
not vai.getResultType() instanceof PointerToMemberType and
|
||||
// Rule out FPs caused by extraction errors.
|
||||
not any(ErrorExpr e).getEnclosingFunction() = f
|
||||
not f.hasErrors()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,23 +13,85 @@
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.Guards
|
||||
|
||||
class WideCharPointerType extends PointerType {
|
||||
WideCharPointerType() { this.getBaseType() instanceof WideCharType }
|
||||
}
|
||||
|
||||
/**
|
||||
* Given type `t`, recurses through and returns all
|
||||
* intermediate base types, including `t`.
|
||||
*/
|
||||
Type getABaseType(Type t) {
|
||||
result = t
|
||||
or
|
||||
result = getABaseType(t.(DerivedType).getBaseType())
|
||||
or
|
||||
result = getABaseType(t.(TypedefType).getBaseType())
|
||||
}
|
||||
|
||||
/**
|
||||
* A type that may also be `CharPointerType`, but that are likely used as arbitrary buffers.
|
||||
*/
|
||||
class UnlikelyToBeAStringType extends Type {
|
||||
UnlikelyToBeAStringType() {
|
||||
this.(PointerType).getBaseType().(CharType).isUnsigned() or
|
||||
this.(PointerType).getBaseType().getName().toLowerCase().matches("%byte") or
|
||||
this.getName().toLowerCase().matches("%byte") or
|
||||
this.(PointerType).getBaseType().hasName("uint8_t")
|
||||
exists(Type targ | getABaseType(this) = targ |
|
||||
// NOTE: not using CharType isUnsigned, but rather look for any explicitly declared unsigned
|
||||
// char types. Assuming these are used for buffers, not strings.
|
||||
targ.(CharType).getName().toLowerCase().matches("unsigned%") or
|
||||
targ.getName().toLowerCase().matches(["uint8_t", "%byte%"])
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Types that can be wide depending on the UNICODE macro
|
||||
// see https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types
|
||||
class UnicodeMacroDependentWidthType extends Type {
|
||||
UnicodeMacroDependentWidthType() {
|
||||
exists(Type targ | getABaseType(this) = targ |
|
||||
targ.getName() in [
|
||||
"LPCTSTR",
|
||||
"LPTSTR",
|
||||
"PCTSTR",
|
||||
"PTSTR",
|
||||
"TBYTE",
|
||||
"TCHAR"
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class UnicodeMacro extends Macro {
|
||||
UnicodeMacro() { this.getName().toLowerCase().matches("%unicode%") }
|
||||
}
|
||||
|
||||
class UnicodeMacroInvocation extends MacroInvocation {
|
||||
UnicodeMacroInvocation() { this.getMacro() instanceof UnicodeMacro }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds when a expression whose type is UnicodeMacroDependentWidthType and
|
||||
* is observed to be guarded by a check involving a bitwise-and operation
|
||||
* with a UnicodeMacroInvocation.
|
||||
* Such expressions are assumed to be checked dynamically, i.e.,
|
||||
* the flag would indicate if UNICODE typing is set correctly to allow
|
||||
* or disallow a widening cast.
|
||||
*/
|
||||
predicate isLikelyDynamicallyChecked(Expr e) {
|
||||
e.getType() instanceof UnicodeMacroDependentWidthType and
|
||||
exists(GuardCondition gc, BitwiseAndExpr bai, UnicodeMacroInvocation umi |
|
||||
bai.getAnOperand() = umi.getExpr()
|
||||
|
|
||||
// bai == 0 is false when reaching `e.getBasicBlock()`.
|
||||
// That is, bai != 0 when reaching `e.getBasicBlock()`.
|
||||
gc.ensuresEq(bai, 0, e.getBasicBlock(), false)
|
||||
or
|
||||
// bai == k and k != 0 is true when reaching `e.getBasicBlock()`.
|
||||
gc.ensuresEq(bai, any(int k | k != 0), e.getBasicBlock(), true)
|
||||
)
|
||||
}
|
||||
|
||||
from Expr e1, Cast e2
|
||||
where
|
||||
e2 = e1.getConversion() and
|
||||
@@ -42,7 +104,11 @@ where
|
||||
not e1.getType() instanceof UnlikelyToBeAStringType and
|
||||
// Avoid castings from 'new' expressions as typically these will be safe
|
||||
// Example: `__Type* ret = reinterpret_cast<__Type*>(New(m_pmo) char[num * sizeof(__Type)]);`
|
||||
not exists(NewOrNewArrayExpr newExpr | newExpr.getAChild*() = e1)
|
||||
not exists(NewOrNewArrayExpr newExpr | newExpr.getAChild*() = e1) and
|
||||
// Avoid cases where the cast is guarded by a check to determine if
|
||||
// unicode encoding is enabled in such a way to disallow the dangerous cast
|
||||
// at runtime.
|
||||
not isLikelyDynamicallyChecked(e1)
|
||||
select e1,
|
||||
"Conversion from " + e1.getType().toString() + " to " + e2.getType().toString() +
|
||||
". Use of invalid string can lead to undefined behavior."
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `cpp/incorrect-string-type-conversion` query now produces fewer false positives caused by failure to detect byte arrays.
|
||||
* The `cpp/incorrect-string-type-conversion` query now produces fewer false positives caused by failure to recognize dynamic checks prior to possible dangerous widening.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Fixed false positives in the `cpp/uninitialized-local` ("Potentially uninitialized local variable") query if there are extraction errors in the function.
|
||||
5
cpp/ql/src/change-notes/released/1.2.4.md
Normal file
5
cpp/ql/src/change-notes/released/1.2.4.md
Normal file
@@ -0,0 +1,5 @@
|
||||
## 1.2.4
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Fixed false positives in the `cpp/wrong-number-format-arguments` ("Too few arguments to formatting function") query when the formatting function has been declared implicitly.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.2.3
|
||||
lastReleaseVersion: 1.2.4
|
||||
|
||||
34
cpp/ql/src/experimental/Security/CWE/CWE-295/CurlSSL.qhelp
Normal file
34
cpp/ql/src/experimental/Security/CWE/CWE-295/CurlSSL.qhelp
Normal file
@@ -0,0 +1,34 @@
|
||||
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>
|
||||
Disabling verification of the SSL certificate allows man-in-the-middle attacks. A SSL
|
||||
connection is vulnerable to man-in-the-middle attacks if the certification is not checked
|
||||
properly. If the peer or the host's certificate verification is not verified, the underlying
|
||||
SSL communication is insecure.</p>
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>It is recommended that all communications be done post verification of the host as well as
|
||||
the
|
||||
peer.</p>
|
||||
</recommendation>
|
||||
<example>
|
||||
<p>The following snippet disables certification verification by setting the value of <code>
|
||||
CURLOPT_SSL_VERIFYHOST</code> and <code>CURLOPT_SSL_VERIFYHOST</code> to <code>0</code>:</p>
|
||||
<sample src="CurlSSLBad.cpp" />
|
||||
<p>This is bad as the certificates are not verified any more. This can be easily fixed by
|
||||
setting the values of the options to <code>2</code>. </p>
|
||||
<sample src="CurlSSLGood.cpp" />
|
||||
</example>
|
||||
<references>
|
||||
<li> Curl Documentation:<a href="https://curl.se/libcurl/c/CURLOPT_SSL_VERIFYHOST.html">
|
||||
CURLOPT_SSL_VERIFYHOST</a></li>
|
||||
<li> Curl Documentation:<a href="https://curl.se/libcurl/c/CURLOPT_SSL_VERIFYPEER.html">
|
||||
CURLOPT_SSL_VERIFYPEER</a></li>
|
||||
<li> Related CVE: <a href="https://github.com/advisories/GHSA-5r3h-c3r7-9w4h"> CVE-2022-33684</a></li>
|
||||
<li> Related security advisory: <a
|
||||
href="https://huntr.com/bounties/42325662-6329-4e04-875a-49e2f5d69f78">
|
||||
openframeworks/openframeworks
|
||||
</a></li>
|
||||
</references>
|
||||
</qhelp>
|
||||
39
cpp/ql/src/experimental/Security/CWE/CWE-295/CurlSSL.ql
Normal file
39
cpp/ql/src/experimental/Security/CWE/CWE-295/CurlSSL.ql
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* @name Disabled certifcate verification
|
||||
* @description Disabling SSL certificate verification of host or peer could expose the communication to man-in-the-middle(MITM) attacks.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @id cpp/curl-disabled-ssl
|
||||
* @tags security
|
||||
* external/cwe/cwe-295
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.dataflow.new.TaintTracking
|
||||
|
||||
/** Models the `curl_easy_setopt` function call */
|
||||
private class CurlSetOptCall extends FunctionCall {
|
||||
CurlSetOptCall() {
|
||||
exists(FunctionCall fc, Function f |
|
||||
f.hasGlobalOrStdName("curl_easy_setopt") and
|
||||
fc.getTarget() = f
|
||||
|
|
||||
this = fc
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Models an access to any enum constant which could affect SSL verification */
|
||||
private class CurlVerificationConstant extends EnumConstantAccess {
|
||||
CurlVerificationConstant() {
|
||||
exists(EnumConstant e | e.getName() = ["CURLOPT_SSL_VERIFYHOST", "CURLOPT_SSL_VERIFYPEER"] |
|
||||
e.getAnAccess() = this
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
from CurlSetOptCall c
|
||||
where
|
||||
c.getArgument(1) = any(CurlVerificationConstant v) and
|
||||
c.getArgument(2).getValue() = "0"
|
||||
select c, "This call disables Secure Socket Layer and could potentially lead to MITM attacks"
|
||||
@@ -0,0 +1,9 @@
|
||||
string host = "codeql.com"
|
||||
void bad(void) {
|
||||
std::unique_ptr<CURL, void(*)(CURL*)> curl =
|
||||
std::unique_ptr<CURL, void(*)(CURL*)>(curl_easy_init(), curl_easy_cleanup);
|
||||
curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYPEER, 0);
|
||||
curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYHOST, 0);
|
||||
curl_easy_setopt(curl.get(), CURLOPT_URL, host.c_str());
|
||||
curl_easy_perform(curl.get());
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
string host = "codeql.com"
|
||||
void good(void) {
|
||||
std::unique_ptr<CURL, void(*)(CURL*)> curl =
|
||||
std::unique_ptr<CURL, void(*)(CURL*)>(curl_easy_init(), curl_easy_cleanup);
|
||||
curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYPEER, 2);
|
||||
curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYHOST, 2);
|
||||
curl_easy_setopt(curl.get(), CURLOPT_URL, host.c_str());
|
||||
curl_easy_perform(curl.get());
|
||||
}
|
||||
@@ -49,7 +49,7 @@ predicate functionsMissingReturnStmt(Function f, ControlFlowNode blame) {
|
||||
predicate functionImperfectlyExtracted(Function f) {
|
||||
exists(CompilerError e | f.getBlock().getLocation().subsumes(e.getLocation()))
|
||||
or
|
||||
exists(ErrorExpr ee | ee.getEnclosingFunction() = f)
|
||||
f.hasErrors()
|
||||
or
|
||||
count(f.getType()) > 1
|
||||
or
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 1.2.3
|
||||
version: 1.2.5-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
#include "../../../../../library-tests/string_concat/stl.h"
|
||||
|
||||
namespace std{
|
||||
struct CURL {};
|
||||
typedef CURL curl;
|
||||
enum curl_constant{
|
||||
CURLOPT_URL,
|
||||
CURLOPT_SSL_VERIFYHOST,
|
||||
CURLOPT_SSL_VERIFYPEER
|
||||
};
|
||||
|
||||
CURL *curl_easy_init();
|
||||
void curl_easy_cleanup(CURL *handle);
|
||||
void curl_easy_perform(CURL *handle);
|
||||
void curl_easy_setopt(CURL *handle, curl_constant param, int p);
|
||||
void curl_easy_setopt(CURL *handle, curl_constant param, char* p);
|
||||
}
|
||||
|
||||
|
||||
using namespace std;
|
||||
char host[] = "codeql.com";
|
||||
|
||||
void bad(void) {
|
||||
std::unique_ptr<CURL> curl = std::unique_ptr<CURL>(curl_easy_init());
|
||||
curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYPEER, 0);
|
||||
curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYHOST, 0);
|
||||
curl_easy_setopt(curl.get(), CURLOPT_URL, host);
|
||||
curl_easy_perform(curl.get());
|
||||
}
|
||||
|
||||
void good(void) {
|
||||
std::unique_ptr<CURL> curl = std::unique_ptr<CURL>(curl_easy_init());
|
||||
curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYPEER, 2);
|
||||
curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYHOST, 2);
|
||||
curl_easy_setopt(curl.get(), CURLOPT_URL, host);
|
||||
curl_easy_perform(curl.get());
|
||||
}
|
||||
|
||||
int main(int c, char** argv){
|
||||
bad();
|
||||
good();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
| CurlSSL.cpp:25:2:25:17 | call to curl_easy_setopt | This call disables Secure Socket Layer and could potentially lead to MITM attacks |
|
||||
| CurlSSL.cpp:26:2:26:17 | call to curl_easy_setopt | This call disables Secure Socket Layer and could potentially lead to MITM attacks |
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Security/CWE/CWE-295/CurlSSL.ql
|
||||
@@ -3,20 +3,20 @@ failures
|
||||
edges
|
||||
| asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | provenance | MaD:10 |
|
||||
| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:2 |
|
||||
| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:2 Sink:MaD:6 |
|
||||
| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:2 Sink:MaD:6 |
|
||||
| asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:98:7:98:14 | send_str | provenance | TaintFunction |
|
||||
| asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:100:64:100:71 | *send_str | provenance | TaintFunction |
|
||||
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | |
|
||||
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:101:7:101:17 | send_buffer | provenance | |
|
||||
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:103:29:103:39 | *send_buffer | provenance | Sink:MaD:6 |
|
||||
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:103:29:103:39 | *send_buffer | provenance | Sink:MaD:6 |
|
||||
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | provenance | |
|
||||
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:10 |
|
||||
| test.cpp:4:5:4:11 | [summary param] 0 in ymlStep | test.cpp:4:5:4:11 | [summary] to write: ReturnValue in ymlStep | provenance | MaD:644 |
|
||||
| test.cpp:7:10:7:18 | call to ymlSource | test.cpp:7:10:7:18 | call to ymlSource | provenance | Src:MaD:642 |
|
||||
| test.cpp:7:10:7:18 | call to ymlSource | test.cpp:11:10:11:10 | x | provenance | Sink:MaD:643 |
|
||||
| test.cpp:7:10:7:18 | call to ymlSource | test.cpp:11:10:11:10 | x | provenance | Sink:MaD:643 |
|
||||
| test.cpp:7:10:7:18 | call to ymlSource | test.cpp:13:18:13:18 | x | provenance | |
|
||||
| test.cpp:13:10:13:16 | call to ymlStep | test.cpp:13:10:13:16 | call to ymlStep | provenance | |
|
||||
| test.cpp:13:10:13:16 | call to ymlStep | test.cpp:15:10:15:10 | y | provenance | Sink:MaD:643 |
|
||||
| test.cpp:13:10:13:16 | call to ymlStep | test.cpp:15:10:15:10 | y | provenance | Sink:MaD:643 |
|
||||
| test.cpp:13:18:13:18 | x | test.cpp:4:5:4:11 | [summary param] 0 in ymlStep | provenance | |
|
||||
| test.cpp:13:18:13:18 | x | test.cpp:13:10:13:16 | call to ymlStep | provenance | MaD:644 |
|
||||
nodes
|
||||
|
||||
@@ -2,25 +2,168 @@
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | false |
|
||||
| file://:0:0:0:0 | __super | false |
|
||||
| file://:0:0:0:0 | __va_list_tag | false |
|
||||
| file://:0:0:0:0 | decltype([...](...){...}) | false |
|
||||
| file://:0:0:0:0 | operator= | false |
|
||||
| file://:0:0:0:0 | operator= | false |
|
||||
| test.cpp:0:0:0:0 | test.cpp | false |
|
||||
| test.cpp:2:1:2:61 | #define FOO class S{int i; void f(void) { int j; return; } }; | false |
|
||||
| test.cpp:2:1:2:68 | #define CLASS_DECL class S{int i; void f(void) { int j; return; } }; | false |
|
||||
| test.cpp:4:1:4:1 | S | false |
|
||||
| test.cpp:4:1:4:1 | declaration of S | false |
|
||||
| test.cpp:4:1:4:1 | declaration of operator= | false |
|
||||
| test.cpp:4:1:4:1 | declaration of operator= | false |
|
||||
| test.cpp:4:1:4:1 | operator= | false |
|
||||
| test.cpp:4:1:4:1 | operator= | false |
|
||||
| test.cpp:4:1:4:3 | FOO | false |
|
||||
| test.cpp:4:1:4:3 | S | false |
|
||||
| test.cpp:4:1:4:3 | declaration | true |
|
||||
| test.cpp:4:1:4:3 | definition of S | true |
|
||||
| test.cpp:4:1:4:3 | definition of f | true |
|
||||
| test.cpp:4:1:4:3 | definition of i | true |
|
||||
| test.cpp:4:1:4:3 | definition of j | true |
|
||||
| test.cpp:4:1:4:3 | f | false |
|
||||
| test.cpp:4:1:4:3 | i | false |
|
||||
| test.cpp:4:1:4:3 | j | true |
|
||||
| test.cpp:4:1:4:3 | return ... | true |
|
||||
| test.cpp:4:1:4:3 | { ... } | true |
|
||||
| test.cpp:4:1:4:10 | CLASS_DECL | false |
|
||||
| test.cpp:4:1:4:10 | S | false |
|
||||
| test.cpp:4:1:4:10 | declaration | true |
|
||||
| test.cpp:4:1:4:10 | definition of S | true |
|
||||
| test.cpp:4:1:4:10 | definition of f | true |
|
||||
| test.cpp:4:1:4:10 | definition of i | true |
|
||||
| test.cpp:4:1:4:10 | definition of j | true |
|
||||
| test.cpp:4:1:4:10 | f | false |
|
||||
| test.cpp:4:1:4:10 | i | false |
|
||||
| test.cpp:4:1:4:10 | j | true |
|
||||
| test.cpp:4:1:4:10 | return ... | true |
|
||||
| test.cpp:4:1:4:10 | { ... } | true |
|
||||
| test.cpp:6:1:6:42 | #define FUNCTION_DECL void f1() { int k; } | false |
|
||||
| test.cpp:8:1:8:13 | FUNCTION_DECL | false |
|
||||
| test.cpp:8:1:8:13 | declaration | true |
|
||||
| test.cpp:8:1:8:13 | definition of f1 | true |
|
||||
| test.cpp:8:1:8:13 | definition of k | true |
|
||||
| test.cpp:8:1:8:13 | f1 | false |
|
||||
| test.cpp:8:1:8:13 | k | true |
|
||||
| test.cpp:8:1:8:13 | return ... | true |
|
||||
| test.cpp:8:1:8:13 | { ... } | true |
|
||||
| test.cpp:10:1:10:33 | #define VARIABLE_DECL int v1 = 1; | false |
|
||||
| test.cpp:12:1:12:13 | 1 | true |
|
||||
| test.cpp:12:1:12:13 | VARIABLE_DECL | false |
|
||||
| test.cpp:12:1:12:13 | definition of v1 | true |
|
||||
| test.cpp:12:1:12:13 | initializer for v1 | true |
|
||||
| test.cpp:12:1:12:13 | v1 | true |
|
||||
| test.cpp:14:1:14:35 | #define TYPE_DECL_1 typedef int t1; | false |
|
||||
| test.cpp:16:1:16:11 | TYPE_DECL_1 | false |
|
||||
| test.cpp:16:1:16:11 | declaration of t1 | true |
|
||||
| test.cpp:16:1:16:11 | t1 | false |
|
||||
| test.cpp:18:1:18:35 | #define TYPE_DECL_2 using t2 = int; | false |
|
||||
| test.cpp:20:1:20:11 | TYPE_DECL_2 | false |
|
||||
| test.cpp:20:1:20:11 | declaration of t2 | true |
|
||||
| test.cpp:20:1:20:11 | t2 | false |
|
||||
| test.cpp:22:1:22:47 | #define NAMESPACE_DECL namespace ns { int v2; } | false |
|
||||
| test.cpp:24:1:24:14 | NAMESPACE_DECL | false |
|
||||
| test.cpp:24:1:24:14 | definition of v2 | true |
|
||||
| test.cpp:24:1:24:14 | ns | false |
|
||||
| test.cpp:24:1:24:14 | ns | false |
|
||||
| test.cpp:24:1:24:14 | v2 | true |
|
||||
| test.cpp:26:1:26:43 | #define USING_NAMESPACE using namespace ns; | false |
|
||||
| test.cpp:28:1:28:34 | #define ENUM_CONSTANT enum_element | false |
|
||||
| test.cpp:30:12:30:21 | definition of enum_class | false |
|
||||
| test.cpp:30:12:30:21 | enum_class | false |
|
||||
| test.cpp:30:25:30:37 | ENUM_CONSTANT | false |
|
||||
| test.cpp:30:25:30:37 | enum_element | false |
|
||||
| test.cpp:32:1:32:41 | #define USING_ENUM using enum enum_class; | false |
|
||||
| test.cpp:34:1:34:10 | USING_ENUM | false |
|
||||
| test.cpp:34:1:34:10 | using enum enum_class | false |
|
||||
| test.cpp:36:1:36:48 | #define STATIC_ASSERT static_assert(1 == 1, ""); | false |
|
||||
| test.cpp:38:1:38:13 | 1 | true |
|
||||
| test.cpp:38:1:38:13 | 1 | true |
|
||||
| test.cpp:38:1:38:13 | ... == ... | true |
|
||||
| test.cpp:38:1:38:13 | STATIC_ASSERT | false |
|
||||
| test.cpp:38:1:38:13 | static_assert(..., "") | false |
|
||||
| test.cpp:40:1:40:42 | #define ATTRIBUTE [[nodiscard("reason1")]] | false |
|
||||
| test.cpp:42:1:42:9 | ATTRIBUTE | false |
|
||||
| test.cpp:42:1:42:9 | nodiscard | false |
|
||||
| test.cpp:42:1:42:9 | reason1 | false |
|
||||
| test.cpp:42:1:42:9 | reason1 | true |
|
||||
| test.cpp:43:5:43:6 | declaration of f2 | false |
|
||||
| test.cpp:43:5:43:6 | f2 | false |
|
||||
| test.cpp:45:1:45:31 | #define ATTRIBUTE_ARG "reason2" | false |
|
||||
| test.cpp:47:3:47:11 | nodiscard | false |
|
||||
| test.cpp:47:13:47:25 | ATTRIBUTE_ARG | false |
|
||||
| test.cpp:47:13:47:25 | reason2 | false |
|
||||
| test.cpp:47:13:47:25 | reason2 | true |
|
||||
| test.cpp:48:5:48:6 | declaration of f3 | false |
|
||||
| test.cpp:48:5:48:6 | f3 | false |
|
||||
| test.cpp:50:1:50:16 | #define TYPE int | false |
|
||||
| test.cpp:52:1:52:4 | TYPE | false |
|
||||
| test.cpp:52:6:52:7 | definition of v3 | true |
|
||||
| test.cpp:52:6:52:7 | v3 | true |
|
||||
| test.cpp:52:11:52:11 | 1 | false |
|
||||
| test.cpp:52:11:52:11 | initializer for v3 | false |
|
||||
| test.cpp:54:1:54:29 | #define DERIVATION : public S | false |
|
||||
| test.cpp:56:7:56:7 | T | false |
|
||||
| test.cpp:56:7:56:7 | T | false |
|
||||
| test.cpp:56:7:56:7 | declaration of T | false |
|
||||
| test.cpp:56:7:56:7 | declaration of operator= | false |
|
||||
| test.cpp:56:7:56:7 | declaration of operator= | false |
|
||||
| test.cpp:56:7:56:7 | definition of T | false |
|
||||
| test.cpp:56:7:56:7 | operator= | false |
|
||||
| test.cpp:56:7:56:7 | operator= | false |
|
||||
| test.cpp:56:9:56:18 | DERIVATION | false |
|
||||
| test.cpp:56:9:56:18 | derivation | false |
|
||||
| test.cpp:58:1:58:31 | #define FRIEND friend int f3(); | false |
|
||||
| test.cpp:60:7:60:7 | U | false |
|
||||
| test.cpp:60:7:60:7 | declaration of operator= | false |
|
||||
| test.cpp:60:7:60:7 | declaration of operator= | false |
|
||||
| test.cpp:60:7:60:7 | definition of U | false |
|
||||
| test.cpp:60:7:60:7 | operator= | false |
|
||||
| test.cpp:60:7:60:7 | operator= | false |
|
||||
| test.cpp:61:3:61:8 | FRIEND | false |
|
||||
| test.cpp:61:3:61:8 | U's friend | false |
|
||||
| test.cpp:64:1:64:24 | #define NAME_QUAL_1 ns:: | false |
|
||||
| test.cpp:66:1:66:22 | #define NAME_QUAL_2 ns | false |
|
||||
| test.cpp:68:1:68:19 | #define LOCAL_VAR m | false |
|
||||
| test.cpp:70:6:70:7 | definition of f4 | false |
|
||||
| test.cpp:70:6:70:7 | f4 | false |
|
||||
| test.cpp:70:11:76:1 | { ... } | false |
|
||||
| test.cpp:71:5:71:8 | ns:: | false |
|
||||
| test.cpp:71:5:71:15 | NAME_QUAL_1 | false |
|
||||
| test.cpp:71:5:71:18 | v2 | false |
|
||||
| test.cpp:71:5:71:19 | ExprStmt | false |
|
||||
| test.cpp:72:5:72:8 | ns:: | false |
|
||||
| test.cpp:72:5:72:15 | NAME_QUAL_2 | false |
|
||||
| test.cpp:72:5:72:21 | v2 | false |
|
||||
| test.cpp:72:5:72:22 | ExprStmt | false |
|
||||
| test.cpp:73:5:73:23 | declaration | false |
|
||||
| test.cpp:73:9:73:17 | LOCAL_VAR | false |
|
||||
| test.cpp:73:9:73:17 | definition of m | true |
|
||||
| test.cpp:73:9:73:17 | m | true |
|
||||
| test.cpp:73:20:73:22 | 42 | false |
|
||||
| test.cpp:73:20:73:22 | initializer for m | false |
|
||||
| test.cpp:74:5:74:41 | declaration | false |
|
||||
| test.cpp:74:10:74:10 | definition of l | false |
|
||||
| test.cpp:74:10:74:10 | l | false |
|
||||
| test.cpp:74:13:74:40 | [...](...){...} | false |
|
||||
| test.cpp:74:13:74:40 | initializer for l | false |
|
||||
| test.cpp:74:13:74:40 | {...} | false |
|
||||
| test.cpp:74:14:74:14 | (unnamed constructor) | false |
|
||||
| test.cpp:74:14:74:14 | (unnamed constructor) | false |
|
||||
| test.cpp:74:14:74:14 | (unnamed constructor) | false |
|
||||
| test.cpp:74:14:74:14 | declaration of (unnamed constructor) | false |
|
||||
| test.cpp:74:14:74:14 | declaration of (unnamed constructor) | false |
|
||||
| test.cpp:74:14:74:14 | definition of (unnamed constructor) | false |
|
||||
| test.cpp:74:14:74:14 | definition of operator= | false |
|
||||
| test.cpp:74:14:74:14 | operator= | false |
|
||||
| test.cpp:74:15:74:15 | definition of m | false |
|
||||
| test.cpp:74:15:74:15 | m | false |
|
||||
| test.cpp:74:15:74:15 | m | false |
|
||||
| test.cpp:74:15:74:23 | LOCAL_VAR | false |
|
||||
| test.cpp:74:15:74:23 | m | true |
|
||||
| test.cpp:74:25:74:25 | definition of operator() | false |
|
||||
| test.cpp:74:25:74:25 | operator() | false |
|
||||
| test.cpp:74:28:74:40 | { ... } | false |
|
||||
| test.cpp:74:30:74:38 | return ... | false |
|
||||
| test.cpp:74:37:74:37 | (int)... | false |
|
||||
| test.cpp:75:5:75:5 | (const lambda [] type at line 74, col. 14)... | false |
|
||||
| test.cpp:75:5:75:5 | l | false |
|
||||
| test.cpp:75:5:75:8 | ExprStmt | false |
|
||||
| test.cpp:75:6:75:6 | call to operator() | false |
|
||||
| test.cpp:76:1:76:1 | return ... | false |
|
||||
| test.cpp:78:1:78:15 | #define ID(x) x | false |
|
||||
| test.cpp:79:1:79:23 | #define NESTED(x) ID(x) | false |
|
||||
| test.cpp:80:5:80:6 | definition of v4 | false |
|
||||
| test.cpp:80:5:80:6 | v4 | false |
|
||||
| test.cpp:80:10:80:18 | ID(x) | false |
|
||||
| test.cpp:80:10:80:18 | NESTED(x) | false |
|
||||
| test.cpp:80:17:80:17 | 1 | true |
|
||||
| test.cpp:80:17:80:17 | initializer for v4 | true |
|
||||
| test.cpp:82:1:82:39 | // semmle-extractor-options: -std=c++20 | false |
|
||||
|
||||
@@ -1,5 +1,82 @@
|
||||
|
||||
#define FOO class S{int i; void f(void) { int j; return; } };
|
||||
#define CLASS_DECL class S{int i; void f(void) { int j; return; } };
|
||||
|
||||
FOO
|
||||
CLASS_DECL
|
||||
|
||||
#define FUNCTION_DECL void f1() { int k; }
|
||||
|
||||
FUNCTION_DECL
|
||||
|
||||
#define VARIABLE_DECL int v1 = 1;
|
||||
|
||||
VARIABLE_DECL
|
||||
|
||||
#define TYPE_DECL_1 typedef int t1;
|
||||
|
||||
TYPE_DECL_1
|
||||
|
||||
#define TYPE_DECL_2 using t2 = int;
|
||||
|
||||
TYPE_DECL_2
|
||||
|
||||
#define NAMESPACE_DECL namespace ns { int v2; }
|
||||
|
||||
NAMESPACE_DECL
|
||||
|
||||
#define USING_NAMESPACE using namespace ns;
|
||||
|
||||
#define ENUM_CONSTANT enum_element
|
||||
|
||||
enum class enum_class { ENUM_CONSTANT };
|
||||
|
||||
#define USING_ENUM using enum enum_class;
|
||||
|
||||
USING_ENUM
|
||||
|
||||
#define STATIC_ASSERT static_assert(1 == 1, "");
|
||||
|
||||
STATIC_ASSERT
|
||||
|
||||
#define ATTRIBUTE [[nodiscard("reason1")]]
|
||||
|
||||
ATTRIBUTE
|
||||
int f2();
|
||||
|
||||
#define ATTRIBUTE_ARG "reason2"
|
||||
|
||||
[[nodiscard(ATTRIBUTE_ARG)]]
|
||||
int f3();
|
||||
|
||||
#define TYPE int
|
||||
|
||||
TYPE v3 = 1;
|
||||
|
||||
#define DERIVATION : public S
|
||||
|
||||
class T DERIVATION {};
|
||||
|
||||
#define FRIEND friend int f3();
|
||||
|
||||
class U {
|
||||
FRIEND
|
||||
};
|
||||
|
||||
#define NAME_QUAL_1 ns::
|
||||
|
||||
#define NAME_QUAL_2 ns
|
||||
|
||||
#define LOCAL_VAR m
|
||||
|
||||
void f4() {
|
||||
NAME_QUAL_1 v2;
|
||||
NAME_QUAL_2 :: v2;
|
||||
int LOCAL_VAR = 42;
|
||||
auto l = [LOCAL_VAR]() { return m; };
|
||||
l();
|
||||
}
|
||||
|
||||
#define ID(x) x
|
||||
#define NESTED(x) ID(x)
|
||||
int v4 = NESTED(1);
|
||||
|
||||
// semmle-extractor-options: -std=c++20
|
||||
|
||||
@@ -10,3 +10,4 @@
|
||||
| test.c:15:2:15:7 | call to printf | Format for printf expects 3 arguments but given 2 |
|
||||
| test.c:19:2:19:7 | call to printf | Format for printf expects 2 arguments but given 1 |
|
||||
| test.c:29:3:29:8 | call to printf | Format for printf expects 2 arguments but given 1 |
|
||||
| test.c:53:2:53:10 | call to my_logger | Format for my_logger expects 3 arguments but given 2 |
|
||||
|
||||
@@ -44,3 +44,6 @@ void test_custom_printf2()
|
||||
printf("", "%i %i", 100, 200); // GOOD
|
||||
printf("%i %i", "" ); // GOOD
|
||||
}
|
||||
|
||||
extern "C" void my_logger(int param, char *fmt, ...) __attribute__((format(printf, 2, 3))) {}
|
||||
|
||||
|
||||
@@ -46,4 +46,12 @@ void test(int i, const char *str)
|
||||
printf("%Y", 1, 2); // GOOD (unknown format character, this might be correct)
|
||||
printf("%1.1Y", 1, 2); // GOOD (unknown format character, this might be correct)
|
||||
printf("%*.*Y", 1, 2); // GOOD (unknown format character, this might be correct)
|
||||
|
||||
// Implicit logger function declaration
|
||||
my_logger(0, "%i %i %i %i %i %i\n", 1, 2, 3, 4, 5, 6); // GOOD
|
||||
my_logger(0, "%i %i %i\n", 1, 2, 3); // GOOD
|
||||
my_logger(0, "%i %i %i\n", 1, 2); // BAD (too few format arguments)
|
||||
}
|
||||
|
||||
// A spurious definition of my_logger
|
||||
extern void my_logger(int param, char *fmt, int, int, int, int, int);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
edges
|
||||
nodes
|
||||
| errors.cpp:13:7:13:7 | definition of x | semmle.label | definition of x |
|
||||
| test.cpp:11:6:11:8 | definition of foo | semmle.label | definition of foo |
|
||||
| test.cpp:111:6:111:8 | definition of foo | semmle.label | definition of foo |
|
||||
| test.cpp:226:7:226:7 | definition of x | semmle.label | definition of x |
|
||||
@@ -14,6 +15,7 @@ nodes
|
||||
| test.cpp:472:6:472:6 | definition of x | semmle.label | definition of x |
|
||||
| test.cpp:479:6:479:6 | definition of x | semmle.label | definition of x |
|
||||
#select
|
||||
| errors.cpp:14:18:14:18 | x | errors.cpp:13:7:13:7 | definition of x | errors.cpp:13:7:13:7 | definition of x | The variable $@ may not be initialized at this access. | errors.cpp:13:7:13:7 | x | x |
|
||||
| test.cpp:12:6:12:8 | foo | test.cpp:11:6:11:8 | definition of foo | test.cpp:11:6:11:8 | definition of foo | The variable $@ may not be initialized at this access. | test.cpp:11:6:11:8 | foo | foo |
|
||||
| test.cpp:113:6:113:8 | foo | test.cpp:111:6:111:8 | definition of foo | test.cpp:111:6:111:8 | definition of foo | The variable $@ may not be initialized at this access. | test.cpp:111:6:111:8 | foo | foo |
|
||||
| test.cpp:227:3:227:3 | x | test.cpp:226:7:226:7 | definition of x | test.cpp:226:7:226:7 | definition of x | The variable $@ may not be initialized at this access. | test.cpp:226:7:226:7 | x | x |
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// semmle-extractor-options: --expect_errors
|
||||
|
||||
int f1() {
|
||||
int x;
|
||||
initialize(&x); // error expression - initialize() is not defined
|
||||
return x; // GOOD - assume x is initialized
|
||||
}
|
||||
|
||||
void * operator new(unsigned long, bool);
|
||||
void operator delete(void*, bool);
|
||||
|
||||
int f2() {
|
||||
int x;
|
||||
new(true) int (x); // BAD, ignore implicit error expression
|
||||
}
|
||||
@@ -53,4 +53,59 @@ void NonStringFalsePositiveTest2(unsigned char* buffer)
|
||||
{
|
||||
wchar_t *lpWchar = NULL;
|
||||
lpWchar = (LPWSTR)buffer; // Possible False Positive
|
||||
}
|
||||
}
|
||||
|
||||
typedef unsigned char BYTE;
|
||||
using FOO = BYTE*;
|
||||
|
||||
void NonStringFalsePositiveTest3(FOO buffer)
|
||||
{
|
||||
wchar_t *lpWchar = NULL;
|
||||
lpWchar = (LPWSTR)buffer; // GOOD
|
||||
}
|
||||
|
||||
#define UNICODE 0x8
|
||||
|
||||
// assume EMPTY_MACRO is tied to if UNICODE is enabled
|
||||
#ifdef EMPTY_MACRO
|
||||
typedef WCHAR* LPTSTR;
|
||||
#else
|
||||
typedef char* LPTSTR;
|
||||
#endif
|
||||
|
||||
void CheckedConversionFalsePositiveTest3(unsigned short flags, LPTSTR buffer)
|
||||
{
|
||||
wchar_t *lpWchar = NULL;
|
||||
if(flags & UNICODE)
|
||||
lpWchar = (LPWSTR)buffer; // GOOD
|
||||
else
|
||||
lpWchar = (LPWSTR)buffer; // BUG
|
||||
|
||||
if((flags & UNICODE) == 0x8)
|
||||
lpWchar = (LPWSTR)buffer; // GOOD
|
||||
else
|
||||
lpWchar = (LPWSTR)buffer; // BUG
|
||||
|
||||
if((flags & UNICODE) != 0x8)
|
||||
lpWchar = (LPWSTR)buffer; // BUG
|
||||
else
|
||||
lpWchar = (LPWSTR)buffer; // GOOD
|
||||
|
||||
// Bad operator precedence
|
||||
if(flags & UNICODE == 0x8)
|
||||
lpWchar = (LPWSTR)buffer; // BUG
|
||||
else
|
||||
lpWchar = (LPWSTR)buffer; // BUG
|
||||
|
||||
if((flags & UNICODE) != 0)
|
||||
lpWchar = (LPWSTR)buffer; // GOOD
|
||||
else
|
||||
lpWchar = (LPWSTR)buffer; // BUG
|
||||
|
||||
if((flags & UNICODE) == 0)
|
||||
lpWchar = (LPWSTR)buffer; // BUG
|
||||
else
|
||||
lpWchar = (LPWSTR)buffer; // GOOD
|
||||
|
||||
lpWchar = (LPWSTR)buffer; // BUG
|
||||
}
|
||||
|
||||
@@ -3,3 +3,11 @@
|
||||
| WcharCharConversion.cpp:24:22:24:27 | lpChar | Conversion from char * to wchar_t *. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:26:23:26:28 | lpChar | Conversion from char * to LPCWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:27:17:27:22 | lpChar | Conversion from char * to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:82:21:82:26 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:87:21:87:26 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:90:21:90:26 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:96:21:96:26 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:98:21:98:26 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:103:21:103:26 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:106:21:106:26 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
| WcharCharConversion.cpp:110:20:110:25 | buffer | Conversion from LPTSTR to LPWSTR. Use of invalid string can lead to undefined behavior. |
|
||||
|
||||
1
csharp/.gitignore
vendored
1
csharp/.gitignore
vendored
@@ -11,7 +11,6 @@ csharp.log
|
||||
*.tlog
|
||||
.vs
|
||||
*.user
|
||||
.vscode/launch.json
|
||||
|
||||
extractor/Semmle.Extraction.CSharp.Driver/Properties/launchSettings.json
|
||||
paket-files/
|
||||
|
||||
65
csharp/.vscode/launch.json
vendored
Normal file
65
csharp/.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "C#: Standalone Debug",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "dotnet: build",
|
||||
"program": "${workspaceFolder}/extractor/Semmle.Extraction.CSharp.Standalone/bin/Debug/net8.0/Semmle.Extraction.CSharp.Standalone.dll",
|
||||
"args": [],
|
||||
// Set the path to the folder that should be extracted:
|
||||
"cwd": "${workspaceFolder}/ql/test/library-tests/standalone/standalonemode",
|
||||
"env": {
|
||||
"CODEQL_THREADS": "1",
|
||||
"CODEQL_EXTRACTOR_CSHARP_OPTION_LOGGING_VERBOSITY": "progress+++",
|
||||
"CODEQL_EXTRACTOR_CSHARP_OPTION_TRAP_COMPRESSION": "NONE",
|
||||
},
|
||||
"stopAtEntry": true,
|
||||
"console": "internalConsole",
|
||||
"justMyCode": false,
|
||||
"symbolOptions": {
|
||||
"searchPaths": [],
|
||||
"searchMicrosoftSymbolServer": true,
|
||||
"searchNuGetOrgSymbolServer": true
|
||||
},
|
||||
"sourceLinkOptions": {
|
||||
"*": {
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
"suppressJITOptimizations": true
|
||||
},
|
||||
{
|
||||
"name": "C#: Autobuild Debug",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "dotnet: build",
|
||||
"program": "${workspaceFolder}/autobuilder/Semmle.Autobuild.CSharp/bin/Debug/net8.0/Semmle.Autobuild.CSharp.dll",
|
||||
// Set the path to the folder that should be extracted:
|
||||
"cwd": "${workspaceFolder}/ql/integration-tests/all-platforms/autobuild",
|
||||
"stopAtEntry": true,
|
||||
"args": [],
|
||||
"env": {
|
||||
// The below folders need to exist before debugging
|
||||
"CODEQL_EXTRACTOR_CSHARP_TRAP_DIR": "${workspaceFolder}/ql/integration-tests/DB",
|
||||
"CODEQL_EXTRACTOR_CSHARP_SOURCE_ARCHIVE_DIR": "${workspaceFolder}/ql/integration-tests/DB",
|
||||
"CODEQL_EXTRACTOR_CSHARP_DIAGNOSTIC_DIR": "${workspaceFolder}/ql/integration-tests/DB",
|
||||
"CODEQL_EXTRACTOR_CSHARP_SCRATCH_DIR": "${workspaceFolder}/ql/integration-tests/DB",
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "C#: Binary Log Debug",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "dotnet: build",
|
||||
"program": "${workspaceFolder}/extractor/Semmle.Extraction.CSharp.Driver/bin/Debug/net8.0/Semmle.Extraction.CSharp.Driver.dll",
|
||||
"stopAtEntry": true,
|
||||
"args": [
|
||||
"--binlog",
|
||||
"${workspaceFolder}/ql/integration-tests/all-platforms/binlog/test.binlog"
|
||||
],
|
||||
"env": {}
|
||||
},
|
||||
]
|
||||
}
|
||||
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 `cil` and `dotnet` related relations and types.
|
||||
compatibility: backwards
|
||||
@@ -144,50 +144,5 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
public override bool NeedsPopulation => Context.Defines(Symbol);
|
||||
|
||||
public Extraction.Entities.Location Location => Context.CreateLocation(ReportingLocation);
|
||||
|
||||
protected void PopulateMetadataHandle(TextWriter trapFile)
|
||||
{
|
||||
var handle = MetadataHandle;
|
||||
|
||||
if (handle.HasValue)
|
||||
trapFile.metadata_handle(this, Location, MetadataTokens.GetToken(handle.Value));
|
||||
}
|
||||
|
||||
private static System.Reflection.PropertyInfo? GetPropertyInfo(object o, string name)
|
||||
{
|
||||
return o.GetType().GetProperty(name, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetProperty);
|
||||
}
|
||||
|
||||
public Handle? MetadataHandle
|
||||
{
|
||||
get
|
||||
{
|
||||
var handleProp = GetPropertyInfo(Symbol, "Handle");
|
||||
object handleObj = Symbol;
|
||||
|
||||
if (handleProp is null)
|
||||
{
|
||||
var underlyingSymbolProp = GetPropertyInfo(Symbol, "UnderlyingSymbol");
|
||||
if (underlyingSymbolProp?.GetValue(Symbol) is object underlying)
|
||||
{
|
||||
handleProp = GetPropertyInfo(underlying, "Handle");
|
||||
handleObj = underlying;
|
||||
}
|
||||
}
|
||||
|
||||
if (handleProp is not null)
|
||||
{
|
||||
switch (handleProp.GetValue(handleObj))
|
||||
{
|
||||
case MethodDefinitionHandle md: return md;
|
||||
case TypeDefinitionHandle td: return td;
|
||||
case PropertyDefinitionHandle pd: return pd;
|
||||
case FieldDefinitionHandle fd: return fd;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public override void Populate(TextWriter trapFile)
|
||||
{
|
||||
PopulateMetadataHandle(trapFile);
|
||||
PopulateAttributes();
|
||||
ContainingType!.PopulateGenerics();
|
||||
PopulateNullability(trapFile, Symbol.GetAnnotatedType());
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
Context.ExtractionError($"Couldn't read file: {originalPath}. {exc.Message}", null, null, exc.StackTrace);
|
||||
Context.ExtractionError($"Couldn't read file: {originalPath}. {exc.Message}", null, null, exc.StackTrace, Semmle.Util.Logging.Severity.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
}
|
||||
}
|
||||
|
||||
PopulateAttributes();
|
||||
PopulateModifiers(trapFile);
|
||||
BindComments();
|
||||
|
||||
|
||||
@@ -360,7 +360,6 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
PopulateParameters();
|
||||
PopulateMethodBody(trapFile);
|
||||
PopulateGenerics(trapFile);
|
||||
PopulateMetadataHandle(trapFile);
|
||||
PopulateNullability(trapFile, Symbol.GetAnnotatedReturnType());
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public override void Populate(TextWriter trapFile)
|
||||
{
|
||||
PopulateMetadataHandle(trapFile);
|
||||
PopulateAttributes();
|
||||
PopulateModifiers(trapFile);
|
||||
BindComments();
|
||||
|
||||
@@ -77,7 +77,6 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
protected void PopulateType(TextWriter trapFile, bool constructUnderlyingTupleType = false)
|
||||
{
|
||||
PopulateMetadataHandle(trapFile);
|
||||
PopulateAttributes();
|
||||
|
||||
trapFile.Write("types(");
|
||||
|
||||
@@ -233,9 +233,6 @@ namespace Semmle.Extraction.CSharp
|
||||
internal static void localvars(this TextWriter trapFile, LocalVariable key, VariableKind kind, string name, int @var, Type type, Expression expr) =>
|
||||
trapFile.WriteTuple("localvars", key, (int)kind, name, @var, type, expr);
|
||||
|
||||
public static void metadata_handle(this TextWriter trapFile, IEntity entity, Location assembly, int handleValue) =>
|
||||
trapFile.WriteTuple("metadata_handle", entity, assembly, handleValue);
|
||||
|
||||
internal static void method_location(this TextWriter trapFile, Method method, Location location) =>
|
||||
trapFile.WriteTuple("method_location", method, location);
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.7.26
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.7.25
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
## 1.7.26
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.7.25
|
||||
lastReleaseVersion: 1.7.26
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-all
|
||||
version: 1.7.25
|
||||
version: 1.7.27-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.7.26
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.7.25
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
## 1.7.26
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.7.25
|
||||
lastReleaseVersion: 1.7.26
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-queries
|
||||
version: 1.7.25
|
||||
version: 1.7.27-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -61,8 +61,3 @@ query predicate preBasicBlockConsistency(ControlFlowElement cfe1, ControlFlowEle
|
||||
bbIntraSuccInconsistency(cfe1, cfe2) and
|
||||
s = "intra succ inconsistency"
|
||||
}
|
||||
|
||||
query predicate multipleToString(Node n, string s) {
|
||||
s = strictconcat(n.toString(), ",") and
|
||||
strictcount(n.toString()) > 1
|
||||
}
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
## 3.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* C#: Add support for MaD directly on properties and indexers using *attributes*. Using `Attribute.Getter` or `Attribute.Setter` in the model `ext` field applies the model to the getter or setter for properties and indexers. Prior to this change `Attribute` models unintentionally worked for property setters (if the property is decorated with the matching attribute). That is, a model that uses the `Attribute` feature directly on a property for a property setter needs to be changed to `Attribute.Setter`.
|
||||
* C#: Remove all CIL tables and related QL library functionality.
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The class `ThreatModelFlowSource` has been renamed to `ActiveThreatModelSource` to more clearly reflect it only contains the currently active threat model sources. `ThreatModelFlowSource` has been marked as deprecated.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* `DataFlow::Node` instances are no longer created for library methods and fields that are not callable (either statically or dynamically) or otherwise referred to from source code. This may affect third-party queries that use these nodes to identify library methods or fields that are present in DLL files where those methods or fields are unreferenced. If this presents a problem, consider using `Callable` and other non-dataflow classes to identify such library entities.
|
||||
* C#: Add extractor support for attributes on indexers.
|
||||
|
||||
## 2.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
15
csharp/ql/lib/change-notes/released/3.0.0.md
Normal file
15
csharp/ql/lib/change-notes/released/3.0.0.md
Normal file
@@ -0,0 +1,15 @@
|
||||
## 3.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* C#: Add support for MaD directly on properties and indexers using *attributes*. Using `Attribute.Getter` or `Attribute.Setter` in the model `ext` field applies the model to the getter or setter for properties and indexers. Prior to this change `Attribute` models unintentionally worked for property setters (if the property is decorated with the matching attribute). That is, a model that uses the `Attribute` feature directly on a property for a property setter needs to be changed to `Attribute.Setter`.
|
||||
* C#: Remove all CIL tables and related QL library functionality.
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The class `ThreatModelFlowSource` has been renamed to `ActiveThreatModelSource` to more clearly reflect it only contains the currently active threat model sources. `ThreatModelFlowSource` has been marked as deprecated.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* `DataFlow::Node` instances are no longer created for library methods and fields that are not callable (either statically or dynamically) or otherwise referred to from source code. This may affect third-party queries that use these nodes to identify library methods or fields that are present in DLL files where those methods or fields are unreferenced. If this presents a problem, consider using `Callable` and other non-dataflow classes to identify such library entities.
|
||||
* C#: Add extractor support for attributes on indexers.
|
||||
@@ -1,5 +0,0 @@
|
||||
/**
|
||||
* The default QL library for modeling the Common Intermediate Language (CIL).
|
||||
*/
|
||||
|
||||
import semmle.code.cil.CIL as CIL
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 2.0.0
|
||||
lastReleaseVersion: 3.0.0
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
/**
|
||||
* The default QL library for modeling .NET definitions for both C# and CIL code.
|
||||
*/
|
||||
|
||||
deprecated import semmle.code.dotnet.DotNet as DotNet
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-all
|
||||
version: 2.0.0
|
||||
version: 3.0.1-dev
|
||||
groups: csharp
|
||||
dbscheme: semmlecode.csharp.dbscheme
|
||||
extractor: csharp
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
/**
|
||||
* Provides classes for accesses.
|
||||
*
|
||||
* An access is any read or write of a variable.
|
||||
*/
|
||||
|
||||
private import CIL
|
||||
|
||||
/** An instruction that accesses a variable. */
|
||||
deprecated class Access extends Instruction, @cil_access {
|
||||
/** Gets the declaration referenced by this instruction. */
|
||||
Variable getTarget() { cil_access(this, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that accesses a variable.
|
||||
* This class is provided for consistency with the C# data model.
|
||||
*/
|
||||
deprecated class VariableAccess extends Access, @cil_access { }
|
||||
|
||||
/** An instruction that reads a variable. */
|
||||
deprecated class ReadAccess extends VariableAccess, Expr, @cil_read_access {
|
||||
override Type getType() { result = this.getTarget().getType() }
|
||||
}
|
||||
|
||||
/** An instruction yielding an address. */
|
||||
deprecated class ReadRef extends Expr, @cil_read_ref { }
|
||||
|
||||
/** An instruction that reads the address of a variable. */
|
||||
deprecated class ReadRefAccess extends ReadAccess, ReadRef { }
|
||||
|
||||
/** An instruction that writes a variable. */
|
||||
deprecated class WriteAccess extends VariableAccess, @cil_write_access {
|
||||
/** Gets the expression whose value is used in this variable write. */
|
||||
Expr getExpr() { none() }
|
||||
}
|
||||
|
||||
/** An instruction that accesses a parameter. */
|
||||
deprecated class ParameterAccess extends StackVariableAccess, @cil_arg_access {
|
||||
override MethodParameter getTarget() { result = StackVariableAccess.super.getTarget() }
|
||||
}
|
||||
|
||||
/** An instruction that reads a parameter. */
|
||||
deprecated class ParameterReadAccess extends ParameterAccess, ReadAccess {
|
||||
override int getPopCount() { result = 0 }
|
||||
}
|
||||
|
||||
/** An instruction that writes to a parameter. */
|
||||
deprecated class ParameterWriteAccess extends ParameterAccess, WriteAccess {
|
||||
override int getPopCount() { result = 1 }
|
||||
|
||||
override Expr getExpr() { result = this.getOperand(0) }
|
||||
}
|
||||
|
||||
/** An access to the `this` parameter. */
|
||||
deprecated class ThisAccess extends ParameterReadAccess {
|
||||
ThisAccess() { this.getTarget() instanceof ThisParameter }
|
||||
}
|
||||
|
||||
/** An instruction that accesses a stack variable. */
|
||||
deprecated class StackVariableAccess extends VariableAccess, @cil_stack_access {
|
||||
override StackVariable getTarget() { result = VariableAccess.super.getTarget() }
|
||||
}
|
||||
|
||||
/** An instruction that accesses a local variable. */
|
||||
deprecated class LocalVariableAccess extends StackVariableAccess, @cil_local_access {
|
||||
override LocalVariable getTarget() { result = StackVariableAccess.super.getTarget() }
|
||||
}
|
||||
|
||||
/** An instruction that writes to a local variable. */
|
||||
deprecated class LocalVariableWriteAccess extends LocalVariableAccess, WriteAccess {
|
||||
override int getPopCount() { result = 1 }
|
||||
|
||||
override Expr getExpr() { result = this.getOperand(0) }
|
||||
|
||||
override string getExtra() { result = "L" + this.getTarget().getIndex() }
|
||||
}
|
||||
|
||||
/** An instruction that reads a local variable. */
|
||||
deprecated class LocalVariableReadAccess extends LocalVariableAccess, ReadAccess {
|
||||
override int getPopCount() { result = 0 }
|
||||
}
|
||||
|
||||
/** An instruction that accesses a field. */
|
||||
deprecated class FieldAccess extends VariableAccess, @cil_field_access {
|
||||
override Field getTarget() { result = VariableAccess.super.getTarget() }
|
||||
|
||||
override string getExtra() { result = this.getTarget().getName() }
|
||||
|
||||
/** Gets the qualifier of the access, if any. */
|
||||
abstract Expr getQualifier();
|
||||
}
|
||||
|
||||
/** An instruction that reads a field. */
|
||||
abstract deprecated class FieldReadAccess extends FieldAccess, ReadAccess { }
|
||||
|
||||
/** An instruction that writes a field. */
|
||||
abstract deprecated class FieldWriteAccess extends FieldAccess, WriteAccess { }
|
||||
@@ -1,45 +0,0 @@
|
||||
/** Provides the `Attribute` class. */
|
||||
|
||||
private import CIL
|
||||
private import semmle.code.csharp.Location as CS
|
||||
|
||||
/** An attribute to a declaration, such as a method, field, type or parameter. */
|
||||
deprecated class Attribute extends Element, @cil_attribute {
|
||||
/** Gets the declaration this attribute is attached to. */
|
||||
Declaration getDeclaration() { cil_attribute(this, result, _) }
|
||||
|
||||
/** Gets the constructor used to construct this attribute. */
|
||||
Method getConstructor() { cil_attribute(this, _, result) }
|
||||
|
||||
/** Gets the type of this attribute. */
|
||||
Type getType() { result = this.getConstructor().getDeclaringType() }
|
||||
|
||||
override string toString() { result = "[" + this.getType().getName() + "(...)]" }
|
||||
|
||||
/** Gets the value of the `i`th argument of this attribute. */
|
||||
string getArgument(int i) { cil_attribute_positional_argument(this, i, result) }
|
||||
|
||||
/** Gets the value of the named argument `name`. */
|
||||
string getNamedArgument(string name) { cil_attribute_named_argument(this, name, result) }
|
||||
|
||||
/** Gets an argument of this attribute, if any. */
|
||||
string getAnArgument() { result = this.getArgument(_) or result = this.getNamedArgument(_) }
|
||||
|
||||
override CS::Location getLocation() { result = this.getDeclaration().getLocation() }
|
||||
}
|
||||
|
||||
/** A generic attribute to a declaration. */
|
||||
deprecated class GenericAttribute extends Attribute {
|
||||
private ConstructedType type;
|
||||
|
||||
GenericAttribute() { type = this.getType() }
|
||||
|
||||
/** Gets the total number of type arguments. */
|
||||
int getNumberOfTypeArguments() { result = count(int i | cil_type_argument(type, i, _)) }
|
||||
|
||||
/** Gets the `i`th type argument, if any. */
|
||||
Type getTypeArgument(int i) { result = type.getTypeArgument(i) }
|
||||
|
||||
/** Get a type argument. */
|
||||
Type getATypeArgument() { result = this.getTypeArgument(_) }
|
||||
}
|
||||
@@ -1,401 +0,0 @@
|
||||
/**
|
||||
* Provides classes representing basic blocks.
|
||||
*/
|
||||
|
||||
private import CIL
|
||||
|
||||
/**
|
||||
* A basic block, that is, a maximal straight-line sequence of control flow nodes
|
||||
* without branches or joins.
|
||||
*/
|
||||
deprecated class BasicBlock extends Cached::TBasicBlockStart {
|
||||
/** Gets an immediate successor of this basic block, if any. */
|
||||
BasicBlock getASuccessor() { result.getFirstNode() = this.getLastNode().getASuccessor() }
|
||||
|
||||
/** Gets an immediate predecessor of this basic block, if any. */
|
||||
BasicBlock getAPredecessor() { result.getASuccessor() = this }
|
||||
|
||||
/**
|
||||
* Gets an immediate `true` successor, if any.
|
||||
*
|
||||
* An immediate `true` successor is a successor that is reached when
|
||||
* the condition that ends this basic block evaluates to `true`.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```csharp
|
||||
* if (x < 0)
|
||||
* x = -x;
|
||||
* ```
|
||||
*
|
||||
* The basic block on line 2 is an immediate `true` successor of the
|
||||
* basic block on line 1.
|
||||
*/
|
||||
BasicBlock getATrueSuccessor() { result.getFirstNode() = this.getLastNode().getTrueSuccessor() }
|
||||
|
||||
/**
|
||||
* Gets an immediate `false` successor, if any.
|
||||
*
|
||||
* An immediate `false` successor is a successor that is reached when
|
||||
* the condition that ends this basic block evaluates to `false`.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```csharp
|
||||
* if (!(x >= 0))
|
||||
* x = -x;
|
||||
* ```
|
||||
*
|
||||
* The basic block on line 2 is an immediate `false` successor of the
|
||||
* basic block on line 1.
|
||||
*/
|
||||
BasicBlock getAFalseSuccessor() { result.getFirstNode() = this.getLastNode().getFalseSuccessor() }
|
||||
|
||||
/** Gets the control flow node at a specific (zero-indexed) position in this basic block. */
|
||||
ControlFlowNode getNode(int pos) { Cached::bbIndex(this.getFirstNode(), result, pos) }
|
||||
|
||||
/** Gets a control flow node in this basic block. */
|
||||
ControlFlowNode getANode() { result = this.getNode(_) }
|
||||
|
||||
/** Gets the first control flow node in this basic block. */
|
||||
ControlFlowNode getFirstNode() { this = Cached::TBasicBlockStart(result) }
|
||||
|
||||
/** Gets the last control flow node in this basic block. */
|
||||
ControlFlowNode getLastNode() { result = this.getNode(this.length() - 1) }
|
||||
|
||||
/** Gets the length of this basic block. */
|
||||
int length() { result = strictcount(this.getANode()) }
|
||||
|
||||
/**
|
||||
* Holds if this basic block strictly dominates basic block `bb`.
|
||||
*
|
||||
* That is, all paths reaching basic block `bb` from some entry point
|
||||
* basic block must go through this basic block (which must be different
|
||||
* from `bb`).
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```csharp
|
||||
* int M(string s) {
|
||||
* if (s == null)
|
||||
* throw new ArgumentNullException(nameof(s));
|
||||
* return s.Length;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The basic block starting on line 2 strictly dominates the
|
||||
* basic block on line 4 (all paths from the entry point of `M`
|
||||
* to `return s.Length;` must go through the null check).
|
||||
*/
|
||||
predicate strictlyDominates(BasicBlock bb) { bbIDominates+(this, bb) }
|
||||
|
||||
/**
|
||||
* Holds if this basic block dominates basic block `bb`.
|
||||
*
|
||||
* That is, all paths reaching basic block `bb` from some entry point
|
||||
* basic block must go through this basic block.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```csharp
|
||||
* int M(string s) {
|
||||
* if (s == null)
|
||||
* throw new ArgumentNullException(nameof(s));
|
||||
* return s.Length;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The basic block starting on line 2 dominates the basic
|
||||
* block on line 4 (all paths from the entry point of `M` to
|
||||
* `return s.Length;` must go through the null check).
|
||||
*
|
||||
* This predicate is *reflexive*, so for example `if (s == null)` dominates
|
||||
* itself.
|
||||
*/
|
||||
predicate dominates(BasicBlock bb) {
|
||||
bb = this or
|
||||
this.strictlyDominates(bb)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `df` is in the dominance frontier of this basic block.
|
||||
* That is, this basic block dominates a predecessor of `df`, but
|
||||
* does not dominate `df` itself.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```csharp
|
||||
* if (x < 0) {
|
||||
* x = -x;
|
||||
* if (x > 10)
|
||||
* x--;
|
||||
* }
|
||||
* Console.Write(x);
|
||||
* ```
|
||||
*
|
||||
* The basic block on line 6 is in the dominance frontier
|
||||
* of the basic block starting on line 2 because that block
|
||||
* dominates the basic block on line 4, which is a predecessor of
|
||||
* `Console.Write(x);`. Also, the basic block starting on line 2
|
||||
* does not dominate the basic block on line 6.
|
||||
*/
|
||||
predicate inDominanceFrontier(BasicBlock df) {
|
||||
this.dominatesPredecessor(df) and
|
||||
not this.strictlyDominates(df)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this basic block dominates a predecessor of `df`.
|
||||
*/
|
||||
private predicate dominatesPredecessor(BasicBlock df) { this.dominates(df.getAPredecessor()) }
|
||||
|
||||
/**
|
||||
* Gets the basic block that immediately dominates this basic block, if any.
|
||||
*
|
||||
* That is, all paths reaching this basic block from some entry point
|
||||
* basic block must go through the result, which is an immediate basic block
|
||||
* predecessor of this basic block.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```csharp
|
||||
* int M(string s) {
|
||||
* if (s == null)
|
||||
* throw new ArgumentNullException(nameof(s));
|
||||
* return s.Length;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The basic block starting on line 2 is an immediate dominator of
|
||||
* the basic block online 4 (all paths from the entry point of `M`
|
||||
* to `return s.Length;` must go through the null check, and the null check
|
||||
* is an immediate predecessor of `return s.Length;`).
|
||||
*/
|
||||
BasicBlock getImmediateDominator() { bbIDominates(result, this) }
|
||||
|
||||
/**
|
||||
* Holds if this basic block strictly post-dominates basic block `bb`.
|
||||
*
|
||||
* That is, all paths reaching an exit point basic block from basic
|
||||
* block `bb` must go through this basic block (which must be different
|
||||
* from `bb`).
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```csharp
|
||||
* int M(string s) {
|
||||
* try {
|
||||
* return s.Length;
|
||||
* }
|
||||
* finally {
|
||||
* Console.WriteLine("M");
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The basic block on line 6 strictly post-dominates the basic block on
|
||||
* line 3 (all paths to the exit point of `M` from `return s.Length;`
|
||||
* must go through the `WriteLine` call).
|
||||
*/
|
||||
predicate strictlyPostDominates(BasicBlock bb) { bbIPostDominates+(this, bb) }
|
||||
|
||||
/**
|
||||
* Holds if this basic block post-dominates basic block `bb`.
|
||||
*
|
||||
* That is, all paths reaching an exit point basic block from basic
|
||||
* block `bb` must go through this basic block.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```csharp
|
||||
* int M(string s) {
|
||||
* try {
|
||||
* return s.Length;
|
||||
* }
|
||||
* finally {
|
||||
* Console.WriteLine("M");
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The basic block on line 6 post-dominates the basic block on line 3
|
||||
* (all paths to the exit point of `M` from `return s.Length;` must go
|
||||
* through the `WriteLine` call).
|
||||
*
|
||||
* This predicate is *reflexive*, so for example `Console.WriteLine("M");`
|
||||
* post-dominates itself.
|
||||
*/
|
||||
predicate postDominates(BasicBlock bb) {
|
||||
this.strictlyPostDominates(bb) or
|
||||
this = bb
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this basic block is in a loop in the control flow graph. This
|
||||
* includes loops created by `goto` statements. This predicate may not hold
|
||||
* even if this basic block is syntactically inside a `while` loop if the
|
||||
* necessary back edges are unreachable.
|
||||
*/
|
||||
predicate inLoop() { this.getASuccessor+() = this }
|
||||
|
||||
/** Gets a textual representation of this basic block. */
|
||||
string toString() { result = this.getFirstNode().toString() }
|
||||
|
||||
/** Gets the location of this basic block. */
|
||||
Location getLocation() { result = this.getFirstNode().getLocation() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal implementation details.
|
||||
*/
|
||||
cached
|
||||
deprecated private module Cached {
|
||||
/** Internal representation of basic blocks. */
|
||||
cached
|
||||
newtype TBasicBlock = TBasicBlockStart(ControlFlowNode cfn) { startsBB(cfn) }
|
||||
|
||||
/** Holds if `cfn` starts a new basic block. */
|
||||
private predicate startsBB(ControlFlowNode cfn) {
|
||||
not exists(cfn.getAPredecessor()) and exists(cfn.getASuccessor())
|
||||
or
|
||||
cfn.isJoin()
|
||||
or
|
||||
cfn.getAPredecessor().isBranch()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `succ` is a control flow successor of `pred` within
|
||||
* the same basic block.
|
||||
*/
|
||||
private predicate intraBBSucc(ControlFlowNode pred, ControlFlowNode succ) {
|
||||
succ = pred.getASuccessor() and
|
||||
not startsBB(succ)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `cfn` is the `i`th node in basic block `bb`.
|
||||
*
|
||||
* In other words, `i` is the shortest distance from a node `bb`
|
||||
* that starts a basic block to `cfn` along the `intraBBSucc` relation.
|
||||
*/
|
||||
cached
|
||||
predicate bbIndex(ControlFlowNode bbStart, ControlFlowNode cfn, int i) =
|
||||
shortestDistances(startsBB/1, intraBBSucc/2)(bbStart, cfn, i)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the first node of basic block `succ` is a control flow
|
||||
* successor of the last node of basic block `pred`.
|
||||
*/
|
||||
deprecated private predicate succBB(BasicBlock pred, BasicBlock succ) {
|
||||
succ = pred.getASuccessor()
|
||||
}
|
||||
|
||||
/** Holds if `dom` is an immediate dominator of `bb`. */
|
||||
deprecated predicate bbIDominates(BasicBlock dom, BasicBlock bb) =
|
||||
idominance(entryBB/1, succBB/2)(_, dom, bb)
|
||||
|
||||
/** Holds if `pred` is a basic block predecessor of `succ`. */
|
||||
deprecated private predicate predBB(BasicBlock succ, BasicBlock pred) { succBB(pred, succ) }
|
||||
|
||||
/** Holds if `dom` is an immediate post-dominator of `bb`. */
|
||||
deprecated predicate bbIPostDominates(BasicBlock dom, BasicBlock bb) =
|
||||
idominance(exitBB/1, predBB/2)(_, dom, bb)
|
||||
|
||||
/**
|
||||
* An entry basic block, that is, a basic block whose first node is
|
||||
* the entry node of a callable.
|
||||
*/
|
||||
deprecated class EntryBasicBlock extends BasicBlock {
|
||||
EntryBasicBlock() { entryBB(this) }
|
||||
}
|
||||
|
||||
/** Holds if `bb` is an entry basic block. */
|
||||
deprecated private predicate entryBB(BasicBlock bb) {
|
||||
bb.getFirstNode() instanceof MethodImplementation
|
||||
}
|
||||
|
||||
/**
|
||||
* An exit basic block, that is, a basic block whose last node is
|
||||
* an exit node.
|
||||
*/
|
||||
deprecated class ExitBasicBlock extends BasicBlock {
|
||||
ExitBasicBlock() { exitBB(this) }
|
||||
}
|
||||
|
||||
/** Holds if `bb` is an exit basic block. */
|
||||
deprecated private predicate exitBB(BasicBlock bb) { not exists(bb.getLastNode().getASuccessor()) }
|
||||
|
||||
/**
|
||||
* A basic block with more than one predecessor.
|
||||
*/
|
||||
deprecated class JoinBlock extends BasicBlock {
|
||||
JoinBlock() { this.getFirstNode().isJoin() }
|
||||
}
|
||||
|
||||
/** A basic block that terminates in a condition, splitting the subsequent control flow. */
|
||||
deprecated class ConditionBlock extends BasicBlock {
|
||||
ConditionBlock() {
|
||||
exists(BasicBlock succ |
|
||||
succ = this.getATrueSuccessor()
|
||||
or
|
||||
succ = this.getAFalseSuccessor()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if basic block `controlled` is controlled by this basic block with
|
||||
* Boolean value `testIsTrue`. That is, `controlled` can only be reached from
|
||||
* the callable entry point by going via the true edge (`testIsTrue = true`)
|
||||
* or false edge (`testIsTrue = false`) out of this basic block.
|
||||
*/
|
||||
predicate controls(BasicBlock controlled, boolean testIsTrue) {
|
||||
/*
|
||||
* For this block to control the block `controlled` with `testIsTrue` the following must be true:
|
||||
* Execution must have passed through the test i.e. `this` must strictly dominate `controlled`.
|
||||
* Execution must have passed through the `testIsTrue` edge leaving `this`.
|
||||
*
|
||||
* Although "passed through the true edge" implies that `this.getATrueSuccessor()` dominates `controlled`,
|
||||
* the reverse is not true, as flow may have passed through another edge to get to `this.getATrueSuccessor()`
|
||||
* so we need to assert that `this.getATrueSuccessor()` dominates `controlled` *and* that
|
||||
* all predecessors of `this.getATrueSuccessor()` are either `this` or dominated by `this.getATrueSuccessor()`.
|
||||
*
|
||||
* For example, in the following C# snippet:
|
||||
* ```csharp
|
||||
* if (x)
|
||||
* controlled;
|
||||
* false_successor;
|
||||
* uncontrolled;
|
||||
* ```
|
||||
* `false_successor` dominates `uncontrolled`, but not all of its predecessors are `this` (`if (x)`)
|
||||
* or dominated by itself. Whereas in the following code:
|
||||
* ```csharp
|
||||
* if (x)
|
||||
* while (controlled)
|
||||
* also_controlled;
|
||||
* false_successor;
|
||||
* uncontrolled;
|
||||
* ```
|
||||
* the block `while controlled` is controlled because all of its predecessors are `this` (`if (x)`)
|
||||
* or (in the case of `also_controlled`) dominated by itself.
|
||||
*
|
||||
* The additional constraint on the predecessors of the test successor implies
|
||||
* that `this` strictly dominates `controlled` so that isn't necessary to check
|
||||
* directly.
|
||||
*/
|
||||
|
||||
exists(BasicBlock succ |
|
||||
this.isCandidateSuccessor(succ, testIsTrue) and
|
||||
succ.dominates(controlled)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isCandidateSuccessor(BasicBlock succ, boolean testIsTrue) {
|
||||
(
|
||||
testIsTrue = true and succ = this.getATrueSuccessor()
|
||||
or
|
||||
testIsTrue = false and succ = this.getAFalseSuccessor()
|
||||
) and
|
||||
forall(BasicBlock pred | pred = succ.getAPredecessor() and pred != this | succ.dominates(pred))
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/** Provides the core CIL data model. */
|
||||
|
||||
import semmle.code.csharp.Location
|
||||
import Element
|
||||
import Instruction
|
||||
import Instructions
|
||||
import Access
|
||||
import Variable
|
||||
import Declaration
|
||||
import Generics
|
||||
import Type
|
||||
import Types
|
||||
import Method
|
||||
import InstructionGroups
|
||||
import BasicBlock
|
||||
import Handler
|
||||
import ControlFlow
|
||||
import DataFlow
|
||||
import Attribute
|
||||
import Stubs
|
||||
import CustomModifierReceiver
|
||||
import Parameterizable
|
||||
import semmle.code.cil.Ssa
|
||||
@@ -1,74 +0,0 @@
|
||||
/**
|
||||
* Provides predicates for analysing the return values of callables.
|
||||
*/
|
||||
|
||||
private import CIL
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
/** Holds if method `m` always returns null. */
|
||||
cached
|
||||
deprecated predicate alwaysNullMethod(Method m) {
|
||||
forex(Expr e | m.canReturn(e) | alwaysNullExpr(e))
|
||||
}
|
||||
|
||||
/** Holds if method `m` always returns non-null. */
|
||||
cached
|
||||
deprecated predicate alwaysNotNullMethod(Method m) {
|
||||
forex(Expr e | m.canReturn(e) | alwaysNotNullExpr(e))
|
||||
}
|
||||
|
||||
/** Holds if method `m` always throws an exception. */
|
||||
cached
|
||||
deprecated predicate alwaysThrowsMethod(Method m) {
|
||||
m.hasBody() and
|
||||
not exists(m.getImplementation().getAnInstruction().(Return))
|
||||
}
|
||||
|
||||
/** Holds if method `m` always throws an exception of type `t`. */
|
||||
cached
|
||||
deprecated predicate alwaysThrowsException(Method m, Type t) {
|
||||
alwaysThrowsMethod(m) and
|
||||
forex(Throw ex | ex = m.getImplementation().getAnInstruction() | t = ex.getExceptionType())
|
||||
}
|
||||
}
|
||||
|
||||
import Cached
|
||||
|
||||
pragma[noinline]
|
||||
deprecated private predicate alwaysNullVariableUpdate(VariableUpdate vu) {
|
||||
forex(Expr src | src = vu.getSource() | alwaysNullExpr(src))
|
||||
}
|
||||
|
||||
/** Holds if expression `expr` always evaluates to `null`. */
|
||||
deprecated private predicate alwaysNullExpr(Expr expr) {
|
||||
expr instanceof NullLiteral
|
||||
or
|
||||
alwaysNullMethod(expr.(StaticCall).getTarget())
|
||||
or
|
||||
forex(Ssa::Definition def |
|
||||
expr = any(Ssa::Definition def0 | def = def0.getAnUltimateDefinition()).getARead()
|
||||
|
|
||||
alwaysNullVariableUpdate(def.getVariableUpdate())
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
deprecated private predicate alwaysNotNullVariableUpdate(VariableUpdate vu) {
|
||||
forex(Expr src | src = vu.getSource() | alwaysNotNullExpr(src))
|
||||
}
|
||||
|
||||
/** Holds if expression `expr` always evaluates to non-null. */
|
||||
deprecated private predicate alwaysNotNullExpr(Expr expr) {
|
||||
expr instanceof Opcodes::NewObj
|
||||
or
|
||||
expr instanceof Literal and not expr instanceof NullLiteral
|
||||
or
|
||||
alwaysNotNullMethod(expr.(StaticCall).getTarget())
|
||||
or
|
||||
forex(Ssa::Definition def |
|
||||
expr = any(Ssa::Definition def0 | def = def0.getAnUltimateDefinition()).getARead()
|
||||
|
|
||||
alwaysNotNullVariableUpdate(def.getVariableUpdate())
|
||||
)
|
||||
}
|
||||
@@ -1,787 +0,0 @@
|
||||
/**
|
||||
* Provides checks for the consistency of the data model and database.
|
||||
*/
|
||||
|
||||
private import CIL
|
||||
private import csharp as CS
|
||||
private import semmle.code.csharp.commons.QualifiedName
|
||||
|
||||
private newtype ConsistencyCheck =
|
||||
MissingEntityCheck() or
|
||||
deprecated TypeCheck(Type t) or
|
||||
deprecated CfgCheck(ControlFlowNode n) or
|
||||
deprecated DeclarationCheck(Declaration d) or
|
||||
MissingCSharpCheck(CS::Declaration d)
|
||||
|
||||
/**
|
||||
* A consistency violation in the database or data model.
|
||||
*/
|
||||
abstract deprecated class ConsistencyViolation extends ConsistencyCheck {
|
||||
abstract string toString();
|
||||
|
||||
abstract string getMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* A check that is deliberately disabled.
|
||||
*/
|
||||
abstract deprecated class DisabledCheck extends ConsistencyViolation {
|
||||
DisabledCheck() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A consistency violation on a control flow node.
|
||||
*/
|
||||
abstract deprecated class CfgViolation extends ConsistencyViolation, CfgCheck {
|
||||
ControlFlowNode node;
|
||||
|
||||
CfgViolation() { this = CfgCheck(node) }
|
||||
|
||||
override string toString() { result = node.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A consistency violation in a specific instruction.
|
||||
*/
|
||||
abstract deprecated class InstructionViolation extends CfgViolation, CfgCheck {
|
||||
Instruction instruction;
|
||||
|
||||
InstructionViolation() { this = CfgCheck(instruction) }
|
||||
|
||||
private string getInstructionsUpTo() {
|
||||
result =
|
||||
concat(Instruction i |
|
||||
i.getIndex() <= instruction.getIndex() and
|
||||
i.getImplementation() = instruction.getImplementation()
|
||||
|
|
||||
i.toString() + " [push: " + i.getPushCount() + ", pop: " + i.getPopCount() + "]", "; "
|
||||
order by
|
||||
i.getIndex()
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result =
|
||||
instruction.getImplementation().getMethod().toStringWithTypes() + ": " +
|
||||
instruction.toString() + ", " + this.getInstructionsUpTo()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A literal that does not have exactly one `getValue()`.
|
||||
*/
|
||||
deprecated class MissingValue extends InstructionViolation {
|
||||
MissingValue() { exists(Literal l | l = instruction | count(l.getValue()) != 1) }
|
||||
|
||||
override string getMessage() { result = "Literal has invalid getValue()" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call that does not have exactly one `getTarget()`.
|
||||
*/
|
||||
deprecated class MissingCallTarget extends InstructionViolation {
|
||||
MissingCallTarget() {
|
||||
exists(Call c | c = instruction |
|
||||
count(c.getTarget()) != 1 and not c instanceof Opcodes::Calli
|
||||
or
|
||||
count(c.(Opcodes::Calli).getTargetType()) != 1 and c instanceof Opcodes::Calli
|
||||
)
|
||||
}
|
||||
|
||||
override string getMessage() { result = "Call has invalid target" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that has not been assigned a specific QL class.
|
||||
*/
|
||||
deprecated class MissingOpCode extends InstructionViolation {
|
||||
MissingOpCode() { not exists(instruction.getOpcodeName()) }
|
||||
|
||||
override string getMessage() {
|
||||
result = "Opcode " + instruction.getOpcode() + " is missing a QL class"
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Unknown instruction in " + instruction.getImplementation().getMethod().toString()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that is missing an operand. It means that there is no instruction which pushes
|
||||
* a value onto the stack for this instruction to pop.
|
||||
*
|
||||
* If this fails, it means that the `getPopCount`/`getPushCount`/control flow graph has failed.
|
||||
* It could also mean that the target of a call has failed and has not determined the
|
||||
* correct number of arguments.
|
||||
*/
|
||||
deprecated class MissingOperand extends InstructionViolation {
|
||||
MissingOperand() {
|
||||
exists(int op | op in [0 .. instruction.getPopCount() - 1] |
|
||||
not exists(instruction.getOperand(op)) and not instruction instanceof DeadInstruction
|
||||
)
|
||||
}
|
||||
|
||||
int getMissingOperand() {
|
||||
result in [0 .. instruction.getPopCount() - 1] and
|
||||
not exists(instruction.getOperand(result))
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
result = "This instruction is missing operand " + this.getMissingOperand()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A dead instruction, not reachable from any entry point.
|
||||
* These should not exist, however it turns out that the Mono compiler sometimes
|
||||
* emits them.
|
||||
*/
|
||||
deprecated class DeadInstruction extends Instruction {
|
||||
DeadInstruction() { not exists(EntryPoint e | e.getASuccessor+() = this) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that is not reachable from any entry point.
|
||||
*
|
||||
* If this fails, it means that the calculation of the call graph is incorrect.
|
||||
* Disabled, because Mono compiler sometimes emits dead instructions.
|
||||
*/
|
||||
deprecated class DeadInstructionViolation extends InstructionViolation, DisabledCheck {
|
||||
DeadInstructionViolation() { instruction instanceof DeadInstruction }
|
||||
|
||||
override string getMessage() { result = "This instruction is not reachable" }
|
||||
}
|
||||
|
||||
deprecated class YesNoBranch extends ConditionalBranch {
|
||||
YesNoBranch() { not this instanceof Opcodes::Switch }
|
||||
}
|
||||
|
||||
/**
|
||||
* A branch instruction that does not have exactly 2 successors.
|
||||
*/
|
||||
deprecated class InvalidBranchSuccessors extends InstructionViolation {
|
||||
InvalidBranchSuccessors() {
|
||||
// Mono compiler sometimes generates branches to the next instruction, which is just wrong.
|
||||
// However it is valid CIL.
|
||||
exists(YesNoBranch i | i = instruction | not count(i.getASuccessor()) in [1 .. 2])
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
result = "Conditional branch has " + count(instruction.getASuccessor()) + " successors"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that has a true/false successor but is not a branch.
|
||||
*/
|
||||
deprecated class OnlyYesNoBranchHasTrueFalseSuccessors extends InstructionViolation {
|
||||
OnlyYesNoBranchHasTrueFalseSuccessors() {
|
||||
(exists(instruction.getTrueSuccessor()) or exists(instruction.getFalseSuccessor())) and
|
||||
not instruction instanceof YesNoBranch
|
||||
}
|
||||
|
||||
override string getMessage() { result = "This instruction has getTrue/FalseSuccessor()" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An unconditional branch instruction that has more than one successor.
|
||||
*/
|
||||
deprecated class UnconditionalBranchSuccessors extends InstructionViolation {
|
||||
UnconditionalBranchSuccessors() {
|
||||
exists(UnconditionalBranch i | i = instruction | count(i.getASuccessor()) != 1)
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
result = "Unconditional branch has " + count(instruction.getASuccessor()) + " successors"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A branch instruction that does not have a true successor.
|
||||
*/
|
||||
deprecated class NoTrueSuccessor extends InstructionViolation {
|
||||
NoTrueSuccessor() { exists(YesNoBranch i | i = instruction | not exists(i.getTrueSuccessor())) }
|
||||
|
||||
override string getMessage() { result = "Missing a true successor" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A branch instruction that does not have a false successor.
|
||||
*/
|
||||
deprecated class NoFalseSuccessor extends InstructionViolation {
|
||||
NoFalseSuccessor() { exists(YesNoBranch i | i = instruction | not exists(i.getFalseSuccessor())) }
|
||||
|
||||
override string getMessage() { result = "Missing a false successor" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction whose true successor is not a successor.
|
||||
*/
|
||||
deprecated class TrueSuccessorIsSuccessor extends InstructionViolation {
|
||||
TrueSuccessorIsSuccessor() {
|
||||
exists(instruction.getTrueSuccessor()) and
|
||||
not instruction.getTrueSuccessor() = instruction.getASuccessor()
|
||||
}
|
||||
|
||||
override string getMessage() { result = "True successor isn't a successor" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction whose false successor is not a successor.
|
||||
*/
|
||||
deprecated class FalseSuccessorIsSuccessor extends InstructionViolation {
|
||||
FalseSuccessorIsSuccessor() {
|
||||
exists(instruction.getFalseSuccessor()) and
|
||||
not instruction.getFalseSuccessor() = instruction.getASuccessor()
|
||||
}
|
||||
|
||||
override string getMessage() { result = "True successor isn't a successor" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An access that does not have exactly one target.
|
||||
*/
|
||||
deprecated class AccessMissingTarget extends InstructionViolation {
|
||||
AccessMissingTarget() { exists(Access i | i = instruction | count(i.getTarget()) != 1) }
|
||||
|
||||
override string getMessage() { result = "Access has invalid getTarget()" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A catch handler that doesn't have a caught exception type.
|
||||
*/
|
||||
deprecated class CatchHandlerMissingType extends CfgViolation {
|
||||
CatchHandlerMissingType() { exists(CatchHandler h | h = node | not exists(h.getCaughtType())) }
|
||||
|
||||
override string getMessage() { result = "Catch handler missing caught type" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A CFG node that does not have a stack size.
|
||||
*/
|
||||
deprecated class MissingStackSize extends CfgViolation {
|
||||
MissingStackSize() {
|
||||
(
|
||||
not exists(node.getStackSizeAfter()) or
|
||||
not exists(node.getStackSizeBefore())
|
||||
) and
|
||||
not node instanceof DeadInstruction
|
||||
}
|
||||
|
||||
override string getMessage() { result = "Inconsistent stack size" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A CFG node that does not have exactly one stack size.
|
||||
* Disabled because inconsistent stack sizes have been observed.
|
||||
*/
|
||||
deprecated class InvalidStackSize extends CfgViolation, DisabledCheck {
|
||||
InvalidStackSize() {
|
||||
(
|
||||
count(node.getStackSizeAfter()) != 1 or
|
||||
count(node.getStackSizeBefore()) != 1
|
||||
) and
|
||||
not node instanceof DeadInstruction
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
result =
|
||||
"Inconsistent stack sizes " + count(node.getStackSizeBefore()) + " before and " +
|
||||
count(node.getStackSizeAfter()) + " after"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A CFG node that does not have exactly 1 `getPopCount()`.
|
||||
*/
|
||||
deprecated class InconsistentPopCount extends CfgViolation {
|
||||
InconsistentPopCount() { count(node.getPopCount()) != 1 }
|
||||
|
||||
override string getMessage() {
|
||||
result = "Cfg node has " + count(node.getPopCount()) + " pop counts"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A CFG node that does not have exactly one `getPushCount()`.
|
||||
*/
|
||||
deprecated class InconsistentPushCount extends CfgViolation {
|
||||
InconsistentPushCount() { count(node.getPushCount()) != 1 }
|
||||
|
||||
override string getMessage() {
|
||||
result = "Cfg node has " + count(node.getPushCount()) + " push counts"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A return instruction that does not have a stack size of 0 after it.
|
||||
*/
|
||||
deprecated class InvalidReturn extends InstructionViolation {
|
||||
InvalidReturn() { instruction instanceof Return and instruction.getStackSizeAfter() != 0 }
|
||||
|
||||
override string getMessage() { result = "Return has invalid stack size" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A throw instruction that does not have a stack size of 0 after it.
|
||||
*/
|
||||
deprecated class InvalidThrow extends InstructionViolation, DisabledCheck {
|
||||
InvalidThrow() { instruction instanceof Throw and instruction.getStackSizeAfter() != 0 }
|
||||
|
||||
override string getMessage() {
|
||||
result = "Throw has invalid stack size: " + instruction.getStackSizeAfter()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A field access where the field is "static" but the instruction is "instance".
|
||||
*/
|
||||
deprecated class StaticFieldTarget extends InstructionViolation {
|
||||
StaticFieldTarget() {
|
||||
exists(FieldAccess i | i = instruction |
|
||||
(i instanceof Opcodes::Stfld or i instanceof Opcodes::Stfld) and
|
||||
i.getTarget().isStatic()
|
||||
)
|
||||
}
|
||||
|
||||
override string getMessage() { result = "Inconsistent static field" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A branch without a target.
|
||||
*/
|
||||
deprecated class BranchWithoutTarget extends InstructionViolation {
|
||||
BranchWithoutTarget() {
|
||||
instruction = any(Branch b | not exists(b.getTarget()) and not b instanceof Opcodes::Switch)
|
||||
}
|
||||
|
||||
override string getMessage() { result = "Branch without target" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A consistency violation in a type.
|
||||
*/
|
||||
deprecated class TypeViolation extends ConsistencyViolation, TypeCheck {
|
||||
/** Gets the type containing the violation. */
|
||||
Type getType() { this = TypeCheck(result) }
|
||||
|
||||
override string toString() { result = this.getType().toString() }
|
||||
|
||||
abstract override string getMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* A type that has both type arguments and type parameters.
|
||||
*/
|
||||
deprecated class TypeIsBothConstructedAndUnbound extends TypeViolation {
|
||||
TypeIsBothConstructedAndUnbound() {
|
||||
this.getType() instanceof ConstructedGeneric and this.getType() instanceof UnboundGeneric
|
||||
}
|
||||
|
||||
override string getMessage() { result = "Type is both constructed and unbound" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The location of a constructed generic type should be the same
|
||||
* as the location of its unbound generic type.
|
||||
*/
|
||||
deprecated class InconsistentTypeLocation extends TypeViolation {
|
||||
InconsistentTypeLocation() {
|
||||
this.getType().getLocation() != this.getType().getUnboundDeclaration().getLocation()
|
||||
}
|
||||
|
||||
override string getMessage() { result = "Inconsistent constructed type location" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A constructed type that does not match its unbound generic type.
|
||||
*/
|
||||
deprecated class TypeParameterMismatch extends TypeViolation {
|
||||
TypeParameterMismatch() {
|
||||
this.getType().(ConstructedGeneric).getNumberOfTypeArguments() !=
|
||||
this.getType().getUnboundType().(UnboundGeneric).getNumberOfTypeParameters()
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
result =
|
||||
"Constructed type (" + this.getType().toStringWithTypes() + ") has " +
|
||||
this.getType().(ConstructedGeneric).getNumberOfTypeArguments() +
|
||||
" type arguments and unbound type (" + this.getType().getUnboundType().toStringWithTypes() +
|
||||
") has " + this.getType().getUnboundType().(UnboundGeneric).getNumberOfTypeParameters() +
|
||||
" type parameters"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A consistency violation in a method.
|
||||
*/
|
||||
deprecated class MethodViolation extends ConsistencyViolation, DeclarationCheck {
|
||||
/** Gets the method containing the violation. */
|
||||
Method getMethod() { this = DeclarationCheck(result) }
|
||||
|
||||
override string toString() { result = this.getMethod().toString() }
|
||||
|
||||
override string getMessage() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The location of a constructed method should be equal to the
|
||||
* location of its unbound generic.
|
||||
*/
|
||||
deprecated class InconsistentMethodLocation extends MethodViolation {
|
||||
InconsistentMethodLocation() {
|
||||
this.getMethod().getLocation() != this.getMethod().getUnboundDeclaration().getLocation()
|
||||
}
|
||||
|
||||
override string getMessage() { result = "Inconsistent constructed method location" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A constructed method that does not match its unbound method.
|
||||
*/
|
||||
deprecated class ConstructedMethodTypeParams extends MethodViolation {
|
||||
ConstructedMethodTypeParams() {
|
||||
this.getMethod().(ConstructedGeneric).getNumberOfTypeArguments() !=
|
||||
this.getMethod().getUnboundDeclaration().(UnboundGeneric).getNumberOfTypeParameters()
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
result =
|
||||
"The constructed method " + this.getMethod().toStringWithTypes() +
|
||||
" does not match unbound method " +
|
||||
this.getMethod().getUnboundDeclaration().toStringWithTypes()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A violation marking an entity that should be present but is not.
|
||||
*/
|
||||
abstract deprecated class MissingEntityViolation extends ConsistencyViolation, MissingEntityCheck {
|
||||
override string toString() { result = "Missing entity" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The type `object` is missing from the database.
|
||||
*/
|
||||
deprecated class MissingObjectViolation extends MissingEntityViolation {
|
||||
MissingObjectViolation() {
|
||||
exists(this) and
|
||||
not exists(ObjectType o)
|
||||
}
|
||||
|
||||
override string getMessage() { result = "Object missing" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An override that is invalid because the overridden method is not in a base class.
|
||||
*/
|
||||
deprecated class InvalidOverride extends MethodViolation {
|
||||
private Method base;
|
||||
|
||||
InvalidOverride() {
|
||||
base = this.getMethod().getOverriddenMethod() and
|
||||
not this.getMethod().getDeclaringType().getABaseType+() = base.getDeclaringType() and
|
||||
base.getDeclaringType().isUnboundDeclaration() // Bases classes of constructed types aren't extracted properly.
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
exists(string qualifier, string type |
|
||||
base.getDeclaringType().hasFullyQualifiedName(qualifier, type)
|
||||
|
|
||||
result =
|
||||
"Overridden method from " + getQualifiedName(qualifier, type) + " is not in a base type"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A pointer type that does not have a pointee type.
|
||||
*/
|
||||
deprecated class InvalidPointerType extends TypeViolation {
|
||||
InvalidPointerType() {
|
||||
exists(PointerType p | p = this.getType() | count(p.getReferentType()) != 1)
|
||||
}
|
||||
|
||||
override string getMessage() { result = "Invalid Pointertype.getPointeeType()" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An array with an invalid `getElementType`.
|
||||
*/
|
||||
deprecated class ArrayTypeMissingElement extends TypeViolation {
|
||||
ArrayTypeMissingElement() {
|
||||
exists(ArrayType t | t = this.getType() | count(t.getElementType()) != 1)
|
||||
}
|
||||
|
||||
override string getMessage() { result = "Invalid ArrayType.getElementType()" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An array with an invalid `getRank`.
|
||||
*/
|
||||
deprecated class ArrayTypeInvalidRank extends TypeViolation {
|
||||
ArrayTypeInvalidRank() { exists(ArrayType t | t = this.getType() | not t.getRank() > 0) }
|
||||
|
||||
override string getMessage() { result = "Invalid ArrayType.getRank()" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A type should have at most one kind, except for missing referenced types
|
||||
* where the interface/class is unknown.
|
||||
*/
|
||||
deprecated class KindViolation extends TypeViolation {
|
||||
KindViolation() {
|
||||
count(typeKind(this.getType())) != 1 and
|
||||
exists(this.getType().getLocation())
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
result = "Invalid kinds on type: " + concat(typeKind(this.getType()), " ")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of a kind must be consistent between a constructed generic and its
|
||||
* unbound generic.
|
||||
*/
|
||||
deprecated class InconsistentKind extends TypeViolation {
|
||||
InconsistentKind() {
|
||||
typeKind(this.getType()) != typeKind(this.getType().getUnboundDeclaration())
|
||||
}
|
||||
|
||||
override string getMessage() { result = "Inconsistent type kind of source declaration" }
|
||||
}
|
||||
|
||||
deprecated private string typeKind(Type t) {
|
||||
t instanceof Interface and result = "interface"
|
||||
or
|
||||
t instanceof Class and result = "class"
|
||||
or
|
||||
t instanceof TypeParameter and result = "type parameter"
|
||||
or
|
||||
t instanceof ArrayType and result = "array"
|
||||
or
|
||||
t instanceof PointerType and result = "pointer"
|
||||
}
|
||||
|
||||
/**
|
||||
* A violation in a `Member`.
|
||||
*/
|
||||
abstract deprecated class DeclarationViolation extends ConsistencyViolation, DeclarationCheck {
|
||||
abstract override string getMessage();
|
||||
|
||||
/** Gets the member containing the potential violation. */
|
||||
Declaration getDeclaration() { this = DeclarationCheck(result) }
|
||||
|
||||
override string toString() { result = this.getDeclaration().toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Properties that have no accessors.
|
||||
*/
|
||||
deprecated class PropertyWithNoAccessors extends DeclarationViolation {
|
||||
PropertyWithNoAccessors() {
|
||||
exists(Property p | p = this.getDeclaration() | not exists(p.getAnAccessor()))
|
||||
}
|
||||
|
||||
override string getMessage() { result = "Property has no accessors" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression that have an unexpected push count.
|
||||
*/
|
||||
deprecated class ExprPushCount extends InstructionViolation {
|
||||
ExprPushCount() {
|
||||
instruction instanceof Expr and
|
||||
not instruction instanceof Opcodes::Dup and
|
||||
if instruction instanceof Call
|
||||
then not instruction.getPushCount() in [0 .. 1]
|
||||
else instruction.(Expr).getPushCount() != 1
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
result = "Instruction has unexpected push count " + instruction.getPushCount()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression that does not have exactly one type.
|
||||
* Note that calls with no return have type `System.Void`.
|
||||
*/
|
||||
deprecated class ExprMissingType extends InstructionViolation {
|
||||
ExprMissingType() {
|
||||
// Don't have types for the following op codes:
|
||||
not instruction instanceof Opcodes::Ldftn and
|
||||
not instruction instanceof Opcodes::Localloc and
|
||||
not instruction instanceof Opcodes::Ldvirtftn and
|
||||
not instruction instanceof Opcodes::Arglist and
|
||||
not instruction instanceof Opcodes::Refanytype and
|
||||
instruction.getPushCount() >= 1 and
|
||||
count(instruction.getType()) != 1 and
|
||||
// OS specific (osx) specific inconsistency
|
||||
not instruction
|
||||
.getImplementation()
|
||||
.getMethod()
|
||||
.hasFullyQualifiedName("System.Runtime.InteropServices.RuntimeInformation",
|
||||
"get_OSDescription")
|
||||
}
|
||||
|
||||
override string getMessage() { result = "Expression is missing getType()" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that has a push count of 0, yet is still used as an operand
|
||||
*/
|
||||
deprecated class InvalidExpressionViolation extends InstructionViolation {
|
||||
InvalidExpressionViolation() {
|
||||
instruction.getPushCount() = 0 and
|
||||
exists(Instruction expr | instruction = expr.getAnOperand())
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
result = "This instruction is used as an operand but pushes no values"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A type that has multiple entities with the same qualified name in `System`.
|
||||
* .NET Core does sometimes duplicate types, so this check is disabled.
|
||||
*/
|
||||
deprecated class TypeMultiplyDefined extends TypeViolation, DisabledCheck {
|
||||
TypeMultiplyDefined() {
|
||||
this.getType().getParent().getName() = "System" and
|
||||
not this.getType() instanceof ConstructedGeneric and
|
||||
not this.getType() instanceof ArrayType and
|
||||
this.getType().isPublic() and
|
||||
count(Type t |
|
||||
not t instanceof ConstructedGeneric and
|
||||
t.toStringWithTypes() = this.getType().toStringWithTypes()
|
||||
) != 1
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
result =
|
||||
"This type (" + this.getType().toStringWithTypes() + ") has " +
|
||||
count(Type t |
|
||||
not t instanceof ConstructedGeneric and
|
||||
t.toStringWithTypes() = this.getType().toStringWithTypes()
|
||||
) + " entities"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A C# declaration which is expected to have a corresponding CIL declaration, but for some reason does not.
|
||||
*/
|
||||
deprecated class MissingCilDeclaration extends ConsistencyViolation, MissingCSharpCheck {
|
||||
MissingCilDeclaration() {
|
||||
exists(CS::Declaration decl | this = MissingCSharpCheck(decl) |
|
||||
expectedCilDeclaration(decl) and
|
||||
not exists(Declaration d | decl = d.getCSharpDeclaration())
|
||||
)
|
||||
}
|
||||
|
||||
CS::Declaration getDeclaration() { this = MissingCSharpCheck(result) }
|
||||
|
||||
override string getMessage() {
|
||||
result =
|
||||
"Cannot locate CIL for " + this.getDeclaration().toStringWithTypes() + " of class " +
|
||||
this.getDeclaration().getPrimaryQlClasses()
|
||||
}
|
||||
|
||||
override string toString() { result = this.getDeclaration().toStringWithTypes() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the C# declaration is expected to have a CIl declaration.
|
||||
*/
|
||||
deprecated private predicate expectedCilDeclaration(CS::Declaration decl) {
|
||||
decl = decl.getUnboundDeclaration() and
|
||||
not decl instanceof CS::ArrayType and
|
||||
decl.getALocation() instanceof CS::Assembly and
|
||||
not decl.(CS::Modifiable).isInternal() and
|
||||
not decl.(CS::Constructor).getNumberOfParameters() = 0 and // These are sometimes implicit
|
||||
not decl.(CS::Method).getReturnType() instanceof CS::UnknownType and
|
||||
not exists(CS::Parameter p | p = decl.(CS::Parameterizable).getAParameter() |
|
||||
not expectedCilDeclaration(p)
|
||||
) and
|
||||
not decl instanceof CS::AnonymousClass and
|
||||
(decl instanceof CS::Parameter implies expectedCilDeclaration(decl.(CS::Parameter).getType())) and
|
||||
(decl instanceof CS::Parameter implies expectedCilDeclaration(decl.getParent())) and
|
||||
(decl instanceof CS::Member implies expectedCilDeclaration(decl.getParent())) and
|
||||
(
|
||||
decl instanceof CS::Field
|
||||
or
|
||||
decl instanceof CS::Property
|
||||
or
|
||||
decl instanceof CS::ValueOrRefType
|
||||
or
|
||||
decl instanceof CS::Event
|
||||
or
|
||||
decl instanceof CS::Constructor
|
||||
or
|
||||
decl instanceof CS::Destructor
|
||||
or
|
||||
decl instanceof CS::Operator
|
||||
or
|
||||
decl instanceof CS::Method
|
||||
or
|
||||
decl instanceof CS::Parameter
|
||||
)
|
||||
}
|
||||
|
||||
/** A member with an invalid name. */
|
||||
deprecated class MemberWithInvalidName extends DeclarationViolation {
|
||||
MemberWithInvalidName() {
|
||||
exists(string name | name = this.getDeclaration().(Member).getName() |
|
||||
exists(name.indexOf(".")) and
|
||||
not name = ".ctor" and
|
||||
not name = ".cctor"
|
||||
)
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
result = "Invalid name " + this.getDeclaration().(Member).getName()
|
||||
}
|
||||
}
|
||||
|
||||
deprecated class ConstructedSourceDeclarationMethod extends MethodViolation {
|
||||
Method method;
|
||||
|
||||
ConstructedSourceDeclarationMethod() {
|
||||
method = this.getMethod() and
|
||||
method = method.getUnboundDeclaration() and
|
||||
(
|
||||
method instanceof ConstructedGeneric or
|
||||
method.getDeclaringType() instanceof ConstructedGeneric
|
||||
)
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
result = "Source declaration " + method.toStringWithTypes() + " is constructed"
|
||||
}
|
||||
}
|
||||
|
||||
/** A declaration with multiple labels. */
|
||||
deprecated class DeclarationWithMultipleLabels extends DeclarationViolation {
|
||||
DeclarationWithMultipleLabels() {
|
||||
exists(Declaration d | this = DeclarationCheck(d) | strictcount(d.getLabel()) > 1)
|
||||
}
|
||||
|
||||
override string getMessage() {
|
||||
result = "Multiple labels " + concat(this.getDeclaration().getLabel(), ", ")
|
||||
}
|
||||
}
|
||||
|
||||
/** A declaration without a label. */
|
||||
deprecated class DeclarationWithoutLabel extends DeclarationViolation {
|
||||
DeclarationWithoutLabel() {
|
||||
exists(Declaration d | this = DeclarationCheck(d) |
|
||||
d.isUnboundDeclaration() and
|
||||
not d instanceof TypeParameter and
|
||||
not exists(d.getLabel()) and
|
||||
(d instanceof Callable or d instanceof Type)
|
||||
)
|
||||
}
|
||||
|
||||
override string getMessage() { result = "No label" }
|
||||
}
|
||||
@@ -1,179 +0,0 @@
|
||||
/**
|
||||
* Provides classes for control flow.
|
||||
*/
|
||||
|
||||
private import CIL
|
||||
|
||||
/** A node in the control flow graph. */
|
||||
deprecated class ControlFlowNode extends @cil_controlflow_node {
|
||||
/** Gets a textual representation of this control flow node. */
|
||||
string toString() { none() }
|
||||
|
||||
/** Gets the location of this control flow node. */
|
||||
Location getLocation() { none() }
|
||||
|
||||
/**
|
||||
* Gets the number of items this node pushes onto the stack.
|
||||
* This value is either 0 or 1, except for the instruction `dup`
|
||||
* which pushes 2 values onto the stack.
|
||||
*/
|
||||
int getPushCount() { result = 0 }
|
||||
|
||||
/** Gets the number of items this node pops from the stack. */
|
||||
int getPopCount() { result = 0 }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final Instruction getASuccessor() { result = this.getASuccessorType(_) }
|
||||
|
||||
/** Gets a true successor of this node, if any. */
|
||||
final Instruction getTrueSuccessor() { result = this.getASuccessorType(any(TrueFlow f)) }
|
||||
|
||||
/** Gets a false successor of this node, if any. */
|
||||
final Instruction getFalseSuccessor() { result = this.getASuccessorType(any(FalseFlow f)) }
|
||||
|
||||
/** Gets a successor to this node, of type `type`, if any. */
|
||||
cached
|
||||
Instruction getASuccessorType(FlowType t) { none() }
|
||||
|
||||
/** Gets a predecessor of this node, if any. */
|
||||
ControlFlowNode getAPredecessor() { result.getASuccessor() = this }
|
||||
|
||||
/**
|
||||
* Gets an instruction that supplies the `i`th operand to this instruction.
|
||||
* Note that this can be multi-valued.
|
||||
*/
|
||||
cached
|
||||
ControlFlowNode getOperand(int i) {
|
||||
// Immediate predecessor pushes the operand
|
||||
i in [0 .. this.getPopCount() - 1] and
|
||||
result = this.getAPredecessor() and
|
||||
i < result.getPushCount()
|
||||
or
|
||||
// Transitive predecessor pushes the operand
|
||||
exists(ControlFlowNode mid, int pushes | this.getOperandRec(mid, i, pushes) |
|
||||
pushes - mid.getStackDelta() < result.getPushCount() and
|
||||
result = mid.getAPredecessor()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of the `i`th operand. Unlike `getOperand(i).getType()`, this
|
||||
* predicate takes into account when there are multiple possible operands with
|
||||
* different types.
|
||||
*/
|
||||
Type getOperandType(int i) {
|
||||
strictcount(this.getOperand(i)) = 1 and
|
||||
result = this.getOperand(i).getType()
|
||||
or
|
||||
strictcount(this.getOperand(i)) = 2 and
|
||||
exists(ControlFlowNode op1, ControlFlowNode op2, Type t2 |
|
||||
op1 = this.getOperand(i) and
|
||||
op2 = this.getOperand(i) and
|
||||
op1 != op2 and
|
||||
result = op1.getType() and
|
||||
t2 = op2.getType()
|
||||
|
|
||||
result = t2
|
||||
or
|
||||
result.(PrimitiveType).getUnderlyingType().getConversionIndex() >
|
||||
t2.(PrimitiveType).getUnderlyingType().getConversionIndex()
|
||||
or
|
||||
op2 instanceof NullLiteral
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets an operand of this instruction, if any. */
|
||||
ControlFlowNode getAnOperand() { result = this.getOperand(_) }
|
||||
|
||||
/** Gets an expression that consumes the output of this instruction on the stack. */
|
||||
Instruction getParentExpr() { this = result.getAnOperand() }
|
||||
|
||||
/**
|
||||
* Holds if `pred` is a transitive predecessor of this instruction, this
|
||||
* instruction pops operand `i`, `pushes` additional pushes are required
|
||||
* for operand `i` at node `pred`, and no instruction between (and including)
|
||||
* `pred` and this instruction is a push for operand `i`.
|
||||
*/
|
||||
private predicate getOperandRec(ControlFlowNode pred, int i, int pushes) {
|
||||
// Invariant: no node is a push for operand `i`
|
||||
pushes >= pred.getPushCount() and
|
||||
(
|
||||
i in [0 .. this.getPopCount() - 1] and
|
||||
pred = this.getAPredecessor() and
|
||||
pushes = i
|
||||
or
|
||||
exists(ControlFlowNode mid, int pushes0 | this.getOperandRec(mid, i, pushes0) |
|
||||
pushes = pushes0 - mid.getStackDelta() and
|
||||
// This is a guard to prevent ill formed programs
|
||||
// and other logic errors going into an infinite loop.
|
||||
pushes <= this.getImplementation().getStackSize() and
|
||||
pred = mid.getAPredecessor()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private int getStackDelta() { result = this.getPushCount() - this.getPopCount() }
|
||||
|
||||
/** Gets the stack size before this instruction. */
|
||||
int getStackSizeBefore() { result = this.getAPredecessor().getStackSizeAfter() }
|
||||
|
||||
/** Gets the stack size after this instruction. */
|
||||
final int getStackSizeAfter() {
|
||||
// This is a guard to prevent ill formed programs
|
||||
// and other logic errors going into an infinite loop.
|
||||
result in [0 .. this.getImplementation().getStackSize()] and
|
||||
result = this.getStackSizeBefore() + this.getStackDelta()
|
||||
}
|
||||
|
||||
/** Gets the method containing this control flow node. */
|
||||
MethodImplementation getImplementation() { none() }
|
||||
|
||||
/**
|
||||
* Gets the type of the item pushed onto the stack, if any.
|
||||
*
|
||||
* If called via `ControlFlowNode::getOperand(i).getType()`, consider using
|
||||
* `ControlFlowNode::getOperandType(i)` instead.
|
||||
*/
|
||||
cached
|
||||
Type getType() { none() }
|
||||
|
||||
/** Holds if this control flow node has more than one predecessor. */
|
||||
predicate isJoin() { strictcount(this.getAPredecessor()) > 1 }
|
||||
|
||||
/** Holds if this control flow node has more than one successor. */
|
||||
predicate isBranch() { strictcount(this.getASuccessor()) > 1 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A control flow entry point. Either a method (`MethodImplementation`) or a handler (`Handler`).
|
||||
*
|
||||
* Handlers are control flow nodes because they push the handled exception onto the stack.
|
||||
*/
|
||||
deprecated class EntryPoint extends ControlFlowNode, @cil_entry_point {
|
||||
override int getStackSizeBefore() { result = 0 }
|
||||
}
|
||||
|
||||
deprecated private newtype TFlowType =
|
||||
TNormalFlow() or
|
||||
TTrueFlow() or
|
||||
TFalseFlow()
|
||||
|
||||
/** A type of control flow. Either normal flow (`NormalFlow`), true flow (`TrueFlow`) or false flow (`FalseFlow`). */
|
||||
abstract deprecated class FlowType extends TFlowType {
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/** Normal control flow. */
|
||||
deprecated class NormalFlow extends FlowType, TNormalFlow {
|
||||
override string toString() { result = "" }
|
||||
}
|
||||
|
||||
/** True control flow. */
|
||||
deprecated class TrueFlow extends FlowType, TTrueFlow {
|
||||
override string toString() { result = "true" }
|
||||
}
|
||||
|
||||
/** False control flow. */
|
||||
deprecated class FalseFlow extends FlowType, TFalseFlow {
|
||||
override string toString() { result = "false" }
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
/**
|
||||
* Provides a class to represent `modopt` and `modreq` declarations.
|
||||
*/
|
||||
|
||||
private import CIL
|
||||
private import dotnet
|
||||
|
||||
/**
|
||||
* A class to represent entities that can receive custom modifiers. Custom modifiers can be attached to
|
||||
* - the type of a `Field`,
|
||||
* - the return type of a `Method` or `Property`,
|
||||
* - the type of parameters.
|
||||
* A `CustomModifierReceiver` is therefore either a `Field`, `Property`, `Method`, or `Parameter`.
|
||||
*/
|
||||
deprecated class CustomModifierReceiver extends Declaration, @cil_custom_modifier_receiver {
|
||||
/** Holds if this targeted type has `modifier` applied as `modreq`. */
|
||||
predicate hasRequiredCustomModifier(Type modifier) { cil_custom_modifiers(this, modifier, 1) }
|
||||
|
||||
/** Holds if this targeted type has `modifier` applied as `modopt`. */
|
||||
predicate hasOptionalCustomModifier(Type modifier) { cil_custom_modifiers(this, modifier, 0) }
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/**
|
||||
* Provides a collection of building blocks and utilities for data flow.
|
||||
*/
|
||||
|
||||
private import CIL
|
||||
|
||||
/**
|
||||
* A node in the data flow graph.
|
||||
*
|
||||
* Either an instruction (`Instruction`), a method return (`Method`), or a variable (`Variable`).
|
||||
*/
|
||||
deprecated class DataFlowNode extends @cil_dataflow_node {
|
||||
/** Gets a textual representation of this data flow node. */
|
||||
abstract string toString();
|
||||
|
||||
/** Gets the type of this data flow node. */
|
||||
Type getType() { none() }
|
||||
|
||||
/** Gets the method that contains this dataflow node. */
|
||||
Method getMethod() { none() }
|
||||
|
||||
/** Gets the location of this dataflow node. */
|
||||
Location getLocation() { none() }
|
||||
}
|
||||
|
||||
/** A node that updates a variable. */
|
||||
abstract deprecated class VariableUpdate extends DataFlowNode {
|
||||
/** Gets the value assigned, if any. */
|
||||
abstract DataFlowNode getSource();
|
||||
|
||||
/** Gets the variable that is updated. */
|
||||
abstract Variable getVariable();
|
||||
|
||||
/** Holds if this variable update happens at index `i` in basic block `bb`. */
|
||||
abstract predicate updatesAt(BasicBlock bb, int i);
|
||||
}
|
||||
|
||||
deprecated private class MethodParameterDef extends VariableUpdate, MethodParameter {
|
||||
override MethodParameter getSource() { result = this }
|
||||
|
||||
override MethodParameter getVariable() { result = this }
|
||||
|
||||
override predicate updatesAt(BasicBlock bb, int i) {
|
||||
bb.(EntryBasicBlock).getANode().getImplementation().getMethod() = this.getMethod() and
|
||||
i = -1
|
||||
}
|
||||
}
|
||||
|
||||
deprecated private class VariableWrite extends VariableUpdate, WriteAccess {
|
||||
override Expr getSource() { result = this.getExpr() }
|
||||
|
||||
override Variable getVariable() { result = this.getTarget() }
|
||||
|
||||
override predicate updatesAt(BasicBlock bb, int i) { this = bb.getNode(i) }
|
||||
}
|
||||
|
||||
deprecated private class MethodOutOrRefTarget extends VariableUpdate, Call {
|
||||
int parameterIndex;
|
||||
|
||||
MethodOutOrRefTarget() { this.getTarget().getRawParameter(parameterIndex).hasOutFlag() }
|
||||
|
||||
override Variable getVariable() {
|
||||
result = this.getRawArgument(parameterIndex).(ReadAccess).getTarget()
|
||||
}
|
||||
|
||||
override Expr getSource() { none() }
|
||||
|
||||
override predicate updatesAt(BasicBlock bb, int i) { this = bb.getNode(i) }
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
/**
|
||||
* Provides classes for declarations and members.
|
||||
*/
|
||||
|
||||
import CIL
|
||||
private import dotnet
|
||||
private import semmle.code.csharp.Member as CS
|
||||
private import semmle.code.csharp.commons.QualifiedName
|
||||
|
||||
/**
|
||||
* A declaration. Either a member (`Member`) or a variable (`Variable`).
|
||||
*/
|
||||
deprecated class Declaration extends DotNet::Declaration, Element, @cil_declaration {
|
||||
/** Gets an attribute (for example `[Obsolete]`) of this declaration, if any. */
|
||||
Attribute getAnAttribute() { result.getDeclaration() = this }
|
||||
|
||||
/**
|
||||
* Gets the C# declaration corresponding to this CIL declaration, if any.
|
||||
* Note that this is only for source/unconstructed declarations.
|
||||
*/
|
||||
CS::Declaration getCSharpDeclaration() {
|
||||
result = toCSharpNonTypeParameter(this) or
|
||||
result = toCSharpTypeParameter(this)
|
||||
}
|
||||
|
||||
override Declaration getUnboundDeclaration() { result = this }
|
||||
|
||||
deprecated override predicate hasQualifiedName(string qualifier, string name) {
|
||||
exists(string dqualifier, string dname |
|
||||
this.getDeclaringType().hasQualifiedName(dqualifier, dname) and
|
||||
qualifier = getQualifiedName(dqualifier, dname)
|
||||
) and
|
||||
name = this.getName()
|
||||
}
|
||||
|
||||
override predicate hasFullyQualifiedName(string qualifier, string name) {
|
||||
exists(string dqualifier, string dname |
|
||||
this.getDeclaringType().hasFullyQualifiedName(dqualifier, dname) and
|
||||
qualifier = getQualifiedName(dqualifier, dname)
|
||||
) and
|
||||
name = this.getName()
|
||||
}
|
||||
}
|
||||
|
||||
deprecated private CS::Declaration toCSharpNonTypeParameter(Declaration d) {
|
||||
result.(DotNet::Declaration).matchesHandle(d)
|
||||
}
|
||||
|
||||
deprecated private CS::TypeParameter toCSharpTypeParameter(TypeParameter tp) {
|
||||
toCSharpTypeParameterJoin(tp, result.getIndex(), result.getGeneric())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
deprecated private predicate toCSharpTypeParameterJoin(
|
||||
TypeParameter tp, int i, CS::UnboundGeneric ug
|
||||
) {
|
||||
exists(TypeContainer tc |
|
||||
tp.getIndex() = i and
|
||||
tc = tp.getGeneric() and
|
||||
ug = toCSharpNonTypeParameter(tc)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A member of a type. Either a type (`Type`), a method (`Method`), a property (`Property`), or an event (`Event`).
|
||||
*/
|
||||
deprecated class Member extends DotNet::Member, Declaration, @cil_member {
|
||||
override predicate isPublic() { cil_public(this) }
|
||||
|
||||
override predicate isProtected() { cil_protected(this) }
|
||||
|
||||
override predicate isPrivate() { cil_private(this) }
|
||||
|
||||
override predicate isInternal() { cil_internal(this) }
|
||||
|
||||
override predicate isSealed() { cil_sealed(this) }
|
||||
|
||||
override predicate isAbstract() { cil_abstract(this) }
|
||||
|
||||
override predicate isStatic() { cil_static(this) }
|
||||
|
||||
/** Holds if this member has a security attribute. */
|
||||
predicate hasSecurity() { cil_security(this) }
|
||||
|
||||
override Location getLocation() { result = this.getDeclaringType().getLocation() }
|
||||
}
|
||||
|
||||
/** A property. */
|
||||
deprecated class Property extends DotNet::Property, Member, CustomModifierReceiver, @cil_property {
|
||||
override string getName() { cil_property(this, _, result, _) }
|
||||
|
||||
/** Gets the type of this property. */
|
||||
override Type getType() { cil_property(this, _, _, result) }
|
||||
|
||||
override ValueOrRefType getDeclaringType() { cil_property(this, result, _, _) }
|
||||
|
||||
/** Gets the getter of this property, if any. */
|
||||
override Getter getGetter() { this = result.getProperty() }
|
||||
|
||||
/** Gets the setter of this property, if any. */
|
||||
override Setter getSetter() { this = result.getProperty() }
|
||||
|
||||
/** Gets an accessor of this property. */
|
||||
Accessor getAnAccessor() { result = this.getGetter() or result = this.getSetter() }
|
||||
|
||||
override string toString() { result = "property " + this.getName() }
|
||||
|
||||
override string toStringWithTypes() {
|
||||
result =
|
||||
this.getType().toStringWithTypes() + " " + this.getDeclaringType().toStringWithTypes() + "." +
|
||||
this.getName()
|
||||
}
|
||||
}
|
||||
|
||||
/** A property that is trivial (wraps a field). */
|
||||
deprecated class TrivialProperty extends Property {
|
||||
TrivialProperty() {
|
||||
this.getGetter().(TrivialGetter).getField() = this.getSetter().(TrivialSetter).getField()
|
||||
}
|
||||
|
||||
/** Gets the underlying field of this property. */
|
||||
Field getField() { result = this.getGetter().(TrivialGetter).getField() }
|
||||
}
|
||||
|
||||
/** An event. */
|
||||
deprecated class Event extends DotNet::Event, Member, @cil_event {
|
||||
override string getName() { cil_event(this, _, result, _) }
|
||||
|
||||
/** Gets the type of this event. */
|
||||
Type getType() { cil_event(this, _, _, result) }
|
||||
|
||||
override ValueOrRefType getDeclaringType() { cil_event(this, result, _, _) }
|
||||
|
||||
/** Gets the add event accessor. */
|
||||
Method getAddEventAccessor() { cil_adder(this, result) }
|
||||
|
||||
/** Gets the remove event accessor. */
|
||||
Method getRemoveEventAccessor() { cil_remover(this, result) }
|
||||
|
||||
/** Gets the raiser. */
|
||||
Method getRaiser() { cil_raiser(this, result) }
|
||||
|
||||
override string toString() { result = "event " + this.getName() }
|
||||
|
||||
override string toStringWithTypes() {
|
||||
result = this.getDeclaringType().toStringWithTypes() + "." + this.getName()
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
/** Provides the `Element` class, the base class of all CIL program elements. */
|
||||
|
||||
private import dotnet
|
||||
import semmle.code.csharp.Location
|
||||
|
||||
/** An element. */
|
||||
deprecated class Element extends DotNet::Element, @cil_element {
|
||||
override Location getLocation() { result = bestLocation(this) }
|
||||
}
|
||||
|
||||
cached
|
||||
deprecated private Location bestLocation(Element e) {
|
||||
result = e.getALocation() and
|
||||
(e.getALocation().getFile().isPdbSourceFile() implies result.getFile().isPdbSourceFile())
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
/** Provides classes for generic types and methods. */
|
||||
|
||||
private import CIL
|
||||
private import dotnet
|
||||
|
||||
/**
|
||||
* A generic declaration. Either an unbound generic (`UnboundGeneric`) or a
|
||||
* constructed generic (`ConstructedGeneric`).
|
||||
*/
|
||||
deprecated class Generic extends DotNet::Generic, Declaration, TypeContainer {
|
||||
Generic() {
|
||||
cil_type_parameter(this, _, _) or
|
||||
cil_type_argument(this, _, _)
|
||||
}
|
||||
}
|
||||
|
||||
/** An unbound generic type or method. */
|
||||
deprecated class UnboundGeneric extends Generic, DotNet::UnboundGeneric {
|
||||
UnboundGeneric() { cil_type_parameter(this, _, _) }
|
||||
|
||||
final override TypeParameter getTypeParameter(int n) { cil_type_parameter(this, n, result) }
|
||||
}
|
||||
|
||||
/** A constructed generic type or method. */
|
||||
deprecated class ConstructedGeneric extends Generic, DotNet::ConstructedGeneric {
|
||||
ConstructedGeneric() { cil_type_argument(this, _, _) }
|
||||
|
||||
final override Type getTypeArgument(int n) { cil_type_argument(this, n, result) }
|
||||
}
|
||||
|
||||
/** Gets the concatenation of the `getName()` of type arguments. */
|
||||
language[monotonicAggregates]
|
||||
deprecated private string getTypeArgumentsNames(ConstructedGeneric cg) {
|
||||
result = strictconcat(Type t, int i | t = cg.getTypeArgument(i) | t.getName(), "," order by i)
|
||||
}
|
||||
|
||||
/** An unbound generic type. */
|
||||
deprecated class UnboundGenericType extends UnboundGeneric, Type { }
|
||||
|
||||
/** An unbound generic method. */
|
||||
deprecated class UnboundGenericMethod extends UnboundGeneric, Method { }
|
||||
|
||||
/** A constructed generic type. */
|
||||
deprecated class ConstructedType extends ConstructedGeneric, Type {
|
||||
final override UnboundGenericType getUnboundGeneric() { result = this.getUnboundType() }
|
||||
|
||||
override predicate isInterface() { this.getUnboundType().isInterface() }
|
||||
|
||||
override predicate isClass() { this.getUnboundType().isClass() }
|
||||
|
||||
final override string getName() {
|
||||
result = this.getUndecoratedName() + "<" + getTypeArgumentsNames(this) + ">"
|
||||
}
|
||||
}
|
||||
|
||||
/** A constructed generic method. */
|
||||
deprecated class ConstructedMethod extends ConstructedGeneric, Method {
|
||||
final override UnboundGenericMethod getUnboundGeneric() { result = this.getUnboundMethod() }
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/**
|
||||
* Provides classes for different types of handler.
|
||||
*/
|
||||
|
||||
private import CIL
|
||||
|
||||
/**
|
||||
* A handler is a piece of code that can be executed out of sequence, for example
|
||||
* when an instruction generates an exception or leaves a `finally` block.
|
||||
*
|
||||
* Each handler has a scope representing the block of instructions guarded by
|
||||
* this handler (corresponding to a C# `try { ... }` block), and a block of instructions
|
||||
* to execute when the handler is triggered (corresponding to a `catch` or `finally` block).
|
||||
*
|
||||
* Handlers are entry points (`EntryPoint`) so that they can
|
||||
* provide values on the stack, for example the value of the current exception. This is why
|
||||
* some handlers have a push count of 1.
|
||||
*
|
||||
* Either a finally handler (`FinallyHandler`), filter handler (`FilterHandler`),
|
||||
* catch handler (`CatchHandler`), or a fault handler (`FaultHandler`).
|
||||
*/
|
||||
deprecated class Handler extends Element, EntryPoint, @cil_handler {
|
||||
override MethodImplementation getImplementation() { cil_handler(this, result, _, _, _, _, _) }
|
||||
|
||||
/** Gets the 0-based index of this handler. Handlers are evaluated in this sequence. */
|
||||
int getIndex() { cil_handler(this, _, result, _, _, _, _) }
|
||||
|
||||
/** Gets the first instruction in the `try` block of this handler. */
|
||||
Instruction getTryStart() { cil_handler(this, _, _, _, result, _, _) }
|
||||
|
||||
/** Gets the last instruction in the `try` block of this handler. */
|
||||
Instruction getTryEnd() { cil_handler(this, _, _, _, _, result, _) }
|
||||
|
||||
/** Gets the first instruction in the `catch`/`finally` block. */
|
||||
Instruction getHandlerStart() { cil_handler(this, _, _, _, _, _, result) }
|
||||
|
||||
/**
|
||||
* Holds if the instruction `i` is in the scope of this handler.
|
||||
*/
|
||||
predicate isInScope(Instruction i) {
|
||||
i.getImplementation() = this.getImplementation() and
|
||||
i.getIndex() in [this.getTryStart().getIndex() .. this.getTryEnd().getIndex()]
|
||||
}
|
||||
|
||||
override string toString() { none() }
|
||||
|
||||
override Instruction getASuccessorType(FlowType t) {
|
||||
result = this.getHandlerStart() and
|
||||
t instanceof NormalFlow
|
||||
}
|
||||
|
||||
/** Gets the type of the caught exception, if any. */
|
||||
Type getCaughtType() { cil_handler_type(this, result) }
|
||||
|
||||
override Location getLocation() { result = this.getTryStart().getLocation() }
|
||||
}
|
||||
|
||||
/** A handler corresponding to a `finally` block. */
|
||||
deprecated class FinallyHandler extends Handler, @cil_finally_handler {
|
||||
override string toString() { result = "finally {...}" }
|
||||
}
|
||||
|
||||
/** A handler corresponding to a `where()` clause. */
|
||||
deprecated class FilterHandler extends Handler, @cil_filter_handler {
|
||||
override string toString() { result = "where (...)" }
|
||||
|
||||
/** Gets the filter clause - the start of a sequence of instructions to evaluate the filter function. */
|
||||
Instruction getFilterClause() { cil_handler_filter(this, result) }
|
||||
|
||||
override int getPushCount() { result = 1 }
|
||||
}
|
||||
|
||||
/** A handler corresponding to a `catch` clause. */
|
||||
deprecated class CatchHandler extends Handler, @cil_catch_handler {
|
||||
override string toString() { result = "catch(" + this.getCaughtType().getName() + ") {...}" }
|
||||
|
||||
override int getPushCount() { result = 1 }
|
||||
}
|
||||
|
||||
/** A handler for memory faults. */
|
||||
deprecated class FaultHandler extends Handler, @cil_fault_handler {
|
||||
override string toString() { result = "fault {...}" }
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
/** Provides the `Instruction` class. */
|
||||
|
||||
private import CIL
|
||||
|
||||
/** An instruction. */
|
||||
deprecated class Instruction extends Element, ControlFlowNode, DataFlowNode, @cil_instruction {
|
||||
override string toString() { result = this.getOpcodeName() }
|
||||
|
||||
/** Gets a more verbose textual representation of this instruction. */
|
||||
string toStringExtra() {
|
||||
result = this.getIndex() + ": " + this.getOpcodeName() + this.getExtraStr()
|
||||
}
|
||||
|
||||
/** Gets the method containing this instruction. */
|
||||
override MethodImplementation getImplementation() { cil_instruction(this, _, _, result) }
|
||||
|
||||
override Method getMethod() { result = this.getImplementation().getMethod() }
|
||||
|
||||
/**
|
||||
* Gets the index of this instruction.
|
||||
* Instructions are sequenced from 0.
|
||||
*/
|
||||
int getIndex() { cil_instruction(this, _, result, _) }
|
||||
|
||||
/** Gets the opcode of this instruction. */
|
||||
final int getOpcode() { cil_instruction(this, result, _, _) }
|
||||
|
||||
/** Gets the opcode name of this instruction, for example `ldnull`. */
|
||||
string getOpcodeName() { none() }
|
||||
|
||||
/** Gets an extra field to display for this instruction, if any. */
|
||||
string getExtra() { none() }
|
||||
|
||||
private string getExtraStr() {
|
||||
if exists(this.getExtra()) then result = " " + this.getExtra() else result = ""
|
||||
}
|
||||
|
||||
/** Gets the declaration accessed by this instruction, if any. */
|
||||
Declaration getAccess() { cil_access(this, result) }
|
||||
|
||||
/** Gets a successor instruction to this instruction. */
|
||||
override Instruction getASuccessorType(FlowType t) {
|
||||
t instanceof NormalFlow and
|
||||
this.canFlowNext() and
|
||||
result = this.getImplementation().getInstruction(this.getIndex() + 1)
|
||||
}
|
||||
|
||||
/** Holds if this instruction passes control flow into the next instruction. */
|
||||
predicate canFlowNext() { any() }
|
||||
|
||||
/**
|
||||
* Gets the `i`th handler that applies to this instruction.
|
||||
* Indexed from 0.
|
||||
*/
|
||||
Handler getHandler(int i) {
|
||||
result.isInScope(this) and
|
||||
result.getIndex() =
|
||||
rank[i + 1](int hi | exists(Handler h | h.isInScope(this) and hi = h.getIndex()))
|
||||
}
|
||||
|
||||
override Type getType() { result = ControlFlowNode.super.getType() }
|
||||
|
||||
override Location getALocation() {
|
||||
cil_instruction_location(this, result) // The source code, if available
|
||||
or
|
||||
result = this.getImplementation().getLocation() // The containing assembly
|
||||
}
|
||||
|
||||
override Location getLocation() { result = Element.super.getLocation() }
|
||||
}
|
||||
@@ -1,263 +0,0 @@
|
||||
/**
|
||||
* Provides classes representing various classes of expression
|
||||
* and other instructions.
|
||||
*/
|
||||
|
||||
private import CIL
|
||||
private import dotnet
|
||||
|
||||
/**
|
||||
* An instruction that pushes a value onto the stack.
|
||||
*/
|
||||
deprecated class Expr extends DotNet::Expr, Instruction, @cil_expr {
|
||||
override int getPushCount() { result = 1 }
|
||||
|
||||
override Type getType() { result = Instruction.super.getType() }
|
||||
|
||||
override Method getEnclosingCallable() { result = this.getImplementation().getMethod() }
|
||||
|
||||
/**
|
||||
* The "parent" of a CIL expression is taken to be the instruction
|
||||
* that consumes the value pushed by this instruction.
|
||||
*/
|
||||
override Expr getParent() { this = result.getAnOperand() }
|
||||
}
|
||||
|
||||
/** An instruction that changes control flow. */
|
||||
deprecated class Branch extends Instruction, @cil_jump {
|
||||
/** Gets the instruction that is jumped to. */
|
||||
Instruction getTarget() { cil_jump(this, result) }
|
||||
|
||||
override string getExtra() { result = this.getTarget().getIndex() + ":" }
|
||||
}
|
||||
|
||||
/** An instruction that unconditionally jumps to another instruction. */
|
||||
deprecated class UnconditionalBranch extends Branch, @cil_unconditional_jump {
|
||||
override Instruction getASuccessorType(FlowType t) {
|
||||
t instanceof NormalFlow and result = this.getTarget()
|
||||
}
|
||||
|
||||
override predicate canFlowNext() { none() }
|
||||
}
|
||||
|
||||
/** An instruction that jumps to a target based on a condition. */
|
||||
deprecated class ConditionalBranch extends Branch, @cil_conditional_jump {
|
||||
override Instruction getASuccessorType(FlowType t) {
|
||||
t instanceof TrueFlow and result = this.getTarget()
|
||||
or
|
||||
t instanceof FalseFlow and result = this.getImplementation().getInstruction(this.getIndex() + 1)
|
||||
}
|
||||
|
||||
override int getPushCount() { result = 0 }
|
||||
}
|
||||
|
||||
/** An expression with two operands. */
|
||||
deprecated class BinaryExpr extends Expr, @cil_binary_expr {
|
||||
override int getPopCount() { result = 2 }
|
||||
}
|
||||
|
||||
/** An expression with one operand. */
|
||||
deprecated class UnaryExpr extends Expr, @cil_unary_expr {
|
||||
override int getPopCount() { result = 1 }
|
||||
|
||||
/** Gets the operand of this unary expression. */
|
||||
Expr getOperand() { result = this.getOperand(0) }
|
||||
}
|
||||
|
||||
/** A binary expression that compares two values. */
|
||||
deprecated class ComparisonOperation extends BinaryExpr, @cil_comparison_operation {
|
||||
override BoolType getType() { exists(result) }
|
||||
}
|
||||
|
||||
/** A binary arithmetic expression. */
|
||||
deprecated class BinaryArithmeticExpr extends BinaryExpr, @cil_binary_arithmetic_operation {
|
||||
override Type getType() {
|
||||
exists(Type t0, Type t1 |
|
||||
t0 = this.getOperandType(0).getUnderlyingType() and
|
||||
t1 = this.getOperandType(1).getUnderlyingType()
|
||||
|
|
||||
t0 = t1 and result = t0
|
||||
or
|
||||
t0.getConversionIndex() < t1.getConversionIndex() and result = t1
|
||||
or
|
||||
t0.getConversionIndex() > t1.getConversionIndex() and result = t0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A binary bitwise expression. */
|
||||
deprecated class BinaryBitwiseOperation extends BinaryExpr, @cil_binary_bitwise_operation {
|
||||
// This is wrong but efficient - should depend on the types of the operands.
|
||||
override IntType getType() { exists(result) }
|
||||
}
|
||||
|
||||
/** A unary bitwise expression. */
|
||||
deprecated class UnaryBitwiseOperation extends UnaryExpr, @cil_unary_bitwise_operation {
|
||||
// This is wrong but efficient - should depend on the types of the operands.
|
||||
override IntType getType() { exists(result) }
|
||||
}
|
||||
|
||||
/** A unary expression that converts a value from one primitive type to another. */
|
||||
deprecated class Conversion extends UnaryExpr, @cil_conversion_operation {
|
||||
/** Gets the expression being converted. */
|
||||
Expr getExpr() { result = this.getOperand(0) }
|
||||
}
|
||||
|
||||
/** A branch that leaves the scope of a `Handler`. */
|
||||
deprecated class Leave extends UnconditionalBranch, @cil_leave_any { }
|
||||
|
||||
/** An expression that pushes a literal value onto the stack. */
|
||||
deprecated class Literal extends DotNet::Literal, Expr, @cil_literal {
|
||||
/** Gets the pushed value. */
|
||||
override string getValue() { cil_value(this, result) }
|
||||
|
||||
override string getExtra() { result = this.getValue() }
|
||||
}
|
||||
|
||||
/** An integer literal. */
|
||||
deprecated class IntLiteral extends Literal, @cil_ldc_i {
|
||||
override string getExtra() { none() }
|
||||
|
||||
override IntType getType() { exists(result) }
|
||||
}
|
||||
|
||||
/** An expression that pushes a `float`/`Single`. */
|
||||
deprecated class FloatLiteral extends Literal, @cil_ldc_r { }
|
||||
|
||||
/** An expression that pushes a `null` value onto the stack. */
|
||||
deprecated class NullLiteral extends Literal, @cil_ldnull { }
|
||||
|
||||
/** An expression that pushes a string onto the stack. */
|
||||
deprecated class StringLiteral extends Literal, @cil_ldstr { }
|
||||
|
||||
/** A branch with one operand. */
|
||||
deprecated class UnaryBranch extends ConditionalBranch, @cil_unary_jump {
|
||||
override int getPopCount() { result = 1 }
|
||||
|
||||
override int getPushCount() { result = 0 }
|
||||
}
|
||||
|
||||
/** A branch with two operands. */
|
||||
deprecated class BinaryBranch extends ConditionalBranch, @cil_binary_jump {
|
||||
override int getPopCount() { result = 2 }
|
||||
|
||||
override int getPushCount() { result = 0 }
|
||||
}
|
||||
|
||||
/** A call. */
|
||||
deprecated class Call extends Expr, DotNet::Call, @cil_call_any {
|
||||
/** Gets the method that is called. */
|
||||
override Method getTarget() { cil_access(this, result) }
|
||||
|
||||
override Method getARuntimeTarget() { result = this.getTarget().getAnOverrider*() }
|
||||
|
||||
override string getExtra() { result = this.getTarget().getFullyQualifiedName() }
|
||||
|
||||
/**
|
||||
* Gets the return type of the call. Methods that do not return a value
|
||||
* return the `void` type, `System.Void`, although the value of `getPushCount` is
|
||||
* 0 in this case.
|
||||
*/
|
||||
override Type getType() { result = this.getTarget().getReturnType() }
|
||||
|
||||
// The number of items popped/pushed from the stack
|
||||
// depends on the target of the call.
|
||||
override int getPopCount() { result = this.getTarget().getCallPopCount() }
|
||||
|
||||
override int getPushCount() { result = this.getTarget().getCallPushCount() }
|
||||
|
||||
/**
|
||||
* Holds if this is a "tail call", meaning that control does not return to the
|
||||
* calling method.
|
||||
*/
|
||||
predicate isTailCall() {
|
||||
this.getImplementation().getInstruction(this.getIndex() - 1) instanceof Opcodes::Tail
|
||||
}
|
||||
|
||||
/** Holds if this call is virtual and could go to an overriding method. */
|
||||
predicate isVirtual() { none() }
|
||||
|
||||
override Expr getRawArgument(int i) { result = this.getOperand(this.getPopCount() - i - 1) }
|
||||
|
||||
/** Gets the qualifier of this call, if any. */
|
||||
Expr getQualifier() { result = this.getRawArgument(0) and not this.getTarget().isStatic() }
|
||||
|
||||
override Expr getArgument(int i) {
|
||||
if this.getTarget().isStatic()
|
||||
then result = this.getRawArgument(i)
|
||||
else (
|
||||
result = this.getRawArgument(i + 1) and i >= 0
|
||||
)
|
||||
}
|
||||
|
||||
override Expr getArgumentForParameter(DotNet::Parameter param) {
|
||||
exists(int index |
|
||||
result = this.getRawArgument(index) and param = this.getTarget().getRawParameter(index)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A tail call. */
|
||||
deprecated class TailCall extends Call {
|
||||
TailCall() { this.isTailCall() }
|
||||
|
||||
override predicate canFlowNext() { none() }
|
||||
}
|
||||
|
||||
/** A call to a static target. */
|
||||
deprecated class StaticCall extends Call {
|
||||
StaticCall() { not this.isVirtual() }
|
||||
}
|
||||
|
||||
/** A call to a virtual target. */
|
||||
deprecated class VirtualCall extends Call {
|
||||
VirtualCall() { this.isVirtual() }
|
||||
}
|
||||
|
||||
/** A read of an array element. */
|
||||
deprecated class ReadArrayElement extends BinaryExpr, @cil_read_array {
|
||||
/** Gets the array being read. */
|
||||
Expr getArray() { result = this.getOperand(1) }
|
||||
|
||||
/** Gets the index into the array. */
|
||||
Expr getArrayIndex() { result = this.getOperand(0) }
|
||||
}
|
||||
|
||||
/** A write of an array element. */
|
||||
deprecated class WriteArrayElement extends Instruction, @cil_write_array {
|
||||
override int getPushCount() { result = 0 }
|
||||
|
||||
override int getPopCount() { result = 3 }
|
||||
}
|
||||
|
||||
/** A `return` statement. */
|
||||
deprecated class Return extends Instruction, @cil_ret {
|
||||
/** Gets the expression being returned, if any. */
|
||||
Expr getExpr() { result = this.getOperand(0) }
|
||||
|
||||
override predicate canFlowNext() { none() }
|
||||
}
|
||||
|
||||
/** A `throw` statement. */
|
||||
deprecated class Throw extends Instruction, DotNet::Throw, @cil_throw_any {
|
||||
override Expr getExpr() { result = this.getOperand(0) }
|
||||
|
||||
/** Gets the type of the exception being thrown. */
|
||||
Type getExceptionType() { result = this.getOperandType(0) }
|
||||
|
||||
override predicate canFlowNext() { none() }
|
||||
}
|
||||
|
||||
/** Stores a value at an address/location. */
|
||||
deprecated class StoreIndirect extends Instruction, @cil_stind {
|
||||
override int getPopCount() { result = 2 }
|
||||
|
||||
/** Gets the location to store the value at. */
|
||||
Expr getAddress() { result = this.getOperand(1) }
|
||||
|
||||
/** Gets the value to store. */
|
||||
Expr getExpr() { result = this.getOperand(0) }
|
||||
}
|
||||
|
||||
/** Loads a value from an address/location. */
|
||||
deprecated class LoadIndirect extends UnaryExpr, @cil_ldind { }
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,296 +0,0 @@
|
||||
/**
|
||||
* Provides classes for methods.
|
||||
*
|
||||
* Methods and implementations are different because there can be several implementations for the same
|
||||
* method in different assemblies. It is not really possible to guarantee which methods will be loaded
|
||||
* at run-time.
|
||||
*/
|
||||
|
||||
private import CIL
|
||||
private import dotnet
|
||||
|
||||
/**
|
||||
* An implementation of a method in an assembly.
|
||||
*/
|
||||
deprecated class MethodImplementation extends EntryPoint, @cil_method_implementation {
|
||||
/** Gets the method of this implementation. */
|
||||
Method getMethod() { cil_method_implementation(this, result, _) }
|
||||
|
||||
override MethodImplementation getImplementation() { result = this }
|
||||
|
||||
/** Gets the location of this implementation. */
|
||||
override Assembly getLocation() { cil_method_implementation(this, _, result) }
|
||||
|
||||
/** Gets the instruction at index `index`. */
|
||||
Instruction getInstruction(int index) { cil_instruction(result, _, index, this) }
|
||||
|
||||
/** Gets the `n`th local variable of this implementation. */
|
||||
LocalVariable getLocalVariable(int n) { cil_local_variable(result, this, n, _) }
|
||||
|
||||
/** Gets a local variable of this implementation, if any. */
|
||||
LocalVariable getALocalVariable() { result = this.getLocalVariable(_) }
|
||||
|
||||
/** Gets an instruction in this implementation, if any. */
|
||||
Instruction getAnInstruction() { result = this.getInstruction(_) }
|
||||
|
||||
/** Gets the total number of instructions in this implementation. */
|
||||
int getNumberOfInstructions() { result = count(this.getAnInstruction()) }
|
||||
|
||||
/** Gets the `i`th handler in this implementation. */
|
||||
Handler getHandler(int i) { result.getImplementation() = this and result.getIndex() = i }
|
||||
|
||||
/** Gets a handler in this implementation, if any. */
|
||||
Handler getAHandler() { result.getImplementation() = this }
|
||||
|
||||
override Instruction getASuccessorType(FlowType t) {
|
||||
t instanceof NormalFlow and result.getImplementation() = this and result.getIndex() = 0
|
||||
}
|
||||
|
||||
/** Gets the maximum stack size of this implementation. */
|
||||
int getStackSize() { cil_method_stack_size(this, result) }
|
||||
|
||||
override string toString() { result = this.getMethod().toString() }
|
||||
|
||||
/** Gets a string representing the disassembly of this implementation. */
|
||||
string getDisassembly() {
|
||||
result =
|
||||
concat(Instruction i |
|
||||
i = this.getAnInstruction()
|
||||
|
|
||||
i.toStringExtra(), ", " order by i.getIndex()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A method, which corresponds to any callable in C#, including constructors,
|
||||
* destructors, operators, accessors and so on.
|
||||
*/
|
||||
deprecated class Method extends DotNet::Callable, Element, Member, TypeContainer, DataFlowNode,
|
||||
CustomModifierReceiver, Parameterizable, @cil_method
|
||||
{
|
||||
/**
|
||||
* Gets a method implementation, if any. Note that there can
|
||||
* be several implementations in different assemblies.
|
||||
*/
|
||||
MethodImplementation getAnImplementation() { result.getMethod() = this }
|
||||
|
||||
/** Gets the "best" implementation of this method, if any. */
|
||||
BestImplementation getImplementation() { result = this.getAnImplementation() }
|
||||
|
||||
override Method getMethod() { result = this }
|
||||
|
||||
override string getName() { cil_method(this, result, _, _) }
|
||||
|
||||
override string getUndecoratedName() { result = this.getName() }
|
||||
|
||||
override string toString() { result = this.getName() }
|
||||
|
||||
override Type getDeclaringType() { cil_method(this, _, result, _) }
|
||||
|
||||
override Location getLocation() { result = Element.super.getLocation() }
|
||||
|
||||
override Location getALocation() { cil_method_location(this.getUnboundMethod+(), result) }
|
||||
|
||||
override MethodParameter getParameter(int n) {
|
||||
if this.isStatic()
|
||||
then result = this.getRawParameter(n)
|
||||
else (
|
||||
result = this.getRawParameter(n + 1) and n >= 0
|
||||
)
|
||||
}
|
||||
|
||||
override Type getType() { result = this.getReturnType() }
|
||||
|
||||
/** Gets the return type of this method. */
|
||||
override Type getReturnType() { cil_method(this, _, _, result) }
|
||||
|
||||
/** Holds if the return type is `void`. */
|
||||
predicate returnsVoid() { this.getReturnType() instanceof VoidType }
|
||||
|
||||
/** Gets the number of stack items pushed in a call to this method. */
|
||||
int getCallPushCount() { if this.returnsVoid() then result = 0 else result = 1 }
|
||||
|
||||
/** Gets the number of stack items popped in a call to this method. */
|
||||
int getCallPopCount() { result = count(this.getRawParameter(_)) }
|
||||
|
||||
/** Gets a method called by this method. */
|
||||
Method getACallee() { result = this.getImplementation().getAnInstruction().(Call).getTarget() }
|
||||
|
||||
/** Holds if this method is `virtual`. */
|
||||
predicate isVirtual() { cil_virtual(this) }
|
||||
|
||||
/** Holds if the name of this method is special, for example an operator. */
|
||||
predicate isSpecial() { cil_specialname(this) }
|
||||
|
||||
/** Holds of this method is marked as secure. */
|
||||
predicate isSecureObject() { cil_requiresecobject(this) }
|
||||
|
||||
/** Holds if the method does not override an existing method. */
|
||||
predicate isNew() { cil_newslot(this) }
|
||||
|
||||
override predicate isStatic() { cil_static(this) }
|
||||
|
||||
/** Gets the unbound declaration of this method, or the method itself. */
|
||||
Method getUnboundMethod() { cil_method_source_declaration(this, result) }
|
||||
|
||||
override Method getUnboundDeclaration() { result = this.getUnboundMethod() }
|
||||
|
||||
/** Holds if this method is an instance constructor. */
|
||||
predicate isInstanceConstructor() { this.isSpecial() and this.getName() = ".ctor" }
|
||||
|
||||
/** Holds if this method is a static class constructor. */
|
||||
predicate isStaticConstructor() { this.isSpecial() and this.getName() = ".cctor" }
|
||||
|
||||
/** Holds if this method is a constructor (static or instance). */
|
||||
predicate isConstructor() { this.isStaticConstructor() or this.isInstanceConstructor() }
|
||||
|
||||
/** Holds if this method is a destructor/finalizer. */
|
||||
predicate isFinalizer() {
|
||||
this.getOverriddenMethod*().hasFullyQualifiedName("System", "Object", "Finalize")
|
||||
}
|
||||
|
||||
/** Holds if this method is an operator. */
|
||||
predicate isOperator() { this.isSpecial() and this.getName().matches("op\\_%") }
|
||||
|
||||
/** Holds if this method is a getter. */
|
||||
predicate isGetter() { this.isSpecial() and this.getName().matches("get\\_%") }
|
||||
|
||||
/** Holds if this method is a setter. */
|
||||
predicate isSetter() { this.isSpecial() and this.getName().matches("set\\_%") }
|
||||
|
||||
/** Holds if this method is an adder/add event accessor. */
|
||||
predicate isAdder() { this.isSpecial() and this.getName().matches("add\\_%") }
|
||||
|
||||
/** Holds if this method is a remover/remove event accessor. */
|
||||
predicate isRemove() { this.isSpecial() and this.getName().matches("remove\\_%") }
|
||||
|
||||
/** Holds if this method is an implicit conversion operator. */
|
||||
predicate isImplicitConversion() { this.isSpecial() and this.getName() = "op_Implicit" }
|
||||
|
||||
/** Holds if this method is an explicit conversion operator. */
|
||||
predicate isExplicitConversion() { this.isSpecial() and this.getName() = "op_Explicit" }
|
||||
|
||||
/** Holds if this method is a conversion operator. */
|
||||
predicate isConversion() { this.isImplicitConversion() or this.isExplicitConversion() }
|
||||
|
||||
/**
|
||||
* Gets a method that is overridden, either in a base class
|
||||
* or in an interface.
|
||||
*/
|
||||
Method getOverriddenMethod() { cil_implements(this, result) }
|
||||
|
||||
/** Gets a method that overrides this method, if any. */
|
||||
final Method getAnOverrider() { result.getOverriddenMethod() = this }
|
||||
|
||||
override predicate hasBody() { exists(this.getImplementation()) }
|
||||
|
||||
override predicate canReturn(DotNet::Expr expr) {
|
||||
exists(Return ret | ret.getImplementation() = this.getImplementation() and expr = ret.getExpr())
|
||||
}
|
||||
}
|
||||
|
||||
/** A destructor/finalizer. */
|
||||
deprecated class Destructor extends Method, DotNet::Destructor {
|
||||
Destructor() { this.isFinalizer() }
|
||||
}
|
||||
|
||||
/** A constructor. */
|
||||
deprecated class Constructor extends Method, DotNet::Constructor {
|
||||
Constructor() { this.isConstructor() }
|
||||
}
|
||||
|
||||
/** A static/class constructor. */
|
||||
deprecated class StaticConstructor extends Constructor {
|
||||
StaticConstructor() { this.isStaticConstructor() }
|
||||
}
|
||||
|
||||
/** An instance constructor. */
|
||||
deprecated class InstanceConstructor extends Constructor {
|
||||
InstanceConstructor() { this.isInstanceConstructor() }
|
||||
}
|
||||
|
||||
/** A method that always returns the `this` parameter. */
|
||||
deprecated class ChainingMethod extends Method {
|
||||
ChainingMethod() {
|
||||
forex(Return ret | ret = this.getImplementation().getAnInstruction() |
|
||||
ret.getExpr() instanceof ThisAccess
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** An accessor. */
|
||||
abstract deprecated class Accessor extends Method {
|
||||
/** Gets the property declaring this accessor. */
|
||||
abstract Property getProperty();
|
||||
}
|
||||
|
||||
/** A getter. */
|
||||
deprecated class Getter extends Accessor {
|
||||
Getter() { cil_getter(_, this) }
|
||||
|
||||
override Property getProperty() { cil_getter(result, this) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A method that does nothing but retrieve a field.
|
||||
* Note that this is not necessarily a property getter.
|
||||
*/
|
||||
deprecated class TrivialGetter extends Method {
|
||||
TrivialGetter() {
|
||||
exists(MethodImplementation impl | impl = this.getAnImplementation() |
|
||||
impl.getInstruction(0) instanceof ThisAccess and
|
||||
impl.getInstruction(1) instanceof FieldReadAccess and
|
||||
impl.getInstruction(2) instanceof Return
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the underlying field of this getter. */
|
||||
Field getField() {
|
||||
this.getImplementation().getAnInstruction().(FieldReadAccess).getTarget() = result
|
||||
}
|
||||
}
|
||||
|
||||
/** A setter. */
|
||||
deprecated class Setter extends Accessor {
|
||||
Setter() { cil_setter(_, this) }
|
||||
|
||||
override Property getProperty() { cil_setter(result, this) }
|
||||
|
||||
/** Holds if this setter is an `init` accessor. */
|
||||
predicate isInitOnly() {
|
||||
exists(Type t | t.hasFullyQualifiedName("System.Runtime.CompilerServices", "IsExternalInit") |
|
||||
this.hasRequiredCustomModifier(t)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A method that does nothing but set a field.
|
||||
* This is not necessarily a property setter.
|
||||
*/
|
||||
deprecated class TrivialSetter extends Method {
|
||||
TrivialSetter() {
|
||||
exists(MethodImplementation impl | impl = this.getAnImplementation() |
|
||||
impl.getInstruction(0) instanceof ThisAccess and
|
||||
impl.getInstruction(1).(ParameterReadAccess).getTarget().getIndex() = 1 and
|
||||
impl.getInstruction(2) instanceof FieldWriteAccess
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the underlying field of this setter. */
|
||||
Field getField() {
|
||||
result = this.getImplementation().getAnInstruction().(FieldWriteAccess).getTarget()
|
||||
}
|
||||
}
|
||||
|
||||
/** An alias for `Method` for compatibility with the C# data model. */
|
||||
deprecated class Callable = Method;
|
||||
|
||||
/** An operator. */
|
||||
deprecated class Operator extends Method {
|
||||
Operator() { this.isOperator() }
|
||||
|
||||
/** Gets the name of the implementing method (for compatibility with C# data model). */
|
||||
string getFunctionName() { result = this.getName() }
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user