mirror of
https://github.com/github/codeql.git
synced 2026-05-21 06:37:10 +02:00
Compare commits
622 Commits
rc/3.21
...
tausbn/pyt
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7ba98cff7 | ||
|
|
682178a370 | ||
|
|
16683aee0e | ||
|
|
e7d3eedc80 | ||
|
|
4cb238f1af | ||
|
|
5e145aa27d | ||
|
|
e06294bcb4 | ||
|
|
39f92e992a | ||
|
|
04cfd37f53 | ||
|
|
b19c648965 | ||
|
|
e259ebe258 | ||
|
|
6f199b90ba | ||
|
|
3ccbd8032c | ||
|
|
5a6eb79470 | ||
|
|
74b0e8c19a | ||
|
|
7d184d0c7f | ||
|
|
fb8b5699f2 | ||
|
|
fb871cdfb8 | ||
|
|
cedacc91db | ||
|
|
4d8b782695 | ||
|
|
88a893efca | ||
|
|
2d76b41293 | ||
|
|
9a1156dd62 | ||
|
|
6d5aff4822 | ||
|
|
9c095bc580 | ||
|
|
43d002e6b5 | ||
|
|
16a7e39e95 | ||
|
|
17ab87d1fc | ||
|
|
dc8dc61196 | ||
|
|
ab34bd232e | ||
|
|
9e97e0433e | ||
|
|
102221d0aa | ||
|
|
c6d1ec5f64 | ||
|
|
21ea7ebe40 | ||
|
|
18a25c5071 | ||
|
|
1836a63122 | ||
|
|
ceec44b819 | ||
|
|
d2839f4ee4 | ||
|
|
2bde364bdd | ||
|
|
5122f7cf92 | ||
|
|
afd33e4dcd | ||
|
|
29500c7eb7 | ||
|
|
2a54dce5cb | ||
|
|
056be6d504 | ||
|
|
71b38b71bf | ||
|
|
cd7bb54039 | ||
|
|
3c78d8a737 | ||
|
|
b83d4e010b | ||
|
|
628f85aebc | ||
|
|
40366042a5 | ||
|
|
106d6b91f3 | ||
|
|
6433b80b25 | ||
|
|
095a9cbc73 | ||
|
|
5db069eb56 | ||
|
|
9f27a5278f | ||
|
|
9247e6af0c | ||
|
|
29768bbed4 | ||
|
|
78c0c7cb76 | ||
|
|
1d028382da | ||
|
|
503c15334a | ||
|
|
599b7a6653 | ||
|
|
9cb8edb41a | ||
|
|
eb35fa0d5e | ||
|
|
6692f23cbd | ||
|
|
8349bd50ba | ||
|
|
59eec7ffa2 | ||
|
|
ce6e6d5db3 | ||
|
|
6fad5b823c | ||
|
|
898d12b0be | ||
|
|
e6adfbca77 | ||
|
|
b595a70384 | ||
|
|
938039d82c | ||
|
|
f5cfc5e282 | ||
|
|
58218ee630 | ||
|
|
2b8558706f | ||
|
|
ea9b99f67c | ||
|
|
0c5e89a68e | ||
|
|
da4a2238bc | ||
|
|
a9449cc991 | ||
|
|
a0b3c2f13a | ||
|
|
187f7c7bcf | ||
|
|
a8b52acaa9 | ||
|
|
4f74d421b9 | ||
|
|
0f8e39a236 | ||
|
|
47d24632e6 | ||
|
|
c07a814515 | ||
|
|
8fc914f636 | ||
|
|
7e1ad825c3 | ||
|
|
6dc98cfd01 | ||
|
|
f897575d3f | ||
|
|
55b95d22e9 | ||
|
|
73360eefb3 | ||
|
|
08e115056d | ||
|
|
c9832c330a | ||
|
|
c4c363d4e5 | ||
|
|
56153d583e | ||
|
|
1a4f333c4a | ||
|
|
b8a8a160c5 | ||
|
|
8a99ef4531 | ||
|
|
21ecf230ce | ||
|
|
7a4b88fadc | ||
|
|
c0ce6699a5 | ||
|
|
c439fc5d45 | ||
|
|
de4fe6d25c | ||
|
|
d69bcca687 | ||
|
|
1ecd9e83b8 | ||
|
|
824d004a27 | ||
|
|
fe565baf06 | ||
|
|
64a52ba07f | ||
|
|
a5be35170b | ||
|
|
6769f08f93 | ||
|
|
2a3d2b882d | ||
|
|
4e6d94bc4f | ||
|
|
c66679c03b | ||
|
|
41bb349a9b | ||
|
|
805c2c3c3c | ||
|
|
8382a352d4 | ||
|
|
b2d9a600e5 | ||
|
|
a6377145ac | ||
|
|
4748c4a4f5 | ||
|
|
c2e1ae3b9c | ||
|
|
a5f27b8f19 | ||
|
|
ded6968558 | ||
|
|
a402ce59f4 | ||
|
|
94ad234a28 | ||
|
|
970b57cbe7 | ||
|
|
fb011842c9 | ||
|
|
ab1f0c13e5 | ||
|
|
ef780c15fb | ||
|
|
346ab9d623 | ||
|
|
147ac37fec | ||
|
|
29acd6960f | ||
|
|
09a2dd4a2e | ||
|
|
6c52de9234 | ||
|
|
c579ec9ea7 | ||
|
|
898713538f | ||
|
|
fba4a83dc8 | ||
|
|
f25d7456da | ||
|
|
851315fb93 | ||
|
|
6295f57a87 | ||
|
|
8cf0954796 | ||
|
|
bedfe1e755 | ||
|
|
0ed037d667 | ||
|
|
dad517ff5e | ||
|
|
db7c61969d | ||
|
|
49c5cc05ac | ||
|
|
8cb5380d84 | ||
|
|
ddc407257f | ||
|
|
0f44d6a780 | ||
|
|
4a637cbe0a | ||
|
|
b554d7dd16 | ||
|
|
f3fc80a080 | ||
|
|
22eda4ef0a | ||
|
|
e986d8922a | ||
|
|
b91a52a050 | ||
|
|
9e60e1217f | ||
|
|
09f930f4e8 | ||
|
|
68039ecd68 | ||
|
|
59c27a2196 | ||
|
|
07603a835a | ||
|
|
5aabd90eff | ||
|
|
d96e8cb704 | ||
|
|
a900fe8657 | ||
|
|
3d2d09d0bc | ||
|
|
96f55fbdf1 | ||
|
|
55516342b2 | ||
|
|
51673312c5 | ||
|
|
149df86ce2 | ||
|
|
569e33b407 | ||
|
|
e2afb000b2 | ||
|
|
2a78183238 | ||
|
|
327757dbcb | ||
|
|
b426c6fb39 | ||
|
|
c8169f576f | ||
|
|
14b3f6211e | ||
|
|
059693ce89 | ||
|
|
70d8c1c76e | ||
|
|
f245da1e52 | ||
|
|
7e6319d648 | ||
|
|
93231794ee | ||
|
|
5762191832 | ||
|
|
fd8821fcb5 | ||
|
|
cc99867969 | ||
|
|
2e76f3471a | ||
|
|
19424627c1 | ||
|
|
680ea0b960 | ||
|
|
a5763303fc | ||
|
|
8d16a2b4fa | ||
|
|
97ebc0e839 | ||
|
|
d82fc67b36 | ||
|
|
ac48eca916 | ||
|
|
93e35661e6 | ||
|
|
a276f721f7 | ||
|
|
1ffcdc9293 | ||
|
|
56c83e250e | ||
|
|
5859590b5d | ||
|
|
8cebf510dc | ||
|
|
b5723bd75d | ||
|
|
fef314e27f | ||
|
|
1363c54a9f | ||
|
|
09caeca7e9 | ||
|
|
c67122b3f1 | ||
|
|
0d0d34cc71 | ||
|
|
be245357cc | ||
|
|
ee00b98476 | ||
|
|
6ae32f22a8 | ||
|
|
a59c865328 | ||
|
|
d0c48893f5 | ||
|
|
d99247cf13 | ||
|
|
a9eb801fea | ||
|
|
9a4bc69843 | ||
|
|
d4fef1c68e | ||
|
|
d2fcced5ad | ||
|
|
093c27955f | ||
|
|
f99f26f908 | ||
|
|
434b3973eb | ||
|
|
3584ad1905 | ||
|
|
50b3b7ee1f | ||
|
|
fa8e4f7314 | ||
|
|
c04b615a07 | ||
|
|
283231bdbc | ||
|
|
025a7d0cca | ||
|
|
8cfdea2001 | ||
|
|
e860d706c9 | ||
|
|
3d20050c0a | ||
|
|
b57e92164c | ||
|
|
cd92162920 | ||
|
|
33ed6034f6 | ||
|
|
1dcc76996d | ||
|
|
f4841e1f39 | ||
|
|
f6c81ff30a | ||
|
|
4b364639a2 | ||
|
|
bde9378cee | ||
|
|
769b3a6aae | ||
|
|
7d65baccb2 | ||
|
|
77cb35380c | ||
|
|
c5457d3e30 | ||
|
|
2f0d3288ce | ||
|
|
93c656065d | ||
|
|
e86ce8feed | ||
|
|
d3177b9e82 | ||
|
|
f4550544ce | ||
|
|
f9521e9e88 | ||
|
|
f342bae962 | ||
|
|
bceab0b44e | ||
|
|
02f8984aff | ||
|
|
b63e34d467 | ||
|
|
ec726f5941 | ||
|
|
208ae7aa01 | ||
|
|
be746b775b | ||
|
|
bc518c08c7 | ||
|
|
06ea72ccc7 | ||
|
|
57086f60b9 | ||
|
|
6452cc549f | ||
|
|
f59bacab30 | ||
|
|
356905ba36 | ||
|
|
dc291ffad7 | ||
|
|
d191d09c55 | ||
|
|
9c6276ef48 | ||
|
|
21f2c81f24 | ||
|
|
d30aab47ea | ||
|
|
fef758998c | ||
|
|
b9592fef2d | ||
|
|
7a33e2f539 | ||
|
|
34101b5ca0 | ||
|
|
07db9cf3c4 | ||
|
|
92c9a8e146 | ||
|
|
21cb11ea5d | ||
|
|
4c525ce7ab | ||
|
|
0f794b57ed | ||
|
|
2e987f8d78 | ||
|
|
2139b97628 | ||
|
|
7fc1d53ede | ||
|
|
50d83ada95 | ||
|
|
10678d3a42 | ||
|
|
7d538988a6 | ||
|
|
7f17b7716d | ||
|
|
b57fa1bffa | ||
|
|
662b1e7df6 | ||
|
|
750f1ae8e9 | ||
|
|
e0b06c8e72 | ||
|
|
8d6aceb008 | ||
|
|
3fad6bdc0c | ||
|
|
518d170acd | ||
|
|
b9ad36c11d | ||
|
|
4ca071210b | ||
|
|
1ddf81c58c | ||
|
|
c155394f25 | ||
|
|
2c76e6e637 | ||
|
|
2ff5c2c234 | ||
|
|
98d8cd1d6d | ||
|
|
e8e46accc0 | ||
|
|
06f0c1189f | ||
|
|
082dc61620 | ||
|
|
2e7da72277 | ||
|
|
5b17d8cf76 | ||
|
|
f2a0724620 | ||
|
|
b8222167d2 | ||
|
|
6efd844180 | ||
|
|
34f405f465 | ||
|
|
d4a0846c6c | ||
|
|
d180900ab4 | ||
|
|
97670b3674 | ||
|
|
ff48ac5434 | ||
|
|
af63e63686 | ||
|
|
19faf8f30b | ||
|
|
3aaee9d981 | ||
|
|
8e19b05a25 | ||
|
|
1ac9e5a2a4 | ||
|
|
3f9ad14473 | ||
|
|
9cb1c89a02 | ||
|
|
a57f803b37 | ||
|
|
1130870168 | ||
|
|
8ddfee9971 | ||
|
|
8df4dfb585 | ||
|
|
2f7526d70b | ||
|
|
eeb09ae389 | ||
|
|
3c4a386f3f | ||
|
|
e3dbf5b022 | ||
|
|
72534e882b | ||
|
|
a99b3f2c3b | ||
|
|
92718a98d0 | ||
|
|
e70727524a | ||
|
|
d6055754b6 | ||
|
|
c24b43d01e | ||
|
|
179a4cd41a | ||
|
|
a929c0bf24 | ||
|
|
427ccee3b9 | ||
|
|
22f16dda85 | ||
|
|
db0a3e38e2 | ||
|
|
e7edf15031 | ||
|
|
4c77e0f315 | ||
|
|
7124cd4e6e | ||
|
|
c076992b83 | ||
|
|
659d8e7c90 | ||
|
|
1e8de0511b | ||
|
|
bce0a4d2a7 | ||
|
|
2160910d56 | ||
|
|
a5c8a5b5f8 | ||
|
|
f8a3ce7bf8 | ||
|
|
f9f1d9eecc | ||
|
|
d3066af2e2 | ||
|
|
8c03136c25 | ||
|
|
d52e9bc18c | ||
|
|
b8b841cfba | ||
|
|
df9f8ee386 | ||
|
|
99f4930e24 | ||
|
|
e9df9147ad | ||
|
|
f32f85399a | ||
|
|
c56feb7644 | ||
|
|
7ef60a8649 | ||
|
|
ca2838b361 | ||
|
|
7a6ab70091 | ||
|
|
7d6e08ecf1 | ||
|
|
dfa6d20072 | ||
|
|
821cc0e875 | ||
|
|
7094fb07a4 | ||
|
|
52809133f5 | ||
|
|
056aa342fe | ||
|
|
f58a6e5d3a | ||
|
|
f11815c633 | ||
|
|
52cfd49087 | ||
|
|
8c1c039edf | ||
|
|
c9e0927992 | ||
|
|
d5f667e585 | ||
|
|
b758732a28 | ||
|
|
ba3fadbf20 | ||
|
|
d7d1554461 | ||
|
|
12e0f3f359 | ||
|
|
0bb6ff58cc | ||
|
|
b9c0aca11a | ||
|
|
ee3674cb80 | ||
|
|
3ee369b710 | ||
|
|
e16bb226c0 | ||
|
|
48bf4fd82a | ||
|
|
c271755985 | ||
|
|
a16c43881b | ||
|
|
39e0382089 | ||
|
|
22e012c6f4 | ||
|
|
1b6f3a43ef | ||
|
|
b8c44be599 | ||
|
|
84d1828a9c | ||
|
|
ca7017f3d7 | ||
|
|
f2e7dca65c | ||
|
|
b9b3b3a0b5 | ||
|
|
6c792e69b3 | ||
|
|
4a39055322 | ||
|
|
6552c849f0 | ||
|
|
00d8a10051 | ||
|
|
da7da80b2b | ||
|
|
5db30c9947 | ||
|
|
6fb10555ff | ||
|
|
bbd02b855b | ||
|
|
48a03e2a04 | ||
|
|
a92d97744f | ||
|
|
ef6c1a9968 | ||
|
|
72142b51f7 | ||
|
|
c06d4d2647 | ||
|
|
4a001f960f | ||
|
|
1253553aec | ||
|
|
68dfa5c83b | ||
|
|
25a20f74f0 | ||
|
|
5a65282241 | ||
|
|
2e04d4b888 | ||
|
|
79499c240a | ||
|
|
267a46d01b | ||
|
|
341059d2d0 | ||
|
|
79841bbc00 | ||
|
|
3c3c58b0a9 | ||
|
|
9bf1072a01 | ||
|
|
a5f23ade8c | ||
|
|
017b6f2e44 | ||
|
|
6a6bb5ebf9 | ||
|
|
b631138b63 | ||
|
|
093d36ebe6 | ||
|
|
c7349740f0 | ||
|
|
efa797a21d | ||
|
|
77d4f5a2dc | ||
|
|
edf88b34da | ||
|
|
0215ea3ee3 | ||
|
|
35ac66d3aa | ||
|
|
219fe03637 | ||
|
|
dbb8bb86ba | ||
|
|
afb2243984 | ||
|
|
a7e426d89f | ||
|
|
fde51e0c29 | ||
|
|
69ed88bccd | ||
|
|
97e1c96200 | ||
|
|
46ba1f9160 | ||
|
|
5d74ad5bc6 | ||
|
|
4013f00b19 | ||
|
|
e0e5319b11 | ||
|
|
d8007a85e6 | ||
|
|
512e27187e | ||
|
|
f2bad1e6e1 | ||
|
|
c5360ba46c | ||
|
|
be9c1d074f | ||
|
|
097681e705 | ||
|
|
63e8061917 | ||
|
|
8bbb0ec954 | ||
|
|
d81b9aa5fd | ||
|
|
fd7093e74d | ||
|
|
a6de855549 | ||
|
|
3b9eba2afc | ||
|
|
4dca9aa958 | ||
|
|
84bef5d4bc | ||
|
|
da99d3660d | ||
|
|
7f6fd34d46 | ||
|
|
d23a3f821e | ||
|
|
2340369e2d | ||
|
|
70c1b58492 | ||
|
|
f3dc0412b5 | ||
|
|
a3e9aed00a | ||
|
|
e96ba4806b | ||
|
|
76346eccd8 | ||
|
|
feb45e5731 | ||
|
|
66ca10c338 | ||
|
|
fa61f6f3df | ||
|
|
0561a63003 | ||
|
|
ff41917147 | ||
|
|
838f3b90e7 | ||
|
|
3c36a9e308 | ||
|
|
eb81743fb5 | ||
|
|
d9ef9f82e1 | ||
|
|
92a719092a | ||
|
|
ffa5110522 | ||
|
|
c9fa7fa283 | ||
|
|
8ef4be49aa | ||
|
|
e6996ea29a | ||
|
|
579c871b69 | ||
|
|
63c71b418c | ||
|
|
3e7a966c0d | ||
|
|
926725a87f | ||
|
|
9bf4262dbb | ||
|
|
c82f75604a | ||
|
|
ea77c0d86c | ||
|
|
ec1d034ee0 | ||
|
|
37a8fc85eb | ||
|
|
b5bf1c578c | ||
|
|
f3898329d6 | ||
|
|
acd6f4156b | ||
|
|
e22d3a1074 | ||
|
|
212374b94b | ||
|
|
aa7a730041 | ||
|
|
1c5afb2306 | ||
|
|
5b30e945ef | ||
|
|
2b3111441d | ||
|
|
99a4fe4828 | ||
|
|
aa28c94562 | ||
|
|
501485b9f6 | ||
|
|
db491fc985 | ||
|
|
1950fd33db | ||
|
|
91b6801db1 | ||
|
|
ea30f02271 | ||
|
|
f41c30e335 | ||
|
|
ddebdad9e1 | ||
|
|
f8f8991d36 | ||
|
|
3c129fcd23 | ||
|
|
6001c735ff | ||
|
|
5a97348e78 | ||
|
|
0eccd902c2 | ||
|
|
45eb14975a | ||
|
|
badfa1a5c5 | ||
|
|
b475f14575 | ||
|
|
d4ba2d68f9 | ||
|
|
05a77a2005 | ||
|
|
ef345a3279 | ||
|
|
2357ef07cc | ||
|
|
088913d925 | ||
|
|
83155df1f7 | ||
|
|
b7992ed8cd | ||
|
|
219ea28217 | ||
|
|
fbf40ef02a | ||
|
|
370c5157f1 | ||
|
|
2782d90d0f | ||
|
|
ad5ab9f270 | ||
|
|
4474e252fe | ||
|
|
18d2f586b3 | ||
|
|
189c16095d | ||
|
|
a604a68fe9 | ||
|
|
4e2a93df55 | ||
|
|
6a904eddd4 | ||
|
|
fe032a5834 | ||
|
|
cfd4be6b4e | ||
|
|
93a28cbfaf | ||
|
|
8807217e49 | ||
|
|
daefd5988e | ||
|
|
d9ea78bfb8 | ||
|
|
f02abb3e93 | ||
|
|
a2f45f1b5b | ||
|
|
bb5bfda14b | ||
|
|
16cd3a8bc0 | ||
|
|
319e3d1ba4 | ||
|
|
8380474acd | ||
|
|
a3d15dbaa3 | ||
|
|
ec7e6e8e03 | ||
|
|
4e63b83fd3 | ||
|
|
ea1fc43732 | ||
|
|
13959ab91e | ||
|
|
e695477f4f | ||
|
|
627654cff9 | ||
|
|
f2cc0da936 | ||
|
|
bd0d69ffca | ||
|
|
97ed67e284 | ||
|
|
db33dadb8e | ||
|
|
1139059d77 | ||
|
|
92f26027e1 | ||
|
|
85875c2879 | ||
|
|
17e6fd2fe9 | ||
|
|
5d75b255a8 | ||
|
|
26e8701ae3 | ||
|
|
cdb41588a9 | ||
|
|
1eccb8ea93 | ||
|
|
66611323e2 | ||
|
|
d804fc5168 | ||
|
|
f223c957ba | ||
|
|
86bd0c0dc3 | ||
|
|
6e0c5615fe | ||
|
|
edde4149aa | ||
|
|
87478d016a | ||
|
|
09d74a3b3e | ||
|
|
271a759490 | ||
|
|
b9595d985e | ||
|
|
ab94524328 | ||
|
|
155e21e729 | ||
|
|
d440b5fa85 | ||
|
|
47895b3334 | ||
|
|
71fb6bf915 | ||
|
|
c673bd9151 | ||
|
|
0f2de46648 | ||
|
|
f0f58dacb3 | ||
|
|
4a3b86c652 | ||
|
|
062fbf2b3c | ||
|
|
ec0b90f4b4 | ||
|
|
96a06bed8d | ||
|
|
f2dc585751 | ||
|
|
478f56b82f | ||
|
|
78f855d7e3 | ||
|
|
75ffb5fc4c | ||
|
|
75fea4245a | ||
|
|
5c108e5c12 | ||
|
|
53e886380c | ||
|
|
97f7a26e11 | ||
|
|
1213369d75 | ||
|
|
e0ab5ce49b | ||
|
|
06a8fd0e4a | ||
|
|
113565ba76 | ||
|
|
ae5ab9c67c | ||
|
|
884c61604e | ||
|
|
c5e1f0ccc9 | ||
|
|
94121f19ca | ||
|
|
2b8e719034 | ||
|
|
bdbbd45909 | ||
|
|
0d0711f2a7 | ||
|
|
d4873dd35e | ||
|
|
f7317b6a2b | ||
|
|
352b3711f6 | ||
|
|
eb37c413f2 | ||
|
|
106a9d479f | ||
|
|
d84e0e262d | ||
|
|
8b0dd7b866 | ||
|
|
b798bc2c8f | ||
|
|
a72cf56a05 | ||
|
|
4d9c0e0c26 | ||
|
|
a6ee1df567 | ||
|
|
581679d27d | ||
|
|
fc8b7c04cf | ||
|
|
ccd28ff66a | ||
|
|
a844d60174 | ||
|
|
6ac8c4f544 | ||
|
|
e0eb653dcc | ||
|
|
fb2799bd47 | ||
|
|
12b9999289 | ||
|
|
7871cd74f6 | ||
|
|
1e9dcea88b | ||
|
|
6fbdb2c52b | ||
|
|
48e3724299 | ||
|
|
0c9931ff8a | ||
|
|
48d7d9cedb | ||
|
|
4a97a449fc | ||
|
|
2e987343dd | ||
|
|
723a896b99 |
2
.github/dependabot.yml
vendored
2
.github/dependabot.yml
vendored
@@ -45,3 +45,5 @@ updates:
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: weekly
|
||||
exclude-paths:
|
||||
- "misc/bazel/registry/**"
|
||||
|
||||
78
.github/workflows/compile-queries.yml
vendored
78
.github/workflows/compile-queries.yml
vendored
@@ -1,78 +0,0 @@
|
||||
name: "Compile all queries using the latest stable CodeQL CLI"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: # makes sure the cache gets populated - running on the branches people tend to merge into.
|
||||
- main
|
||||
- "rc/*"
|
||||
- "codeql-cli-*"
|
||||
pull_request:
|
||||
paths:
|
||||
- '**.ql'
|
||||
- '**.qll'
|
||||
- '**/qlpack.yml'
|
||||
- '**.dbscheme'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
detect-changes:
|
||||
if: github.repository_owner == 'github'
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
languages: ${{ steps.detect.outputs.languages }}
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- name: Detect changed languages
|
||||
id: detect
|
||||
run: |
|
||||
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
|
||||
# For PRs, detect which languages have changes
|
||||
changed_files=$(gh pr view ${{ github.event.pull_request.number }} --json files --jq '.files.[].path')
|
||||
languages=()
|
||||
for lang in actions cpp csharp go java javascript python ql ruby rust swift; do
|
||||
if echo "$changed_files" | grep -qE "^($lang/|shared/)" ; then
|
||||
languages+=("$lang")
|
||||
fi
|
||||
done
|
||||
echo "languages=$(jq -c -n '$ARGS.positional' --args "${languages[@]}")" >> $GITHUB_OUTPUT
|
||||
else
|
||||
# For pushes to main/rc branches, run all languages
|
||||
echo 'languages=["actions","cpp","csharp","go","java","javascript","python","ql","ruby","rust","swift"]' >> $GITHUB_OUTPUT
|
||||
fi
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
|
||||
compile-queries:
|
||||
needs: detect-changes
|
||||
if: github.repository_owner == 'github' && needs.detect-changes.outputs.languages != '[]'
|
||||
runs-on: ubuntu-latest-xl
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: ${{ fromJson(needs.detect-changes.outputs.languages) }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- name: Setup CodeQL
|
||||
uses: ./.github/actions/fetch-codeql
|
||||
with:
|
||||
channel: 'release'
|
||||
- name: Cache compilation cache
|
||||
id: query-cache
|
||||
uses: ./.github/actions/cache-query-compilation
|
||||
with:
|
||||
key: ${{ matrix.language }}-queries
|
||||
- name: check formatting
|
||||
run: find shared ${{ matrix.language }}/ql -type f \( -name "*.qll" -o -name "*.ql" \) -print0 | xargs -0 -n 3000 -P 10 codeql query format -q --check-only
|
||||
- name: compile queries - check-only
|
||||
# run with --check-only if running in a PR (github.sha != main)
|
||||
if : ${{ github.event_name == 'pull_request' }}
|
||||
shell: bash
|
||||
run: codeql query compile -q -j0 ${{ matrix.language }}/ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500 --ram=56000
|
||||
- name: compile queries - full
|
||||
# do full compile if running on main - this populates the cache
|
||||
if : ${{ github.event_name != 'pull_request' }}
|
||||
shell: bash
|
||||
run: codeql query compile -q -j0 ${{ matrix.language }}/ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500 --ram=56000
|
||||
236
.github/workflows/ruby-build.yml
vendored
236
.github/workflows/ruby-build.yml
vendored
@@ -1,236 +0,0 @@
|
||||
name: "Ruby: Build"
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "ruby/**"
|
||||
- .github/workflows/ruby-build.yml
|
||||
- .github/actions/fetch-codeql/action.yml
|
||||
- codeql-workspace.yml
|
||||
- "shared/tree-sitter-extractor/**"
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
pull_request:
|
||||
paths:
|
||||
- "ruby/**"
|
||||
- .github/workflows/ruby-build.yml
|
||||
- .github/actions/fetch-codeql/action.yml
|
||||
- codeql-workspace.yml
|
||||
- "shared/tree-sitter-extractor/**"
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "Version tag to create"
|
||||
required: false
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ruby
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- name: Install GNU tar
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
brew install gnu-tar
|
||||
echo "/usr/local/opt/gnu-tar/libexec/gnubin" >> $GITHUB_PATH
|
||||
- name: Prepare Windows
|
||||
if: runner.os == 'Windows'
|
||||
shell: powershell
|
||||
run: |
|
||||
git config --global core.longpaths true
|
||||
- uses: ./.github/actions/os-version
|
||||
id: os_version
|
||||
- name: Cache entire extractor
|
||||
uses: actions/cache@v3
|
||||
id: cache-extractor
|
||||
with:
|
||||
path: |
|
||||
target/release/codeql-extractor-ruby
|
||||
target/release/codeql-extractor-ruby.exe
|
||||
ruby/extractor/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
|
||||
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-ruby-extractor-${{ hashFiles('ruby/extractor/rust-toolchain.toml', 'ruby/extractor/Cargo.lock') }}-${{ hashFiles('shared/tree-sitter-extractor') }}-${{ hashFiles('ruby/extractor/**/*.rs') }}
|
||||
- uses: actions/cache@v3
|
||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
target
|
||||
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-ruby-rust-cargo-${{ hashFiles('ruby/extractor/rust-toolchain.toml', 'ruby/extractor/**/Cargo.lock') }}
|
||||
- name: Check formatting
|
||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||
run: cd extractor && cargo fmt -- --check
|
||||
- name: Build
|
||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||
run: cd extractor && cargo build --verbose
|
||||
- name: Run tests
|
||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||
run: cd extractor && cargo test --verbose
|
||||
- name: Release build
|
||||
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||
run: cd extractor && cargo build --release
|
||||
- name: Generate dbscheme
|
||||
if: ${{ matrix.os == 'ubuntu-latest' && steps.cache-extractor.outputs.cache-hit != 'true'}}
|
||||
run: ../target/release/codeql-extractor-ruby generate --dbscheme ql/lib/ruby.dbscheme --library ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
with:
|
||||
name: ruby.dbscheme
|
||||
path: ruby/ql/lib/ruby.dbscheme
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
with:
|
||||
name: TreeSitter.qll
|
||||
path: ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: extractor-${{ matrix.os }}
|
||||
path: |
|
||||
target/release/codeql-extractor-ruby
|
||||
target/release/codeql-extractor-ruby.exe
|
||||
retention-days: 1
|
||||
compile-queries:
|
||||
if: github.repository_owner == 'github'
|
||||
runs-on: ubuntu-latest-xl
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- name: Fetch CodeQL
|
||||
uses: ./.github/actions/fetch-codeql
|
||||
- name: Cache compilation cache
|
||||
id: query-cache
|
||||
uses: ./.github/actions/cache-query-compilation
|
||||
with:
|
||||
key: ruby-build
|
||||
- name: Build Query Pack
|
||||
run: |
|
||||
PACKS=${{ runner.temp }}/query-packs
|
||||
rm -rf $PACKS
|
||||
codeql pack create ../misc/suite-helpers --output "$PACKS"
|
||||
codeql pack create ../shared/regex --output "$PACKS"
|
||||
codeql pack create ../shared/ssa --output "$PACKS"
|
||||
codeql pack create ../shared/tutorial --output "$PACKS"
|
||||
codeql pack create ql/lib --output "$PACKS"
|
||||
codeql pack create -j0 ql/src --output "$PACKS" --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
PACK_FOLDER=$(readlink -f "$PACKS"/codeql/ruby-queries/*)
|
||||
codeql generate query-help --format=sarifv2.1.0 --output="${PACK_FOLDER}/rules.sarif" ql/src
|
||||
(cd ql/src; find queries \( -name '*.qhelp' -o -name '*.rb' -o -name '*.erb' \) -exec bash -c 'mkdir -p "'"${PACK_FOLDER}"'/$(dirname "{}")"' \; -exec cp "{}" "${PACK_FOLDER}/{}" \;)
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: codeql-ruby-queries
|
||||
path: |
|
||||
${{ runner.temp }}/query-packs/*
|
||||
retention-days: 1
|
||||
include-hidden-files: true
|
||||
|
||||
package:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build, compile-queries]
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ruby.dbscheme
|
||||
path: ruby/ruby
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: extractor-ubuntu-latest
|
||||
path: ruby/linux64
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: extractor-windows-latest
|
||||
path: ruby/win64
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: extractor-macos-latest
|
||||
path: ruby/osx64
|
||||
- run: |
|
||||
mkdir -p ruby
|
||||
cp -r codeql-extractor.yml tools ql/lib/ruby.dbscheme.stats ruby/
|
||||
mkdir -p ruby/tools/{linux64,osx64,win64}
|
||||
cp linux64/codeql-extractor-ruby ruby/tools/linux64/extractor
|
||||
cp osx64/codeql-extractor-ruby ruby/tools/osx64/extractor
|
||||
cp win64/codeql-extractor-ruby.exe ruby/tools/win64/extractor.exe
|
||||
chmod +x ruby/tools/{linux64,osx64}/extractor
|
||||
zip -rq codeql-ruby.zip ruby
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: codeql-ruby-pack
|
||||
path: ruby/codeql-ruby.zip
|
||||
retention-days: 1
|
||||
include-hidden-files: true
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: codeql-ruby-queries
|
||||
path: ruby/qlpacks
|
||||
- run: |
|
||||
echo '{
|
||||
"provide": [
|
||||
"ruby/codeql-extractor.yml",
|
||||
"qlpacks/*/*/*/qlpack.yml"
|
||||
]
|
||||
}' > .codeqlmanifest.json
|
||||
zip -rq codeql-ruby-bundle.zip .codeqlmanifest.json ruby qlpacks
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: codeql-ruby-bundle
|
||||
path: ruby/codeql-ruby-bundle.zip
|
||||
retention-days: 1
|
||||
include-hidden-files: true
|
||||
|
||||
test:
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ${{ github.workspace }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
needs: [package]
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- name: Fetch CodeQL
|
||||
uses: ./.github/actions/fetch-codeql
|
||||
|
||||
- name: Download Ruby bundle
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: codeql-ruby-bundle
|
||||
path: ${{ runner.temp }}
|
||||
- name: Unzip Ruby bundle
|
||||
shell: bash
|
||||
run: unzip -q -d "${{ runner.temp }}/ruby-bundle" "${{ runner.temp }}/codeql-ruby-bundle.zip"
|
||||
|
||||
- name: Run QL test
|
||||
shell: bash
|
||||
run: |
|
||||
codeql test run --search-path "${{ runner.temp }}/ruby-bundle" --additional-packs "${{ runner.temp }}/ruby-bundle" ruby/ql/test/library-tests/ast/constants/
|
||||
- name: Create database
|
||||
shell: bash
|
||||
run: |
|
||||
codeql database create --search-path "${{ runner.temp }}/ruby-bundle" --language ruby --source-root ruby/ql/test/library-tests/ast/constants/ ../database
|
||||
- name: Analyze database
|
||||
shell: bash
|
||||
run: |
|
||||
codeql database analyze --search-path "${{ runner.temp }}/ruby-bundle" --format=sarifv2.1.0 --output=out.sarif ../database ruby-code-scanning.qls
|
||||
75
.github/workflows/ruby-dataset-measure.yml
vendored
75
.github/workflows/ruby-dataset-measure.yml
vendored
@@ -1,75 +0,0 @@
|
||||
name: "Ruby: Collect database stats"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
paths:
|
||||
- ruby/ql/lib/ruby.dbscheme
|
||||
- .github/workflows/ruby-dataset-measure.yml
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
paths:
|
||||
- ruby/ql/lib/ruby.dbscheme
|
||||
- .github/workflows/ruby-dataset-measure.yml
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
measure:
|
||||
env:
|
||||
CODEQL_THREADS: 4 # TODO: remove this once it's set by the CLI
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
repo: [rails/rails, discourse/discourse, spree/spree, ruby/ruby]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
|
||||
- uses: ./ruby/actions/create-extractor-pack
|
||||
|
||||
- name: Checkout ${{ matrix.repo }}
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
repository: ${{ matrix.repo }}
|
||||
path: ${{ github.workspace }}/repo
|
||||
- name: Create database
|
||||
run: |
|
||||
codeql database create \
|
||||
--search-path "${{ github.workspace }}" \
|
||||
--threads 4 \
|
||||
--language ruby --source-root "${{ github.workspace }}/repo" \
|
||||
"${{ runner.temp }}/database"
|
||||
- name: Measure database
|
||||
run: |
|
||||
mkdir -p "stats/${{ matrix.repo }}"
|
||||
codeql dataset measure --threads 4 --output "stats/${{ matrix.repo }}/stats.xml" "${{ runner.temp }}/database/db-ruby"
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: measurements-${{ hashFiles('stats/**') }}
|
||||
path: stats
|
||||
retention-days: 1
|
||||
|
||||
merge:
|
||||
runs-on: ubuntu-latest
|
||||
needs: measure
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: stats
|
||||
- run: |
|
||||
python -m pip install --user lxml
|
||||
find stats -name 'stats.xml' | sort | xargs python ruby/scripts/merge_stats.py --output ruby/ql/lib/ruby.dbscheme.stats --normalise ruby_tokeninfo
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ruby.dbscheme.stats
|
||||
path: ruby/ql/lib/ruby.dbscheme.stats
|
||||
40
.github/workflows/ruby-qltest-rtjo.yml
vendored
40
.github/workflows/ruby-qltest-rtjo.yml
vendored
@@ -1,40 +0,0 @@
|
||||
name: "Ruby: Run RTJO Language Tests"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
- reopened
|
||||
- labeled
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ruby
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
qltest-rtjo:
|
||||
if: "github.repository_owner == 'github' && github.event.label.name == 'Run: RTJO Language Tests'"
|
||||
runs-on: ubuntu-latest-xl
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- uses: ./ruby/actions/create-extractor-pack
|
||||
- name: Cache compilation cache
|
||||
id: query-cache
|
||||
uses: ./.github/actions/cache-query-compilation
|
||||
with:
|
||||
key: ruby-qltest
|
||||
- name: Run QL tests
|
||||
run: |
|
||||
codeql test run --dynamic-join-order-mode=all --threads=0 --ram 50000 --search-path "${{ github.workspace }}" --check-databases --check-diff-informed --check-undefined-labels --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --consistency-queries ql/consistency-queries ql/test --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
73
.github/workflows/ruby-qltest.yml
vendored
73
.github/workflows/ruby-qltest.yml
vendored
@@ -1,73 +0,0 @@
|
||||
name: "Ruby: Run QL Tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "ruby/**"
|
||||
- "shared/**"
|
||||
- .github/workflows/ruby-build.yml
|
||||
- .github/actions/fetch-codeql/action.yml
|
||||
- codeql-workspace.yml
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
pull_request:
|
||||
paths:
|
||||
- "ruby/**"
|
||||
- "shared/**"
|
||||
- .github/workflows/ruby-qltest.yml
|
||||
- .github/actions/fetch-codeql/action.yml
|
||||
- codeql-workspace.yml
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ruby
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
qlupgrade:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- name: Check DB upgrade scripts
|
||||
run: |
|
||||
echo >empty.trap
|
||||
codeql dataset import -S ql/lib/upgrades/initial/ruby.dbscheme testdb empty.trap
|
||||
codeql dataset upgrade testdb --additional-packs ql/lib
|
||||
diff -q testdb/ruby.dbscheme ql/lib/ruby.dbscheme
|
||||
- name: Check DB downgrade scripts
|
||||
run: |
|
||||
echo >empty.trap
|
||||
rm -rf testdb; codeql dataset import -S ql/lib/ruby.dbscheme testdb empty.trap
|
||||
codeql resolve upgrades --format=lines --allow-downgrades --additional-packs downgrades \
|
||||
--dbscheme=ql/lib/ruby.dbscheme --target-dbscheme=downgrades/initial/ruby.dbscheme |
|
||||
xargs codeql execute upgrades testdb
|
||||
diff -q testdb/ruby.dbscheme downgrades/initial/ruby.dbscheme
|
||||
qltest:
|
||||
if: github.repository_owner == 'github'
|
||||
runs-on: ubuntu-latest-xl
|
||||
strategy:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- uses: ./ruby/actions/create-extractor-pack
|
||||
- name: Cache compilation cache
|
||||
id: query-cache
|
||||
uses: ./.github/actions/cache-query-compilation
|
||||
with:
|
||||
key: ruby-qltest
|
||||
- name: Run QL tests
|
||||
run: |
|
||||
codeql test run --threads=0 --ram 50000 --search-path "${{ github.workspace }}" --check-databases --check-diff-informed --check-undefined-labels --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --consistency-queries ql/consistency-queries ql/test --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
@@ -7,9 +7,9 @@ repos:
|
||||
rev: v3.2.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
exclude: /test/.*$(?<!\.qlref)|.*\.patch$|.*\.qll?$
|
||||
exclude: /test([^/]*)/.*$(?<!\.qlref)|.*\.patch$|.*\.qll?$
|
||||
- id: end-of-file-fixer
|
||||
exclude: Cargo.lock$|/test/.*$(?<!\.qlref)|.*\.patch$|.*\.qll?$
|
||||
exclude: Cargo.lock$|/test([^/]*)/.*$(?<!\.qlref)|.*\.patch$|.*\.qll?$
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: v17.0.6
|
||||
|
||||
25
MODULE.bazel
25
MODULE.bazel
@@ -15,23 +15,23 @@ local_path_override(
|
||||
# see https://registry.bazel.build/ for a list of available packages
|
||||
|
||||
bazel_dep(name = "platforms", version = "1.0.0")
|
||||
bazel_dep(name = "rules_cc", version = "0.2.16")
|
||||
bazel_dep(name = "rules_go", version = "0.59.0")
|
||||
bazel_dep(name = "rules_java", version = "9.0.3")
|
||||
bazel_dep(name = "rules_pkg", version = "1.0.1")
|
||||
bazel_dep(name = "rules_cc", version = "0.2.17")
|
||||
bazel_dep(name = "rules_go", version = "0.60.0")
|
||||
bazel_dep(name = "rules_java", version = "9.6.1")
|
||||
bazel_dep(name = "rules_pkg", version = "1.2.0")
|
||||
bazel_dep(name = "rules_nodejs", version = "6.7.3")
|
||||
bazel_dep(name = "rules_python", version = "0.40.0")
|
||||
bazel_dep(name = "rules_shell", version = "0.5.0")
|
||||
bazel_dep(name = "bazel_skylib", version = "1.8.1")
|
||||
bazel_dep(name = "abseil-cpp", version = "20240116.1", repo_name = "absl")
|
||||
bazel_dep(name = "rules_python", version = "1.9.0")
|
||||
bazel_dep(name = "rules_shell", version = "0.7.1")
|
||||
bazel_dep(name = "bazel_skylib", version = "1.9.0")
|
||||
bazel_dep(name = "abseil-cpp", version = "20260107.1", repo_name = "absl")
|
||||
bazel_dep(name = "nlohmann_json", version = "3.11.3", repo_name = "json")
|
||||
bazel_dep(name = "fmt", version = "12.1.0-codeql.1")
|
||||
bazel_dep(name = "rules_kotlin", version = "2.2.2-codeql.1")
|
||||
bazel_dep(name = "gazelle", version = "0.47.0")
|
||||
bazel_dep(name = "rules_dotnet", version = "0.21.5-codeql.1")
|
||||
bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
|
||||
bazel_dep(name = "rules_rust", version = "0.68.1.codeql.1")
|
||||
bazel_dep(name = "zstd", version = "1.5.5.bcr.1")
|
||||
bazel_dep(name = "googletest", version = "1.17.0.bcr.2")
|
||||
bazel_dep(name = "rules_rust", version = "0.69.0")
|
||||
bazel_dep(name = "zstd", version = "1.5.7.bcr.1")
|
||||
|
||||
bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True)
|
||||
|
||||
@@ -242,6 +242,7 @@ use_repo(
|
||||
"kotlin-compiler-2.2.0-Beta1",
|
||||
"kotlin-compiler-2.2.20-Beta2",
|
||||
"kotlin-compiler-2.3.0",
|
||||
"kotlin-compiler-2.3.20",
|
||||
"kotlin-compiler-embeddable-1.8.0",
|
||||
"kotlin-compiler-embeddable-1.9.0-Beta",
|
||||
"kotlin-compiler-embeddable-1.9.20-Beta",
|
||||
@@ -252,6 +253,7 @@ use_repo(
|
||||
"kotlin-compiler-embeddable-2.2.0-Beta1",
|
||||
"kotlin-compiler-embeddable-2.2.20-Beta2",
|
||||
"kotlin-compiler-embeddable-2.3.0",
|
||||
"kotlin-compiler-embeddable-2.3.20",
|
||||
"kotlin-stdlib-1.8.0",
|
||||
"kotlin-stdlib-1.9.0-Beta",
|
||||
"kotlin-stdlib-1.9.20-Beta",
|
||||
@@ -262,6 +264,7 @@ use_repo(
|
||||
"kotlin-stdlib-2.2.0-Beta1",
|
||||
"kotlin-stdlib-2.2.20-Beta2",
|
||||
"kotlin-stdlib-2.3.0",
|
||||
"kotlin-stdlib-2.3.20",
|
||||
)
|
||||
|
||||
go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
## 0.4.32
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.31
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.30
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.29
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
3
actions/ql/lib/change-notes/released/0.4.30.md
Normal file
3
actions/ql/lib/change-notes/released/0.4.30.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.4.30
|
||||
|
||||
No user-facing changes.
|
||||
3
actions/ql/lib/change-notes/released/0.4.31.md
Normal file
3
actions/ql/lib/change-notes/released/0.4.31.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.4.31
|
||||
|
||||
No user-facing changes.
|
||||
3
actions/ql/lib/change-notes/released/0.4.32.md
Normal file
3
actions/ql/lib/change-notes/released/0.4.32.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.4.32
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.4.29
|
||||
lastReleaseVersion: 0.4.32
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/actions-all
|
||||
version: 0.4.30-dev
|
||||
version: 0.4.33-dev
|
||||
library: true
|
||||
warnOnImplicitThis: true
|
||||
dependencies:
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
## 0.6.24
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.23
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.22
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.21
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
3
actions/ql/src/change-notes/released/0.6.22.md
Normal file
3
actions/ql/src/change-notes/released/0.6.22.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.6.22
|
||||
|
||||
No user-facing changes.
|
||||
3
actions/ql/src/change-notes/released/0.6.23.md
Normal file
3
actions/ql/src/change-notes/released/0.6.23.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.6.23
|
||||
|
||||
No user-facing changes.
|
||||
3
actions/ql/src/change-notes/released/0.6.24.md
Normal file
3
actions/ql/src/change-notes/released/0.6.24.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.6.24
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.6.21
|
||||
lastReleaseVersion: 0.6.24
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/actions-queries
|
||||
version: 0.6.22-dev
|
||||
version: 0.6.25-dev
|
||||
library: false
|
||||
warnOnImplicitThis: true
|
||||
groups: [actions, queries]
|
||||
|
||||
@@ -199,6 +199,7 @@ def annotate_as_appropriate(filename, lines):
|
||||
# as overlay[local?]. It is not clear that these heuristics are exactly what we want,
|
||||
# but they seem to work well enough for now (as determined by speed and accuracy numbers).
|
||||
if (filename.endswith("Test.qll") or
|
||||
re.search(r"go/ql/lib/semmle/go/security/[^/]+[.]qll$", filename.replace(os.sep, "/")) or
|
||||
((filename.endswith("Query.qll") or filename.endswith("Config.qll")) and
|
||||
any("implements DataFlow::ConfigSig" in line for line in lines))):
|
||||
return None
|
||||
|
||||
@@ -172,10 +172,6 @@
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/reachability/PrintDominance.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll"
|
||||
],
|
||||
"C# ControlFlowReachability": [
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ControlFlowReachability.qll"
|
||||
],
|
||||
"C++ ExternalAPIs": [
|
||||
"cpp/ql/src/Security/CWE/CWE-020/ExternalAPIs.qll",
|
||||
"cpp/ql/src/Security/CWE/CWE-020/ir/ExternalAPIs.qll"
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
class Element extends @element {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Trap extends @trap {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Tag extends @tag {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from Element e, Trap trap
|
||||
where
|
||||
in_trap_or_tag(e, trap)
|
||||
or
|
||||
exists(Tag tag |
|
||||
in_trap_or_tag(e, tag) and
|
||||
trap_uses_tag(trap, tag)
|
||||
)
|
||||
select e, trap
|
||||
2545
cpp/downgrades/770002bb02322e04fa25345838ce6e82af285a0b/old.dbscheme
Normal file
2545
cpp/downgrades/770002bb02322e04fa25345838ce6e82af285a0b/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,13 @@
|
||||
class SourceFile extends @source_file {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Trap extends @trap {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from SourceFile source_file, string name, Trap trap
|
||||
where
|
||||
source_file_uses_trap(source_file, trap) and
|
||||
source_file_name(source_file, name)
|
||||
select name, trap
|
||||
@@ -0,0 +1,8 @@
|
||||
description: Add source_file_name
|
||||
compatibility: backwards
|
||||
source_file_uses_trap.rel: run source_file_uses_trap.ql
|
||||
source_file_name.rel: delete
|
||||
tag_name.rel: delete
|
||||
trap_uses_tag.rel: delete
|
||||
in_trap.rel: run in_trap.ql
|
||||
in_trap_or_tag.rel: delete
|
||||
@@ -52,5 +52,6 @@ ql/cpp/ql/src/Summary/LinesOfUserCode.ql
|
||||
ql/cpp/ql/src/Telemetry/CompilerErrors.ql
|
||||
ql/cpp/ql/src/Telemetry/DatabaseQuality.ql
|
||||
ql/cpp/ql/src/Telemetry/ExtractionMetrics.ql
|
||||
ql/cpp/ql/src/Telemetry/ExtractorInformation.ql
|
||||
ql/cpp/ql/src/Telemetry/MissingIncludes.ql
|
||||
ql/cpp/ql/src/Telemetry/SucceededIncludes.ql
|
||||
|
||||
@@ -160,6 +160,7 @@ ql/cpp/ql/src/Summary/LinesOfUserCode.ql
|
||||
ql/cpp/ql/src/Telemetry/CompilerErrors.ql
|
||||
ql/cpp/ql/src/Telemetry/DatabaseQuality.ql
|
||||
ql/cpp/ql/src/Telemetry/ExtractionMetrics.ql
|
||||
ql/cpp/ql/src/Telemetry/ExtractorInformation.ql
|
||||
ql/cpp/ql/src/Telemetry/MissingIncludes.ql
|
||||
ql/cpp/ql/src/Telemetry/SucceededIncludes.ql
|
||||
ql/cpp/ql/src/jsf/4.06 Pre-Processing Directives/AV Rule 32.ql
|
||||
|
||||
@@ -93,5 +93,6 @@ ql/cpp/ql/src/Summary/LinesOfUserCode.ql
|
||||
ql/cpp/ql/src/Telemetry/CompilerErrors.ql
|
||||
ql/cpp/ql/src/Telemetry/DatabaseQuality.ql
|
||||
ql/cpp/ql/src/Telemetry/ExtractionMetrics.ql
|
||||
ql/cpp/ql/src/Telemetry/ExtractorInformation.ql
|
||||
ql/cpp/ql/src/Telemetry/MissingIncludes.ql
|
||||
ql/cpp/ql/src/Telemetry/SucceededIncludes.ql
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
## 8.0.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 8.0.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 8.0.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Inline expectations test comments, which are of the form `// $ tag` or `// $ tag=value`, are now parsed more strictly and will not be recognized if there isn't a space after the `$` symbol.
|
||||
|
||||
## 8.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Added a class `IndirectUninitializedNode` to represent the indirection of an uninitialized local variable as a dataflow node.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Added a class `DataFlow::IndirectParameterNode` to represent the indirection of a parameter as a dataflow node.
|
||||
* Added a predicate `Node::asIndirectInstruction` which returns the `Instruction` that defines the indirect dataflow node, if any.
|
||||
5
cpp/ql/lib/change-notes/2026-03-24-field-init.md
Normal file
5
cpp/ql/lib/change-notes/2026-03-24-field-init.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Added a class `ConstructorDirectFieldInit` to represent field initializations that occur in member initializer lists.
|
||||
* Added a class `ConstructorDefaultFieldInit` to represent default field initializations.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: breaking
|
||||
---
|
||||
* The `SourceModelCsv`, `SinkModelCsv`, and `SummaryModelCsv` classes and the associated CSV parsing infrastructure have been removed from `ExternalFlow.qll`. New models should be added as `.model.yml` files in the `ext/` directory.
|
||||
4
cpp/ql/lib/change-notes/2026-03-30-nsdmi-dataflow.md
Normal file
4
cpp/ql/lib/change-notes/2026-03-30-nsdmi-dataflow.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added dataflow through members initialized via non-static data member initialization (NSDMI).
|
||||
4
cpp/ql/lib/change-notes/2026-03-31-http-flow-sources.md
Normal file
4
cpp/ql/lib/change-notes/2026-03-31-http-flow-sources.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added `HttpReceiveHttpRequest`, `HttpReceiveRequestEntityBody`, and `HttpReceiveClientCertificate` from Win32's `http.h` as remote flow sources.
|
||||
4
cpp/ql/lib/change-notes/2026-03-31-meson.md
Normal file
4
cpp/ql/lib/change-notes/2026-03-31-meson.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Added a subclass `MesonPrivateTestFile` of `ConfigurationTestFile` that represents files created by Meson to test the build configuration.
|
||||
4
cpp/ql/lib/change-notes/2026-04-07-autoconf.md
Normal file
4
cpp/ql/lib/change-notes/2026-04-07-autoconf.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Added a subclass `AutoconfConfigureTestFile` of `ConfigurationTestFile` that represents files created by GNU autoconf configure scripts to test the build configuration.
|
||||
5
cpp/ql/lib/change-notes/released/8.0.1.md
Normal file
5
cpp/ql/lib/change-notes/released/8.0.1.md
Normal file
@@ -0,0 +1,5 @@
|
||||
## 8.0.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Inline expectations test comments, which are of the form `// $ tag` or `// $ tag=value`, are now parsed more strictly and will not be recognized if there isn't a space after the `$` symbol.
|
||||
3
cpp/ql/lib/change-notes/released/8.0.2.md
Normal file
3
cpp/ql/lib/change-notes/released/8.0.2.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 8.0.2
|
||||
|
||||
No user-facing changes.
|
||||
3
cpp/ql/lib/change-notes/released/8.0.3.md
Normal file
3
cpp/ql/lib/change-notes/released/8.0.3.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 8.0.3
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 8.0.0
|
||||
lastReleaseVersion: 8.0.3
|
||||
|
||||
@@ -31,6 +31,9 @@ extensions:
|
||||
- ["", "", False, "WinHttpQueryHeadersEx", "", "", "Argument[*5]", "remote", "manual"]
|
||||
- ["", "", False, "WinHttpQueryHeadersEx", "", "", "Argument[*6]", "remote", "manual"]
|
||||
- ["", "", False, "WinHttpQueryHeadersEx", "", "", "Argument[**8]", "remote", "manual"]
|
||||
- ["", "", False, "HttpReceiveHttpRequest", "", "", "Argument[*3]", "remote", "manual"]
|
||||
- ["", "", False, "HttpReceiveRequestEntityBody", "", "", "Argument[*3]", "remote", "manual"]
|
||||
- ["", "", False, "HttpReceiveClientCertificate", "", "", "Argument[*3]", "remote", "manual"]
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: summaryModel
|
||||
|
||||
22
cpp/ql/lib/ext/ZMQ.model.yml
Normal file
22
cpp/ql/lib/ext/ZMQ.model.yml
Normal file
@@ -0,0 +1,22 @@
|
||||
# ZeroMQ networking library models
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: sourceModel
|
||||
data: # namespace, type, subtypes, name, signature, ext, output, kind, provenance
|
||||
- ["", "", False, "zmq_recv", "", "", "Argument[*1]", "remote", "manual"]
|
||||
- ["", "", False, "zmq_recvmsg", "", "", "Argument[*1]", "remote", "manual"]
|
||||
- ["", "", False, "zmq_msg_recv", "", "", "Argument[*0]", "remote", "manual"]
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: sinkModel
|
||||
data: # namespace, type, subtypes, name, signature, ext, input, kind, provenance
|
||||
- ["", "", False, "zmq_send", "", "", "Argument[*1]", "remote-sink", "manual"]
|
||||
- ["", "", False, "zmq_sendmsg", "", "", "Argument[*1]", "remote-sink", "manual"]
|
||||
- ["", "", False, "zmq_msg_send", "", "", "Argument[*0]", "remote-sink", "manual"]
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: summaryModel
|
||||
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
|
||||
- ["", "", False, "zmq_msg_init_data", "", "", "Argument[*1]", "Argument[*0]", "taint", "manual"]
|
||||
- ["", "", False, "zmq_msg_data", "", "", "Argument[*0]", "ReturnValue[*]", "taint", "manual"]
|
||||
19
cpp/ql/lib/ext/getc.model.yml
Normal file
19
cpp/ql/lib/ext/getc.model.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
# Models for getc and similar character-reading functions
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: sourceModel
|
||||
data: # namespace, type, subtypes, name, signature, ext, output, kind, provenance
|
||||
- ["", "", False, "getc", "", "", "ReturnValue", "remote", "manual"]
|
||||
- ["", "", False, "getwc", "", "", "ReturnValue", "remote", "manual"]
|
||||
- ["", "", False, "_getc_nolock", "", "", "ReturnValue", "remote", "manual"]
|
||||
- ["", "", False, "_getwc_nolock", "", "", "ReturnValue", "remote", "manual"]
|
||||
- ["", "", False, "getch", "", "", "ReturnValue", "local", "manual"]
|
||||
- ["", "", False, "_getch", "", "", "ReturnValue", "local", "manual"]
|
||||
- ["", "", False, "_getwch", "", "", "ReturnValue", "local", "manual"]
|
||||
- ["", "", False, "_getch_nolock", "", "", "ReturnValue", "local", "manual"]
|
||||
- ["", "", False, "_getwch_nolock", "", "", "ReturnValue", "local", "manual"]
|
||||
- ["", "", False, "getchar", "", "", "ReturnValue", "local", "manual"]
|
||||
- ["", "", False, "getwchar", "", "", "ReturnValue", "local", "manual"]
|
||||
- ["", "", False, "_getchar_nolock", "", "", "ReturnValue", "local", "manual"]
|
||||
- ["", "", False, "_getwchar_nolock", "", "", "ReturnValue", "local", "manual"]
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 8.0.1-dev
|
||||
version: 8.0.4-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -26,3 +26,26 @@ class CmakeTryCompileFile extends ConfigurationTestFile {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A file created by Meson to test the system configuration.
|
||||
*/
|
||||
class MesonPrivateTestFile extends ConfigurationTestFile {
|
||||
MesonPrivateTestFile() {
|
||||
this.getBaseName() = "testfile.c" and
|
||||
exists(Folder folder, Folder parent |
|
||||
folder = this.getParentContainer() and
|
||||
parent = folder.getParentContainer()
|
||||
|
|
||||
folder.getBaseName().matches("tmp%") and
|
||||
parent.getBaseName() = "meson-private"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A file created by a GNU autoconf configure script to test the system configuration.
|
||||
*/
|
||||
class AutoconfConfigureTestFile extends ConfigurationTestFile {
|
||||
AutoconfConfigureTestFile() { this.getBaseName().regexpMatch("conftest[0-9]*\\.c(pp)?") }
|
||||
}
|
||||
|
||||
@@ -524,6 +524,12 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
|
||||
not exists(NewOrNewArrayExpr new | e = new.getAllocatorCall().getArgument(0))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this function has an ambiguous return type, meaning that zero or multiple return
|
||||
* types for this function are present in the database (this can occur in `build-mode: none`).
|
||||
*/
|
||||
predicate hasAmbiguousReturnType() { count(this.getType()) != 1 }
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
|
||||
@@ -163,12 +163,23 @@ predicate primitiveVariadicFormatter(
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a function call whose target is a variadic formatter with the given
|
||||
* `type`, `format` parameter index and `output` parameter index.
|
||||
*
|
||||
* Join-order helper for `callsVariadicFormatter`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate callsVariadicFormatterCall(FunctionCall fc, string type, int format, int output) {
|
||||
variadicFormatter(fc.getTarget(), type, format, output)
|
||||
}
|
||||
|
||||
private predicate callsVariadicFormatter(
|
||||
Function f, string type, int formatParamIndex, int outputParamIndex
|
||||
) {
|
||||
// calls a variadic formatter with `formatParamIndex`, `outputParamIndex` linked
|
||||
exists(FunctionCall fc, int format, int output |
|
||||
variadicFormatter(pragma[only_bind_into](fc.getTarget()), type, format, output) and
|
||||
callsVariadicFormatterCall(fc, type, format, output) and
|
||||
fc.getEnclosingFunction() = f and
|
||||
fc.getArgument(format) = f.getParameter(formatParamIndex).getAnAccess() and
|
||||
fc.getArgument(output) = f.getParameter(outputParamIndex).getAnAccess()
|
||||
@@ -176,7 +187,7 @@ private predicate callsVariadicFormatter(
|
||||
or
|
||||
// calls a variadic formatter with only `formatParamIndex` linked
|
||||
exists(FunctionCall fc, string calledType, int format, int output |
|
||||
variadicFormatter(pragma[only_bind_into](fc.getTarget()), calledType, format, output) and
|
||||
callsVariadicFormatterCall(fc, calledType, format, output) and
|
||||
fc.getEnclosingFunction() = f and
|
||||
fc.getArgument(format) = f.getParameter(formatParamIndex).getAnAccess() and
|
||||
not fc.getArgument(output) = f.getParameter(_).getAnAccess() and
|
||||
|
||||
@@ -1663,7 +1663,7 @@ private module Cached {
|
||||
private predicate compares_ge(
|
||||
ValueNumber test, Operand left, Operand right, int k, boolean isGe, GuardValue value
|
||||
) {
|
||||
exists(int onemk | k = 1 - onemk | compares_lt(test, right, left, onemk, isGe, value))
|
||||
compares_lt(test, right, left, 1 - k, isGe, value)
|
||||
}
|
||||
|
||||
/** Rearrange various simple comparisons into `left < right + k` form. */
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
/**
|
||||
* INTERNAL use only. This is an experimental API subject to change without notice.
|
||||
*
|
||||
* Provides classes and predicates for dealing with flow models specified in CSV format.
|
||||
* Provides classes and predicates for dealing with flow models specified
|
||||
* in data extension files.
|
||||
*
|
||||
* The CSV specification has the following columns:
|
||||
* The extensible relations have the following columns:
|
||||
* - Sources:
|
||||
* `namespace; type; subtypes; name; signature; ext; output; kind`
|
||||
* - Sinks:
|
||||
@@ -104,117 +105,9 @@ private import internal.FlowSummaryImpl::Private
|
||||
private import internal.FlowSummaryImpl::Private::External
|
||||
private import internal.ExternalFlowExtensions::Extensions as Extensions
|
||||
private import codeql.mad.ModelValidation as SharedModelVal
|
||||
private import codeql.util.Unit
|
||||
private import codeql.mad.static.ModelsAsData as SharedMaD
|
||||
|
||||
/**
|
||||
* A unit class for adding additional source model rows.
|
||||
*
|
||||
* Extend this class to add additional source definitions.
|
||||
*/
|
||||
class SourceModelCsv extends Unit {
|
||||
/** Holds if `row` specifies a source definition. */
|
||||
abstract predicate row(string row);
|
||||
}
|
||||
|
||||
/**
|
||||
* A unit class for adding additional sink model rows.
|
||||
*
|
||||
* Extend this class to add additional sink definitions.
|
||||
*/
|
||||
class SinkModelCsv extends Unit {
|
||||
/** Holds if `row` specifies a sink definition. */
|
||||
abstract predicate row(string row);
|
||||
}
|
||||
|
||||
/**
|
||||
* A unit class for adding additional summary model rows.
|
||||
*
|
||||
* Extend this class to add additional flow summary definitions.
|
||||
*/
|
||||
class SummaryModelCsv extends Unit {
|
||||
/** Holds if `row` specifies a summary definition. */
|
||||
abstract predicate row(string row);
|
||||
}
|
||||
|
||||
/** Holds if `row` is a source model. */
|
||||
predicate sourceModel(string row) { any(SourceModelCsv s).row(row) }
|
||||
|
||||
/** Holds if `row` is a sink model. */
|
||||
predicate sinkModel(string row) { any(SinkModelCsv s).row(row) }
|
||||
|
||||
/** Holds if `row` is a summary model. */
|
||||
predicate summaryModel(string row) { any(SummaryModelCsv s).row(row) }
|
||||
|
||||
private module MadInput implements SharedMaD::InputSig {
|
||||
/** Holds if a source model exists for the given parameters. */
|
||||
predicate additionalSourceModel(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string output, string kind, string provenance, string model
|
||||
) {
|
||||
exists(string row |
|
||||
sourceModel(row) and
|
||||
row.splitAt(";", 0) = namespace and
|
||||
row.splitAt(";", 1) = type and
|
||||
row.splitAt(";", 2) = subtypes.toString() and
|
||||
subtypes = [true, false] and
|
||||
row.splitAt(";", 3) = name and
|
||||
row.splitAt(";", 4) = signature and
|
||||
row.splitAt(";", 5) = ext and
|
||||
row.splitAt(";", 6) = output and
|
||||
row.splitAt(";", 7) = kind
|
||||
) and
|
||||
provenance = "manual" and
|
||||
model = ""
|
||||
}
|
||||
|
||||
/** Holds if a sink model exists for the given parameters. */
|
||||
predicate additionalSinkModel(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string kind, string provenance, string model
|
||||
) {
|
||||
exists(string row |
|
||||
sinkModel(row) and
|
||||
row.splitAt(";", 0) = namespace and
|
||||
row.splitAt(";", 1) = type and
|
||||
row.splitAt(";", 2) = subtypes.toString() and
|
||||
subtypes = [true, false] and
|
||||
row.splitAt(";", 3) = name and
|
||||
row.splitAt(";", 4) = signature and
|
||||
row.splitAt(";", 5) = ext and
|
||||
row.splitAt(";", 6) = input and
|
||||
row.splitAt(";", 7) = kind
|
||||
) and
|
||||
provenance = "manual" and
|
||||
model = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a summary model exists for the given parameters.
|
||||
*
|
||||
* This predicate does not expand `@` to `*`s.
|
||||
*/
|
||||
predicate additionalSummaryModel(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string output, string kind, string provenance, string model
|
||||
) {
|
||||
exists(string row |
|
||||
summaryModel(row) and
|
||||
row.splitAt(";", 0) = namespace and
|
||||
row.splitAt(";", 1) = type and
|
||||
row.splitAt(";", 2) = subtypes.toString() and
|
||||
subtypes = [true, false] and
|
||||
row.splitAt(";", 3) = name and
|
||||
row.splitAt(";", 4) = signature and
|
||||
row.splitAt(";", 5) = ext and
|
||||
row.splitAt(";", 6) = input and
|
||||
row.splitAt(";", 7) = output and
|
||||
row.splitAt(";", 8) = kind
|
||||
) and
|
||||
provenance = "manual" and
|
||||
model = ""
|
||||
}
|
||||
|
||||
string namespaceSegmentSeparator() { result = "::" }
|
||||
}
|
||||
|
||||
@@ -250,8 +143,8 @@ predicate summaryModel(
|
||||
)
|
||||
}
|
||||
|
||||
/** Provides a query predicate to check the CSV data for validation errors. */
|
||||
module CsvValidation {
|
||||
/** Provides a query predicate to check the data for validation errors. */
|
||||
module ModelValidation {
|
||||
private string getInvalidModelInput() {
|
||||
exists(string pred, AccessPath input, string part |
|
||||
sinkModel(_, _, _, _, _, _, input, _, _, _) and pred = "sink"
|
||||
@@ -294,40 +187,6 @@ module CsvValidation {
|
||||
|
||||
private module KindVal = SharedModelVal::KindValidation<KindValConfig>;
|
||||
|
||||
private string getInvalidModelSubtype() {
|
||||
exists(string pred, string row |
|
||||
sourceModel(row) and pred = "source"
|
||||
or
|
||||
sinkModel(row) and pred = "sink"
|
||||
or
|
||||
summaryModel(row) and pred = "summary"
|
||||
|
|
||||
exists(string b |
|
||||
b = row.splitAt(";", 2) and
|
||||
not b = ["true", "false"] and
|
||||
result = "Invalid boolean \"" + b + "\" in " + pred + " model."
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private string getInvalidModelColumnCount() {
|
||||
exists(string pred, string row, int expect |
|
||||
sourceModel(row) and expect = 8 and pred = "source"
|
||||
or
|
||||
sinkModel(row) and expect = 8 and pred = "sink"
|
||||
or
|
||||
summaryModel(row) and expect = 9 and pred = "summary"
|
||||
|
|
||||
exists(int cols |
|
||||
cols = 1 + max(int n | exists(row.splitAt(";", n))) and
|
||||
cols != expect and
|
||||
result =
|
||||
"Wrong number of columns in " + pred + " model row, expected " + expect + ", got " + cols +
|
||||
"."
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private string getInvalidModelSignature() {
|
||||
exists(string pred, string namespace, string type, string name, string signature, string ext |
|
||||
sourceModel(namespace, type, _, name, signature, ext, _, _, _, _) and pred = "source"
|
||||
@@ -353,12 +212,25 @@ module CsvValidation {
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if some row in a CSV-based flow model appears to contain typos. */
|
||||
private string getIncorrectConstructorSummaryOutput() {
|
||||
exists(string namespace, string type, string name, string output |
|
||||
type = name or
|
||||
type = name + "<" + any(string s)
|
||||
|
|
||||
summaryModel(namespace, type, _, name, _, _, _, output, _, _, _) and
|
||||
output.matches("ReturnValue%") and
|
||||
result =
|
||||
"Constructor model for " + namespace + "." + type +
|
||||
" should use `Argument[this]` in the output, not `ReturnValue`."
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if some row in a MaD flow model appears to contain typos. */
|
||||
query predicate invalidModelRow(string msg) {
|
||||
msg =
|
||||
[
|
||||
getInvalidModelSignature(), getInvalidModelInput(), getInvalidModelOutput(),
|
||||
getInvalidModelSubtype(), getInvalidModelColumnCount(), KindVal::getInvalidModelKind()
|
||||
KindVal::getInvalidModelKind(), getIncorrectConstructorSummaryOutput()
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -555,6 +427,7 @@ private Locatable getSupportedFunctionTemplateArgument(Function templateFunction
|
||||
* Normalize the `n`'th parameter of `f` by replacing template names
|
||||
* with `func:N` (where `N` is the index of the template).
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private string getTypeNameWithoutFunctionTemplates(Function f, int n, int remaining) {
|
||||
exists(Function templateFunction |
|
||||
templateFunction = getFullyTemplatedFunction(f) and
|
||||
@@ -1011,7 +884,7 @@ private module Cached {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is specified as a source with the given kind in a CSV flow
|
||||
* Holds if `node` is specified as a source with the given kind in a MaD flow
|
||||
* model.
|
||||
*/
|
||||
cached
|
||||
@@ -1022,7 +895,7 @@ private module Cached {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is specified as a sink with the given kind in a CSV flow
|
||||
* Holds if `node` is specified as a sink with the given kind in a MaD flow
|
||||
* model.
|
||||
*/
|
||||
cached
|
||||
|
||||
@@ -201,7 +201,7 @@ module SourceSinkInterpretationInput implements
|
||||
string toString() {
|
||||
result = this.asElement().toString()
|
||||
or
|
||||
result = this.asNode().toString()
|
||||
result = this.asNode().toStringImpl()
|
||||
or
|
||||
result = this.asCall().toString()
|
||||
}
|
||||
|
||||
@@ -585,12 +585,15 @@ class ConstructorDelegationInit extends ConstructorBaseInit, @ctordelegatinginit
|
||||
|
||||
/**
|
||||
* An initialization of a member variable performed as part of a
|
||||
* constructor's explicit initializer list or implicit actions.
|
||||
* constructor's initializer list or by default initialization.
|
||||
*
|
||||
* In the example below, member variable `b` is being initialized by
|
||||
* constructor parameter `a`:
|
||||
* constructor parameter `a`, and `c` is initialized by default
|
||||
* initialization:
|
||||
* ```
|
||||
* struct S {
|
||||
* int b;
|
||||
* int c = 3;
|
||||
* S(int a): b(a) {}
|
||||
* } s(2);
|
||||
* ```
|
||||
@@ -616,6 +619,28 @@ class ConstructorFieldInit extends ConstructorInit, @ctorfieldinit {
|
||||
override predicate mayBeGloballyImpure() { this.getExpr().mayBeGloballyImpure() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An initialization of a member variable performed as part of a
|
||||
* constructor's explicit initializer list.
|
||||
*/
|
||||
class ConstructorDirectFieldInit extends ConstructorFieldInit {
|
||||
ConstructorDirectFieldInit() { exists(this.getChild(0)) }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ConstructorDirectFieldInit" }
|
||||
}
|
||||
|
||||
/**
|
||||
* An initialization of a member variable performed by default
|
||||
* initialization.
|
||||
*/
|
||||
class ConstructorDefaultFieldInit extends ConstructorFieldInit {
|
||||
ConstructorDefaultFieldInit() {
|
||||
not exists(this.getChild(0)) and exists(this.getTarget().getInitializer())
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ConstructorDefaultFieldInit" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a destructor of a base class or field as part of a destructor's
|
||||
* compiler-generated actions.
|
||||
|
||||
@@ -6,117 +6,67 @@ private import OverlayXml
|
||||
|
||||
/**
|
||||
* Holds always for the overlay variant and never for the base variant.
|
||||
* This local predicate is used to define local predicates that behave
|
||||
* differently for the base and overlay variant.
|
||||
*/
|
||||
overlay[local]
|
||||
predicate isOverlay() { databaseMetadata("isOverlay", "true") }
|
||||
|
||||
overlay[local]
|
||||
private string getLocationFilePath(@location_default loc) {
|
||||
exists(@file file | locations_default(loc, file, _, _, _, _) | files(file, result))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the file path for an element with a single location.
|
||||
* Holds if the TRAP file or tag `t` is reachable from source file `sourceFile`
|
||||
* in the base (isOverlayVariant=false) or overlay (isOverlayVariant=true) variant.
|
||||
*/
|
||||
overlay[local]
|
||||
private string getSingleLocationFilePath(@element e) {
|
||||
exists(@location_default loc |
|
||||
var_decls(e, _, _, _, loc)
|
||||
or
|
||||
fun_decls(e, _, _, _, loc)
|
||||
or
|
||||
type_decls(e, _, loc)
|
||||
or
|
||||
namespace_decls(e, _, loc, _)
|
||||
or
|
||||
macroinvocations(e, _, loc, _)
|
||||
or
|
||||
preprocdirects(e, _, loc)
|
||||
or
|
||||
diagnostics(e, _, _, _, _, loc)
|
||||
or
|
||||
usings(e, _, loc, _)
|
||||
or
|
||||
static_asserts(e, _, _, loc, _)
|
||||
or
|
||||
derivations(e, _, _, _, loc)
|
||||
or
|
||||
frienddecls(e, _, _, loc)
|
||||
or
|
||||
comments(e, _, loc)
|
||||
or
|
||||
exprs(e, _, loc)
|
||||
or
|
||||
stmts(e, _, loc)
|
||||
or
|
||||
initialisers(e, _, _, loc)
|
||||
or
|
||||
attributes(e, _, _, _, loc)
|
||||
or
|
||||
attribute_args(e, _, _, _, loc)
|
||||
or
|
||||
namequalifiers(e, _, _, loc)
|
||||
or
|
||||
enumconstants(e, _, _, _, _, loc)
|
||||
or
|
||||
type_mentions(e, _, loc, _)
|
||||
or
|
||||
lambda_capture(e, _, _, _, _, _, loc)
|
||||
or
|
||||
concept_templates(e, _, loc)
|
||||
|
|
||||
result = getLocationFilePath(loc)
|
||||
private predicate locallyReachableTrapOrTag(
|
||||
boolean isOverlayVariant, string sourceFile, @trap_or_tag t
|
||||
) {
|
||||
exists(@source_file sf, @trap trap |
|
||||
(if isOverlay() then isOverlayVariant = true else isOverlayVariant = false) and
|
||||
source_file_uses_trap(sf, trap) and
|
||||
source_file_name(sf, sourceFile) and
|
||||
(t = trap or trap_uses_tag(trap, t))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the file path for an element with potentially multiple locations.
|
||||
* Holds if element `e` is in TRAP file or tag `t`
|
||||
* in the base (isOverlayVariant=false) or overlay (isOverlayVariant=true) variant.
|
||||
*/
|
||||
overlay[local]
|
||||
private string getMultiLocationFilePath(@element e) {
|
||||
exists(@location_default loc |
|
||||
var_decls(_, e, _, _, loc)
|
||||
or
|
||||
fun_decls(_, e, _, _, loc)
|
||||
or
|
||||
type_decls(_, e, loc)
|
||||
or
|
||||
namespace_decls(_, e, loc, _)
|
||||
|
|
||||
result = getLocationFilePath(loc)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A local helper predicate that holds in the base variant and never in the
|
||||
* overlay variant.
|
||||
*/
|
||||
overlay[local]
|
||||
private predicate isBase() { not isOverlay() }
|
||||
|
||||
/**
|
||||
* Holds if `path` was extracted in the overlay database.
|
||||
*/
|
||||
overlay[local]
|
||||
private predicate overlayHasFile(string path) {
|
||||
isOverlay() and
|
||||
files(_, path) and
|
||||
path != ""
|
||||
private predicate locallyInTrapOrTag(boolean isOverlayVariant, @element e, @trap_or_tag t) {
|
||||
(if isOverlay() then isOverlayVariant = true else isOverlayVariant = false) and
|
||||
in_trap_or_tag(e, t)
|
||||
}
|
||||
|
||||
/**
|
||||
* Discards an element from the base variant if:
|
||||
* - It has a single location in a file extracted in the overlay, or
|
||||
* - All of its locations are in files extracted in the overlay.
|
||||
* - We have knowledge about what TRAP file or tag it is in (in the base).
|
||||
* - It is not in any overlay TRAP file or tag that is reachable from an overlay source file.
|
||||
* - For every base TRAP file or tag that contains it and is reachable from a base source file,
|
||||
* either the source file has changed, or the overlay has redefined the TRAP file or tag,
|
||||
* or the overlay runner has re-extracted the same source file.
|
||||
*/
|
||||
overlay[discard_entity]
|
||||
private predicate discardElement(@element e) {
|
||||
isBase() and
|
||||
(
|
||||
overlayHasFile(getSingleLocationFilePath(e))
|
||||
or
|
||||
forex(string path | path = getMultiLocationFilePath(e) | overlayHasFile(path))
|
||||
// If we don't have any knowledge about what TRAP file something
|
||||
// is in, then we don't want to discard it, so we only consider
|
||||
// entities that are known to be in a base TRAP file or tag.
|
||||
locallyInTrapOrTag(false, e, _) and
|
||||
// Anything that is reachable from an overlay source file should
|
||||
// not be discarded.
|
||||
not exists(@trap_or_tag t | locallyInTrapOrTag(true, e, t) |
|
||||
locallyReachableTrapOrTag(true, _, t)
|
||||
) and
|
||||
// Finally, we have to make sure the base variant does not retain it.
|
||||
// If it is reachable from a base source file, then that is
|
||||
// sufficient unless either the base source file has changed (in
|
||||
// particular, been deleted), or the overlay has redefined the TRAP
|
||||
// file or tag it is in, or the overlay runner has re-extracted the same
|
||||
// source file (e.g. because a header it includes has changed).
|
||||
forall(@trap_or_tag t, string sourceFile |
|
||||
locallyInTrapOrTag(false, e, t) and
|
||||
locallyReachableTrapOrTag(false, sourceFile, t)
|
||||
|
|
||||
overlayChangedFiles(sourceFile) or
|
||||
locallyReachableTrapOrTag(true, _, t) or
|
||||
locallyReachableTrapOrTag(true, sourceFile, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -238,7 +238,12 @@ private module TrackVirtualDispatch<methodDispatchSig/1 virtualDispatch0> {
|
||||
|
||||
private import TypeTracking<Location, TtInput>::TypeTrack<qualifierSource/1>::Graph<qualifierOfVirtualCall/1>
|
||||
|
||||
private predicate edgePlus(PathNode n1, PathNode n2) = fastTC(edges/2)(n1, n2)
|
||||
private predicate isSource(PathNode n) { n.isSource() }
|
||||
|
||||
private predicate isSink(PathNode n) { n.isSink() }
|
||||
|
||||
private predicate edgePlus(PathNode n1, PathNode n2) =
|
||||
doublyBoundedFastTC(edges/2, isSource/1, isSink/1)(n1, n2)
|
||||
|
||||
/**
|
||||
* Gets the most specific implementation of `mf` that may be called when the
|
||||
@@ -255,6 +260,15 @@ private module TrackVirtualDispatch<methodDispatchSig/1 virtualDispatch0> {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private MemberFunction mostSpecificForSource(PathNode p1, MemberFunction mf) {
|
||||
p1.isSource() and
|
||||
exists(Class derived |
|
||||
qualifierSourceImpl(p1.getNode(), derived) and
|
||||
result = mostSpecific(mf, derived)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a possible pair of end-points `(p1, p2)` where:
|
||||
* - `p1` is a derived-to-base conversion that converts from some
|
||||
@@ -264,16 +278,16 @@ private module TrackVirtualDispatch<methodDispatchSig/1 virtualDispatch0> {
|
||||
* - `callable` is the most specific implementation that may be called when
|
||||
* the qualifier has type `derived`.
|
||||
*/
|
||||
bindingset[p1, p2]
|
||||
pragma[inline_late]
|
||||
private predicate pairCand(
|
||||
PathNode p1, PathNode p2, DataFlowPrivate::DataFlowCallable callable,
|
||||
DataFlowPrivate::DataFlowCall call
|
||||
) {
|
||||
exists(Class derived, MemberFunction mf |
|
||||
qualifierSourceImpl(p1.getNode(), derived) and
|
||||
p2.isSink() and
|
||||
exists(MemberFunction mf |
|
||||
qualifierOfVirtualCallImpl(p2.getNode(), call.asCallInstruction(), mf) and
|
||||
p1.isSource() and
|
||||
p2.isSink() and
|
||||
callable.asSourceCallable() = mostSpecific(mf, derived)
|
||||
callable.asSourceCallable() = mostSpecificForSource(p1, mf)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
1881
cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll
Normal file
1881
cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
private import cpp as Cpp
|
||||
private import DataFlowUtil
|
||||
private import DataFlowNodes
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import DataFlowDispatch
|
||||
private import semmle.code.cpp.ir.internal.IRCppLanguage
|
||||
@@ -16,28 +17,42 @@ private import semmle.code.cpp.dataflow.ExternalFlow as External
|
||||
cached
|
||||
private module Cached {
|
||||
cached
|
||||
module Nodes0 {
|
||||
cached
|
||||
newtype TIRDataFlowNode0 =
|
||||
TInstructionNode0(Instruction i) {
|
||||
not Ssa::ignoreInstruction(i) and
|
||||
not exists(Operand op |
|
||||
not Ssa::ignoreOperand(op) and i = Ssa::getIRRepresentationOfOperand(op)
|
||||
) and
|
||||
// We exclude `void`-typed instructions because they cannot contain data.
|
||||
// However, if the instruction is a glvalue, and their type is `void`, then the result
|
||||
// type of the instruction is really `void*`, and thus we still want to have a dataflow
|
||||
// node for it.
|
||||
(not i.getResultType() instanceof VoidType or i.isGLValue())
|
||||
} or
|
||||
TMultipleUseOperandNode0(Operand op) {
|
||||
not Ssa::ignoreOperand(op) and not exists(Ssa::getIRRepresentationOfOperand(op))
|
||||
} or
|
||||
TSingleUseOperandNode0(Operand op) {
|
||||
not Ssa::ignoreOperand(op) and exists(Ssa::getIRRepresentationOfOperand(op))
|
||||
}
|
||||
newtype TIRDataFlowNode0 =
|
||||
TInstructionNode0(Instruction i) {
|
||||
not Ssa::ignoreInstruction(i) and
|
||||
not exists(Operand op |
|
||||
not Ssa::ignoreOperand(op) and i = Ssa::getIRRepresentationOfOperand(op)
|
||||
) and
|
||||
// We exclude `void`-typed instructions because they cannot contain data.
|
||||
// However, if the instruction is a glvalue, and their type is `void`, then the result
|
||||
// type of the instruction is really `void*`, and thus we still want to have a dataflow
|
||||
// node for it.
|
||||
(not i.getResultType() instanceof VoidType or i.isGLValue())
|
||||
} or
|
||||
TMultipleUseOperandNode0(Operand op) {
|
||||
not Ssa::ignoreOperand(op) and not exists(Ssa::getIRRepresentationOfOperand(op))
|
||||
} or
|
||||
TSingleUseOperandNode0(Operand op) {
|
||||
not Ssa::ignoreOperand(op) and exists(Ssa::getIRRepresentationOfOperand(op))
|
||||
}
|
||||
|
||||
cached
|
||||
string toStringCached(Node n) {
|
||||
result = toExprString(n)
|
||||
or
|
||||
not exists(toExprString(n)) and
|
||||
result = n.toStringImpl()
|
||||
}
|
||||
|
||||
cached
|
||||
Location getLocationCached(Node n) { result = n.getLocationImpl() }
|
||||
|
||||
cached
|
||||
newtype TContentApprox =
|
||||
TFieldApproxContent(string s) { fieldHasApproxName(_, s) } or
|
||||
TUnionApproxContent(string s) { unionHasApproxName(_, s) } or
|
||||
TElementApproxContent()
|
||||
|
||||
/**
|
||||
* Gets an additional term that is added to the `join` and `branch` computations to reflect
|
||||
* an additional forward or backwards branching factor that is not taken into account
|
||||
@@ -59,38 +74,174 @@ private module Cached {
|
||||
result = countNumberOfBranchesUsingParameter(switch, p)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import Cached
|
||||
private import Nodes0
|
||||
cached
|
||||
newtype TDataFlowCallable =
|
||||
TSourceCallable(Cpp::Declaration decl) or
|
||||
TSummarizedCallable(FlowSummaryImpl::Public::SummarizedCallable c)
|
||||
|
||||
/**
|
||||
* A module for calculating the number of stars (i.e., `*`s) needed for various
|
||||
* dataflow node `toString` predicates.
|
||||
*/
|
||||
module NodeStars {
|
||||
private int getNumberOfIndirections(Node n) {
|
||||
result = n.(RawIndirectOperand).getIndirectionIndex()
|
||||
cached
|
||||
newtype TDataFlowCall =
|
||||
TNormalCall(CallInstruction call) or
|
||||
TSummaryCall(
|
||||
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
|
||||
) {
|
||||
FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` in a way that loses the
|
||||
* calling context. For example, this would happen with flow through a
|
||||
* global or static variable.
|
||||
*/
|
||||
cached
|
||||
predicate jumpStep(Node n1, Node n2) {
|
||||
exists(GlobalLikeVariable v |
|
||||
exists(Ssa::GlobalUse globalUse |
|
||||
v = globalUse.getVariable() and
|
||||
n1.(FinalGlobalValue).getGlobalUse() = globalUse
|
||||
|
|
||||
globalUse.getIndirection() = getMinIndirectionForGlobalUse(globalUse) and
|
||||
v = n2.asVariable()
|
||||
or
|
||||
v = n2.asIndirectVariable(globalUse.getIndirection())
|
||||
)
|
||||
or
|
||||
exists(Ssa::GlobalDef globalDef |
|
||||
v = globalDef.getVariable() and
|
||||
n2.(InitialGlobalValue).getGlobalDef() = globalDef
|
||||
|
|
||||
globalDef.getIndirection() = getMinIndirectionForGlobalDef(globalDef) and
|
||||
v = n1.asVariable()
|
||||
or
|
||||
v = n1.asIndirectVariable(globalDef.getIndirection())
|
||||
)
|
||||
)
|
||||
or
|
||||
result = n.(RawIndirectInstruction).getIndirectionIndex()
|
||||
or
|
||||
result = n.(VariableNode).getIndirectionIndex()
|
||||
or
|
||||
result = n.(PostUpdateNodeImpl).getIndirectionIndex()
|
||||
or
|
||||
result = n.(FinalParameterNode).getIndirectionIndex()
|
||||
or
|
||||
result = n.(BodyLessParameterNodeImpl).getIndirectionIndex()
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryJumpStep(n1.(FlowSummaryNode).getSummaryNode(),
|
||||
n2.(FlowSummaryNode).getSummaryNode())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of stars (i.e., `*`s) needed to produce the `toString`
|
||||
* output for `n`.
|
||||
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
|
||||
* Thus, `node2` references an object with a field `f` that contains the
|
||||
* value of `node1`.
|
||||
*
|
||||
* The boolean `certain` is true if the destination address does not involve
|
||||
* any pointer arithmetic, and false otherwise.
|
||||
*/
|
||||
string stars(Node n) { result = repeatStars(getNumberOfIndirections(n)) }
|
||||
cached
|
||||
predicate storeStepImpl(Node node1, Content c, Node node2, boolean certain) {
|
||||
exists(
|
||||
PostFieldUpdateNode postFieldUpdate, int indirectionIndex1, int numberOfLoads,
|
||||
StoreInstruction store, FieldContent fc
|
||||
|
|
||||
postFieldUpdate = node2 and
|
||||
fc = c and
|
||||
nodeHasInstruction(node1, pragma[only_bind_into](store),
|
||||
pragma[only_bind_into](indirectionIndex1)) and
|
||||
postFieldUpdate.getIndirectionIndex() = 1 and
|
||||
numberOfLoadsFromOperand(postFieldUpdate.getFieldAddress(),
|
||||
store.getDestinationAddressOperand(), numberOfLoads, certain) and
|
||||
fc.getAField() = postFieldUpdate.getUpdatedField() and
|
||||
getIndirectionIndexLate(fc) = 1 + indirectionIndex1 + numberOfLoads
|
||||
)
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), c,
|
||||
node2.(FlowSummaryNode).getSummaryNode()) and
|
||||
certain = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
|
||||
* Thus, `node2` references an object with a field `f` that contains the
|
||||
* value of `node1`.
|
||||
*/
|
||||
cached
|
||||
predicate storeStep(Node node1, ContentSet c, Node node2) { storeStepImpl(node1, c, node2, _) }
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via a read of `f`.
|
||||
* Thus, `node1` references an object with a field `f` whose value ends up in
|
||||
* `node2`.
|
||||
*/
|
||||
cached
|
||||
predicate readStep(Node node1, ContentSet c, Node node2) {
|
||||
exists(
|
||||
FieldAddress fa1, Operand operand, int numberOfLoads, int indirectionIndex2, FieldContent fc
|
||||
|
|
||||
fc = c and
|
||||
nodeHasOperand(node2, operand, indirectionIndex2) and
|
||||
// The `1` here matches the `node2.getIndirectionIndex() = 1` conjunct
|
||||
// in `storeStep`.
|
||||
nodeHasOperand(node1, fa1.getObjectAddressOperand(), 1) and
|
||||
numberOfLoadsFromOperand(fa1, operand, numberOfLoads, _) and
|
||||
fc.getAField() = fa1.getField() and
|
||||
getIndirectionIndexLate(fc) = indirectionIndex2 + numberOfLoads
|
||||
)
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), c,
|
||||
node2.(FlowSummaryNode).getSummaryNode())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if values stored inside content `c` are cleared at node `n`.
|
||||
*/
|
||||
cached
|
||||
predicate clearsContent(Node n, ContentSet c) {
|
||||
n =
|
||||
any(PostUpdateNode pun, Content d |
|
||||
d.impliesClearOf(c) and storeStepImpl(_, d, pun, true)
|
||||
|
|
||||
pun
|
||||
).getPreUpdateNode() and
|
||||
(
|
||||
not exists(Operand op, Cpp::Operation p |
|
||||
n.(IndirectOperand).hasOperandAndIndirectionIndex(op, _) and
|
||||
(
|
||||
p instanceof Cpp::AssignPointerAddExpr or
|
||||
p instanceof Cpp::AssignPointerSubExpr or
|
||||
p instanceof Cpp::CrementOperation
|
||||
)
|
||||
|
|
||||
p.getAnOperand() = op.getUse().getAst()
|
||||
)
|
||||
or
|
||||
forex(PostUpdateNode pun, Content d |
|
||||
pragma[only_bind_into](d).impliesClearOf(pragma[only_bind_into](c)) and
|
||||
storeStepImpl(_, d, pun, true) and
|
||||
pun.getPreUpdateNode() = n
|
||||
|
|
||||
c.(Content).getIndirectionIndex() = d.getIndirectionIndex()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import NodeStars
|
||||
import Cached
|
||||
|
||||
private int getNumberOfIndirections(Node n) {
|
||||
result = n.(RawIndirectOperand).getIndirectionIndex()
|
||||
or
|
||||
result = n.(RawIndirectInstruction).getIndirectionIndex()
|
||||
or
|
||||
result = n.(VariableNode).getIndirectionIndex()
|
||||
or
|
||||
result = n.(PostUpdateNodeImpl).getIndirectionIndex()
|
||||
or
|
||||
result = n.(FinalParameterNode).getIndirectionIndex()
|
||||
or
|
||||
result = n.(BodyLessParameterNodeImpl).getIndirectionIndex()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of stars (i.e., `*`s) needed to produce the `toString`
|
||||
* output for `n`.
|
||||
*/
|
||||
string stars(Node n) { result = repeatStars(getNumberOfIndirections(n)) }
|
||||
|
||||
/**
|
||||
* A cut-down `DataFlow::Node` class that does not depend on the output of SSA.
|
||||
@@ -828,85 +979,10 @@ private int getMinIndirectionForGlobalDef(Ssa::GlobalDef def) {
|
||||
result = getMinIndirectionsForType(def.getUnspecifiedType())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` in a way that loses the
|
||||
* calling context. For example, this would happen with flow through a
|
||||
* global or static variable.
|
||||
*/
|
||||
predicate jumpStep(Node n1, Node n2) {
|
||||
exists(GlobalLikeVariable v |
|
||||
exists(Ssa::GlobalUse globalUse |
|
||||
v = globalUse.getVariable() and
|
||||
n1.(FinalGlobalValue).getGlobalUse() = globalUse
|
||||
|
|
||||
globalUse.getIndirection() = getMinIndirectionForGlobalUse(globalUse) and
|
||||
v = n2.asVariable()
|
||||
or
|
||||
v = n2.asIndirectVariable(globalUse.getIndirection())
|
||||
)
|
||||
or
|
||||
exists(Ssa::GlobalDef globalDef |
|
||||
v = globalDef.getVariable() and
|
||||
n2.(InitialGlobalValue).getGlobalDef() = globalDef
|
||||
|
|
||||
globalDef.getIndirection() = getMinIndirectionForGlobalDef(globalDef) and
|
||||
v = n1.asVariable()
|
||||
or
|
||||
v = n1.asIndirectVariable(globalDef.getIndirection())
|
||||
)
|
||||
)
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryJumpStep(n1.(FlowSummaryNode).getSummaryNode(),
|
||||
n2.(FlowSummaryNode).getSummaryNode())
|
||||
}
|
||||
|
||||
bindingset[c]
|
||||
pragma[inline_late]
|
||||
private int getIndirectionIndexLate(Content c) { result = c.getIndirectionIndex() }
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
|
||||
* Thus, `node2` references an object with a field `f` that contains the
|
||||
* value of `node1`.
|
||||
*
|
||||
* The boolean `certain` is true if the destination address does not involve
|
||||
* any pointer arithmetic, and false otherwise. This has to do with whether a
|
||||
* store step can be used to clear a field (see `clearsContent`).
|
||||
*/
|
||||
predicate storeStepImpl(Node node1, Content c, Node node2, boolean certain) {
|
||||
exists(
|
||||
PostFieldUpdateNode postFieldUpdate, int indirectionIndex1, int numberOfLoads,
|
||||
StoreInstruction store, FieldContent fc
|
||||
|
|
||||
postFieldUpdate = node2 and
|
||||
fc = c and
|
||||
nodeHasInstruction(node1, pragma[only_bind_into](store),
|
||||
pragma[only_bind_into](indirectionIndex1)) and
|
||||
postFieldUpdate.getIndirectionIndex() = 1 and
|
||||
numberOfLoadsFromOperand(postFieldUpdate.getFieldAddress(),
|
||||
store.getDestinationAddressOperand(), numberOfLoads, certain) and
|
||||
fc.getAField() = postFieldUpdate.getUpdatedField() and
|
||||
getIndirectionIndexLate(fc) = 1 + indirectionIndex1 + numberOfLoads
|
||||
)
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), c,
|
||||
node2.(FlowSummaryNode).getSummaryNode()) and
|
||||
certain = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
|
||||
* Thus, `node2` references an object with a field `f` that contains the
|
||||
* value of `node1`.
|
||||
*/
|
||||
predicate storeStep(Node node1, ContentSet c, Node node2) { storeStepImpl(node1, c, node2, _) }
|
||||
|
||||
/**
|
||||
* Holds if `operandFrom` flows to `operandTo` using a sequence of conversion-like
|
||||
* operations and exactly `n` `LoadInstruction` operations.
|
||||
*/
|
||||
private predicate numberOfLoadsFromOperandRec(
|
||||
Operand operandFrom, Operand operandTo, int ind, boolean certain
|
||||
) {
|
||||
@@ -957,63 +1033,6 @@ predicate nodeHasInstruction(Node node, Instruction instr, int indirectionIndex)
|
||||
hasInstructionAndIndex(node, instr, indirectionIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via a read of `f`.
|
||||
* Thus, `node1` references an object with a field `f` whose value ends up in
|
||||
* `node2`.
|
||||
*/
|
||||
predicate readStep(Node node1, ContentSet c, Node node2) {
|
||||
exists(
|
||||
FieldAddress fa1, Operand operand, int numberOfLoads, int indirectionIndex2, FieldContent fc
|
||||
|
|
||||
fc = c and
|
||||
nodeHasOperand(node2, operand, indirectionIndex2) and
|
||||
// The `1` here matches the `node2.getIndirectionIndex() = 1` conjunct
|
||||
// in `storeStep`.
|
||||
nodeHasOperand(node1, fa1.getObjectAddressOperand(), 1) and
|
||||
numberOfLoadsFromOperand(fa1, operand, numberOfLoads, _) and
|
||||
fc.getAField() = fa1.getField() and
|
||||
getIndirectionIndexLate(fc) = indirectionIndex2 + numberOfLoads
|
||||
)
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), c,
|
||||
node2.(FlowSummaryNode).getSummaryNode())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if values stored inside content `c` are cleared at node `n`.
|
||||
*/
|
||||
predicate clearsContent(Node n, ContentSet c) {
|
||||
n =
|
||||
any(PostUpdateNode pun, Content d | d.impliesClearOf(c) and storeStepImpl(_, d, pun, true) | pun)
|
||||
.getPreUpdateNode() and
|
||||
(
|
||||
// The crement operations and pointer addition and subtraction self-assign. We do not
|
||||
// want to clear the contents if it is indirectly pointed at by any of these operations,
|
||||
// as part of the contents might still be accessible afterwards. If there is no such
|
||||
// indirection clearing the contents is safe.
|
||||
not exists(Operand op, Cpp::Operation p |
|
||||
n.(IndirectOperand).hasOperandAndIndirectionIndex(op, _) and
|
||||
(
|
||||
p instanceof Cpp::AssignPointerAddExpr or
|
||||
p instanceof Cpp::AssignPointerSubExpr or
|
||||
p instanceof Cpp::CrementOperation
|
||||
)
|
||||
|
|
||||
p.getAnOperand() = op.getUse().getAst()
|
||||
)
|
||||
or
|
||||
forex(PostUpdateNode pun, Content d |
|
||||
pragma[only_bind_into](d).impliesClearOf(pragma[only_bind_into](c)) and
|
||||
storeStepImpl(_, d, pun, true) and
|
||||
pun.getPreUpdateNode() = n
|
||||
|
|
||||
c.(Content).getIndirectionIndex() = d.getIndirectionIndex()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the value that is being tracked is expected to be stored inside content `c`
|
||||
* at node `n`.
|
||||
@@ -1046,11 +1065,6 @@ class CastNode extends Node {
|
||||
CastNode() { none() } // stub implementation
|
||||
}
|
||||
|
||||
cached
|
||||
private newtype TDataFlowCallable =
|
||||
TSourceCallable(Cpp::Declaration decl) or
|
||||
TSummarizedCallable(FlowSummaryImpl::Public::SummarizedCallable c)
|
||||
|
||||
/**
|
||||
* A callable, which may be:
|
||||
* - a function (that may contain code)
|
||||
@@ -1134,15 +1148,6 @@ class DataFlowType extends TypeFinal {
|
||||
string toString() { result = "" }
|
||||
}
|
||||
|
||||
cached
|
||||
private newtype TDataFlowCall =
|
||||
TNormalCall(CallInstruction call) or
|
||||
TSummaryCall(
|
||||
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
|
||||
) {
|
||||
FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
|
||||
}
|
||||
|
||||
private predicate summarizedCallableIsManual(SummarizedCallable sc) {
|
||||
sc.asSummarizedCallable().hasManualModel()
|
||||
}
|
||||
@@ -1165,7 +1170,7 @@ class DataFlowCall extends TDataFlowCall {
|
||||
/**
|
||||
* Gets the `Function` that the call targets, if this is statically known.
|
||||
*/
|
||||
Function getStaticCallSourceTarget() { none() }
|
||||
Declaration getStaticCallSourceTarget() { none() }
|
||||
|
||||
/**
|
||||
* Gets the target of this call. We use the following strategy for deciding
|
||||
@@ -1177,7 +1182,7 @@ class DataFlowCall extends TDataFlowCall {
|
||||
* whether is it manual or generated.
|
||||
*/
|
||||
final DataFlowCallable getStaticCallTarget() {
|
||||
exists(Function target | target = this.getStaticCallSourceTarget() |
|
||||
exists(Declaration target | target = this.getStaticCallSourceTarget() |
|
||||
// Don't use the source callable if there is a manual model for the
|
||||
// target
|
||||
not exists(SummarizedCallable sc |
|
||||
@@ -1237,7 +1242,7 @@ private class NormalCall extends DataFlowCall, TNormalCall {
|
||||
|
||||
override CallTargetOperand getCallTargetOperand() { result = call.getCallTargetOperand() }
|
||||
|
||||
override Function getStaticCallSourceTarget() { result = call.getStaticCallTarget() }
|
||||
override Declaration getStaticCallSourceTarget() { result = call.getStaticCallTarget() }
|
||||
|
||||
override ArgumentOperand getArgumentOperand(int index) { result = call.getArgumentOperand(index) }
|
||||
|
||||
@@ -1523,12 +1528,6 @@ private predicate fieldHasApproxName(Field f, string s) {
|
||||
|
||||
private predicate unionHasApproxName(Cpp::Union u, string s) { s = u.getName().charAt(0) }
|
||||
|
||||
cached
|
||||
private newtype TContentApprox =
|
||||
TFieldApproxContent(string s) { fieldHasApproxName(_, s) } or
|
||||
TUnionApproxContent(string s) { unionHasApproxName(_, s) } or
|
||||
TElementApproxContent()
|
||||
|
||||
/** An approximated `Content`. */
|
||||
class ContentApprox extends TContentApprox {
|
||||
string toString() { none() } // overridden in subclasses
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,8 +6,8 @@ private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import DataFlowUtil
|
||||
private import DataFlowPrivate
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedExpr
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.InstructionTag
|
||||
private import DataFlowNodes
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
@@ -73,17 +73,9 @@ private module Cached {
|
||||
// a result for `getConvertedResultExpression`. We remap this here so that
|
||||
// this `ConvertInstruction` maps to the result of the expression that
|
||||
// represents the extent.
|
||||
exists(TranslatedNonConstantAllocationSize tas |
|
||||
result = tas.getExtent().getExpr() and
|
||||
instr = tas.getInstruction(AllocationExtentConvertTag())
|
||||
)
|
||||
result = IRConstruction::Raw::getAllocationExtentConvertExpr(instr)
|
||||
or
|
||||
// There's no instruction that returns `ParenthesisExpr`, but some queries
|
||||
// expect this
|
||||
exists(TranslatedTransparentConversion ttc |
|
||||
result = ttc.getExpr().(ParenthesisExpr) and
|
||||
instr = ttc.getResult()
|
||||
)
|
||||
result = IRConstruction::Raw::getTransparentConversionParenthesisExpr(instr)
|
||||
or
|
||||
// Certain expressions generate `CopyValueInstruction`s only when they
|
||||
// are needed. Examples of this include crement operations and compound
|
||||
@@ -112,10 +104,10 @@ private module Cached {
|
||||
// needed, and in that case the only value that will propagate forward in
|
||||
// the program is the value that's been updated. So in those cases we just
|
||||
// use the result of `node.asDefinition()` as the result of `node.asExpr()`.
|
||||
exists(TranslatedCoreExpr tco |
|
||||
tco.getInstruction(_) = instr and
|
||||
tco.producesExprResult() and
|
||||
result = asDefinitionImpl0(instr)
|
||||
exists(StoreInstruction store |
|
||||
store = instr and
|
||||
IRConstruction::Raw::instructionProducesExprResult(store) and
|
||||
result = asDefinitionImpl0(store)
|
||||
)
|
||||
or
|
||||
// IR construction breaks an array aggregate literal `{1, 2, 3}` into a
|
||||
@@ -145,18 +137,9 @@ private module Cached {
|
||||
// For an expression such as `i += 2` we pretend that the generated
|
||||
// `StoreInstruction` contains the result of the expression even though
|
||||
// this isn't totally aligned with the C/C++ standard.
|
||||
exists(TranslatedAssignOperation tao |
|
||||
store = tao.getInstruction(AssignmentStoreTag()) and
|
||||
result = tao.getExpr()
|
||||
)
|
||||
result = IRConstruction::Raw::getAssignOperationStoreExpr(store)
|
||||
or
|
||||
// Similarly for `i++` and `++i` we pretend that the generated
|
||||
// `StoreInstruction` contains the result of the expression even though
|
||||
// this isn't totally aligned with the C/C++ standard.
|
||||
exists(TranslatedCrementOperation tco |
|
||||
store = tco.getInstruction(CrementStoreTag()) and
|
||||
result = tco.getExpr()
|
||||
)
|
||||
result = IRConstruction::Raw::getCrementOperationStoreExpr(store)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -166,11 +149,7 @@ private module Cached {
|
||||
*/
|
||||
private predicate excludeAsDefinitionResult(StoreInstruction store) {
|
||||
// Exclude the store to the temporary generated by a ternary expression.
|
||||
exists(TranslatedConditionalExpr tce |
|
||||
store = tce.getInstruction(ConditionValueFalseStoreTag())
|
||||
or
|
||||
store = tce.getInstruction(ConditionValueTrueStoreTag())
|
||||
)
|
||||
IRConstruction::Raw::isConditionalExprTempStore(store)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs
|
||||
private import DataFlowUtil
|
||||
private import DataFlowNodes
|
||||
private import DataFlowPrivate
|
||||
private import SsaImpl as Ssa
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes
|
||||
private import PrintIRUtilities
|
||||
|
||||
/** A property provider for local IR dataflow store steps. */
|
||||
|
||||
@@ -2,6 +2,7 @@ private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes
|
||||
private import SsaImpl as Ssa
|
||||
private import PrintIRUtilities
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes
|
||||
|
||||
private Instruction getInstruction(Node n, string stars) {
|
||||
result = [n.asInstruction(), n.(RawIndirectInstruction).getInstruction()] and
|
||||
|
||||
@@ -10,8 +10,9 @@ private import semmle.code.cpp.models.interfaces.PartialFlow as PartialFlow
|
||||
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs as FIO
|
||||
private import semmle.code.cpp.ir.internal.IRCppLanguage
|
||||
private import semmle.code.cpp.ir.dataflow.internal.ModelUtil
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedInitialization
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
|
||||
private import DataFlowPrivate
|
||||
private import DataFlowNodes
|
||||
import SsaImplCommon
|
||||
|
||||
private module SourceVariables {
|
||||
@@ -438,10 +439,7 @@ private predicate sourceVariableHasBaseAndIndex(SourceVariable v, BaseSourceVari
|
||||
* initialize `v`.
|
||||
*/
|
||||
private Instruction getInitializationTargetAddress(IRVariable v) {
|
||||
exists(TranslatedVariableInitialization init |
|
||||
init.getIRVariable() = v and
|
||||
result = init.getTargetAddress()
|
||||
)
|
||||
result = IRConstruction::Raw::getInitializationTargetAddress(v)
|
||||
}
|
||||
|
||||
/** An initial definition of an SSA variable address. */
|
||||
|
||||
@@ -4,75 +4,25 @@ import semmle.code.cpp.ir.internal.IRCppLanguage
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.SideEffects as SideEffects
|
||||
private import DataFlowImplCommon as DataFlowImplCommon
|
||||
private import DataFlowUtil
|
||||
private import DataFlowNodes
|
||||
private import semmle.code.cpp.models.interfaces.PointerWrapper
|
||||
private import DataFlowPrivate
|
||||
private import TypeFlow
|
||||
private import semmle.code.cpp.ir.ValueNumbering
|
||||
|
||||
/**
|
||||
* Holds if `operand` is an operand that is not used by the dataflow library.
|
||||
* Ignored operands are not recognized as uses by SSA, and they don't have a
|
||||
* corresponding `(Indirect)OperandNode`.
|
||||
*/
|
||||
predicate ignoreOperand(Operand operand) {
|
||||
operand = any(Instruction instr | ignoreInstruction(instr)).getAnOperand() or
|
||||
operand = any(Instruction instr | ignoreInstruction(instr)).getAUse() or
|
||||
operand instanceof MemoryOperand
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` is an instruction that is not used by the dataflow library.
|
||||
* Ignored instructions are not recognized as reads/writes by SSA, and they
|
||||
* don't have a corresponding `(Indirect)InstructionNode`.
|
||||
*/
|
||||
predicate ignoreInstruction(Instruction instr) {
|
||||
DataFlowImplCommon::forceCachingInSameStage() and
|
||||
(
|
||||
instr instanceof CallSideEffectInstruction or
|
||||
instr instanceof CallReadSideEffectInstruction or
|
||||
instr instanceof ExitFunctionInstruction or
|
||||
instr instanceof EnterFunctionInstruction or
|
||||
instr instanceof WriteSideEffectInstruction or
|
||||
instr instanceof PhiInstruction or
|
||||
instr instanceof ReadSideEffectInstruction or
|
||||
instr instanceof ChiInstruction or
|
||||
instr instanceof InitializeIndirectionInstruction or
|
||||
instr instanceof AliasedDefinitionInstruction or
|
||||
instr instanceof AliasedUseInstruction or
|
||||
instr instanceof InitializeNonLocalInstruction or
|
||||
instr instanceof ReturnIndirectionInstruction or
|
||||
instr instanceof UninitializedGroupInstruction
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the C++ type of `this` in the member function `f`.
|
||||
* Gets the C++ type of `this` in an `IRFunction` generated from `f`.
|
||||
* The result is a glvalue if `isGLValue` is true, and
|
||||
* a prvalue if `isGLValue` is false.
|
||||
*/
|
||||
bindingset[isGLValue]
|
||||
private CppType getThisType(Cpp::MemberFunction f, boolean isGLValue) {
|
||||
result.hasType(f.getTypeOfThis(), isGLValue)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the C++ type of the instruction `i`.
|
||||
*
|
||||
* This is equivalent to `i.getResultLanguageType()` with the exception
|
||||
* of instructions that directly references a `this` IRVariable. In this
|
||||
* case, `i.getResultLanguageType()` gives an unknown type, whereas the
|
||||
* predicate gives the expected type (i.e., a potentially cv-qualified
|
||||
* type `A*` where `A` is the declaring type of the member function that
|
||||
* contains `i`).
|
||||
*/
|
||||
cached
|
||||
CppType getResultLanguageType(Instruction i) {
|
||||
if i.(VariableAddressInstruction).getIRVariable() instanceof IRThisVariable
|
||||
then
|
||||
if i.isGLValue()
|
||||
then result = getThisType(i.getEnclosingFunction(), true)
|
||||
else result = getThisType(i.getEnclosingFunction(), false)
|
||||
else result = i.getResultLanguageType()
|
||||
private CppType getThisType(Cpp::Declaration f, boolean isGLValue) {
|
||||
result.hasType(f.(Cpp::MemberFunction).getTypeOfThis(), isGLValue)
|
||||
or
|
||||
exists(Cpp::PointerType pt |
|
||||
pt.getBaseType() = f.(Cpp::Field).getDeclaringType() and
|
||||
result.hasType(pt, isGLValue)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -230,7 +180,8 @@ private class PointerWrapperTypeIndirection extends Indirection instanceof Point
|
||||
override predicate isAdditionalDereference(Instruction deref, Operand address) {
|
||||
exists(CallInstruction call |
|
||||
operandForFullyConvertedCall(getAUse(deref), call) and
|
||||
this = call.getStaticCallTarget().getClassAndName(["operator*", "operator->", "get"]) and
|
||||
this =
|
||||
call.getStaticCallTarget().(Function).getClassAndName(["operator*", "operator->", "get"]) and
|
||||
address = call.getThisArgumentOperand()
|
||||
)
|
||||
}
|
||||
@@ -249,7 +200,7 @@ private module IteratorIndirections {
|
||||
|
||||
override predicate isAdditionalWrite(Node0Impl value, Operand address, boolean certain) {
|
||||
exists(CallInstruction call | call.getArgumentOperand(0) = value.asOperand() |
|
||||
this = call.getStaticCallTarget().getClassAndName("operator=") and
|
||||
this = call.getStaticCallTarget().(Function).getClassAndName("operator=") and
|
||||
address = call.getThisArgumentOperand() and
|
||||
certain = false
|
||||
)
|
||||
@@ -347,10 +298,6 @@ predicate isWrite(Node0Impl value, Operand address, boolean certain) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate isAdditionalConversionFlow(Operand opFrom, Instruction instrTo) {
|
||||
any(Indirection ind).isAdditionalConversionFlow(opFrom, instrTo)
|
||||
}
|
||||
|
||||
newtype TBaseSourceVariable =
|
||||
// Each IR variable gets its own source variable
|
||||
TBaseIRVariable(IRVariable var) or
|
||||
@@ -572,6 +519,69 @@ private class BaseCallInstruction extends BaseSourceVariableInstruction, CallIns
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
/**
|
||||
* Holds if `operand` is an operand that is not used by the dataflow library.
|
||||
* Ignored operands are not recognized as uses by SSA, and they don't have a
|
||||
* corresponding `(Indirect)OperandNode`.
|
||||
*/
|
||||
cached
|
||||
predicate ignoreOperand(Operand operand) {
|
||||
operand = any(Instruction instr | ignoreInstruction(instr)).getAnOperand() or
|
||||
operand = any(Instruction instr | ignoreInstruction(instr)).getAUse() or
|
||||
operand instanceof MemoryOperand
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` is an instruction that is not used by the dataflow library.
|
||||
* Ignored instructions are not recognized as reads/writes by SSA, and they
|
||||
* don't have a corresponding `(Indirect)InstructionNode`.
|
||||
*/
|
||||
cached
|
||||
predicate ignoreInstruction(Instruction instr) {
|
||||
DataFlowImplCommon::forceCachingInSameStage() and
|
||||
(
|
||||
instr instanceof CallSideEffectInstruction or
|
||||
instr instanceof CallReadSideEffectInstruction or
|
||||
instr instanceof ExitFunctionInstruction or
|
||||
instr instanceof EnterFunctionInstruction or
|
||||
instr instanceof WriteSideEffectInstruction or
|
||||
instr instanceof PhiInstruction or
|
||||
instr instanceof ReadSideEffectInstruction or
|
||||
instr instanceof ChiInstruction or
|
||||
instr instanceof InitializeIndirectionInstruction or
|
||||
instr instanceof AliasedDefinitionInstruction or
|
||||
instr instanceof AliasedUseInstruction or
|
||||
instr instanceof InitializeNonLocalInstruction or
|
||||
instr instanceof ReturnIndirectionInstruction or
|
||||
instr instanceof UninitializedGroupInstruction
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate isAdditionalConversionFlow(Operand opFrom, Instruction instrTo) {
|
||||
any(Indirection ind).isAdditionalConversionFlow(opFrom, instrTo)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the C++ type of the instruction `i`.
|
||||
*
|
||||
* This is equivalent to `i.getResultLanguageType()` with the exception
|
||||
* of instructions that directly references a `this` IRVariable. In this
|
||||
* case, `i.getResultLanguageType()` gives an unknown type, whereas the
|
||||
* predicate gives the expected type (i.e., a potentially cv-qualified
|
||||
* type `A*` where `A` is the declaring type of the member function that
|
||||
* contains `i`).
|
||||
*/
|
||||
cached
|
||||
CppType getResultLanguageType(Instruction i) {
|
||||
if i.(VariableAddressInstruction).getIRVariable() instanceof IRThisVariable
|
||||
then
|
||||
if i.isGLValue()
|
||||
then result = getThisType(i.getEnclosingFunction(), true)
|
||||
else result = getThisType(i.getEnclosingFunction(), false)
|
||||
else result = i.getResultLanguageType()
|
||||
}
|
||||
|
||||
/** Holds if `op` is the only use of its defining instruction, and that op is used in a conversation */
|
||||
private predicate isConversion(Operand op) {
|
||||
exists(Instruction def, Operand use |
|
||||
|
||||
@@ -5,64 +5,81 @@ private import semmle.code.cpp.models.interfaces.DataFlow
|
||||
private import semmle.code.cpp.models.interfaces.SideEffect
|
||||
private import DataFlowUtil
|
||||
private import DataFlowPrivate
|
||||
private import DataFlowNodes
|
||||
private import SsaImpl as Ssa
|
||||
private import semmle.code.cpp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
|
||||
private import semmle.code.cpp.ir.dataflow.FlowSteps
|
||||
|
||||
/**
|
||||
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
|
||||
* (intra-procedural) step. This relation is only used for local taint flow
|
||||
* (for example `TaintTracking::localTaint(source, sink)`) so it may contain
|
||||
* special cases that should only apply to local taint flow.
|
||||
*/
|
||||
predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
// dataflow step
|
||||
DataFlow::localFlowStep(nodeFrom, nodeTo)
|
||||
or
|
||||
// taint flow step
|
||||
localAdditionalTaintStep(nodeFrom, nodeTo, _)
|
||||
or
|
||||
// models-as-data summarized flow for local data flow (i.e. special case for flow
|
||||
// through calls to modeled functions, without relying on global dataflow to join
|
||||
// the dots).
|
||||
FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(nodeFrom, nodeTo, _)
|
||||
cached
|
||||
private module Cached {
|
||||
private import DataFlowImplCommon as DataFlowImplCommon
|
||||
|
||||
/**
|
||||
* This predicate exists to collapse the `cached` predicates in this module with the
|
||||
* `cached` predicates in other C/C++ dataflow files, which is then collapsed
|
||||
* with the `cached` predicates in `DataFlowImplCommon.qll`.
|
||||
*/
|
||||
cached
|
||||
predicate forceCachingInSameStage() { DataFlowImplCommon::forceCachingInSameStage() }
|
||||
|
||||
/**
|
||||
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
|
||||
* (intra-procedural) step. This relation is only used for local taint flow
|
||||
* (for example `TaintTracking::localTaint(source, sink)`) so it may contain
|
||||
* special cases that should only apply to local taint flow.
|
||||
*/
|
||||
cached
|
||||
predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
// dataflow step
|
||||
DataFlow::localFlowStep(nodeFrom, nodeTo)
|
||||
or
|
||||
// taint flow step
|
||||
localAdditionalTaintStep(nodeFrom, nodeTo, _)
|
||||
or
|
||||
// models-as-data summarized flow for local data flow (i.e. special case for flow
|
||||
// through calls to modeled functions, without relying on global dataflow to join
|
||||
// the dots).
|
||||
FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(nodeFrom, nodeTo, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint can flow in one local step from `nodeFrom` to `nodeTo` excluding
|
||||
* local data flow steps. That is, `nodeFrom` and `nodeTo` are likely to represent
|
||||
* different objects.
|
||||
*/
|
||||
cached
|
||||
predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, string model) {
|
||||
operandToInstructionTaintStep(nodeFrom.asOperand(), nodeTo.asInstruction()) and
|
||||
model = ""
|
||||
or
|
||||
modeledTaintStep(nodeFrom, nodeTo, model)
|
||||
or
|
||||
// Flow from (the indirection of) an operand of a pointer arithmetic instruction to the
|
||||
// indirection of the pointer arithmetic instruction. This provides flow from `source`
|
||||
// in `x[source]` to the result of the associated load instruction.
|
||||
exists(PointerArithmeticInstruction pai, int indirectionIndex |
|
||||
nodeHasOperand(nodeFrom, pai.getAnOperand(), pragma[only_bind_into](indirectionIndex)) and
|
||||
hasInstructionAndIndex(nodeTo, pai, indirectionIndex + 1)
|
||||
) and
|
||||
model = ""
|
||||
or
|
||||
any(Ssa::Indirection ind).isAdditionalTaintStep(nodeFrom, nodeTo) and
|
||||
model = ""
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
|
||||
nodeTo.(FlowSummaryNode).getSummaryNode(), false, model)
|
||||
or
|
||||
// object->field conflation for content that is a `TaintInheritingContent`.
|
||||
exists(DataFlow::ContentSet f |
|
||||
readStep(nodeFrom, f, nodeTo) and
|
||||
f.getAReadContent() instanceof TaintInheritingContent
|
||||
) and
|
||||
model = ""
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint can flow in one local step from `nodeFrom` to `nodeTo` excluding
|
||||
* local data flow steps. That is, `nodeFrom` and `nodeTo` are likely to represent
|
||||
* different objects.
|
||||
*/
|
||||
cached
|
||||
predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, string model) {
|
||||
operandToInstructionTaintStep(nodeFrom.asOperand(), nodeTo.asInstruction()) and
|
||||
model = ""
|
||||
or
|
||||
modeledTaintStep(nodeFrom, nodeTo, model)
|
||||
or
|
||||
// Flow from (the indirection of) an operand of a pointer arithmetic instruction to the
|
||||
// indirection of the pointer arithmetic instruction. This provides flow from `source`
|
||||
// in `x[source]` to the result of the associated load instruction.
|
||||
exists(PointerArithmeticInstruction pai, int indirectionIndex |
|
||||
nodeHasOperand(nodeFrom, pai.getAnOperand(), pragma[only_bind_into](indirectionIndex)) and
|
||||
hasInstructionAndIndex(nodeTo, pai, indirectionIndex + 1)
|
||||
) and
|
||||
model = ""
|
||||
or
|
||||
any(Ssa::Indirection ind).isAdditionalTaintStep(nodeFrom, nodeTo) and
|
||||
model = ""
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
|
||||
nodeTo.(FlowSummaryNode).getSummaryNode(), false, model)
|
||||
or
|
||||
// object->field conflation for content that is a `TaintInheritingContent`.
|
||||
exists(DataFlow::ContentSet f |
|
||||
readStep(nodeFrom, f, nodeTo) and
|
||||
f.getAReadContent() instanceof TaintInheritingContent
|
||||
) and
|
||||
model = ""
|
||||
}
|
||||
import Cached
|
||||
|
||||
/**
|
||||
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
|
||||
@@ -196,7 +213,7 @@ predicate modeledTaintStep(DataFlow::Node nodeIn, DataFlow::Node nodeOut, string
|
||||
// Taint flow from a pointer argument to an output, when the model specifies flow from the deref
|
||||
// to that output, but the deref is not modeled in the IR for the caller.
|
||||
exists(
|
||||
CallInstruction call, DataFlow::SideEffectOperandNode indirectArgument, Function func,
|
||||
CallInstruction call, SideEffectOperandNode indirectArgument, Function func,
|
||||
FunctionInput modelIn, FunctionOutput modelOut
|
||||
|
|
||||
indirectArgument = callInput(call, modelIn) and
|
||||
|
||||
@@ -495,7 +495,7 @@ class FieldInstruction extends Instruction {
|
||||
* `FunctionAddress` instruction.
|
||||
*/
|
||||
class FunctionInstruction extends Instruction {
|
||||
Language::Function funcSymbol;
|
||||
Language::Declaration funcSymbol;
|
||||
|
||||
FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) }
|
||||
|
||||
@@ -504,7 +504,7 @@ class FunctionInstruction extends Instruction {
|
||||
/**
|
||||
* Gets the function that this instruction references.
|
||||
*/
|
||||
final Language::Function getFunctionSymbol() { result = funcSymbol }
|
||||
final Language::Declaration getFunctionSymbol() { result = funcSymbol }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1678,7 +1678,7 @@ class CallInstruction extends Instruction {
|
||||
/**
|
||||
* Gets the `Function` that the call targets, if this is statically known.
|
||||
*/
|
||||
final Language::Function getStaticCallTarget() {
|
||||
final Language::Declaration getStaticCallTarget() {
|
||||
result = this.getCallTarget().(FunctionAddressInstruction).getFunctionSymbol()
|
||||
}
|
||||
|
||||
|
||||
@@ -495,7 +495,7 @@ class FieldInstruction extends Instruction {
|
||||
* `FunctionAddress` instruction.
|
||||
*/
|
||||
class FunctionInstruction extends Instruction {
|
||||
Language::Function funcSymbol;
|
||||
Language::Declaration funcSymbol;
|
||||
|
||||
FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) }
|
||||
|
||||
@@ -504,7 +504,7 @@ class FunctionInstruction extends Instruction {
|
||||
/**
|
||||
* Gets the function that this instruction references.
|
||||
*/
|
||||
final Language::Function getFunctionSymbol() { result = funcSymbol }
|
||||
final Language::Declaration getFunctionSymbol() { result = funcSymbol }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1678,7 +1678,7 @@ class CallInstruction extends Instruction {
|
||||
/**
|
||||
* Gets the `Function` that the call targets, if this is statically known.
|
||||
*/
|
||||
final Language::Function getStaticCallTarget() {
|
||||
final Language::Declaration getStaticCallTarget() {
|
||||
result = this.getCallTarget().(FunctionAddressInstruction).getFunctionSymbol()
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@ private import TranslatedCall
|
||||
private import TranslatedStmt
|
||||
private import TranslatedFunction
|
||||
private import TranslatedGlobalVar
|
||||
private import TranslatedNonStaticDataMember
|
||||
private import TranslatedInitialization
|
||||
|
||||
TranslatedElement getInstructionTranslatedElement(Instruction instruction) {
|
||||
instruction = TRawInstruction(result, _)
|
||||
@@ -44,6 +46,9 @@ module Raw {
|
||||
or
|
||||
not var.isFromUninstantiatedTemplate(_) and
|
||||
var instanceof StaticInitializedStaticLocalVariable
|
||||
or
|
||||
not var.isFromUninstantiatedTemplate(_) and
|
||||
var instanceof Field
|
||||
) and
|
||||
var.hasInitializer() and
|
||||
(
|
||||
@@ -63,6 +68,8 @@ module Raw {
|
||||
getTranslatedFunction(decl).hasUserVariable(var, type)
|
||||
or
|
||||
getTranslatedVarInit(decl).hasUserVariable(var, type)
|
||||
or
|
||||
getTranslatedFieldInit(decl).hasUserVariable(var, type)
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -109,7 +116,7 @@ module Raw {
|
||||
}
|
||||
|
||||
cached
|
||||
Function getInstructionFunction(Instruction instruction) {
|
||||
Declaration getInstructionFunction(Instruction instruction) {
|
||||
result =
|
||||
getInstructionTranslatedElement(instruction)
|
||||
.getInstructionFunction(getInstructionTag(instruction))
|
||||
@@ -194,6 +201,89 @@ module Raw {
|
||||
Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
|
||||
result = getInstructionConvertedResultExpression(instruction).getUnconverted()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expression associated with the instruction `instr` that computes
|
||||
* the `Convert` instruction on the extent expression of an allocation.
|
||||
*/
|
||||
cached
|
||||
Expr getAllocationExtentConvertExpr(Instruction instr) {
|
||||
exists(TranslatedNonConstantAllocationSize tas |
|
||||
instr = tas.getInstruction(AllocationExtentConvertTag()) and
|
||||
result = tas.getExtent().getExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `ParenthesisExpr` associated with a transparent conversion
|
||||
* instruction, if any.
|
||||
*/
|
||||
cached
|
||||
ParenthesisExpr getTransparentConversionParenthesisExpr(Instruction instr) {
|
||||
exists(TranslatedTransparentConversion ttc |
|
||||
result = ttc.getExpr() and
|
||||
instr = ttc.getResult()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` belongs to a `TranslatedCoreExpr` that produces an
|
||||
* expression result. This indicates that the instruction represents a
|
||||
* definition whose result should be mapped back to the expression.
|
||||
*/
|
||||
cached
|
||||
predicate instructionProducesExprResult(Instruction instr) {
|
||||
exists(TranslatedCoreExpr tco |
|
||||
tco.getInstruction(_) = instr and
|
||||
tco.producesExprResult()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expression associated with a `StoreInstruction` generated
|
||||
* by an `TranslatedAssignOperation`.
|
||||
*/
|
||||
cached
|
||||
Expr getAssignOperationStoreExpr(StoreInstruction store) {
|
||||
exists(TranslatedAssignOperation tao |
|
||||
store = tao.getInstruction(AssignmentStoreTag()) and
|
||||
result = tao.getExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expression associated with a `StoreInstruction` generated
|
||||
* by an `TranslatedCrementOperation`.
|
||||
*/
|
||||
cached
|
||||
Expr getCrementOperationStoreExpr(StoreInstruction store) {
|
||||
exists(TranslatedCrementOperation tco |
|
||||
store = tco.getInstruction(CrementStoreTag()) and
|
||||
result = tco.getExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `store` is a `StoreInstruction` that defines the temporary
|
||||
* `IRVariable` generated as part of the translation of a ternary expression.
|
||||
*/
|
||||
cached
|
||||
predicate isConditionalExprTempStore(StoreInstruction store) {
|
||||
exists(TranslatedConditionalExpr tce |
|
||||
store = tce.getInstruction(ConditionValueFalseStoreTag())
|
||||
or
|
||||
store = tce.getInstruction(ConditionValueTrueStoreTag())
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the instruction that computes the address used to initialize `v`. */
|
||||
cached
|
||||
Instruction getInitializationTargetAddress(IRVariable v) {
|
||||
exists(TranslatedVariableInitialization init |
|
||||
init.getIRVariable() = v and
|
||||
result = init.getTargetAddress()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TStageInstruction = TRawInstruction or TRawUnreachedInstruction;
|
||||
|
||||
@@ -130,27 +130,31 @@ private predicate hasDefaultSideEffect(Call call, ParameterIndex i, boolean buff
|
||||
}
|
||||
|
||||
/**
|
||||
* A `Call` or `NewOrNewArrayExpr` or `DeleteOrDeleteArrayExpr`.
|
||||
* An expression that can have call side effects.
|
||||
*
|
||||
* All kinds of expression invoke a function as part of their evaluation. This class provides a
|
||||
* way to treat both kinds of function similarly, and to get the invoked `Function`.
|
||||
* All kinds of expressions invoke a function as part of their evaluation. This class provides a
|
||||
* way to treat those expressions similarly, and to get the invoked `Declaration`.
|
||||
*/
|
||||
class CallOrAllocationExpr extends Expr {
|
||||
CallOrAllocationExpr() {
|
||||
class ExprWithCallSideEffects extends Expr {
|
||||
ExprWithCallSideEffects() {
|
||||
this instanceof Call
|
||||
or
|
||||
this instanceof NewOrNewArrayExpr
|
||||
or
|
||||
this instanceof DeleteOrDeleteArrayExpr
|
||||
or
|
||||
this instanceof ConstructorDefaultFieldInit
|
||||
}
|
||||
|
||||
/** Gets the `Function` invoked by this expression, if known. */
|
||||
final Function getTarget() {
|
||||
/** Gets the `Declaration` invoked by this expression, if known. */
|
||||
final Declaration getTarget() {
|
||||
result = this.(Call).getTarget()
|
||||
or
|
||||
result = this.(NewOrNewArrayExpr).getAllocator()
|
||||
or
|
||||
result = this.(DeleteOrDeleteArrayExpr).getDeallocator()
|
||||
or
|
||||
result = this.(ConstructorDefaultFieldInit).getTarget()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,7 +162,7 @@ class CallOrAllocationExpr extends Expr {
|
||||
* Returns the side effect opcode, if any, that represents any side effects not specifically modeled
|
||||
* by an argument side effect.
|
||||
*/
|
||||
Opcode getCallSideEffectOpcode(CallOrAllocationExpr expr) {
|
||||
Opcode getCallSideEffectOpcode(ExprWithCallSideEffects expr) {
|
||||
not exists(expr.getTarget().(SideEffectFunction)) and result instanceof Opcode::CallSideEffect
|
||||
or
|
||||
exists(SideEffectFunction sideEffectFunction |
|
||||
@@ -175,7 +179,7 @@ Opcode getCallSideEffectOpcode(CallOrAllocationExpr expr) {
|
||||
/**
|
||||
* Returns a side effect opcode for parameter index `i` of the specified call.
|
||||
*
|
||||
* This predicate will return at most two results: one read side effect, and one write side effect.
|
||||
* This predicate will yield at most two results: one read side effect, and one write side effect.
|
||||
*/
|
||||
Opcode getASideEffectOpcode(Call call, ParameterIndex i) {
|
||||
exists(boolean buffer |
|
||||
@@ -228,3 +232,14 @@ Opcode getASideEffectOpcode(Call call, ParameterIndex i) {
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a side effect opcode for a default field initialization.
|
||||
*
|
||||
* This predicate will yield two results: one read side effect, and one write side effect.
|
||||
*/
|
||||
Opcode getDefaultFieldInitSideEffectOpcode() {
|
||||
result instanceof Opcode::IndirectReadSideEffect
|
||||
or
|
||||
result instanceof Opcode::IndirectMayWriteSideEffect
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ private import SideEffects
|
||||
private import TranslatedElement
|
||||
private import TranslatedExpr
|
||||
private import TranslatedFunction
|
||||
private import TranslatedInitialization
|
||||
private import DefaultOptions as DefaultOptions
|
||||
|
||||
/**
|
||||
@@ -348,7 +349,7 @@ class TranslatedExprCall extends TranslatedCallExpr {
|
||||
class TranslatedFunctionCall extends TranslatedCallExpr, TranslatedDirectCall {
|
||||
override FunctionCall expr;
|
||||
|
||||
override Function getInstructionFunction(InstructionTag tag) {
|
||||
override Declaration getInstructionFunction(InstructionTag tag) {
|
||||
tag = CallTargetTag() and result = expr.getTarget()
|
||||
}
|
||||
|
||||
@@ -429,6 +430,9 @@ class TranslatedCallSideEffects extends TranslatedSideEffects, TTranslatedCallSi
|
||||
or
|
||||
expr instanceof DeleteOrDeleteArrayExpr and
|
||||
result = getTranslatedDeleteOrDeleteArray(expr).getInstruction(CallTag())
|
||||
or
|
||||
expr instanceof ConstructorDefaultFieldInit and
|
||||
result = getTranslatedConstructorFieldInitialization(expr).getInstruction(CallTag())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -504,11 +508,25 @@ abstract class TranslatedSideEffect extends TranslatedElement {
|
||||
abstract predicate sideEffectInstruction(Opcode opcode, CppType type);
|
||||
}
|
||||
|
||||
private class CallOrDefaultFieldInit extends Expr {
|
||||
CallOrDefaultFieldInit() {
|
||||
this instanceof Call
|
||||
or
|
||||
this instanceof ConstructorDefaultFieldInit
|
||||
}
|
||||
|
||||
Declaration getTarget() {
|
||||
result = this.(Call).getTarget()
|
||||
or
|
||||
result = this.(ConstructorDefaultFieldInit).getTarget()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The IR translation of a single argument side effect for a call.
|
||||
*/
|
||||
abstract class TranslatedArgumentSideEffect extends TranslatedSideEffect {
|
||||
Call call;
|
||||
CallOrDefaultFieldInit callOrInit;
|
||||
int index;
|
||||
SideEffectOpcode sideEffectOpcode;
|
||||
|
||||
@@ -524,7 +542,7 @@ abstract class TranslatedArgumentSideEffect extends TranslatedSideEffect {
|
||||
result = "(read side effect for " + this.getArgString() + ")"
|
||||
}
|
||||
|
||||
override Call getPrimaryExpr() { result = call }
|
||||
override Expr getPrimaryExpr() { result = callOrInit }
|
||||
|
||||
override predicate sortOrder(int group, int indexInGroup) {
|
||||
indexInGroup = index and
|
||||
@@ -586,9 +604,10 @@ abstract class TranslatedArgumentSideEffect extends TranslatedSideEffect {
|
||||
tag instanceof OnlyInstructionTag and
|
||||
operandTag instanceof BufferSizeOperandTag and
|
||||
result =
|
||||
getTranslatedExpr(call.getArgument(call.getTarget()
|
||||
.(SideEffectFunction)
|
||||
.getParameterSizeIndex(index)).getFullyConverted()).getResult()
|
||||
getTranslatedExpr(callOrInit
|
||||
.(Call)
|
||||
.getArgument(callOrInit.getTarget().(SideEffectFunction).getParameterSizeIndex(index))
|
||||
.getFullyConverted()).getResult()
|
||||
}
|
||||
|
||||
/** Holds if this side effect is a write side effect, rather than a read side effect. */
|
||||
@@ -616,7 +635,7 @@ class TranslatedArgumentExprSideEffect extends TranslatedArgumentSideEffect,
|
||||
Expr arg;
|
||||
|
||||
TranslatedArgumentExprSideEffect() {
|
||||
this = TTranslatedArgumentExprSideEffect(call, arg, index, sideEffectOpcode)
|
||||
this = TTranslatedArgumentExprSideEffect(callOrInit, arg, index, sideEffectOpcode)
|
||||
}
|
||||
|
||||
final override Locatable getAst() { result = arg }
|
||||
@@ -640,28 +659,31 @@ class TranslatedArgumentExprSideEffect extends TranslatedArgumentSideEffect,
|
||||
* The IR translation of an argument side effect for `*this` on a call, where there is no `Expr`
|
||||
* object that represents the `this` argument.
|
||||
*
|
||||
* The applies only to constructor calls, as the AST has exploit qualifier `Expr`s for all other
|
||||
* calls to non-static member functions.
|
||||
* This applies to constructor calls and default field initializations, as the AST has explicit
|
||||
* qualifier `Expr`s for all other calls to non-static member functions.
|
||||
*/
|
||||
class TranslatedStructorQualifierSideEffect extends TranslatedArgumentSideEffect,
|
||||
TTranslatedStructorQualifierSideEffect
|
||||
class TranslatedImplicitThisQualifierSideEffect extends TranslatedArgumentSideEffect,
|
||||
TTranslatedImplicitThisQualifierSideEffect
|
||||
{
|
||||
TranslatedStructorQualifierSideEffect() {
|
||||
this = TTranslatedStructorQualifierSideEffect(call, sideEffectOpcode) and
|
||||
TranslatedImplicitThisQualifierSideEffect() {
|
||||
this = TTranslatedImplicitThisQualifierSideEffect(callOrInit, sideEffectOpcode) and
|
||||
index = -1
|
||||
}
|
||||
|
||||
final override Locatable getAst() { result = call }
|
||||
final override Locatable getAst() { result = callOrInit }
|
||||
|
||||
final override Type getIndirectionType() { result = call.getTarget().getDeclaringType() }
|
||||
final override Type getIndirectionType() { result = callOrInit.getTarget().getDeclaringType() }
|
||||
|
||||
final override string getArgString() { result = "this" }
|
||||
|
||||
final override Instruction getArgInstruction() {
|
||||
exists(TranslatedStructorCall structorCall |
|
||||
structorCall.getExpr() = call and
|
||||
structorCall.getExpr() = callOrInit and
|
||||
result = structorCall.getQualifierResult()
|
||||
)
|
||||
or
|
||||
callOrInit instanceof ConstructorDefaultFieldInit and
|
||||
result = getTranslatedFunction(callOrInit.getEnclosingFunction()).getLoadThisInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,8 @@ abstract class TranslatedCondition extends TranslatedElement {
|
||||
final override Declaration getFunction() {
|
||||
result = getEnclosingFunction(expr) or
|
||||
result = getEnclosingVariable(expr).(GlobalOrNamespaceVariable) or
|
||||
result = getEnclosingVariable(expr).(StaticInitializedStaticLocalVariable)
|
||||
result = getEnclosingVariable(expr).(StaticInitializedStaticLocalVariable) or
|
||||
result = getEnclosingVariable(expr).(Field)
|
||||
}
|
||||
|
||||
final Type getResultType() { result = expr.getUnspecifiedType() }
|
||||
|
||||
@@ -34,8 +34,11 @@ abstract class TranslatedDeclarationEntry extends TranslatedElement, TTranslated
|
||||
or
|
||||
result = entry.getDeclaration().(GlobalOrNamespaceVariable)
|
||||
or
|
||||
result = entry.getDeclaration().(Field)
|
||||
or
|
||||
not entry.getDeclaration() instanceof StaticInitializedStaticLocalVariable and
|
||||
not entry.getDeclaration() instanceof GlobalOrNamespaceVariable and
|
||||
not entry.getDeclaration() instanceof Field and
|
||||
result = stmt.getEnclosingFunction()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -767,7 +767,7 @@ newtype TTranslatedElement =
|
||||
expr = initList.getFieldExpr(field, position).getFullyConverted()
|
||||
)
|
||||
or
|
||||
exists(ConstructorFieldInit init |
|
||||
exists(ConstructorDirectFieldInit init |
|
||||
not ignoreExpr(init) and
|
||||
ast = init and
|
||||
field = init.getTarget() and
|
||||
@@ -775,6 +775,14 @@ newtype TTranslatedElement =
|
||||
position = -1
|
||||
)
|
||||
} or
|
||||
// The initialization of a field via a default member initializer.
|
||||
TTranslatedDefaultFieldInitialization(Expr ast, Field field) {
|
||||
exists(ConstructorDefaultFieldInit init |
|
||||
not ignoreExpr(init) and
|
||||
ast = init and
|
||||
field = init.getTarget()
|
||||
)
|
||||
} or
|
||||
// The value initialization of a field due to an omitted member of an
|
||||
// initializer list.
|
||||
TTranslatedFieldValueInitialization(Expr ast, Field field) {
|
||||
@@ -871,7 +879,7 @@ newtype TTranslatedElement =
|
||||
// The declaration/initialization part of a `ConditionDeclExpr`
|
||||
TTranslatedConditionDecl(ConditionDeclExpr expr) { not ignoreExpr(expr) } or
|
||||
// The side effects of a `Call`
|
||||
TTranslatedCallSideEffects(CallOrAllocationExpr expr) {
|
||||
TTranslatedCallSideEffects(ExprWithCallSideEffects expr) {
|
||||
not ignoreExpr(expr) and
|
||||
not ignoreSideEffects(expr)
|
||||
} or
|
||||
@@ -910,15 +918,23 @@ newtype TTranslatedElement =
|
||||
} or
|
||||
// Constructor calls lack a qualifier (`this`) expression, so we need to handle the side effects
|
||||
// on `*this` without an `Expr`.
|
||||
TTranslatedStructorQualifierSideEffect(Call call, SideEffectOpcode opcode) {
|
||||
TTranslatedImplicitThisQualifierSideEffect(ExprWithCallSideEffects call, SideEffectOpcode opcode) {
|
||||
not ignoreExpr(call) and
|
||||
not ignoreSideEffects(call) and
|
||||
call instanceof ConstructorCall and
|
||||
opcode = getASideEffectOpcode(call, -1)
|
||||
(
|
||||
call instanceof ConstructorCall and
|
||||
opcode = getASideEffectOpcode(call, -1)
|
||||
or
|
||||
call instanceof ConstructorFieldInit and
|
||||
opcode = getDefaultFieldInitSideEffectOpcode()
|
||||
)
|
||||
} or
|
||||
// The side effect that initializes newly-allocated memory.
|
||||
TTranslatedAllocationSideEffect(AllocationExpr expr) { not ignoreSideEffects(expr) } or
|
||||
TTranslatedStaticStorageDurationVarInit(Variable var) { Raw::varHasIRFunc(var) } or
|
||||
TTranslatedStaticStorageDurationVarInit(Variable var) {
|
||||
Raw::varHasIRFunc(var) and not var instanceof Field
|
||||
} or
|
||||
TTranslatedNonStaticDataMemberVarInit(Field var) { Raw::varHasIRFunc(var) } or
|
||||
TTranslatedAssertionOperand(MacroInvocation mi, int index) { hasAssertionOperand(mi, index) }
|
||||
|
||||
/**
|
||||
@@ -1179,7 +1195,7 @@ abstract class TranslatedElement extends TTranslatedElement {
|
||||
* If the instruction specified by `tag` is a `FunctionInstruction`, gets the
|
||||
* `Function` for that instruction.
|
||||
*/
|
||||
Function getInstructionFunction(InstructionTag tag) { none() }
|
||||
Declaration getInstructionFunction(InstructionTag tag) { none() }
|
||||
|
||||
/**
|
||||
* If the instruction specified by `tag` is a `VariableInstruction`, gets the
|
||||
@@ -1297,5 +1313,7 @@ abstract class TranslatedRootElement extends TranslatedElement {
|
||||
this instanceof TTranslatedFunction
|
||||
or
|
||||
this instanceof TTranslatedStaticStorageDurationVarInit
|
||||
or
|
||||
this instanceof TTranslatedNonStaticDataMemberVarInit
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ private import TranslatedFunction
|
||||
private import TranslatedInitialization
|
||||
private import TranslatedStmt
|
||||
private import TranslatedGlobalVar
|
||||
private import TranslatedNonStaticDataMember
|
||||
private import IRConstruction
|
||||
import TranslatedCall
|
||||
|
||||
@@ -138,6 +139,8 @@ abstract class TranslatedExpr extends TranslatedElement {
|
||||
result = getTranslatedFunction(getEnclosingFunction(expr))
|
||||
or
|
||||
result = getTranslatedVarInit(getEnclosingVariable(expr))
|
||||
or
|
||||
result = getTranslatedFieldInit(getEnclosingVariable(expr))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +156,10 @@ Declaration getEnclosingDeclaration0(Expr e) {
|
||||
i.getExpr().getFullyConverted() = e and
|
||||
v = i.getDeclaration()
|
||||
|
|
||||
if v instanceof StaticInitializedStaticLocalVariable or v instanceof GlobalOrNamespaceVariable
|
||||
if
|
||||
v instanceof StaticInitializedStaticLocalVariable or
|
||||
v instanceof GlobalOrNamespaceVariable or
|
||||
v instanceof Field
|
||||
then result = v
|
||||
else result = e.getEnclosingDeclaration()
|
||||
)
|
||||
@@ -173,7 +179,10 @@ Variable getEnclosingVariable0(Expr e) {
|
||||
i.getExpr().getFullyConverted() = e and
|
||||
v = i.getDeclaration()
|
||||
|
|
||||
if v instanceof StaticInitializedStaticLocalVariable or v instanceof GlobalOrNamespaceVariable
|
||||
if
|
||||
v instanceof StaticInitializedStaticLocalVariable or
|
||||
v instanceof GlobalOrNamespaceVariable or
|
||||
v instanceof Field
|
||||
then result = v
|
||||
else result = e.getEnclosingVariable()
|
||||
)
|
||||
@@ -826,6 +835,46 @@ class TranslatedPostfixCrementOperation extends TranslatedCrementOperation {
|
||||
override Instruction getResult() { result = this.getLoadedOperand().getResult() }
|
||||
}
|
||||
|
||||
class TranslatedParamAccessForType extends TranslatedNonConstantExpr {
|
||||
override ParamAccessForType expr;
|
||||
|
||||
TranslatedParamAccessForType() {
|
||||
// Currently only needed for this parameter accesses.
|
||||
expr.isThisAccess()
|
||||
}
|
||||
|
||||
final override Instruction getFirstInstruction(EdgeKind kind) {
|
||||
result = this.getInstruction(OnlyInstructionTag()) and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
override Instruction getALastInstructionInternal() {
|
||||
result = this.getInstruction(OnlyInstructionTag())
|
||||
}
|
||||
|
||||
final override TranslatedElement getChildInternal(int id) { none() }
|
||||
|
||||
override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
|
||||
tag = OnlyInstructionTag() and
|
||||
result = this.getParent().getChildSuccessor(this, kind)
|
||||
}
|
||||
|
||||
override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) }
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = OnlyInstructionTag() and
|
||||
opcode instanceof Opcode::CopyValue and
|
||||
resultType = getTypeForPRValue(expr.getType())
|
||||
}
|
||||
|
||||
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
tag = OnlyInstructionTag() and
|
||||
operandTag instanceof UnaryOperandTag and
|
||||
result =
|
||||
this.getEnclosingFunction().(TranslatedNonStaticDataMemberVarInit).getLoadThisInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* IR translation of an array access expression (e.g. `a[i]`). The array being accessed will either
|
||||
* be a prvalue of pointer type (possibly due to an implicit array-to-pointer conversion), or a
|
||||
@@ -1215,7 +1264,7 @@ class TranslatedFunctionAccess extends TranslatedNonConstantExpr {
|
||||
resultType = this.getResultType()
|
||||
}
|
||||
|
||||
override Function getInstructionFunction(InstructionTag tag) {
|
||||
override Declaration getInstructionFunction(InstructionTag tag) {
|
||||
tag = OnlyInstructionTag() and
|
||||
result = expr.getTarget()
|
||||
}
|
||||
@@ -2498,7 +2547,7 @@ class TranslatedAllocatorCall extends TTranslatedAllocatorCall, TranslatedDirect
|
||||
any()
|
||||
}
|
||||
|
||||
override Function getInstructionFunction(InstructionTag tag) {
|
||||
override Declaration getInstructionFunction(InstructionTag tag) {
|
||||
tag = CallTargetTag() and result = expr.getAllocator()
|
||||
}
|
||||
|
||||
@@ -2581,7 +2630,7 @@ class TranslatedDeleteOrDeleteArrayExpr extends TranslatedNonConstantExpr, Trans
|
||||
result = this.getFirstArgumentOrCallInstruction(kind)
|
||||
}
|
||||
|
||||
override Function getInstructionFunction(InstructionTag tag) {
|
||||
override Declaration getInstructionFunction(InstructionTag tag) {
|
||||
tag = CallTargetTag() and result = expr.getDeallocator()
|
||||
}
|
||||
|
||||
|
||||
@@ -148,7 +148,8 @@ abstract class TranslatedInitialization extends TranslatedElement, TTranslatedIn
|
||||
final override Declaration getFunction() {
|
||||
result = getEnclosingFunction(expr) or
|
||||
result = getEnclosingVariable(expr).(GlobalOrNamespaceVariable) or
|
||||
result = getEnclosingVariable(expr).(StaticInitializedStaticLocalVariable)
|
||||
result = getEnclosingVariable(expr).(StaticInitializedStaticLocalVariable) or
|
||||
result = getEnclosingVariable(expr).(Field)
|
||||
}
|
||||
|
||||
final override Locatable getAst() { result = expr }
|
||||
@@ -514,8 +515,8 @@ TranslatedFieldInitialization getTranslatedConstructorFieldInitialization(Constr
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR translation of the initialization of a field from an
|
||||
* element of an initializer list.
|
||||
* The IR translation of the initialization of a field from an element of
|
||||
* an initializer list.
|
||||
*/
|
||||
abstract class TranslatedFieldInitialization extends TranslatedElement {
|
||||
Expr ast;
|
||||
@@ -528,13 +529,11 @@ abstract class TranslatedFieldInitialization extends TranslatedElement {
|
||||
final override Declaration getFunction() {
|
||||
result = getEnclosingFunction(ast) or
|
||||
result = getEnclosingVariable(ast).(GlobalOrNamespaceVariable) or
|
||||
result = getEnclosingVariable(ast).(StaticInitializedStaticLocalVariable)
|
||||
result = getEnclosingVariable(ast).(StaticInitializedStaticLocalVariable) or
|
||||
result = getEnclosingVariable(ast).(Field)
|
||||
}
|
||||
|
||||
final override Instruction getFirstInstruction(EdgeKind kind) {
|
||||
result = this.getInstruction(this.getFieldAddressTag()) and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
final Field getField() { result = field }
|
||||
|
||||
/**
|
||||
* Gets the zero-based index describing the order in which this field is to be
|
||||
@@ -542,6 +541,20 @@ abstract class TranslatedFieldInitialization extends TranslatedElement {
|
||||
*/
|
||||
final int getOrder() { result = field.getInitializationOrder() }
|
||||
|
||||
/** Gets the position in the initializer list, or `-1` if the initialization is implicit. */
|
||||
int getPosition() { result = -1 }
|
||||
}
|
||||
|
||||
/**
|
||||
* The IR translation of the initialization of a field from an element of an initializer
|
||||
* list where default initialization is not used.
|
||||
*/
|
||||
abstract class TranslatedNonDefaultFieldInitialization extends TranslatedFieldInitialization {
|
||||
final override Instruction getFirstInstruction(EdgeKind kind) {
|
||||
result = this.getInstruction(this.getFieldAddressTag()) and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = this.getFieldAddressTag() and
|
||||
opcode instanceof Opcode::FieldAddress and
|
||||
@@ -559,18 +572,13 @@ abstract class TranslatedFieldInitialization extends TranslatedElement {
|
||||
}
|
||||
|
||||
final InstructionTag getFieldAddressTag() { result = InitializerFieldAddressTag() }
|
||||
|
||||
final Field getField() { result = field }
|
||||
|
||||
/** Gets the position in the initializer list, or `-1` if the initialization is implicit. */
|
||||
int getPosition() { result = -1 }
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR translation of the initialization of a field from an
|
||||
* explicit element in an initializer list.
|
||||
* The IR translation of the initialization of a field from an explicit element in
|
||||
* an initializer list.
|
||||
*/
|
||||
class TranslatedExplicitFieldInitialization extends TranslatedFieldInitialization,
|
||||
class TranslatedExplicitFieldInitialization extends TranslatedNonDefaultFieldInitialization,
|
||||
InitializationContext, TTranslatedExplicitFieldInitialization
|
||||
{
|
||||
Expr expr;
|
||||
@@ -610,15 +618,81 @@ class TranslatedExplicitFieldInitialization extends TranslatedFieldInitializatio
|
||||
override int getPosition() { result = position }
|
||||
}
|
||||
|
||||
/**
|
||||
* The IR translation of the initialization of a field from an element of an initializer
|
||||
* list where default initialization is used.
|
||||
*/
|
||||
class TranslatedDefaultFieldInitialization extends TranslatedFieldInitialization,
|
||||
TTranslatedDefaultFieldInitialization
|
||||
{
|
||||
TranslatedDefaultFieldInitialization() {
|
||||
this = TTranslatedDefaultFieldInitialization(ast, field)
|
||||
}
|
||||
|
||||
final override Instruction getFirstInstruction(EdgeKind kind) {
|
||||
result = this.getInstruction(CallTargetTag()) and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
override Instruction getALastInstructionInternal() {
|
||||
result = this.getSideEffects().getALastInstruction()
|
||||
}
|
||||
|
||||
override TranslatedElement getLastChild() { result = this.getSideEffects() }
|
||||
|
||||
override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
|
||||
tag = CallTargetTag() and
|
||||
result = this.getInstruction(CallTag())
|
||||
or
|
||||
tag = CallTag() and
|
||||
result = this.getSideEffects().getFirstInstruction(kind)
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
|
||||
child = this.getSideEffects() and
|
||||
result = this.getParent().getChildSuccessor(this, kind)
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = CallTargetTag() and
|
||||
opcode instanceof Opcode::FunctionAddress and
|
||||
resultType = getFunctionGLValueType()
|
||||
or
|
||||
tag = CallTag() and
|
||||
opcode instanceof Opcode::Call and
|
||||
resultType = getVoidType()
|
||||
}
|
||||
|
||||
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
tag = CallTag() and
|
||||
(
|
||||
operandTag instanceof CallTargetOperandTag and
|
||||
result = this.getInstruction(CallTargetTag())
|
||||
or
|
||||
operandTag instanceof ThisArgumentOperandTag and
|
||||
result = getTranslatedFunction(this.getFunction()).getLoadThisInstruction()
|
||||
)
|
||||
}
|
||||
|
||||
override Declaration getInstructionFunction(InstructionTag tag) {
|
||||
tag = CallTargetTag() and
|
||||
result = field
|
||||
}
|
||||
|
||||
override TranslatedElement getChild(int id) { id = 0 and result = this.getSideEffects() }
|
||||
|
||||
final TranslatedSideEffects getSideEffects() { result.getExpr() = ast }
|
||||
}
|
||||
|
||||
private string getZeroValue(Type type) {
|
||||
if type instanceof FloatingPointType then result = "0.0" else result = "0"
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR translation of the initialization of a field without a
|
||||
* corresponding element in the initializer list.
|
||||
* The IR translation of the initialization of a field without a corresponding
|
||||
* element in the initializer list.
|
||||
*/
|
||||
class TranslatedFieldValueInitialization extends TranslatedFieldInitialization,
|
||||
class TranslatedFieldValueInitialization extends TranslatedNonDefaultFieldInitialization,
|
||||
TTranslatedFieldValueInitialization
|
||||
{
|
||||
TranslatedFieldValueInitialization() { this = TTranslatedFieldValueInitialization(ast, field) }
|
||||
@@ -628,7 +702,7 @@ class TranslatedFieldValueInitialization extends TranslatedFieldInitialization,
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
TranslatedFieldInitialization.super.hasInstruction(opcode, tag, resultType)
|
||||
TranslatedNonDefaultFieldInitialization.super.hasInstruction(opcode, tag, resultType)
|
||||
or
|
||||
tag = this.getFieldDefaultValueTag() and
|
||||
opcode instanceof Opcode::Constant and
|
||||
@@ -659,7 +733,8 @@ class TranslatedFieldValueInitialization extends TranslatedFieldInitialization,
|
||||
}
|
||||
|
||||
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
result = TranslatedFieldInitialization.super.getInstructionRegisterOperand(tag, operandTag)
|
||||
result =
|
||||
TranslatedNonDefaultFieldInitialization.super.getInstructionRegisterOperand(tag, operandTag)
|
||||
or
|
||||
tag = this.getFieldDefaultValueStoreTag() and
|
||||
(
|
||||
@@ -683,8 +758,8 @@ class TranslatedFieldValueInitialization extends TranslatedFieldInitialization,
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR translation of the initialization of an array element from
|
||||
* an element of an initializer list.
|
||||
* The IR translation of the initialization of an array element from an element
|
||||
* of an initializer list.
|
||||
*/
|
||||
abstract class TranslatedElementInitialization extends TranslatedElement {
|
||||
ArrayOrVectorAggregateLiteral initList;
|
||||
@@ -701,6 +776,8 @@ abstract class TranslatedElementInitialization extends TranslatedElement {
|
||||
result = getEnclosingVariable(initList).(GlobalOrNamespaceVariable)
|
||||
or
|
||||
result = getEnclosingVariable(initList).(StaticInitializedStaticLocalVariable)
|
||||
or
|
||||
result = getEnclosingVariable(initList).(Field)
|
||||
}
|
||||
|
||||
final override Instruction getFirstInstruction(EdgeKind kind) {
|
||||
@@ -759,8 +836,8 @@ abstract class TranslatedElementInitialization extends TranslatedElement {
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR translation of the initialization of an array element from
|
||||
* an explicit element in an initializer list.
|
||||
* The IR translation of the initialization of an array element from an explicit
|
||||
* element in an initializer list.
|
||||
*/
|
||||
class TranslatedExplicitElementInitialization extends TranslatedElementInitialization,
|
||||
TTranslatedExplicitElementInitialization, InitializationContext
|
||||
@@ -808,8 +885,8 @@ class TranslatedExplicitElementInitialization extends TranslatedElementInitializ
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the IR translation of the initialization of a range of array
|
||||
* elements without corresponding elements in the initializer list.
|
||||
* The IR translation of the initialization of a range of array elements without
|
||||
* corresponding elements in the initializer list.
|
||||
*/
|
||||
class TranslatedElementValueInitialization extends TranslatedElementInitialization,
|
||||
TTranslatedElementValueInitialization
|
||||
|
||||
@@ -0,0 +1,217 @@
|
||||
import semmle.code.cpp.ir.implementation.raw.internal.TranslatedElement
|
||||
private import TranslatedExpr
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||
private import semmle.code.cpp.ir.internal.TempVariableTag
|
||||
private import semmle.code.cpp.ir.internal.CppType
|
||||
private import TranslatedInitialization
|
||||
private import InstructionTag
|
||||
private import semmle.code.cpp.ir.internal.IRUtilities
|
||||
|
||||
class TranslatedNonStaticDataMemberVarInit extends TranslatedRootElement,
|
||||
TTranslatedNonStaticDataMemberVarInit, InitializationContext
|
||||
{
|
||||
Field field;
|
||||
Class cls;
|
||||
|
||||
TranslatedNonStaticDataMemberVarInit() {
|
||||
this = TTranslatedNonStaticDataMemberVarInit(field) and
|
||||
cls.getAMember() = field
|
||||
}
|
||||
|
||||
override string toString() { result = cls.toString() + "::" + field.toString() }
|
||||
|
||||
final override Field getAst() { result = field }
|
||||
|
||||
final override Declaration getFunction() { result = field }
|
||||
|
||||
override Instruction getFirstInstruction(EdgeKind kind) {
|
||||
result = this.getInstruction(EnterFunctionTag()) and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
override Instruction getALastInstructionInternal() {
|
||||
result = this.getInstruction(ExitFunctionTag())
|
||||
}
|
||||
|
||||
override TranslatedElement getChild(int n) {
|
||||
n = 1 and
|
||||
result = getTranslatedInitialization(field.getInitializer().getExpr().getFullyConverted())
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode op, InstructionTag tag, CppType type) {
|
||||
op instanceof Opcode::EnterFunction and
|
||||
tag = EnterFunctionTag() and
|
||||
type = getVoidType()
|
||||
or
|
||||
op instanceof Opcode::AliasedDefinition and
|
||||
tag = AliasedDefinitionTag() and
|
||||
type = getUnknownType()
|
||||
or
|
||||
op instanceof Opcode::InitializeNonLocal and
|
||||
tag = InitializeNonLocalTag() and
|
||||
type = getUnknownType()
|
||||
or
|
||||
tag = ThisAddressTag() and
|
||||
op instanceof Opcode::VariableAddress and
|
||||
type = getTypeForGLValue(any(UnknownType t))
|
||||
or
|
||||
tag = InitializerStoreTag() and
|
||||
op instanceof Opcode::InitializeParameter and
|
||||
type = this.getThisType()
|
||||
or
|
||||
tag = ThisLoadTag() and
|
||||
op instanceof Opcode::Load and
|
||||
type = this.getThisType()
|
||||
or
|
||||
tag = InitializerIndirectStoreTag() and
|
||||
op instanceof Opcode::InitializeIndirection and
|
||||
type = getTypeForPRValue(cls)
|
||||
or
|
||||
op instanceof Opcode::FieldAddress and
|
||||
tag = InitializerFieldAddressTag() and
|
||||
type = getTypeForGLValue(field.getType())
|
||||
or
|
||||
op instanceof Opcode::ReturnVoid and
|
||||
tag = ReturnTag() and
|
||||
type = getVoidType()
|
||||
or
|
||||
op instanceof Opcode::AliasedUse and
|
||||
tag = AliasedUseTag() and
|
||||
type = getVoidType()
|
||||
or
|
||||
op instanceof Opcode::ExitFunction and
|
||||
tag = ExitFunctionTag() and
|
||||
type = getVoidType()
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
|
||||
kind instanceof GotoEdge and
|
||||
(
|
||||
tag = EnterFunctionTag() and
|
||||
result = this.getInstruction(AliasedDefinitionTag())
|
||||
or
|
||||
tag = AliasedDefinitionTag() and
|
||||
result = this.getInstruction(InitializeNonLocalTag())
|
||||
or
|
||||
tag = InitializeNonLocalTag() and
|
||||
result = this.getInstruction(ThisAddressTag())
|
||||
or
|
||||
tag = ThisAddressTag() and
|
||||
result = this.getInstruction(InitializerStoreTag())
|
||||
or
|
||||
tag = InitializerStoreTag() and
|
||||
result = this.getInstruction(ThisLoadTag())
|
||||
or
|
||||
tag = ThisLoadTag() and
|
||||
result = this.getInstruction(InitializerIndirectStoreTag())
|
||||
or
|
||||
tag = InitializerIndirectStoreTag() and
|
||||
result = this.getInstruction(InitializerFieldAddressTag())
|
||||
)
|
||||
or
|
||||
tag = InitializerFieldAddressTag() and
|
||||
result = this.getChild(1).getFirstInstruction(kind)
|
||||
or
|
||||
kind instanceof GotoEdge and
|
||||
(
|
||||
tag = ReturnTag() and
|
||||
result = this.getInstruction(AliasedUseTag())
|
||||
or
|
||||
tag = AliasedUseTag() and
|
||||
result = this.getInstruction(ExitFunctionTag())
|
||||
)
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
|
||||
child = this.getChild(1) and
|
||||
result = this.getInstruction(ReturnTag()) and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
final override CppType getInstructionMemoryOperandType(
|
||||
InstructionTag tag, TypedOperandTag operandTag
|
||||
) {
|
||||
tag = AliasedUseTag() and
|
||||
operandTag instanceof SideEffectOperandTag and
|
||||
result = getUnknownType()
|
||||
}
|
||||
|
||||
override IRVariable getInstructionVariable(InstructionTag tag) {
|
||||
(
|
||||
tag = ThisAddressTag() or
|
||||
tag = InitializerStoreTag() or
|
||||
tag = InitializerIndirectStoreTag()
|
||||
) and
|
||||
result = getIRTempVariable(field, ThisTempVar())
|
||||
}
|
||||
|
||||
override Field getInstructionField(InstructionTag tag) {
|
||||
tag = InitializerFieldAddressTag() and
|
||||
result = field
|
||||
}
|
||||
|
||||
override predicate hasTempVariable(TempVariableTag tag, CppType type) {
|
||||
tag = ThisTempVar() and
|
||||
type = this.getThisType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this variable defines or accesses variable `var` with type `type`. This includes all
|
||||
* parameters and local variables, plus any global variables or static data members that are
|
||||
* directly accessed by the function.
|
||||
*/
|
||||
final predicate hasUserVariable(Variable varUsed, CppType type) {
|
||||
(
|
||||
(
|
||||
varUsed instanceof GlobalOrNamespaceVariable
|
||||
or
|
||||
varUsed instanceof StaticLocalVariable
|
||||
or
|
||||
varUsed instanceof MemberVariable and not varUsed instanceof Field
|
||||
) and
|
||||
exists(VariableAccess access |
|
||||
access.getTarget() = varUsed and
|
||||
getEnclosingVariable(access) = field
|
||||
)
|
||||
or
|
||||
field = varUsed
|
||||
or
|
||||
varUsed.(LocalScopeVariable).getEnclosingElement*() = field
|
||||
or
|
||||
varUsed.(Parameter).getCatchBlock().getEnclosingElement*() = field
|
||||
) and
|
||||
type = getTypeForPRValue(getVariableType(varUsed))
|
||||
}
|
||||
|
||||
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
(
|
||||
tag = InitializerStoreTag()
|
||||
or
|
||||
tag = ThisLoadTag()
|
||||
) and
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = this.getInstruction(ThisAddressTag())
|
||||
or
|
||||
(
|
||||
tag = InitializerIndirectStoreTag() and
|
||||
operandTag instanceof AddressOperandTag
|
||||
or
|
||||
tag = InitializerFieldAddressTag() and
|
||||
operandTag instanceof UnaryOperandTag
|
||||
) and
|
||||
result = this.getInstruction(ThisLoadTag())
|
||||
}
|
||||
|
||||
override Instruction getTargetAddress() {
|
||||
result = this.getInstruction(InitializerFieldAddressTag())
|
||||
}
|
||||
|
||||
override Type getTargetType() { result = field.getUnspecifiedType() }
|
||||
|
||||
final Instruction getLoadThisInstruction() { result = this.getInstruction(ThisLoadTag()) }
|
||||
|
||||
private CppType getThisType() { result = getTypeForGLValue(cls) }
|
||||
}
|
||||
|
||||
TranslatedNonStaticDataMemberVarInit getTranslatedFieldInit(Field field) { result.getAst() = field }
|
||||
@@ -495,7 +495,7 @@ class FieldInstruction extends Instruction {
|
||||
* `FunctionAddress` instruction.
|
||||
*/
|
||||
class FunctionInstruction extends Instruction {
|
||||
Language::Function funcSymbol;
|
||||
Language::Declaration funcSymbol;
|
||||
|
||||
FunctionInstruction() { funcSymbol = Raw::getInstructionFunction(this) }
|
||||
|
||||
@@ -504,7 +504,7 @@ class FunctionInstruction extends Instruction {
|
||||
/**
|
||||
* Gets the function that this instruction references.
|
||||
*/
|
||||
final Language::Function getFunctionSymbol() { result = funcSymbol }
|
||||
final Language::Declaration getFunctionSymbol() { result = funcSymbol }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1678,7 +1678,7 @@ class CallInstruction extends Instruction {
|
||||
/**
|
||||
* Gets the `Function` that the call targets, if this is statically known.
|
||||
*/
|
||||
final Language::Function getStaticCallTarget() {
|
||||
final Language::Declaration getStaticCallTarget() {
|
||||
result = this.getCallTarget().(FunctionAddressInstruction).getFunctionSymbol()
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,6 @@ private import implementations.SqLite3
|
||||
private import implementations.PostgreSql
|
||||
private import implementations.System
|
||||
private import implementations.StructuredExceptionHandling
|
||||
private import implementations.ZMQ
|
||||
private import implementations.Win32CommandExecution
|
||||
private import implementations.CA2AEX
|
||||
private import implementations.CComBSTR
|
||||
@@ -58,3 +57,4 @@ private import implementations.CAtlFileMapping
|
||||
private import implementations.CAtlTemporaryFile
|
||||
private import implementations.CRegKey
|
||||
private import implementations.WinHttp
|
||||
private import implementations.Http
|
||||
|
||||
@@ -112,21 +112,3 @@ private class GetsFunction extends DataFlowFunction, ArrayFunction, AliasFunctio
|
||||
|
||||
override predicate hasArrayOutput(int bufParam) { bufParam = 0 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A model for `getc` and similar functions that are flow sources.
|
||||
*/
|
||||
private class GetcSource extends SourceModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
";;false;getc;;;ReturnValue;remote", ";;false;getwc;;;ReturnValue;remote",
|
||||
";;false;_getc_nolock;;;ReturnValue;remote", ";;false;_getwc_nolock;;;ReturnValue;remote",
|
||||
";;false;getch;;;ReturnValue;local", ";;false;_getch;;;ReturnValue;local",
|
||||
";;false;_getwch;;;ReturnValue;local", ";;false;_getch_nolock;;;ReturnValue;local",
|
||||
";;false;_getwch_nolock;;;ReturnValue;local", ";;false;getchar;;;ReturnValue;local",
|
||||
";;false;getwchar;;;ReturnValue;local", ";;false;_getchar_nolock;;;ReturnValue;local",
|
||||
";;false;_getwchar_nolock;;;ReturnValue;local",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
193
cpp/ql/lib/semmle/code/cpp/models/implementations/Http.qll
Normal file
193
cpp/ql/lib/semmle/code/cpp/models/implementations/Http.qll
Normal file
@@ -0,0 +1,193 @@
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.dataflow.FlowSteps
|
||||
private import semmle.code.cpp.dataflow.new.DataFlow
|
||||
|
||||
private class HttpRequest extends Class {
|
||||
HttpRequest() { this.hasGlobalName("_HTTP_REQUEST_V1") }
|
||||
}
|
||||
|
||||
private class HttpRequestInheritingContent extends TaintInheritingContent, DataFlow::FieldContent {
|
||||
HttpRequestInheritingContent() {
|
||||
this.getAField().getDeclaringType() instanceof HttpRequest and
|
||||
(
|
||||
this.getAField().hasName("pRawUrl") and
|
||||
this.getIndirectionIndex() = 2
|
||||
or
|
||||
this.getAField().hasName("CookedUrl") and
|
||||
this.getIndirectionIndex() = 1
|
||||
or
|
||||
this.getAField().hasName("Headers") and
|
||||
this.getIndirectionIndex() = 1
|
||||
or
|
||||
this.getAField().hasName("pEntityChunks") and
|
||||
this.getIndirectionIndex() = 2
|
||||
or
|
||||
this.getAField().hasName("pSslInfo") and
|
||||
this.getIndirectionIndex() = 2
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class HttpCookedUrl extends Class {
|
||||
HttpCookedUrl() { this.hasGlobalName("_HTTP_COOKED_URL") }
|
||||
}
|
||||
|
||||
private class HttpCookedUrlInheritingContent extends TaintInheritingContent, DataFlow::FieldContent {
|
||||
HttpCookedUrlInheritingContent() {
|
||||
this.getAField().getDeclaringType() instanceof HttpCookedUrl and
|
||||
this.getAField().hasName(["pFullUrl", "pHost", "pAbsPath", "pQueryString"]) and
|
||||
this.getIndirectionIndex() = 2
|
||||
}
|
||||
}
|
||||
|
||||
private class HttpRequestHeaders extends Class {
|
||||
HttpRequestHeaders() { this.hasGlobalName("_HTTP_REQUEST_HEADERS") }
|
||||
}
|
||||
|
||||
private class HttpRequestHeadersInheritingContent extends TaintInheritingContent,
|
||||
DataFlow::FieldContent
|
||||
{
|
||||
HttpRequestHeadersInheritingContent() {
|
||||
this.getAField().getDeclaringType() instanceof HttpRequestHeaders and
|
||||
(
|
||||
this.getAField().hasName("KnownHeaders") and
|
||||
this.getIndirectionIndex() = 1
|
||||
or
|
||||
this.getAField().hasName("pUnknownHeaders") and
|
||||
this.getIndirectionIndex() = 2
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class HttpKnownHeader extends Class {
|
||||
HttpKnownHeader() { this.hasGlobalName("_HTTP_KNOWN_HEADER") }
|
||||
}
|
||||
|
||||
private class HttpKnownHeaderInheritingContent extends TaintInheritingContent,
|
||||
DataFlow::FieldContent
|
||||
{
|
||||
HttpKnownHeaderInheritingContent() {
|
||||
this.getAField().getDeclaringType() instanceof HttpKnownHeader and
|
||||
this.getAField().hasName("pRawValue") and
|
||||
this.getIndirectionIndex() = 2
|
||||
}
|
||||
}
|
||||
|
||||
private class HttpUnknownHeader extends Class {
|
||||
HttpUnknownHeader() { this.hasGlobalName("_HTTP_UNKNOWN_HEADER") }
|
||||
}
|
||||
|
||||
private class HttpUnknownHeaderInheritingContent extends TaintInheritingContent,
|
||||
DataFlow::FieldContent
|
||||
{
|
||||
HttpUnknownHeaderInheritingContent() {
|
||||
this.getAField().getDeclaringType() instanceof HttpUnknownHeader and
|
||||
this.getAField().hasName(["pName", "pRawValue"]) and
|
||||
this.getIndirectionIndex() = 2
|
||||
}
|
||||
}
|
||||
|
||||
private class HttpDataChunk extends Class {
|
||||
HttpDataChunk() { this.hasGlobalName("_HTTP_DATA_CHUNK") }
|
||||
}
|
||||
|
||||
private class HttpDataChunkInheritingContent extends TaintInheritingContent, DataFlow::FieldContent {
|
||||
HttpDataChunkInheritingContent() {
|
||||
this.getAField().getDeclaringType().(Union).getDeclaringType() instanceof HttpDataChunk and
|
||||
(
|
||||
this.getAField().hasName("FromMemory") and
|
||||
this.getIndirectionIndex() = 1
|
||||
or
|
||||
this.getAField().hasName("FromFileHandle") and
|
||||
this.getIndirectionIndex() = 1
|
||||
or
|
||||
this.getAField().hasName("FromFragmentCache") and
|
||||
this.getIndirectionIndex() = 1
|
||||
or
|
||||
this.getAField().hasName("FromFragmentCacheEx") and
|
||||
this.getIndirectionIndex() = 1
|
||||
or
|
||||
this.getAField().hasName("Trailers") and
|
||||
this.getIndirectionIndex() = 1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class FromMemory extends Class {
|
||||
FromMemory() {
|
||||
this.getDeclaringType().(Union).getDeclaringType() instanceof HttpDataChunk and
|
||||
this.getAField().hasName("pBuffer")
|
||||
}
|
||||
}
|
||||
|
||||
private class FromMemoryInheritingContent extends TaintInheritingContent, DataFlow::FieldContent {
|
||||
FromMemoryInheritingContent() {
|
||||
this.getAField().getDeclaringType() instanceof FromMemory and
|
||||
this.getAField().hasName("pBuffer") and
|
||||
this.getIndirectionIndex() = 2
|
||||
}
|
||||
}
|
||||
|
||||
private class FromFileHandle extends Class {
|
||||
FromFileHandle() {
|
||||
this.getDeclaringType().(Union).getDeclaringType() instanceof HttpDataChunk and
|
||||
this.getAField().hasName("FileHandle")
|
||||
}
|
||||
}
|
||||
|
||||
private class FromFileHandleInheritingContent extends TaintInheritingContent, DataFlow::FieldContent
|
||||
{
|
||||
FromFileHandleInheritingContent() {
|
||||
this.getAField().getDeclaringType() instanceof FromFileHandle and
|
||||
this.getIndirectionIndex() = 1 and
|
||||
this.getAField().hasName("FileHandle")
|
||||
}
|
||||
}
|
||||
|
||||
private class FromFragmentCacheOrCacheEx extends Class {
|
||||
FromFragmentCacheOrCacheEx() {
|
||||
this.getDeclaringType().(Union).getDeclaringType() instanceof HttpDataChunk and
|
||||
this.getAField().hasName("pFragmentName")
|
||||
}
|
||||
}
|
||||
|
||||
private class FromFragmentCacheInheritingContent extends TaintInheritingContent,
|
||||
DataFlow::FieldContent
|
||||
{
|
||||
FromFragmentCacheInheritingContent() {
|
||||
this.getAField().getDeclaringType() instanceof FromFragmentCacheOrCacheEx and
|
||||
this.getIndirectionIndex() = 2 and
|
||||
this.getAField().hasName("pFragmentName")
|
||||
}
|
||||
}
|
||||
|
||||
private class HttpSslInfo extends Class {
|
||||
HttpSslInfo() { this.hasGlobalName("_HTTP_SSL_INFO") }
|
||||
}
|
||||
|
||||
private class HttpSslInfoInheritingContent extends TaintInheritingContent, DataFlow::FieldContent {
|
||||
HttpSslInfoInheritingContent() {
|
||||
this.getAField().getDeclaringType() instanceof HttpSslInfo and
|
||||
this.getAField().hasName(["pServerCertIssuer", "pServerCertSubject", "pClientCertInfo"]) and
|
||||
this.getIndirectionIndex() = 2
|
||||
}
|
||||
}
|
||||
|
||||
private class HttpSslClientCertInfo extends Class {
|
||||
HttpSslClientCertInfo() { this.hasGlobalName("_HTTP_SSL_CLIENT_CERT_INFO") }
|
||||
}
|
||||
|
||||
private class HttpSslClientCertInfoInheritingContent extends TaintInheritingContent,
|
||||
DataFlow::FieldContent
|
||||
{
|
||||
HttpSslClientCertInfoInheritingContent() {
|
||||
this.getAField().getDeclaringType() instanceof HttpSslClientCertInfo and
|
||||
(
|
||||
this.getAField().hasName("pCertEncoded") and
|
||||
this.getIndirectionIndex() = 2
|
||||
or
|
||||
this.getAField().hasName("Token") and
|
||||
this.getIndirectionIndex() = 1
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/**
|
||||
* Provides implementation classes modeling the ZeroMQ networking library.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.models.interfaces.FlowSource
|
||||
|
||||
/**
|
||||
* Remote flow sources.
|
||||
*/
|
||||
private class ZmqSource extends SourceModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
";;false;zmq_recv;;;Argument[*1];remote", ";;false;zmq_recvmsg;;;Argument[*1];remote",
|
||||
";;false;zmq_msg_recv;;;Argument[*0];remote",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remote flow sinks.
|
||||
*/
|
||||
private class ZmqSinks extends SinkModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
";;false;zmq_send;;;Argument[*1];remote-sink",
|
||||
";;false;zmq_sendmsg;;;Argument[*1];remote-sink",
|
||||
";;false;zmq_msg_send;;;Argument[*0];remote-sink",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flow steps.
|
||||
*/
|
||||
private class ZmqSummaries extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
";;false;zmq_msg_init_data;;;Argument[*1];Argument[*0];taint",
|
||||
";;false;zmq_msg_data;;;Argument[*0];ReturnValue[*];taint",
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -245,6 +245,25 @@ trap_filename(
|
||||
string filename: string ref
|
||||
);
|
||||
|
||||
/**
|
||||
* Gives the tag name for `tag`.
|
||||
* For debugging only.
|
||||
*/
|
||||
tag_name(
|
||||
int tag: @tag,
|
||||
string name: string ref
|
||||
);
|
||||
|
||||
@trap_or_tag = @tag | @trap;
|
||||
|
||||
/**
|
||||
* Gives the name for the source file.
|
||||
*/
|
||||
source_file_name(
|
||||
int sf: @source_file,
|
||||
string name: string ref
|
||||
);
|
||||
|
||||
/**
|
||||
* In `build-mode: none` overlay mode, indicates that `source_file`
|
||||
* (`/path/to/foo.c`) uses the TRAP file `trap_file`; i.e. it is the
|
||||
@@ -252,16 +271,25 @@ trap_filename(
|
||||
* includes, or a template instantiation it transitively uses.
|
||||
*/
|
||||
source_file_uses_trap(
|
||||
string source_file: string ref,
|
||||
int source_file: @source_file ref,
|
||||
int trap_file: @trap ref
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds if there is a definition of `element` in TRAP file `trap_file`.
|
||||
* In `build-mode: none` overlay mode, indicates that the TRAP file
|
||||
* `trap_file` uses tag `tag`.
|
||||
*/
|
||||
in_trap(
|
||||
trap_uses_tag(
|
||||
int trap_file: @trap ref,
|
||||
int tag: @tag ref
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds if there is a definition of `element` in TRAP file or tag `t`.
|
||||
*/
|
||||
in_trap_or_tag(
|
||||
int element: @element ref,
|
||||
int trap_file: @trap ref
|
||||
int t: @trap_or_tag ref
|
||||
);
|
||||
|
||||
pch_uses(
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
class Element extends @element {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Trap extends @trap {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from Element e, Trap trap
|
||||
where in_trap(e, trap)
|
||||
select e, trap
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,22 @@
|
||||
newtype TSourceFile = MkSourceFile(string name) { source_file_uses_trap(name, _) }
|
||||
|
||||
module FreshSourceFile = QlBuiltins::NewEntity<TSourceFile>;
|
||||
|
||||
class SourceFile extends FreshSourceFile::EntityId {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Trap extends @trap {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
query predicate mk_source_file_name(SourceFile source_file, string name) {
|
||||
source_file = FreshSourceFile::map(MkSourceFile(name))
|
||||
}
|
||||
|
||||
query predicate mk_source_file_uses_trap(SourceFile source_file, Trap trap) {
|
||||
exists(string name |
|
||||
source_file_uses_trap(name, trap) and
|
||||
mk_source_file_name(source_file, name)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
description: Add source_file_name
|
||||
compatibility: backwards
|
||||
source_file_uses_trap.rel: run source_files.ql mk_source_file_uses_trap
|
||||
source_file_name.rel: run source_files.ql mk_source_file_name
|
||||
in_trap.rel: delete
|
||||
in_trap_or_tag.rel: run in_trap_or_tag.ql
|
||||
@@ -1,3 +1,15 @@
|
||||
## 1.5.15
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.5.14
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.5.13
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.5.12
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -50,7 +50,7 @@ private newtype TExtractionProblem =
|
||||
/**
|
||||
* Superclass for the extraction problem hierarchy.
|
||||
*/
|
||||
class ExtractionProblem extends TExtractionProblem {
|
||||
abstract class ExtractionProblem extends TExtractionProblem {
|
||||
/** Gets the string representation of the problem. */
|
||||
string toString() { none() }
|
||||
|
||||
@@ -65,6 +65,9 @@ class ExtractionProblem extends TExtractionProblem {
|
||||
|
||||
/** Gets the SARIF severity of this problem. */
|
||||
int getSeverity() { none() }
|
||||
|
||||
/** Gets the `Compilation` the problem is associated with. */
|
||||
abstract Compilation getCompilation();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,6 +99,8 @@ class ExtractionUnrecoverableError extends ExtractionProblem, TCompilationFailed
|
||||
// [errors](https://docs.oasis-open.org/sarif/sarif/v2.1.0/csprd01/sarif-v2.1.0-csprd01.html#_Toc10541338).
|
||||
result = 2
|
||||
}
|
||||
|
||||
override Compilation getCompilation() { result = c }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,6 +127,8 @@ class ExtractionRecoverableWarning extends ExtractionProblem, TReportableWarning
|
||||
// [warnings](https://docs.oasis-open.org/sarif/sarif/v2.1.0/csprd01/sarif-v2.1.0-csprd01.html#_Toc10541338).
|
||||
result = 1
|
||||
}
|
||||
|
||||
override Compilation getCompilation() { result = err.getCompilation() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,4 +155,6 @@ class ExtractionUnknownProblem extends ExtractionProblem, TUnknownProblem {
|
||||
// [warnings](https://docs.oasis-open.org/sarif/sarif/v2.1.0/csprd01/sarif-v2.1.0-csprd01.html#_Toc10541338).
|
||||
result = 1
|
||||
}
|
||||
|
||||
override Compilation getCompilation() { result = err.getCompilation() }
|
||||
}
|
||||
|
||||
@@ -10,7 +10,9 @@ import ExtractionProblems
|
||||
|
||||
from ExtractionProblem warning
|
||||
where
|
||||
warning instanceof ExtractionRecoverableWarning and exists(warning.getFile().getRelativePath())
|
||||
warning instanceof ExtractionRecoverableWarning and
|
||||
exists(warning.getFile().getRelativePath()) and
|
||||
not warning.getCompilation().buildModeNone()
|
||||
or
|
||||
warning instanceof ExtractionUnknownProblem
|
||||
select warning,
|
||||
|
||||
@@ -218,7 +218,9 @@ where
|
||||
// only report if we cannot prove that the result of the
|
||||
// multiplication will be less (resp. greater) than the
|
||||
// maximum (resp. minimum) number we can compute.
|
||||
overflows(me, t1)
|
||||
overflows(me, t1) and
|
||||
// exclude cases where the expression type may not have been extracted accurately
|
||||
not me.getParent().(Call).getTarget().hasAmbiguousReturnType()
|
||||
select me,
|
||||
"Multiplication result may overflow '" + me.getType().toString() + "' before it is converted to '"
|
||||
+ me.getFullyConverted().getType().toString() + "'."
|
||||
|
||||
@@ -168,9 +168,11 @@ where
|
||||
formatOtherArgType(ffc, n, expected, arg, actual) and
|
||||
not actual.getUnspecifiedType().(IntegralType).getSize() = sizeof_IntType()
|
||||
) and
|
||||
// Exclude some cases where we're less confident the result is correct / clear / valuable
|
||||
not arg.isAffectedByMacro() and
|
||||
not arg.isFromUninstantiatedTemplate(_) and
|
||||
not actual.stripType() instanceof ErroneousType and
|
||||
not arg.getType().stripType().(RoutineType).getReturnType() instanceof ErroneousType and
|
||||
not arg.(Call).mayBeFromImplicitlyDeclaredFunction() and
|
||||
// Make sure that the format function definition is consistent
|
||||
count(ffc.getTarget().getFormatParameterIndex()) = 1
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
|
||||
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes
|
||||
|
||||
/** Gets a loop that contains `e`. */
|
||||
Loop getAnEnclosingLoopOfExpr(Expr e) { result = getAnEnclosingLoopOfStmt(e.getEnclosingStmt()) }
|
||||
@@ -45,9 +46,9 @@ private Expr getExpr(DataFlow::Node node) {
|
||||
or
|
||||
result = node.asOperand().getUse().getAst()
|
||||
or
|
||||
result = node.(DataFlow::RawIndirectInstruction).getInstruction().getAst()
|
||||
result = node.(RawIndirectInstruction).getInstruction().getAst()
|
||||
or
|
||||
result = node.(DataFlow::RawIndirectOperand).getOperand().getUse().getAst()
|
||||
result = node.(RawIndirectOperand).getOperand().getUse().getAst()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -208,7 +209,7 @@ class LoopWithAlloca extends Stmt {
|
||||
this.conditionRequiresInequality(va, _, _) and
|
||||
DataFlow::localFlow(result, DataFlow::exprNode(va)) and
|
||||
// Phi nodes will be preceded by nodes that represent actual definitions
|
||||
not result instanceof DataFlow::SsaSynthNode and
|
||||
not result instanceof SsaSynthNode and
|
||||
// A source is outside the loop if it's not inside the loop
|
||||
not exists(Expr e | e = getExpr(result) | this = getAnEnclosingLoopOfExpr(e))
|
||||
)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* allows for a cross-site scripting vulnerability.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @security-severity 6.1
|
||||
* @security-severity 7.8
|
||||
* @precision high
|
||||
* @id cpp/cgi-xss
|
||||
* @tags security
|
||||
|
||||
@@ -23,13 +23,31 @@ import Flow::PathGraph
|
||||
|
||||
predicate isSource(FlowSource source, string sourceType) { sourceType = source.getSourceType() }
|
||||
|
||||
/**
|
||||
* Holds if `f` is a printf-like function or a (possibly nested) wrapper
|
||||
* that forwards a format-string parameter to one.
|
||||
*
|
||||
* Functions that *implement* printf-like behavior (e.g. a custom
|
||||
* `vsnprintf` variant) internally parse the caller-supplied format string
|
||||
* and build small, bounded, local format strings such as `"%d"` or `"%ld"`
|
||||
* for inner `sprintf` calls. Taint that reaches those inner calls via the
|
||||
* parsed format specifier is not exploitable, so sinks inside such
|
||||
* functions should be excluded.
|
||||
*/
|
||||
private predicate isPrintfImplementation(Function f) {
|
||||
f instanceof PrintfLikeFunction
|
||||
or
|
||||
exists(PrintfLikeFunction printf | printf.wrapperFunction(f, _, _))
|
||||
}
|
||||
|
||||
module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node node) { isSource(node, _) }
|
||||
|
||||
predicate isSink(DataFlow::Node node) {
|
||||
exists(PrintfLikeFunction printf |
|
||||
printf.outermostWrapperFunctionCall([node.asExpr(), node.asIndirectExpr()], _)
|
||||
)
|
||||
) and
|
||||
not isPrintfImplementation([node.asExpr(), node.asIndirectExpr()].getEnclosingFunction())
|
||||
}
|
||||
|
||||
private predicate isArithmeticNonCharType(ArithmeticType type) {
|
||||
|
||||
@@ -18,7 +18,8 @@ import IncorrectPointerScalingCommon
|
||||
private predicate isCharSzPtrExpr(Expr e) {
|
||||
exists(PointerType pt | pt = e.getFullyConverted().getUnspecifiedType() |
|
||||
pt.getBaseType() instanceof CharType or
|
||||
pt.getBaseType() instanceof VoidType
|
||||
pt.getBaseType() instanceof VoidType or
|
||||
pt.getBaseType() instanceof ErroneousType // this could be char / void type in a successful compilation
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
48
cpp/ql/src/Telemetry/DatabaseQuality.qll
Normal file
48
cpp/ql/src/Telemetry/DatabaseQuality.qll
Normal file
@@ -0,0 +1,48 @@
|
||||
import cpp
|
||||
import codeql.util.ReportStats
|
||||
|
||||
/** A file that is included in the quality statistics. */
|
||||
private class RelevantFile extends File {
|
||||
RelevantFile() { this.fromSource() and exists(this.getRelativePath()) }
|
||||
}
|
||||
|
||||
module CallTargetStats implements StatsSig {
|
||||
private class RelevantCall extends Call {
|
||||
RelevantCall() { this.getFile() instanceof RelevantFile }
|
||||
}
|
||||
|
||||
// We assume that calls with an implicit target are calls that could not be
|
||||
// resolved. This is accurate in the vast majority of cases, but is inaccurate
|
||||
// for calls that deliberately rely on implicitly declared functions.
|
||||
private predicate hasImplicitTarget(RelevantCall call) {
|
||||
call.getTarget().getADeclarationEntry().isImplicit()
|
||||
}
|
||||
|
||||
int getNumberOfOk() { result = count(RelevantCall call | not hasImplicitTarget(call)) }
|
||||
|
||||
int getNumberOfNotOk() { result = count(RelevantCall call | hasImplicitTarget(call)) }
|
||||
|
||||
string getOkText() { result = "calls with call target" }
|
||||
|
||||
string getNotOkText() { result = "calls with missing call target" }
|
||||
}
|
||||
|
||||
private class SourceExpr extends Expr {
|
||||
SourceExpr() { this.getFile() instanceof RelevantFile }
|
||||
}
|
||||
|
||||
private predicate hasGoodType(Expr e) { not e.getType() instanceof ErroneousType }
|
||||
|
||||
module ExprTypeStats implements StatsSig {
|
||||
int getNumberOfOk() { result = count(SourceExpr e | hasGoodType(e)) }
|
||||
|
||||
int getNumberOfNotOk() { result = count(SourceExpr e | not hasGoodType(e)) }
|
||||
|
||||
string getOkText() { result = "expressions with known type" }
|
||||
|
||||
string getNotOkText() { result = "expressions with unknown type" }
|
||||
}
|
||||
|
||||
module CallTargetStatsReport = ReportStats<CallTargetStats>;
|
||||
|
||||
module ExprTypeStatsReport = ReportStats<ExprTypeStats>;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user