mirror of
https://github.com/github/codeql.git
synced 2026-05-16 12:17:07 +02:00
Compare commits
844 Commits
dataflow/l
...
codeql-cli
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b2e55bc2a | ||
|
|
92d614dbcd | ||
|
|
8c64648520 | ||
|
|
f7174f6e4d | ||
|
|
a6a4ad6400 | ||
|
|
5a2a784ed5 | ||
|
|
32d757f65c | ||
|
|
0d206bd0bb | ||
|
|
671e61f3b3 | ||
|
|
1569621605 | ||
|
|
2bb59e2850 | ||
|
|
174cb7c0e2 | ||
|
|
8886292eec | ||
|
|
4d5c55e533 | ||
|
|
8b5050e427 | ||
|
|
4a7413cf11 | ||
|
|
84d3532a05 | ||
|
|
d6fda1ae72 | ||
|
|
c6f089585a | ||
|
|
459b76ac3f | ||
|
|
a0cb9c19fa | ||
|
|
80bd129621 | ||
|
|
e0e82ad7ad | ||
|
|
96564b7128 | ||
|
|
f56b2c912a | ||
|
|
02752fa051 | ||
|
|
4a0875f78d | ||
|
|
963f084d87 | ||
|
|
80d466ffea | ||
|
|
9c4030ed45 | ||
|
|
f2d457d083 | ||
|
|
ec0c0f1b35 | ||
|
|
b7792d690c | ||
|
|
b54d8dc6bd | ||
|
|
10592bb1c4 | ||
|
|
ed6f873478 | ||
|
|
03fdceb0fd | ||
|
|
c0676f4269 | ||
|
|
eefa066d44 | ||
|
|
b6f0ae0460 | ||
|
|
7092f13584 | ||
|
|
5285fc0698 | ||
|
|
4371433eb6 | ||
|
|
31b9b3adaa | ||
|
|
b9be002e01 | ||
|
|
7463c51026 | ||
|
|
33fe51da4e | ||
|
|
547e232d3b | ||
|
|
c6e936f2c3 | ||
|
|
a1e2e920f4 | ||
|
|
1aa6056bd8 | ||
|
|
801f696bbb | ||
|
|
53503002a1 | ||
|
|
4bf7bbb696 | ||
|
|
bb015cf56d | ||
|
|
f4aa3603ad | ||
|
|
63c8769323 | ||
|
|
9885a1cad1 | ||
|
|
919405e586 | ||
|
|
14c4d949d6 | ||
|
|
8c99ad4fcb | ||
|
|
8a5fc97b06 | ||
|
|
f38602e9fe | ||
|
|
b12a1c078c | ||
|
|
e846855bca | ||
|
|
dbb260dfd2 | ||
|
|
a66de28d8e | ||
|
|
cca27e4c77 | ||
|
|
3d8493757e | ||
|
|
89d20fd086 | ||
|
|
c3ea883b11 | ||
|
|
1420f564a5 | ||
|
|
e89f37df1a | ||
|
|
99cbeb7eb6 | ||
|
|
67052bf9e5 | ||
|
|
ca40b60e62 | ||
|
|
8271ad60c1 | ||
|
|
da7bfb9297 | ||
|
|
4a2c02543c | ||
|
|
041df780c1 | ||
|
|
d22ef44f44 | ||
|
|
e6641e7630 | ||
|
|
70c60868a6 | ||
|
|
395bdd0cec | ||
|
|
6928f7d443 | ||
|
|
309202ef89 | ||
|
|
b50834aee8 | ||
|
|
277c9f4087 | ||
|
|
8ea973f838 | ||
|
|
c113503b41 | ||
|
|
353f1cafe6 | ||
|
|
c654a05998 | ||
|
|
371a11e6da | ||
|
|
0d9e578857 | ||
|
|
fbff4b6e21 | ||
|
|
acc260cc3c | ||
|
|
20f06abe6f | ||
|
|
f07f2b0f4a | ||
|
|
2c0baff76a | ||
|
|
4675426241 | ||
|
|
06b1d8e448 | ||
|
|
952f41e17e | ||
|
|
cc4382c785 | ||
|
|
db18d1046b | ||
|
|
8287cdd7b3 | ||
|
|
b99e234cdc | ||
|
|
3c767b086b | ||
|
|
27d2f9e402 | ||
|
|
0bebfa6e45 | ||
|
|
e377a0e05a | ||
|
|
1e1674a08a | ||
|
|
6b7522fe77 | ||
|
|
52dc79eb7d | ||
|
|
3e5f4b7f89 | ||
|
|
fbeb6f3940 | ||
|
|
395901b8e0 | ||
|
|
86515b0140 | ||
|
|
61cb03ea3f | ||
|
|
8e2beb7410 | ||
|
|
e89cf303e7 | ||
|
|
4bd5cc458b | ||
|
|
c0e55a06e7 | ||
|
|
b57a37479b | ||
|
|
0865397e29 | ||
|
|
8375c49ce1 | ||
|
|
ed22f49cdd | ||
|
|
0a93a31565 | ||
|
|
e1c65aae90 | ||
|
|
43eba85589 | ||
|
|
1e656a49b0 | ||
|
|
b8fd20eb05 | ||
|
|
972cd2b21a | ||
|
|
08ef0dc1f2 | ||
|
|
f56e337a7f | ||
|
|
3420f1f43f | ||
|
|
7db9b7d758 | ||
|
|
012ea4bbf1 | ||
|
|
2a7ce9a0ab | ||
|
|
7f9adbd371 | ||
|
|
2e9f8574a3 | ||
|
|
b0d3c11885 | ||
|
|
4f08fdd232 | ||
|
|
3e0e374783 | ||
|
|
10be890cab | ||
|
|
4d0c53d493 | ||
|
|
14c0bbf531 | ||
|
|
e7ffddd52c | ||
|
|
99bd75c429 | ||
|
|
5d3c9d050d | ||
|
|
824aab884a | ||
|
|
d02f7971a3 | ||
|
|
67745e6332 | ||
|
|
2a33539e01 | ||
|
|
9486e8b734 | ||
|
|
f87024c620 | ||
|
|
7cd344caff | ||
|
|
fbf7e0584f | ||
|
|
6cb0866d0f | ||
|
|
7c1aa84459 | ||
|
|
f7aab2e3e7 | ||
|
|
488903280f | ||
|
|
90fa3ec4ed | ||
|
|
11dedbef1b | ||
|
|
b3896df15c | ||
|
|
a462ec91f5 | ||
|
|
96c1086dfc | ||
|
|
e33f7aa1c7 | ||
|
|
029b567bb7 | ||
|
|
a5521b90fc | ||
|
|
5d79ed6a9e | ||
|
|
a763dd7267 | ||
|
|
986e1cb597 | ||
|
|
a09262b4c6 | ||
|
|
f7874c37c4 | ||
|
|
5b6a4e616c | ||
|
|
f63f80ab68 | ||
|
|
5020e36d0a | ||
|
|
647515bd84 | ||
|
|
e93ce7c7d5 | ||
|
|
7e0e5a3f4e | ||
|
|
4bcc4254c6 | ||
|
|
f8af648524 | ||
|
|
bd56a3564a | ||
|
|
9d4e737bc2 | ||
|
|
3171f38cdd | ||
|
|
06746e540f | ||
|
|
bcb7901758 | ||
|
|
49b569cc4b | ||
|
|
0f3469313f | ||
|
|
47487cca0e | ||
|
|
a6f20a6ac1 | ||
|
|
b8d60cbb13 | ||
|
|
ad7480591b | ||
|
|
5f41b6d3f2 | ||
|
|
13afd6310b | ||
|
|
8feca3d532 | ||
|
|
32bfaa8569 | ||
|
|
de325133c7 | ||
|
|
dbe9f22034 | ||
|
|
b36f3f97ee | ||
|
|
f7896b4c2b | ||
|
|
6f18d69925 | ||
|
|
6d37efc0d8 | ||
|
|
f9d9f9ba62 | ||
|
|
088a3ef15c | ||
|
|
9f6a2e090e | ||
|
|
a7a77a5f23 | ||
|
|
5b50a8270d | ||
|
|
1d0338444a | ||
|
|
5bcc694f6a | ||
|
|
08648f912e | ||
|
|
1c06c4aae0 | ||
|
|
61a4b251c0 | ||
|
|
418ab4b22a | ||
|
|
7acbf1a984 | ||
|
|
072713f771 | ||
|
|
d2de9a2238 | ||
|
|
9ca0fe4cbf | ||
|
|
2810d64b22 | ||
|
|
a9817a0281 | ||
|
|
b05d290bf0 | ||
|
|
fd773603e6 | ||
|
|
9a1c1f4be3 | ||
|
|
50c917d2eb | ||
|
|
c1937ea549 | ||
|
|
1d2e08a3b6 | ||
|
|
62194f5337 | ||
|
|
e673348ed3 | ||
|
|
a2c46749c6 | ||
|
|
1ca57cfb9d | ||
|
|
c71778f1aa | ||
|
|
dbae553146 | ||
|
|
fe28657c7d | ||
|
|
98fd97799c | ||
|
|
1ae174849f | ||
|
|
76318035ff | ||
|
|
9c2366a660 | ||
|
|
875478c1c6 | ||
|
|
aa557cf950 | ||
|
|
a0df33c3ac | ||
|
|
155f1fca85 | ||
|
|
23b18aeca9 | ||
|
|
eca7a88615 | ||
|
|
7db6f7c721 | ||
|
|
faef9dd877 | ||
|
|
41fef0f2b3 | ||
|
|
18c7b18f82 | ||
|
|
89f3b6f8d3 | ||
|
|
38be0e4c0a | ||
|
|
41f21d429b | ||
|
|
5727fda07a | ||
|
|
e8ddb6b180 | ||
|
|
1b224c1ab2 | ||
|
|
1a0442c5a6 | ||
|
|
5790f5d5dc | ||
|
|
2bc89900fb | ||
|
|
5c2a6b8865 | ||
|
|
a8188598b0 | ||
|
|
4e7115538b | ||
|
|
d89678f49f | ||
|
|
5251dc2058 | ||
|
|
d86fea5ba5 | ||
|
|
27738eaacc | ||
|
|
c113a0b5a1 | ||
|
|
60c212bb10 | ||
|
|
ba560f2fe9 | ||
|
|
e96f15d9b4 | ||
|
|
df2e2e503a | ||
|
|
c580046f8c | ||
|
|
9ec9d79b4f | ||
|
|
46abb9083b | ||
|
|
5ef496dd1b | ||
|
|
7402276ec7 | ||
|
|
85778f7fea | ||
|
|
8f886c6603 | ||
|
|
2b0c7a209b | ||
|
|
a4b2ee1205 | ||
|
|
b820b324bd | ||
|
|
216d298780 | ||
|
|
89b2a6b726 | ||
|
|
0e94ee81ae | ||
|
|
2cba97e87d | ||
|
|
1bc1472b0b | ||
|
|
4990f16ba5 | ||
|
|
8dc0688b6f | ||
|
|
593896b40e | ||
|
|
553bc8c13d | ||
|
|
86c7a49264 | ||
|
|
556774edc7 | ||
|
|
92427ab0c1 | ||
|
|
8abd3c4707 | ||
|
|
d779ae5c3e | ||
|
|
24eb65692f | ||
|
|
141259c003 | ||
|
|
7ab5663fa6 | ||
|
|
8d59159691 | ||
|
|
d30f3e2822 | ||
|
|
e42c7452ef | ||
|
|
39b61598e9 | ||
|
|
f7cf5af720 | ||
|
|
36acfeb305 | ||
|
|
6d6f269e6c | ||
|
|
0c6b4cdb8f | ||
|
|
f65f11b404 | ||
|
|
6aa7c93af2 | ||
|
|
fc6c327ab7 | ||
|
|
047e9742a0 | ||
|
|
e1f70a0dec | ||
|
|
5279857d06 | ||
|
|
adbd4d35ed | ||
|
|
a6fc41ec4b | ||
|
|
38eb3e4952 | ||
|
|
2ff2d25784 | ||
|
|
408a38d9fb | ||
|
|
0d45f0efb2 | ||
|
|
2b1caa8a35 | ||
|
|
5a4b720322 | ||
|
|
6f32c4129d | ||
|
|
7f86f8cac7 | ||
|
|
bcc89ecb7c | ||
|
|
196634ecdb | ||
|
|
8c111382ad | ||
|
|
47eb407be9 | ||
|
|
9f09454db9 | ||
|
|
cb0ac61db6 | ||
|
|
d9b278de66 | ||
|
|
f508f8eb83 | ||
|
|
7a86257968 | ||
|
|
d73dcd6753 | ||
|
|
8a01161d4a | ||
|
|
8252e1da02 | ||
|
|
44b1ad52d9 | ||
|
|
8c6e08c94e | ||
|
|
96a796585f | ||
|
|
460df89f28 | ||
|
|
1090164b77 | ||
|
|
28c0e899b7 | ||
|
|
e6302cae53 | ||
|
|
e8981a505d | ||
|
|
77f5168590 | ||
|
|
be5bd1da0a | ||
|
|
82f2c6075f | ||
|
|
88fc7be0a2 | ||
|
|
9ead2dc03c | ||
|
|
93e7202a69 | ||
|
|
5e7cd46117 | ||
|
|
2fb670a27c | ||
|
|
511f791511 | ||
|
|
c3b4447586 | ||
|
|
74aa47a809 | ||
|
|
269ea75036 | ||
|
|
b47e9612eb | ||
|
|
261e0a1a53 | ||
|
|
8fd581dd7e | ||
|
|
d06b5833cf | ||
|
|
f92e8555a6 | ||
|
|
e9a13aec1d | ||
|
|
adafe3e5b0 | ||
|
|
05b6700607 | ||
|
|
c2b342f1a0 | ||
|
|
d5c8dfd88c | ||
|
|
25664d0e53 | ||
|
|
03ab74e07d | ||
|
|
0de6658660 | ||
|
|
e9dff4d68f | ||
|
|
0d02126f12 | ||
|
|
37935eea3b | ||
|
|
d6372aebc7 | ||
|
|
e38b63ebcd | ||
|
|
178da21fb8 | ||
|
|
e6161a5019 | ||
|
|
5eb91fd516 | ||
|
|
68a4ea3be0 | ||
|
|
bded7085f0 | ||
|
|
d38f0eec7b | ||
|
|
3d467b24f8 | ||
|
|
4b0b038513 | ||
|
|
f8d623e905 | ||
|
|
940a99db3b | ||
|
|
fb04e39935 | ||
|
|
7210786721 | ||
|
|
f0045692a7 | ||
|
|
addef2f171 | ||
|
|
c6eaed343d | ||
|
|
7f84cf6d72 | ||
|
|
7baaa2373f | ||
|
|
4c50c083fb | ||
|
|
f2f577f86c | ||
|
|
d8b58f21c7 | ||
|
|
b1b62f2362 | ||
|
|
b32e578580 | ||
|
|
4dab0390c9 | ||
|
|
f3cd61f043 | ||
|
|
fcf16848d2 | ||
|
|
3b4fdb3fc2 | ||
|
|
60155ce205 | ||
|
|
4fa8c6ae65 | ||
|
|
227f9c7c1b | ||
|
|
4d851440b6 | ||
|
|
e7c10c6325 | ||
|
|
86c25d0396 | ||
|
|
28d517da59 | ||
|
|
626b1cef17 | ||
|
|
2e90c80a6f | ||
|
|
143d7e2084 | ||
|
|
faabc9982e | ||
|
|
6e627f6543 | ||
|
|
cdfb085e99 | ||
|
|
d2021b9c65 | ||
|
|
75a3c931d1 | ||
|
|
fa7c6f8b5e | ||
|
|
169671ad93 | ||
|
|
fe2d0b631c | ||
|
|
194f967d74 | ||
|
|
ed67dae850 | ||
|
|
9a07b3c3d4 | ||
|
|
e49a5be62f | ||
|
|
ab9a2bdf9a | ||
|
|
44c94e02fe | ||
|
|
20eaaa5699 | ||
|
|
e81c3483db | ||
|
|
292b29b0e3 | ||
|
|
176e9a425f | ||
|
|
e64f139c98 | ||
|
|
374769873a | ||
|
|
be40085982 | ||
|
|
a85ad4ec29 | ||
|
|
ca424d1e61 | ||
|
|
3fa93e5ca9 | ||
|
|
30581d7c1d | ||
|
|
b6cdae20d8 | ||
|
|
d3dd94433b | ||
|
|
61e00861e5 | ||
|
|
258f72db46 | ||
|
|
37365c746c | ||
|
|
66cf736b4c | ||
|
|
583651ba40 | ||
|
|
248f1c4ebe | ||
|
|
7059fc3e31 | ||
|
|
01cddcc042 | ||
|
|
44126913cd | ||
|
|
f8fff4b18c | ||
|
|
c65ce97ada | ||
|
|
602f52f09b | ||
|
|
f7448f5b43 | ||
|
|
40bb7ec6ef | ||
|
|
f4d6db4c79 | ||
|
|
9b2590ec7a | ||
|
|
50ec400fe4 | ||
|
|
c0474c4e45 | ||
|
|
ed922f6519 | ||
|
|
7c8ca7a4d3 | ||
|
|
a82d267223 | ||
|
|
4effe9e364 | ||
|
|
fa8aba88af | ||
|
|
6776b31c0d | ||
|
|
b7c7a9ee7c | ||
|
|
ae6b7b0277 | ||
|
|
fffeac6a13 | ||
|
|
49e002843e | ||
|
|
bb70bfce43 | ||
|
|
636c047c41 | ||
|
|
0836c3d6a5 | ||
|
|
38fa3c10d6 | ||
|
|
d3e44028ea | ||
|
|
8050b8246b | ||
|
|
10f692b57c | ||
|
|
d3e8292db9 | ||
|
|
ac4121dd6c | ||
|
|
6f3e6edd0e | ||
|
|
7ee0a7b398 | ||
|
|
edb9b47111 | ||
|
|
65be8a8aed | ||
|
|
c80a45f2a3 | ||
|
|
c2b426df76 | ||
|
|
6a6154913b | ||
|
|
36d8a6d05f | ||
|
|
295626d53b | ||
|
|
d8b453fc0d | ||
|
|
5012332bb2 | ||
|
|
86a7c486f9 | ||
|
|
be7aca9780 | ||
|
|
e6887f982e | ||
|
|
ca18005e44 | ||
|
|
c8736e8a3d | ||
|
|
1c2fdc29a3 | ||
|
|
fab29361cb | ||
|
|
6dc599c200 | ||
|
|
932ced4ace | ||
|
|
8c74478ef4 | ||
|
|
82ca369dce | ||
|
|
d6ceb89324 | ||
|
|
f25c16245c | ||
|
|
d828941b7c | ||
|
|
6aa74123af | ||
|
|
43eda58f83 | ||
|
|
afc2d3e6d2 | ||
|
|
09f73d8d6f | ||
|
|
d609c1b7e6 | ||
|
|
fd45e11f4b | ||
|
|
b4af5a61d1 | ||
|
|
596cfcfb42 | ||
|
|
9aede5f433 | ||
|
|
69ad69c38a | ||
|
|
69df07ed12 | ||
|
|
64c45debdb | ||
|
|
9dbf7d1828 | ||
|
|
dcf3b31f62 | ||
|
|
d9a830e008 | ||
|
|
59df4de8af | ||
|
|
cdf43f7118 | ||
|
|
a957e00fe5 | ||
|
|
b4718792d1 | ||
|
|
58faa2d71e | ||
|
|
6344f83e4b | ||
|
|
3f56fc9e89 | ||
|
|
42e0d7ce10 | ||
|
|
5f9b8c05bd | ||
|
|
e5eed2302f | ||
|
|
93f6f042e1 | ||
|
|
aab0d5e9e4 | ||
|
|
52cd7f2c5c | ||
|
|
4d04c5af83 | ||
|
|
9b4b01a442 | ||
|
|
24adbb80c7 | ||
|
|
55121d866c | ||
|
|
6a3e34cc4c | ||
|
|
57973df795 | ||
|
|
745e52f659 | ||
|
|
9a8a27750e | ||
|
|
4fb028cbb2 | ||
|
|
d80aa6fa6a | ||
|
|
cf84c08abf | ||
|
|
4e777561f0 | ||
|
|
f21439a6e3 | ||
|
|
23485f185b | ||
|
|
a69daa0d20 | ||
|
|
ae1ed385f6 | ||
|
|
07847762e1 | ||
|
|
38a5f63437 | ||
|
|
5a18f1ff07 | ||
|
|
63ddd81059 | ||
|
|
26d590a616 | ||
|
|
3909df75dc | ||
|
|
a2c6278282 | ||
|
|
aa4cc72f30 | ||
|
|
dd87b1a9de | ||
|
|
bf824cac0a | ||
|
|
e4f982c12c | ||
|
|
fce13aeb35 | ||
|
|
a398f707fe | ||
|
|
ef3fc5e29f | ||
|
|
9783a11565 | ||
|
|
a709fc6a54 | ||
|
|
d4ec8f650a | ||
|
|
3b01efaf5d | ||
|
|
5bb765d834 | ||
|
|
0fc46f5855 | ||
|
|
2da1d6aaa8 | ||
|
|
54e7db2294 | ||
|
|
1c874d3221 | ||
|
|
e5951516b8 | ||
|
|
22287be5d1 | ||
|
|
7a065746d6 | ||
|
|
e2530cf14f | ||
|
|
358098230c | ||
|
|
a4ccda5fe3 | ||
|
|
2c9bee6208 | ||
|
|
95a8881428 | ||
|
|
28ead4011a | ||
|
|
f1e95a8a1d | ||
|
|
2f3624b625 | ||
|
|
6ed895064f | ||
|
|
6ae979293c | ||
|
|
758092b1d6 | ||
|
|
49eefccde1 | ||
|
|
918b0bfc53 | ||
|
|
307fdc0864 | ||
|
|
e57d8983f5 | ||
|
|
9fc0dc5690 | ||
|
|
874dc83f3f | ||
|
|
81907bc743 | ||
|
|
23bfa8a9bc | ||
|
|
bc784268fd | ||
|
|
791313fbdf | ||
|
|
cc62db796c | ||
|
|
5a0cd2e7d6 | ||
|
|
8cbab0c66e | ||
|
|
d37c816bd9 | ||
|
|
25cd4d4585 | ||
|
|
a0729fc760 | ||
|
|
35cbc162b0 | ||
|
|
85c7e8c221 | ||
|
|
fbaad09179 | ||
|
|
b4c84be3be | ||
|
|
e4eef6791a | ||
|
|
4cca6cff59 | ||
|
|
2282a8184b | ||
|
|
1c305aa8f3 | ||
|
|
1ab50fc62c | ||
|
|
fb050e8b43 | ||
|
|
d9d3e74e8c | ||
|
|
1315a1e9ae | ||
|
|
924467bebe | ||
|
|
c7c6924fda | ||
|
|
6a7fb06086 | ||
|
|
bacc37d886 | ||
|
|
2df565c84f | ||
|
|
28d0ad94d5 | ||
|
|
3673c7c813 | ||
|
|
45458ed72b | ||
|
|
b3668f8183 | ||
|
|
2307df41ed | ||
|
|
e3990b7d04 | ||
|
|
4208f031e3 | ||
|
|
aea7c3fc81 | ||
|
|
e8677b46d5 | ||
|
|
bb8d0b4881 | ||
|
|
b6103e1ef4 | ||
|
|
40b8406d62 | ||
|
|
263a4a9fcb | ||
|
|
f89e80f402 | ||
|
|
05a19adc8f | ||
|
|
d8313fc7b4 | ||
|
|
6b9d9a2c94 | ||
|
|
57e0e2dba1 | ||
|
|
201a5e9faa | ||
|
|
6e33f979c7 | ||
|
|
ef9f3835e5 | ||
|
|
2bfd7326d9 | ||
|
|
c03d69af1e | ||
|
|
b64b837db3 | ||
|
|
1b0f8aa657 | ||
|
|
99494dd540 | ||
|
|
46b4bad510 | ||
|
|
c85a5f9644 | ||
|
|
72a69cfa17 | ||
|
|
e2f17c63d7 | ||
|
|
c5bec1cc7f | ||
|
|
b622c6e9ca | ||
|
|
792231c949 | ||
|
|
ba545ca5d8 | ||
|
|
84f3e6a0d3 | ||
|
|
1c7b5aebb5 | ||
|
|
f2f83f77e0 | ||
|
|
f7ee5f4bf5 | ||
|
|
8377ee545f | ||
|
|
4b83a451bd | ||
|
|
de05aee483 | ||
|
|
ccca0b6ba4 | ||
|
|
4a4552bbc1 | ||
|
|
08bf6d7d30 | ||
|
|
28391d19b6 | ||
|
|
493ea6da31 | ||
|
|
0943389ca1 | ||
|
|
e077bf0732 | ||
|
|
6785b93ed8 | ||
|
|
86672b7e8c | ||
|
|
abd73e16d4 | ||
|
|
74b5ebe4bf | ||
|
|
8be1127e8c | ||
|
|
d9b86f55c8 | ||
|
|
86e95f14e0 | ||
|
|
04072591c4 | ||
|
|
90d7616f14 | ||
|
|
58a1b004ab | ||
|
|
4e97a9554a | ||
|
|
9457bc3548 | ||
|
|
88be4b88ab | ||
|
|
fa52d03194 | ||
|
|
213ce225e0 | ||
|
|
8ae05d8be4 | ||
|
|
c02ad65fdc | ||
|
|
3786ad4277 | ||
|
|
b11388c49b | ||
|
|
6a0a7dda76 | ||
|
|
b84b687b0d | ||
|
|
8137419d93 | ||
|
|
0356cdc3cc | ||
|
|
1a198bfb3a | ||
|
|
75375be7ac | ||
|
|
d178d84ea9 | ||
|
|
0e025abd13 | ||
|
|
a23850940f | ||
|
|
63bc1ef69f | ||
|
|
1304ab7065 | ||
|
|
19d53fba8c | ||
|
|
06b72e5782 | ||
|
|
5745969462 | ||
|
|
409f2c1251 | ||
|
|
459bb6ed04 | ||
|
|
5f9d3d7b09 | ||
|
|
feea29b8fe | ||
|
|
c80bea33e5 | ||
|
|
a28fc8e772 | ||
|
|
7250099f6c | ||
|
|
e081b9a420 | ||
|
|
fcb65534a8 | ||
|
|
ea90698fc1 | ||
|
|
15953bf569 | ||
|
|
7cb9d07f59 | ||
|
|
b1ac02795b | ||
|
|
bed1f25b3f | ||
|
|
f04fd5cdcc | ||
|
|
e3b83bb4b4 | ||
|
|
9bf53f50fa | ||
|
|
631a3770ec | ||
|
|
da5573203e | ||
|
|
42c1937776 | ||
|
|
229d40ad8b | ||
|
|
b10696c155 | ||
|
|
50b9702afd | ||
|
|
6e7256f9d4 | ||
|
|
bb85aa2fc9 | ||
|
|
442968c3c2 | ||
|
|
db38069290 | ||
|
|
a40c1d50b8 | ||
|
|
6fa3ff39a0 | ||
|
|
ba239a1be0 | ||
|
|
bf0fba6c49 | ||
|
|
efb34aea45 | ||
|
|
c8c15a0899 | ||
|
|
b333f523df | ||
|
|
2b0def1ed3 | ||
|
|
52330e834c | ||
|
|
20685918bd | ||
|
|
3fdd35cfdc | ||
|
|
b581723a63 | ||
|
|
176acabd9d | ||
|
|
a31e983e9e | ||
|
|
c86bbbb063 | ||
|
|
4ca6c80eb5 | ||
|
|
0fa3ba6b4d | ||
|
|
90579947cf | ||
|
|
97de35c689 | ||
|
|
788a88aaca | ||
|
|
84234d59b9 | ||
|
|
8512cb44ff | ||
|
|
cf90430ec0 | ||
|
|
d3f5b479f6 | ||
|
|
2df3d1b251 | ||
|
|
a0cac46b46 | ||
|
|
ed44358143 | ||
|
|
02bd204111 | ||
|
|
46da5960ee | ||
|
|
b7098b72a4 | ||
|
|
2bb5603b30 | ||
|
|
e7844e2855 | ||
|
|
df4b596180 | ||
|
|
a66f8209f9 | ||
|
|
67684d1813 | ||
|
|
2d9bc43506 | ||
|
|
b4c84d3d3c | ||
|
|
a65f80ef76 | ||
|
|
37712d2e21 | ||
|
|
ef18a6e562 | ||
|
|
78edafc94c | ||
|
|
c2c6b77b11 | ||
|
|
274d9421a7 | ||
|
|
44e865114a | ||
|
|
d31700cf92 | ||
|
|
dfd8e7d397 | ||
|
|
5f8ff125e9 | ||
|
|
7427a24ca1 | ||
|
|
3215967cbc | ||
|
|
3f0a54c2e8 | ||
|
|
def8d75cb8 | ||
|
|
03292310b6 | ||
|
|
63d84edfae | ||
|
|
00790bf3f4 | ||
|
|
1eabb6cbdd | ||
|
|
2f032ec7b8 | ||
|
|
5ef92a281b | ||
|
|
34361b81eb | ||
|
|
82f09f1f8b | ||
|
|
07c59f7562 | ||
|
|
0298743f2a | ||
|
|
9f0fba16cd | ||
|
|
db1b698689 | ||
|
|
54172774d5 | ||
|
|
a5e13ee71b | ||
|
|
74a6d9812d | ||
|
|
8e6844e4da | ||
|
|
98b7d50e8a | ||
|
|
d9d37dc341 | ||
|
|
94ba6473dd | ||
|
|
f77f2b7ff0 | ||
|
|
a13c70bd11 | ||
|
|
d52a2d67a2 | ||
|
|
ede72b2680 | ||
|
|
e05b126215 | ||
|
|
f827ad8157 | ||
|
|
b9ea78fb32 | ||
|
|
be45e3deed | ||
|
|
04926df6ea | ||
|
|
0d1bd8a9cd | ||
|
|
7b265b2df3 | ||
|
|
7279cc42f8 | ||
|
|
70cf1a57bc | ||
|
|
c2baf0bd6d | ||
|
|
dbd57e3870 | ||
|
|
a4fe728af2 | ||
|
|
514375dbf9 | ||
|
|
b45b40ea4f | ||
|
|
42600c93ff | ||
|
|
71bf900c6c | ||
|
|
a60d9c2ca2 | ||
|
|
449cee91c8 | ||
|
|
4106663d89 | ||
|
|
5e8b1b061f | ||
|
|
7825a46085 | ||
|
|
b239bfabf1 | ||
|
|
ccee34d6d3 | ||
|
|
459d16824e | ||
|
|
ac411f1254 | ||
|
|
0483b8004c | ||
|
|
02a664319a | ||
|
|
e6b775422d | ||
|
|
b1c0e28aff | ||
|
|
05765c4284 | ||
|
|
5d12f7bd30 | ||
|
|
6efb3c69ef | ||
|
|
bd2564ee44 | ||
|
|
581e7f5d3c | ||
|
|
326eb6946e | ||
|
|
5c8c99d31f | ||
|
|
bf11e2cd0f | ||
|
|
9b43b4994e | ||
|
|
7e98d02d56 | ||
|
|
2757b0ba6e | ||
|
|
1e1bbe92a3 | ||
|
|
8b73d4af86 | ||
|
|
1079486032 | ||
|
|
cc6b09da48 | ||
|
|
a99dd69d87 | ||
|
|
de2f8a1577 | ||
|
|
e142818fe5 | ||
|
|
e8aac2be9a | ||
|
|
27ad882f54 | ||
|
|
2bfca21a2f | ||
|
|
9b92ff7e78 | ||
|
|
211cda390d | ||
|
|
cfa1ad65c8 | ||
|
|
49a4318ab1 |
1
.bazelrc
1
.bazelrc
@@ -23,6 +23,5 @@ common --registry=file:///%workspace%/misc/bazel/registry
|
||||
common --registry=https://bcr.bazel.build
|
||||
|
||||
common --@rules_dotnet//dotnet/settings:strict_deps=false
|
||||
common --experimental_isolated_extension_usages
|
||||
|
||||
try-import %workspace%/local.bazelrc
|
||||
|
||||
@@ -8,4 +8,3 @@ common --registry=https://bcr.bazel.build
|
||||
# its implementation packages without providing any code itself.
|
||||
# We either can depend on internal implementation details, or turn of strict deps.
|
||||
common --@rules_dotnet//dotnet/settings:strict_deps=false
|
||||
common --experimental_isolated_extension_usages
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04",
|
||||
"extensions": [
|
||||
"rust-lang.rust-analyzer",
|
||||
"bungcip.better-toml",
|
||||
|
||||
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.101
|
||||
dotnet-version: 9.0.100
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
9
.github/workflows/compile-queries.yml
vendored
9
.github/workflows/compile-queries.yml
vendored
@@ -7,6 +7,11 @@ on:
|
||||
- "rc/*"
|
||||
- "codeql-cli-*"
|
||||
pull_request:
|
||||
paths:
|
||||
- '**.ql'
|
||||
- '**.qll'
|
||||
- '**/qlpack.yml'
|
||||
- '**.dbscheme'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -33,9 +38,9 @@ jobs:
|
||||
# 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 */ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500
|
||||
run: codeql query compile -q -j0 */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 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500
|
||||
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500 --ram=56000
|
||||
|
||||
2
.github/workflows/cpp-swift-analysis.yml
vendored
2
.github/workflows/cpp-swift-analysis.yml
vendored
@@ -48,7 +48,7 @@ jobs:
|
||||
- name: "Build Swift extractor using Bazel"
|
||||
run: |
|
||||
bazel clean --expunge
|
||||
bazel run //swift:create-extractor-pack --nouse_action_cache --noremote_accept_cached --noremote_upload_local_results --spawn_strategy=local
|
||||
bazel run //swift:install --nouse_action_cache --noremote_accept_cached --noremote_upload_local_results --spawn_strategy=local
|
||||
bazel shutdown
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
|
||||
14
.github/workflows/csharp-qltest.yml
vendored
14
.github/workflows/csharp-qltest.yml
vendored
@@ -5,8 +5,10 @@ on:
|
||||
paths:
|
||||
- "csharp/**"
|
||||
- "shared/**"
|
||||
- "misc/bazel/**"
|
||||
- .github/actions/fetch-codeql/action.yml
|
||||
- codeql-workspace.yml
|
||||
- "MODULE.bazel"
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
@@ -14,9 +16,11 @@ on:
|
||||
paths:
|
||||
- "csharp/**"
|
||||
- "shared/**"
|
||||
- "misc/bazel/**"
|
||||
- .github/workflows/csharp-qltest.yml
|
||||
- .github/actions/fetch-codeql/action.yml
|
||||
- codeql-workspace.yml
|
||||
- "MODULE.bazel"
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
@@ -39,14 +43,14 @@ jobs:
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.101
|
||||
dotnet-version: 9.0.100
|
||||
- name: Extractor unit tests
|
||||
run: |
|
||||
dotnet tool restore
|
||||
dotnet test -p:RuntimeFrameworkVersion=8.0.1 extractor/Semmle.Util.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=8.0.1 extractor/Semmle.Extraction.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=8.0.1 autobuilder/Semmle.Autobuild.CSharp.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=8.0.1 autobuilder/Semmle.Autobuild.Cpp.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.0 extractor/Semmle.Util.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.0 extractor/Semmle.Extraction.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.0 autobuilder/Semmle.Autobuild.CSharp.Tests
|
||||
dotnet test -p:RuntimeFrameworkVersion=9.0.0 autobuilder/Semmle.Autobuild.Cpp.Tests
|
||||
shell: bash
|
||||
stubgentest:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -72,7 +72,7 @@ repos:
|
||||
|
||||
- id: rust-codegen
|
||||
name: Run Rust checked in code generation
|
||||
files: ^misc/codegen/|^rust/(schema.py$|codegen/|.*/generated/|ql/lib/(rust\.dbscheme$|codeql/rust/elements)|\.generated.list)
|
||||
files: ^misc/codegen/|^rust/(prefix\.dbscheme|schema/|codegen/|.*/generated/|ql/lib/(rust\.dbscheme$|codeql/rust/elements)|\.generated.list)
|
||||
language: system
|
||||
entry: bazel run //rust/codegen -- --quiet
|
||||
pass_filenames: false
|
||||
|
||||
87
.vscode/tasks.json
vendored
87
.vscode/tasks.json
vendored
@@ -38,6 +38,93 @@
|
||||
"command": "${config:python.pythonPath}",
|
||||
},
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Create query change note",
|
||||
"type": "process",
|
||||
"command": "python3",
|
||||
"args": [
|
||||
"misc/scripts/create-change-note.py",
|
||||
"${input:language}",
|
||||
"src",
|
||||
"${input:name}",
|
||||
"${input:categoryQuery}"
|
||||
],
|
||||
"presentation": {
|
||||
"reveal": "never",
|
||||
"close": true
|
||||
},
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Create library change note",
|
||||
"type": "process",
|
||||
"command": "python3",
|
||||
"args": [
|
||||
"misc/scripts/create-change-note.py",
|
||||
"${input:language}",
|
||||
"lib",
|
||||
"${input:name}",
|
||||
"${input:categoryLibrary}"
|
||||
],
|
||||
"presentation": {
|
||||
"reveal": "never",
|
||||
"close": true
|
||||
},
|
||||
"problemMatcher": []
|
||||
}
|
||||
],
|
||||
"inputs": [
|
||||
{
|
||||
"type": "pickString",
|
||||
"id": "language",
|
||||
"description": "Language",
|
||||
"options":
|
||||
[
|
||||
"go",
|
||||
"java",
|
||||
"javascript",
|
||||
"cpp",
|
||||
"csharp",
|
||||
"python",
|
||||
"ruby",
|
||||
"rust",
|
||||
"swift",
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "promptString",
|
||||
"id": "name",
|
||||
"description": "Short name (kebab-case)"
|
||||
},
|
||||
{
|
||||
"type": "pickString",
|
||||
"id": "categoryQuery",
|
||||
"description": "Category (query change)",
|
||||
"options":
|
||||
[
|
||||
"breaking",
|
||||
"deprecated",
|
||||
"newQuery",
|
||||
"queryMetadata",
|
||||
"majorAnalysis",
|
||||
"minorAnalysis",
|
||||
"fix",
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "pickString",
|
||||
"id": "categoryLibrary",
|
||||
"description": "Category (library change)",
|
||||
"options":
|
||||
[
|
||||
"breaking",
|
||||
"deprecated",
|
||||
"feature",
|
||||
"majorAnalysis",
|
||||
"minorAnalysis",
|
||||
"fix",
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
4
2024-11-25-ts57.md
Normal file
4
2024-11-25-ts57.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: majorAnalysis
|
||||
---
|
||||
* Added support for TypeScript 5.7.
|
||||
@@ -1 +1,5 @@
|
||||
exports_files(["LICENSE"])
|
||||
exports_files([
|
||||
"LICENSE",
|
||||
"Cargo.lock",
|
||||
"Cargo.toml",
|
||||
])
|
||||
|
||||
@@ -42,3 +42,6 @@ MODULE.bazel @github/codeql-ci-reviewers
|
||||
# Misc
|
||||
/misc/scripts/accept-expected-changes-from-ci.py @RasmusWL
|
||||
/misc/scripts/generate-code-scanning-query-list.py @RasmusWL
|
||||
|
||||
# .devcontainer
|
||||
/.devcontainer/ @github/codeql-ci-reviewers
|
||||
|
||||
15
Cargo.lock
generated
15
Cargo.lock
generated
@@ -381,18 +381,22 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argfile",
|
||||
"chrono",
|
||||
"clap",
|
||||
"codeql-extractor",
|
||||
"dunce",
|
||||
"figment",
|
||||
"glob",
|
||||
"itertools 0.13.0",
|
||||
"log",
|
||||
"num-traits",
|
||||
"ra_ap_base_db",
|
||||
"ra_ap_cfg",
|
||||
"ra_ap_hir",
|
||||
"ra_ap_hir_def",
|
||||
"ra_ap_hir_expand",
|
||||
"ra_ap_ide_db",
|
||||
"ra_ap_intern",
|
||||
"ra_ap_load-cargo",
|
||||
"ra_ap_parser",
|
||||
"ra_ap_paths",
|
||||
@@ -402,6 +406,7 @@ dependencies = [
|
||||
"ra_ap_vfs",
|
||||
"rust-extractor-macros",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_with",
|
||||
"stderrlog",
|
||||
"triomphe",
|
||||
@@ -538,6 +543,12 @@ version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1"
|
||||
|
||||
[[package]]
|
||||
name = "dunce"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.13.0"
|
||||
@@ -2032,9 +2043,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.132"
|
||||
version = "1.0.133"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03"
|
||||
checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
|
||||
71
MODULE.bazel
71
MODULE.bazel
@@ -25,50 +25,53 @@ bazel_dep(name = "nlohmann_json", version = "3.11.3", repo_name = "json")
|
||||
bazel_dep(name = "fmt", version = "10.0.0")
|
||||
bazel_dep(name = "rules_kotlin", version = "2.0.0-codeql.1")
|
||||
bazel_dep(name = "gazelle", version = "0.38.0")
|
||||
bazel_dep(name = "rules_dotnet", version = "0.16.1")
|
||||
bazel_dep(name = "rules_dotnet", version = "0.17.4")
|
||||
bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
|
||||
bazel_dep(name = "rules_rust", version = "0.52.2")
|
||||
|
||||
bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True)
|
||||
|
||||
# crate_py but shortened due to Windows file path considerations
|
||||
cp = use_extension(
|
||||
"@rules_rust//crate_universe:extension.bzl",
|
||||
"crate",
|
||||
isolate = True,
|
||||
)
|
||||
cp.from_cargo(
|
||||
name = "py_deps",
|
||||
cargo_lockfile = "//python/extractor/tsg-python:Cargo.lock",
|
||||
manifests = [
|
||||
"//python/extractor/tsg-python:Cargo.toml",
|
||||
"//python/extractor/tsg-python/tsp:Cargo.toml",
|
||||
],
|
||||
)
|
||||
use_repo(cp, "py_deps")
|
||||
# Keep edition and version approximately in sync with internal repo.
|
||||
# the versions there are canonical, the versions here are used for CI in github/codeql, as well as for the vendoring of dependencies.
|
||||
RUST_EDITION = "2021"
|
||||
|
||||
# deps for ruby+rust, but shortened due to windows file paths
|
||||
r = use_extension(
|
||||
"@rules_rust//crate_universe:extension.bzl",
|
||||
"crate",
|
||||
isolate = True,
|
||||
)
|
||||
r.from_cargo(
|
||||
name = "r",
|
||||
cargo_lockfile = "//:Cargo.lock",
|
||||
manifests = [
|
||||
"//:Cargo.toml",
|
||||
"//ruby/extractor:Cargo.toml",
|
||||
"//rust/extractor:Cargo.toml",
|
||||
"//rust/extractor/macros:Cargo.toml",
|
||||
"//rust/ast-generator:Cargo.toml",
|
||||
"//shared/tree-sitter-extractor:Cargo.toml",
|
||||
RUST_VERSION = "1.81.0"
|
||||
|
||||
rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
|
||||
rust.toolchain(
|
||||
edition = RUST_EDITION,
|
||||
# We need those extra target triples so that we can build universal binaries on macos
|
||||
extra_target_triples = [
|
||||
"x86_64-apple-darwin",
|
||||
"aarch64-apple-darwin",
|
||||
],
|
||||
versions = [RUST_VERSION],
|
||||
)
|
||||
use_repo(r, tree_sitter_extractors_deps = "r")
|
||||
use_repo(rust, "rust_toolchains")
|
||||
|
||||
register_toolchains("@rust_toolchains//:all")
|
||||
|
||||
rust_host_tools = use_extension("@rules_rust//rust:extensions.bzl", "rust_host_tools")
|
||||
|
||||
# Don't download a second toolchain as host toolchain, make sure this is the same version as above
|
||||
# The host toolchain is used for vendoring dependencies.
|
||||
rust_host_tools.host_tools(
|
||||
edition = RUST_EDITION,
|
||||
version = RUST_VERSION,
|
||||
)
|
||||
|
||||
# deps for python extractor
|
||||
# keep in sync by running `misc/bazel/3rdparty/update_cargo_deps.sh`
|
||||
py_deps = use_extension("//misc/bazel/3rdparty:py_deps_extension.bzl", "p")
|
||||
use_repo(py_deps, "vendor__anyhow-1.0.44", "vendor__cc-1.0.70", "vendor__clap-2.33.3", "vendor__regex-1.5.5", "vendor__smallvec-1.6.1", "vendor__string-interner-0.12.2", "vendor__thiserror-1.0.29", "vendor__tree-sitter-0.20.4", "vendor__tree-sitter-graph-0.7.0")
|
||||
|
||||
# deps for ruby+rust
|
||||
# keep in sync by running `misc/bazel/3rdparty/update_cargo_deps.sh`
|
||||
tree_sitter_extractors_deps = use_extension("//misc/bazel/3rdparty:tree_sitter_extractors_extension.bzl", "r")
|
||||
use_repo(tree_sitter_extractors_deps, "vendor__anyhow-1.0.93", "vendor__argfile-0.2.1", "vendor__chrono-0.4.38", "vendor__clap-4.5.20", "vendor__dunce-1.0.5", "vendor__encoding-0.2.33", "vendor__figment-0.10.19", "vendor__flate2-1.0.34", "vendor__glob-0.3.1", "vendor__globset-0.4.15", "vendor__itertools-0.10.5", "vendor__itertools-0.13.0", "vendor__lazy_static-1.5.0", "vendor__log-0.4.22", "vendor__num-traits-0.2.19", "vendor__num_cpus-1.16.0", "vendor__proc-macro2-1.0.89", "vendor__quote-1.0.37", "vendor__ra_ap_base_db-0.0.232", "vendor__ra_ap_cfg-0.0.232", "vendor__ra_ap_hir-0.0.232", "vendor__ra_ap_hir_def-0.0.232", "vendor__ra_ap_hir_expand-0.0.232", "vendor__ra_ap_ide_db-0.0.232", "vendor__ra_ap_intern-0.0.232", "vendor__ra_ap_load-cargo-0.0.232", "vendor__ra_ap_parser-0.0.232", "vendor__ra_ap_paths-0.0.232", "vendor__ra_ap_project_model-0.0.232", "vendor__ra_ap_span-0.0.232", "vendor__ra_ap_syntax-0.0.232", "vendor__ra_ap_vfs-0.0.232", "vendor__rand-0.8.5", "vendor__rayon-1.10.0", "vendor__regex-1.11.1", "vendor__serde-1.0.214", "vendor__serde_json-1.0.133", "vendor__serde_with-3.11.0", "vendor__stderrlog-0.6.0", "vendor__syn-2.0.87", "vendor__tracing-0.1.40", "vendor__tracing-subscriber-0.3.18", "vendor__tree-sitter-0.24.4", "vendor__tree-sitter-embedded-template-0.23.2", "vendor__tree-sitter-json-0.24.8", "vendor__tree-sitter-ql-0.23.1", "vendor__tree-sitter-ruby-0.23.1", "vendor__triomphe-0.1.14", "vendor__ungrammar-1.16.1")
|
||||
|
||||
dotnet = use_extension("@rules_dotnet//dotnet:extensions.bzl", "dotnet")
|
||||
dotnet.toolchain(dotnet_version = "8.0.101")
|
||||
dotnet.toolchain(dotnet_version = "9.0.100")
|
||||
use_repo(dotnet, "dotnet_toolchains")
|
||||
|
||||
register_toolchains("@dotnet_toolchains//:all")
|
||||
|
||||
@@ -2,19 +2,8 @@ load("//misc/bazel:pkg.bzl", "codeql_pack")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
[
|
||||
codeql_pack(
|
||||
name = "-".join(parts),
|
||||
srcs = [
|
||||
"//actions/extractor",
|
||||
],
|
||||
pack_prefix = "/".join(parts),
|
||||
)
|
||||
for parts in (
|
||||
[
|
||||
"experimental",
|
||||
"actions",
|
||||
],
|
||||
["actions"],
|
||||
)
|
||||
]
|
||||
codeql_pack(
|
||||
name = "actions",
|
||||
srcs = ["//actions/extractor"],
|
||||
experimental = True,
|
||||
)
|
||||
|
||||
@@ -1,58 +1,4 @@
|
||||
{
|
||||
"DataFlow Java/C++/C#/Go/Python/Ruby/Swift Legacy Configuration": [
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl1.qll",
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll",
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll",
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll",
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll",
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl1.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl1.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl1.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll",
|
||||
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl1.qll",
|
||||
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl2.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl1.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl1.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll",
|
||||
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl1.qll"
|
||||
],
|
||||
"TaintTracking Legacy Configuration Java/C++/C#/Go/Python/Ruby/Swift": [
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll",
|
||||
"go/ql/lib/semmle/go/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||
"go/ql/lib/semmle/go/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/tainttracking3/TaintTrackingImpl.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking2/TaintTrackingImpl.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking3/TaintTrackingImpl.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking4/TaintTrackingImpl.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||
"swift/ql/lib/codeql/swift/dataflow/internal/tainttracking1/TaintTrackingImpl.qll"
|
||||
],
|
||||
"SsaReadPosition Java/C#": [
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll"
|
||||
|
||||
2339
cpp/downgrades/f0156f5f88ab5967c79162012c20f30600ca5ebf/old.dbscheme
Normal file
2339
cpp/downgrades/f0156f5f88ab5967c79162012c20f30600ca5ebf/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
description: Implement compilation_build_mode/2
|
||||
compatibility: full
|
||||
compilation_build_mode.rel: delete
|
||||
@@ -1,3 +1,17 @@
|
||||
## 3.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* Deleted the old deprecated data flow API that was based on extending a configuration class. See https://github.blog/changelog/2023-08-14-new-dataflow-api-for-writing-custom-codeql-queries for instructions on migrating your queries to use the new API.
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The `NonThrowing` class (`semmle.code.cpp.models.interfaces.NonThrowing`) has been deprecated. Please use the `NonCppThrowingFunction` class instead.
|
||||
|
||||
## 2.1.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 2.1.0
|
||||
|
||||
### New Features
|
||||
|
||||
3
cpp/ql/lib/change-notes/released/2.1.1.md
Normal file
3
cpp/ql/lib/change-notes/released/2.1.1.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 2.1.1
|
||||
|
||||
No user-facing changes.
|
||||
9
cpp/ql/lib/change-notes/released/3.0.0.md
Normal file
9
cpp/ql/lib/change-notes/released/3.0.0.md
Normal file
@@ -0,0 +1,9 @@
|
||||
## 3.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* Deleted the old deprecated data flow API that was based on extending a configuration class. See https://github.blog/changelog/2023-08-14-new-dataflow-api-for-writing-custom-codeql-queries for instructions on migrating your queries to use the new API.
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The `NonThrowing` class (`semmle.code.cpp.models.interfaces.NonThrowing`) has been deprecated. Please use the `NonCppThrowingFunction` class instead.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 2.1.0
|
||||
lastReleaseVersion: 3.0.0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 2.1.1-dev
|
||||
version: 3.0.0
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -112,4 +112,7 @@ class Compilation extends @compilation {
|
||||
* termination, but crashing due to something like a segfault is not.
|
||||
*/
|
||||
predicate normalTermination() { compilation_finished(this, _, _) }
|
||||
|
||||
/** Holds if this compilation was compiled using the "none" build mode. */
|
||||
predicate buildModeNone() { compilation_build_mode(this, 0) }
|
||||
}
|
||||
|
||||
@@ -29,5 +29,5 @@ deprecated module DataFlow {
|
||||
private import semmle.code.cpp.dataflow.internal.DataFlowImplSpecific
|
||||
private import codeql.dataflow.DataFlow
|
||||
import DataFlowMake<Location, CppOldDataFlow>
|
||||
import semmle.code.cpp.dataflow.internal.DataFlowImpl1
|
||||
import Public
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
/**
|
||||
* Provides a `DataFlow2` module, which is a copy of the `DataFlow` module. Use
|
||||
* this class when data-flow configurations must depend on each other. Two
|
||||
* classes extending `DataFlow::Configuration` should never depend on each
|
||||
* other, but one of them should instead depend on a
|
||||
* `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a
|
||||
* `DataFlow4::Configuration`.
|
||||
*
|
||||
* See `semmle.code.cpp.dataflow.DataFlow` for the full documentation.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `semmle.code.cpp.dataflow.new.DataFlow2` instead.
|
||||
*
|
||||
* Provides classes for performing local (intra-procedural) and
|
||||
* global (inter-procedural) data flow analyses.
|
||||
*/
|
||||
deprecated module DataFlow2 {
|
||||
import semmle.code.cpp.dataflow.internal.DataFlowImpl2
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
/**
|
||||
* Provides a `DataFlow3` module, which is a copy of the `DataFlow` module. Use
|
||||
* this class when data-flow configurations must depend on each other. Two
|
||||
* classes extending `DataFlow::Configuration` should never depend on each
|
||||
* other, but one of them should instead depend on a
|
||||
* `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a
|
||||
* `DataFlow4::Configuration`.
|
||||
*
|
||||
* See `semmle.code.cpp.dataflow.DataFlow` for the full documentation.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `semmle.code.cpp.dataflow.new.DataFlow3` instead.
|
||||
*
|
||||
* Provides classes for performing local (intra-procedural) and
|
||||
* global (inter-procedural) data flow analyses.
|
||||
*/
|
||||
deprecated module DataFlow3 {
|
||||
import semmle.code.cpp.dataflow.internal.DataFlowImpl3
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
/**
|
||||
* Provides a `DataFlow4` module, which is a copy of the `DataFlow` module. Use
|
||||
* this class when data-flow configurations must depend on each other. Two
|
||||
* classes extending `DataFlow::Configuration` should never depend on each
|
||||
* other, but one of them should instead depend on a
|
||||
* `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a
|
||||
* `DataFlow4::Configuration`.
|
||||
*
|
||||
* See `semmle.code.cpp.dataflow.DataFlow` for the full documentation.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `semmle.code.cpp.dataflow.new.DataFlow4` instead.
|
||||
*
|
||||
* Provides classes for performing local (intra-procedural) and
|
||||
* global (inter-procedural) data flow analyses.
|
||||
*/
|
||||
deprecated module DataFlow4 {
|
||||
import semmle.code.cpp.dataflow.internal.DataFlowImpl4
|
||||
}
|
||||
@@ -793,28 +793,27 @@ private Element interpretElement0(
|
||||
) {
|
||||
(
|
||||
// Non-member functions
|
||||
elementSpec(namespace, type, subtypes, name, signature, _) and
|
||||
funcHasQualifiedName(result, namespace, name) and
|
||||
subtypes = false and
|
||||
type = "" and
|
||||
(
|
||||
elementSpecMatchesSignature(result, namespace, type, subtypes, name, signature)
|
||||
or
|
||||
signature = "" and
|
||||
elementSpec(namespace, type, subtypes, name, "", _) and
|
||||
funcHasQualifiedName(result, namespace, name)
|
||||
elementSpec(namespace, type, subtypes, name, signature, _)
|
||||
)
|
||||
or
|
||||
// Member functions
|
||||
exists(Class namedClass, Class classWithMethod |
|
||||
hasClassAndName(classWithMethod, result, name) and
|
||||
classHasQualifiedName(namedClass, namespace, type)
|
||||
|
|
||||
(
|
||||
elementSpecMatchesSignature(result, namespace, type, subtypes, name, signature) and
|
||||
hasClassAndName(classWithMethod, result, name)
|
||||
elementSpecMatchesSignature(result, namespace, type, subtypes, name, signature)
|
||||
or
|
||||
signature = "" and
|
||||
elementSpec(namespace, type, subtypes, name, "", _) and
|
||||
hasClassAndName(classWithMethod, result, name)
|
||||
elementSpec(namespace, type, subtypes, name, "", _)
|
||||
) and
|
||||
classHasQualifiedName(namedClass, namespace, type) and
|
||||
(
|
||||
// member declared in the named type or a subtype of it
|
||||
subtypes = true and
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
/**
|
||||
* DEPRECATED: Recursion through `DataFlow::Configuration` is impossible in
|
||||
* any supported tooling. There is no need for this module because it's
|
||||
* impossible to accidentally depend on recursion through
|
||||
* `DataFlow::Configuration` in current releases.
|
||||
*
|
||||
* When this module is imported, recursive use of `DataFlow::Configuration` is
|
||||
* disallowed. Importing this module will guarantee the absence of such
|
||||
* recursion, which is unsupported and will be unconditionally disallowed in a
|
||||
* future release.
|
||||
*
|
||||
* Recursive use of `DataFlow{2..4}::Configuration` is always disallowed, so no
|
||||
* import is needed for those.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
private import semmle.code.cpp.dataflow.DataFlow
|
||||
|
||||
/**
|
||||
* This class exists to prevent mutual recursion between the user-overridden
|
||||
* member predicates of `Configuration` and the rest of the data-flow library.
|
||||
* Good performance cannot be guaranteed in the presence of such recursion, so
|
||||
* it should be replaced by using more than one copy of the data flow library.
|
||||
* Four copies are available: `DataFlow` through `DataFlow4`.
|
||||
*/
|
||||
abstract private class ConfigurationRecursionPrevention extends DataFlow::Configuration {
|
||||
bindingset[this]
|
||||
ConfigurationRecursionPrevention() { any() }
|
||||
|
||||
override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) {
|
||||
strictcount(DataFlow::Node n | this.isSource(n)) < 0
|
||||
or
|
||||
strictcount(DataFlow::Node n | this.isSink(n)) < 0
|
||||
or
|
||||
strictcount(DataFlow::Node n1, DataFlow::Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
|
||||
or
|
||||
super.hasFlow(source, sink)
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.dataflow.DataFlow
|
||||
import semmle.code.cpp.dataflow.DataFlow2
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `semmle.code.cpp.dataflow.new.TaintTracking` instead.
|
||||
@@ -25,10 +24,9 @@ import semmle.code.cpp.dataflow.DataFlow2
|
||||
* global (inter-procedural) taint-tracking analyses.
|
||||
*/
|
||||
deprecated module TaintTracking {
|
||||
import semmle.code.cpp.dataflow.internal.tainttracking1.TaintTrackingParameter::Public
|
||||
import semmle.code.cpp.dataflow.internal.TaintTrackingUtil
|
||||
private import semmle.code.cpp.dataflow.internal.DataFlowImplSpecific
|
||||
private import semmle.code.cpp.dataflow.internal.TaintTrackingImplSpecific
|
||||
private import codeql.dataflow.TaintTracking
|
||||
import TaintFlowMake<Location, CppOldDataFlow, CppOldTaintTracking>
|
||||
import semmle.code.cpp.dataflow.internal.tainttracking1.TaintTrackingImpl
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
/**
|
||||
* Provides a `TaintTracking2` module, which is a copy of the `TaintTracking`
|
||||
* module. Use this class when data-flow configurations or taint-tracking
|
||||
* configurations must depend on each other. Two classes extending
|
||||
* `DataFlow::Configuration` should never depend on each other, but one of them
|
||||
* should instead depend on a `DataFlow2::Configuration`, a
|
||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`. The
|
||||
* `TaintTracking::Configuration` class extends `DataFlow::Configuration`, and
|
||||
* `TaintTracking2::Configuration` extends `DataFlow2::Configuration`.
|
||||
*
|
||||
* See `semmle.code.cpp.dataflow.TaintTracking` for the full documentation.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `semmle.code.cpp.dataflow.new.TaintTracking2` instead.
|
||||
*
|
||||
* Provides classes for performing local (intra-procedural) and
|
||||
* global (inter-procedural) taint-tracking analyses.
|
||||
*/
|
||||
deprecated module TaintTracking2 {
|
||||
import semmle.code.cpp.dataflow.internal.tainttracking2.TaintTrackingImpl
|
||||
}
|
||||
@@ -1,361 +0,0 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
||||
* flow library.
|
||||
*/
|
||||
|
||||
private import DataFlowImplCommon
|
||||
private import DataFlowImplSpecific::Private
|
||||
import DataFlowImplSpecific::Public
|
||||
private import DataFlowImpl
|
||||
import DataFlowImplCommonPublic
|
||||
deprecated import FlowStateString
|
||||
private import codeql.util.Unit
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* A configuration of interprocedural data flow analysis. This defines
|
||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
||||
* use of the global data flow library must define its own unique extension
|
||||
* of this abstract class. To create a configuration, extend this class with
|
||||
* a subclass whose characteristic predicate is a unique singleton string.
|
||||
* For example, write
|
||||
*
|
||||
* ```ql
|
||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
* // Optionally override `isBarrier`.
|
||||
* // Optionally override `isAdditionalFlowStep`.
|
||||
* }
|
||||
* ```
|
||||
* Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and
|
||||
* the edges are those data-flow steps that preserve the value of the node
|
||||
* along with any additional edges defined by `isAdditionalFlowStep`.
|
||||
* Specifying nodes in `isBarrier` will remove those nodes from the graph, and
|
||||
* specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going
|
||||
* and/or out-going edges from those nodes, respectively.
|
||||
*
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
* Multiple configurations can coexist, but two classes extending
|
||||
* `DataFlow::Configuration` should never depend on each other. One of them
|
||||
* should instead depend on a `DataFlow2::Configuration`, a
|
||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
|
||||
*/
|
||||
abstract deprecated class Configuration extends string {
|
||||
bindingset[this]
|
||||
Configuration() { any() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source.
|
||||
*/
|
||||
predicate isSource(Node source) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source with the given initial
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSource(Node source, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink.
|
||||
*/
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
||||
*/
|
||||
predicate isSink(Node sink, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited. This completely removes
|
||||
* `node` from the data flow graph.
|
||||
*/
|
||||
predicate isBarrier(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isBarrier(Node node, FlowState state) { none() }
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
predicate isBarrierIn(Node node) { none() }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
int fieldFlowBranchLimit() { result = 2 }
|
||||
|
||||
/**
|
||||
* Gets a data flow configuration feature to add restrictions to the set of
|
||||
* valid flow paths.
|
||||
*
|
||||
* - `FeatureHasSourceCallContext`:
|
||||
* Assume that sources have some existing call context to disallow
|
||||
* conflicting return-flow directly following the source.
|
||||
* - `FeatureHasSinkCallContext`:
|
||||
* Assume that sinks have some existing call context to disallow
|
||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
||||
* - `FeatureEqualSourceSinkCallContext`:
|
||||
* Implies both of the above and additionally ensures that the entire flow
|
||||
* path preserves the call context.
|
||||
*
|
||||
* These features are generally not relevant for typical end-to-end data flow
|
||||
* queries, but should only be used for constructing paths that need to
|
||||
* somehow be pluggable in another path context.
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlow(Node source, Node sink) { hasFlow(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (for example in a `path-problem` query).
|
||||
*/
|
||||
predicate includeHiddenNodes() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* This class exists to prevent mutual recursion between the user-overridden
|
||||
* member predicates of `Configuration` and the rest of the data-flow library.
|
||||
* Good performance cannot be guaranteed in the presence of such recursion, so
|
||||
* it should be replaced by using more than one copy of the data flow library.
|
||||
*/
|
||||
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
|
||||
bindingset[this]
|
||||
ConfigurationRecursionPrevention() { any() }
|
||||
|
||||
override predicate hasFlow(Node source, Node sink) {
|
||||
strictcount(Node n | this.isSource(n)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSource(n, _)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSink(n)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSink(n, _)) < 0
|
||||
or
|
||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
|
||||
or
|
||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0
|
||||
or
|
||||
super.hasFlow(source, sink)
|
||||
}
|
||||
}
|
||||
|
||||
deprecated private FlowState relevantState(Configuration config) {
|
||||
config.isSource(_, result) or
|
||||
config.isSink(_, result) or
|
||||
config.isBarrier(_, result) or
|
||||
config.isAdditionalFlowStep(_, result, _, _) or
|
||||
config.isAdditionalFlowStep(_, _, _, result)
|
||||
}
|
||||
|
||||
private newtype TConfigState =
|
||||
deprecated TMkConfigState(Configuration config, FlowState state) {
|
||||
state = relevantState(config) or state instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
|
||||
|
||||
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
|
||||
|
||||
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
|
||||
|
||||
deprecated private module Config implements FullStateConfigSig {
|
||||
class FlowState = TConfigState;
|
||||
|
||||
predicate isSource(Node source, FlowState state) {
|
||||
getConfig(state).isSource(source, getState(state))
|
||||
or
|
||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
predicate isSink(Node sink, FlowState state) {
|
||||
getConfig(state).isSink(sink, getState(state))
|
||||
or
|
||||
getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isBarrier(Node node) { none() }
|
||||
|
||||
predicate isBarrier(Node node, FlowState state) {
|
||||
getConfig(state).isBarrier(node, getState(state)) or
|
||||
getConfig(state).isBarrier(node)
|
||||
}
|
||||
|
||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
||||
|
||||
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
|
||||
|
||||
predicate isBarrierIn(Node node, FlowState state) { none() }
|
||||
|
||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
||||
singleConfiguration() and
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2) and
|
||||
model = ""
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
Node node1, FlowState state1, Node node2, FlowState state2, string model
|
||||
) {
|
||||
getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and
|
||||
getConfig(state2) = getConfig(state1) and
|
||||
model = ""
|
||||
or
|
||||
not singleConfiguration() and
|
||||
getConfig(state1).isAdditionalFlowStep(node1, node2) and
|
||||
state2 = state1 and
|
||||
model = ""
|
||||
}
|
||||
|
||||
predicate allowImplicitRead(Node node, ContentSet c) {
|
||||
any(Configuration config).allowImplicitRead(node, c)
|
||||
}
|
||||
|
||||
predicate neverSkip(Node node) { none() }
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
int accessPathLimit() { result = 5 }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { none() }
|
||||
}
|
||||
|
||||
deprecated private import Impl<Config> as I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
||||
*/
|
||||
deprecated class PathNode instanceof I::PathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
final string toString() { result = super.toString() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
final string toStringWithContext() { result = super.toStringWithContext() }
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
final predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
final Node getNode() { result = super.getNode() }
|
||||
|
||||
/** Gets the `FlowState` of this node. */
|
||||
deprecated final FlowState getState() { result = getState(super.getState()) }
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() { result = super.getASuccessor() }
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { super.isSourceGroup(group) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
deprecated module PathGraph = I::PathGraph;
|
||||
|
||||
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
source0.getNode() = source and
|
||||
sink0.getNode() = sink
|
||||
)
|
||||
}
|
||||
|
||||
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
deprecated predicate flowsTo = hasFlow/3;
|
||||
@@ -1,361 +0,0 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
||||
* flow library.
|
||||
*/
|
||||
|
||||
private import DataFlowImplCommon
|
||||
private import DataFlowImplSpecific::Private
|
||||
import DataFlowImplSpecific::Public
|
||||
private import DataFlowImpl
|
||||
import DataFlowImplCommonPublic
|
||||
deprecated import FlowStateString
|
||||
private import codeql.util.Unit
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* A configuration of interprocedural data flow analysis. This defines
|
||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
||||
* use of the global data flow library must define its own unique extension
|
||||
* of this abstract class. To create a configuration, extend this class with
|
||||
* a subclass whose characteristic predicate is a unique singleton string.
|
||||
* For example, write
|
||||
*
|
||||
* ```ql
|
||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
* // Optionally override `isBarrier`.
|
||||
* // Optionally override `isAdditionalFlowStep`.
|
||||
* }
|
||||
* ```
|
||||
* Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and
|
||||
* the edges are those data-flow steps that preserve the value of the node
|
||||
* along with any additional edges defined by `isAdditionalFlowStep`.
|
||||
* Specifying nodes in `isBarrier` will remove those nodes from the graph, and
|
||||
* specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going
|
||||
* and/or out-going edges from those nodes, respectively.
|
||||
*
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
* Multiple configurations can coexist, but two classes extending
|
||||
* `DataFlow::Configuration` should never depend on each other. One of them
|
||||
* should instead depend on a `DataFlow2::Configuration`, a
|
||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
|
||||
*/
|
||||
abstract deprecated class Configuration extends string {
|
||||
bindingset[this]
|
||||
Configuration() { any() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source.
|
||||
*/
|
||||
predicate isSource(Node source) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source with the given initial
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSource(Node source, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink.
|
||||
*/
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
||||
*/
|
||||
predicate isSink(Node sink, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited. This completely removes
|
||||
* `node` from the data flow graph.
|
||||
*/
|
||||
predicate isBarrier(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isBarrier(Node node, FlowState state) { none() }
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
predicate isBarrierIn(Node node) { none() }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
int fieldFlowBranchLimit() { result = 2 }
|
||||
|
||||
/**
|
||||
* Gets a data flow configuration feature to add restrictions to the set of
|
||||
* valid flow paths.
|
||||
*
|
||||
* - `FeatureHasSourceCallContext`:
|
||||
* Assume that sources have some existing call context to disallow
|
||||
* conflicting return-flow directly following the source.
|
||||
* - `FeatureHasSinkCallContext`:
|
||||
* Assume that sinks have some existing call context to disallow
|
||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
||||
* - `FeatureEqualSourceSinkCallContext`:
|
||||
* Implies both of the above and additionally ensures that the entire flow
|
||||
* path preserves the call context.
|
||||
*
|
||||
* These features are generally not relevant for typical end-to-end data flow
|
||||
* queries, but should only be used for constructing paths that need to
|
||||
* somehow be pluggable in another path context.
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlow(Node source, Node sink) { hasFlow(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (for example in a `path-problem` query).
|
||||
*/
|
||||
predicate includeHiddenNodes() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* This class exists to prevent mutual recursion between the user-overridden
|
||||
* member predicates of `Configuration` and the rest of the data-flow library.
|
||||
* Good performance cannot be guaranteed in the presence of such recursion, so
|
||||
* it should be replaced by using more than one copy of the data flow library.
|
||||
*/
|
||||
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
|
||||
bindingset[this]
|
||||
ConfigurationRecursionPrevention() { any() }
|
||||
|
||||
override predicate hasFlow(Node source, Node sink) {
|
||||
strictcount(Node n | this.isSource(n)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSource(n, _)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSink(n)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSink(n, _)) < 0
|
||||
or
|
||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
|
||||
or
|
||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0
|
||||
or
|
||||
super.hasFlow(source, sink)
|
||||
}
|
||||
}
|
||||
|
||||
deprecated private FlowState relevantState(Configuration config) {
|
||||
config.isSource(_, result) or
|
||||
config.isSink(_, result) or
|
||||
config.isBarrier(_, result) or
|
||||
config.isAdditionalFlowStep(_, result, _, _) or
|
||||
config.isAdditionalFlowStep(_, _, _, result)
|
||||
}
|
||||
|
||||
private newtype TConfigState =
|
||||
deprecated TMkConfigState(Configuration config, FlowState state) {
|
||||
state = relevantState(config) or state instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
|
||||
|
||||
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
|
||||
|
||||
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
|
||||
|
||||
deprecated private module Config implements FullStateConfigSig {
|
||||
class FlowState = TConfigState;
|
||||
|
||||
predicate isSource(Node source, FlowState state) {
|
||||
getConfig(state).isSource(source, getState(state))
|
||||
or
|
||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
predicate isSink(Node sink, FlowState state) {
|
||||
getConfig(state).isSink(sink, getState(state))
|
||||
or
|
||||
getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isBarrier(Node node) { none() }
|
||||
|
||||
predicate isBarrier(Node node, FlowState state) {
|
||||
getConfig(state).isBarrier(node, getState(state)) or
|
||||
getConfig(state).isBarrier(node)
|
||||
}
|
||||
|
||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
||||
|
||||
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
|
||||
|
||||
predicate isBarrierIn(Node node, FlowState state) { none() }
|
||||
|
||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
||||
singleConfiguration() and
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2) and
|
||||
model = ""
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
Node node1, FlowState state1, Node node2, FlowState state2, string model
|
||||
) {
|
||||
getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and
|
||||
getConfig(state2) = getConfig(state1) and
|
||||
model = ""
|
||||
or
|
||||
not singleConfiguration() and
|
||||
getConfig(state1).isAdditionalFlowStep(node1, node2) and
|
||||
state2 = state1 and
|
||||
model = ""
|
||||
}
|
||||
|
||||
predicate allowImplicitRead(Node node, ContentSet c) {
|
||||
any(Configuration config).allowImplicitRead(node, c)
|
||||
}
|
||||
|
||||
predicate neverSkip(Node node) { none() }
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
int accessPathLimit() { result = 5 }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { none() }
|
||||
}
|
||||
|
||||
deprecated private import Impl<Config> as I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
||||
*/
|
||||
deprecated class PathNode instanceof I::PathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
final string toString() { result = super.toString() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
final string toStringWithContext() { result = super.toStringWithContext() }
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
final predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
final Node getNode() { result = super.getNode() }
|
||||
|
||||
/** Gets the `FlowState` of this node. */
|
||||
deprecated final FlowState getState() { result = getState(super.getState()) }
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() { result = super.getASuccessor() }
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { super.isSourceGroup(group) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
deprecated module PathGraph = I::PathGraph;
|
||||
|
||||
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
source0.getNode() = source and
|
||||
sink0.getNode() = sink
|
||||
)
|
||||
}
|
||||
|
||||
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
deprecated predicate flowsTo = hasFlow/3;
|
||||
@@ -1,361 +0,0 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
||||
* flow library.
|
||||
*/
|
||||
|
||||
private import DataFlowImplCommon
|
||||
private import DataFlowImplSpecific::Private
|
||||
import DataFlowImplSpecific::Public
|
||||
private import DataFlowImpl
|
||||
import DataFlowImplCommonPublic
|
||||
deprecated import FlowStateString
|
||||
private import codeql.util.Unit
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* A configuration of interprocedural data flow analysis. This defines
|
||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
||||
* use of the global data flow library must define its own unique extension
|
||||
* of this abstract class. To create a configuration, extend this class with
|
||||
* a subclass whose characteristic predicate is a unique singleton string.
|
||||
* For example, write
|
||||
*
|
||||
* ```ql
|
||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
* // Optionally override `isBarrier`.
|
||||
* // Optionally override `isAdditionalFlowStep`.
|
||||
* }
|
||||
* ```
|
||||
* Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and
|
||||
* the edges are those data-flow steps that preserve the value of the node
|
||||
* along with any additional edges defined by `isAdditionalFlowStep`.
|
||||
* Specifying nodes in `isBarrier` will remove those nodes from the graph, and
|
||||
* specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going
|
||||
* and/or out-going edges from those nodes, respectively.
|
||||
*
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
* Multiple configurations can coexist, but two classes extending
|
||||
* `DataFlow::Configuration` should never depend on each other. One of them
|
||||
* should instead depend on a `DataFlow2::Configuration`, a
|
||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
|
||||
*/
|
||||
abstract deprecated class Configuration extends string {
|
||||
bindingset[this]
|
||||
Configuration() { any() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source.
|
||||
*/
|
||||
predicate isSource(Node source) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source with the given initial
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSource(Node source, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink.
|
||||
*/
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
||||
*/
|
||||
predicate isSink(Node sink, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited. This completely removes
|
||||
* `node` from the data flow graph.
|
||||
*/
|
||||
predicate isBarrier(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isBarrier(Node node, FlowState state) { none() }
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
predicate isBarrierIn(Node node) { none() }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
int fieldFlowBranchLimit() { result = 2 }
|
||||
|
||||
/**
|
||||
* Gets a data flow configuration feature to add restrictions to the set of
|
||||
* valid flow paths.
|
||||
*
|
||||
* - `FeatureHasSourceCallContext`:
|
||||
* Assume that sources have some existing call context to disallow
|
||||
* conflicting return-flow directly following the source.
|
||||
* - `FeatureHasSinkCallContext`:
|
||||
* Assume that sinks have some existing call context to disallow
|
||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
||||
* - `FeatureEqualSourceSinkCallContext`:
|
||||
* Implies both of the above and additionally ensures that the entire flow
|
||||
* path preserves the call context.
|
||||
*
|
||||
* These features are generally not relevant for typical end-to-end data flow
|
||||
* queries, but should only be used for constructing paths that need to
|
||||
* somehow be pluggable in another path context.
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlow(Node source, Node sink) { hasFlow(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (for example in a `path-problem` query).
|
||||
*/
|
||||
predicate includeHiddenNodes() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* This class exists to prevent mutual recursion between the user-overridden
|
||||
* member predicates of `Configuration` and the rest of the data-flow library.
|
||||
* Good performance cannot be guaranteed in the presence of such recursion, so
|
||||
* it should be replaced by using more than one copy of the data flow library.
|
||||
*/
|
||||
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
|
||||
bindingset[this]
|
||||
ConfigurationRecursionPrevention() { any() }
|
||||
|
||||
override predicate hasFlow(Node source, Node sink) {
|
||||
strictcount(Node n | this.isSource(n)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSource(n, _)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSink(n)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSink(n, _)) < 0
|
||||
or
|
||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
|
||||
or
|
||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0
|
||||
or
|
||||
super.hasFlow(source, sink)
|
||||
}
|
||||
}
|
||||
|
||||
deprecated private FlowState relevantState(Configuration config) {
|
||||
config.isSource(_, result) or
|
||||
config.isSink(_, result) or
|
||||
config.isBarrier(_, result) or
|
||||
config.isAdditionalFlowStep(_, result, _, _) or
|
||||
config.isAdditionalFlowStep(_, _, _, result)
|
||||
}
|
||||
|
||||
private newtype TConfigState =
|
||||
deprecated TMkConfigState(Configuration config, FlowState state) {
|
||||
state = relevantState(config) or state instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
|
||||
|
||||
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
|
||||
|
||||
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
|
||||
|
||||
deprecated private module Config implements FullStateConfigSig {
|
||||
class FlowState = TConfigState;
|
||||
|
||||
predicate isSource(Node source, FlowState state) {
|
||||
getConfig(state).isSource(source, getState(state))
|
||||
or
|
||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
predicate isSink(Node sink, FlowState state) {
|
||||
getConfig(state).isSink(sink, getState(state))
|
||||
or
|
||||
getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isBarrier(Node node) { none() }
|
||||
|
||||
predicate isBarrier(Node node, FlowState state) {
|
||||
getConfig(state).isBarrier(node, getState(state)) or
|
||||
getConfig(state).isBarrier(node)
|
||||
}
|
||||
|
||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
||||
|
||||
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
|
||||
|
||||
predicate isBarrierIn(Node node, FlowState state) { none() }
|
||||
|
||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
||||
singleConfiguration() and
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2) and
|
||||
model = ""
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
Node node1, FlowState state1, Node node2, FlowState state2, string model
|
||||
) {
|
||||
getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and
|
||||
getConfig(state2) = getConfig(state1) and
|
||||
model = ""
|
||||
or
|
||||
not singleConfiguration() and
|
||||
getConfig(state1).isAdditionalFlowStep(node1, node2) and
|
||||
state2 = state1 and
|
||||
model = ""
|
||||
}
|
||||
|
||||
predicate allowImplicitRead(Node node, ContentSet c) {
|
||||
any(Configuration config).allowImplicitRead(node, c)
|
||||
}
|
||||
|
||||
predicate neverSkip(Node node) { none() }
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
int accessPathLimit() { result = 5 }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { none() }
|
||||
}
|
||||
|
||||
deprecated private import Impl<Config> as I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
||||
*/
|
||||
deprecated class PathNode instanceof I::PathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
final string toString() { result = super.toString() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
final string toStringWithContext() { result = super.toStringWithContext() }
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
final predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
final Node getNode() { result = super.getNode() }
|
||||
|
||||
/** Gets the `FlowState` of this node. */
|
||||
deprecated final FlowState getState() { result = getState(super.getState()) }
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() { result = super.getASuccessor() }
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { super.isSourceGroup(group) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
deprecated module PathGraph = I::PathGraph;
|
||||
|
||||
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
source0.getNode() = source and
|
||||
sink0.getNode() = sink
|
||||
)
|
||||
}
|
||||
|
||||
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
deprecated predicate flowsTo = hasFlow/3;
|
||||
@@ -1,361 +0,0 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
||||
* flow library.
|
||||
*/
|
||||
|
||||
private import DataFlowImplCommon
|
||||
private import DataFlowImplSpecific::Private
|
||||
import DataFlowImplSpecific::Public
|
||||
private import DataFlowImpl
|
||||
import DataFlowImplCommonPublic
|
||||
deprecated import FlowStateString
|
||||
private import codeql.util.Unit
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* A configuration of interprocedural data flow analysis. This defines
|
||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
||||
* use of the global data flow library must define its own unique extension
|
||||
* of this abstract class. To create a configuration, extend this class with
|
||||
* a subclass whose characteristic predicate is a unique singleton string.
|
||||
* For example, write
|
||||
*
|
||||
* ```ql
|
||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
* // Optionally override `isBarrier`.
|
||||
* // Optionally override `isAdditionalFlowStep`.
|
||||
* }
|
||||
* ```
|
||||
* Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and
|
||||
* the edges are those data-flow steps that preserve the value of the node
|
||||
* along with any additional edges defined by `isAdditionalFlowStep`.
|
||||
* Specifying nodes in `isBarrier` will remove those nodes from the graph, and
|
||||
* specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going
|
||||
* and/or out-going edges from those nodes, respectively.
|
||||
*
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
* Multiple configurations can coexist, but two classes extending
|
||||
* `DataFlow::Configuration` should never depend on each other. One of them
|
||||
* should instead depend on a `DataFlow2::Configuration`, a
|
||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
|
||||
*/
|
||||
abstract deprecated class Configuration extends string {
|
||||
bindingset[this]
|
||||
Configuration() { any() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source.
|
||||
*/
|
||||
predicate isSource(Node source) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source with the given initial
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSource(Node source, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink.
|
||||
*/
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
||||
*/
|
||||
predicate isSink(Node sink, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited. This completely removes
|
||||
* `node` from the data flow graph.
|
||||
*/
|
||||
predicate isBarrier(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isBarrier(Node node, FlowState state) { none() }
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
predicate isBarrierIn(Node node) { none() }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
int fieldFlowBranchLimit() { result = 2 }
|
||||
|
||||
/**
|
||||
* Gets a data flow configuration feature to add restrictions to the set of
|
||||
* valid flow paths.
|
||||
*
|
||||
* - `FeatureHasSourceCallContext`:
|
||||
* Assume that sources have some existing call context to disallow
|
||||
* conflicting return-flow directly following the source.
|
||||
* - `FeatureHasSinkCallContext`:
|
||||
* Assume that sinks have some existing call context to disallow
|
||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
||||
* - `FeatureEqualSourceSinkCallContext`:
|
||||
* Implies both of the above and additionally ensures that the entire flow
|
||||
* path preserves the call context.
|
||||
*
|
||||
* These features are generally not relevant for typical end-to-end data flow
|
||||
* queries, but should only be used for constructing paths that need to
|
||||
* somehow be pluggable in another path context.
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlow(Node source, Node sink) { hasFlow(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (for example in a `path-problem` query).
|
||||
*/
|
||||
predicate includeHiddenNodes() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* This class exists to prevent mutual recursion between the user-overridden
|
||||
* member predicates of `Configuration` and the rest of the data-flow library.
|
||||
* Good performance cannot be guaranteed in the presence of such recursion, so
|
||||
* it should be replaced by using more than one copy of the data flow library.
|
||||
*/
|
||||
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
|
||||
bindingset[this]
|
||||
ConfigurationRecursionPrevention() { any() }
|
||||
|
||||
override predicate hasFlow(Node source, Node sink) {
|
||||
strictcount(Node n | this.isSource(n)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSource(n, _)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSink(n)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSink(n, _)) < 0
|
||||
or
|
||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
|
||||
or
|
||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0
|
||||
or
|
||||
super.hasFlow(source, sink)
|
||||
}
|
||||
}
|
||||
|
||||
deprecated private FlowState relevantState(Configuration config) {
|
||||
config.isSource(_, result) or
|
||||
config.isSink(_, result) or
|
||||
config.isBarrier(_, result) or
|
||||
config.isAdditionalFlowStep(_, result, _, _) or
|
||||
config.isAdditionalFlowStep(_, _, _, result)
|
||||
}
|
||||
|
||||
private newtype TConfigState =
|
||||
deprecated TMkConfigState(Configuration config, FlowState state) {
|
||||
state = relevantState(config) or state instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
|
||||
|
||||
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
|
||||
|
||||
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
|
||||
|
||||
deprecated private module Config implements FullStateConfigSig {
|
||||
class FlowState = TConfigState;
|
||||
|
||||
predicate isSource(Node source, FlowState state) {
|
||||
getConfig(state).isSource(source, getState(state))
|
||||
or
|
||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
predicate isSink(Node sink, FlowState state) {
|
||||
getConfig(state).isSink(sink, getState(state))
|
||||
or
|
||||
getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isBarrier(Node node) { none() }
|
||||
|
||||
predicate isBarrier(Node node, FlowState state) {
|
||||
getConfig(state).isBarrier(node, getState(state)) or
|
||||
getConfig(state).isBarrier(node)
|
||||
}
|
||||
|
||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
||||
|
||||
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
|
||||
|
||||
predicate isBarrierIn(Node node, FlowState state) { none() }
|
||||
|
||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
||||
singleConfiguration() and
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2) and
|
||||
model = ""
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
Node node1, FlowState state1, Node node2, FlowState state2, string model
|
||||
) {
|
||||
getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and
|
||||
getConfig(state2) = getConfig(state1) and
|
||||
model = ""
|
||||
or
|
||||
not singleConfiguration() and
|
||||
getConfig(state1).isAdditionalFlowStep(node1, node2) and
|
||||
state2 = state1 and
|
||||
model = ""
|
||||
}
|
||||
|
||||
predicate allowImplicitRead(Node node, ContentSet c) {
|
||||
any(Configuration config).allowImplicitRead(node, c)
|
||||
}
|
||||
|
||||
predicate neverSkip(Node node) { none() }
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
int accessPathLimit() { result = 5 }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { none() }
|
||||
}
|
||||
|
||||
deprecated private import Impl<Config> as I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
||||
*/
|
||||
deprecated class PathNode instanceof I::PathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
final string toString() { result = super.toString() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
final string toStringWithContext() { result = super.toStringWithContext() }
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
final predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
final Node getNode() { result = super.getNode() }
|
||||
|
||||
/** Gets the `FlowState` of this node. */
|
||||
deprecated final FlowState getState() { result = getState(super.getState()) }
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() { result = super.getASuccessor() }
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { super.isSourceGroup(group) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
deprecated module PathGraph = I::PathGraph;
|
||||
|
||||
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
source0.getNode() = source and
|
||||
sink0.getNode() = sink
|
||||
)
|
||||
}
|
||||
|
||||
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
deprecated predicate flowsTo = hasFlow/3;
|
||||
@@ -1,361 +0,0 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
||||
* flow library.
|
||||
*/
|
||||
|
||||
private import DataFlowImplCommon
|
||||
private import DataFlowImplSpecific::Private
|
||||
import DataFlowImplSpecific::Public
|
||||
private import DataFlowImpl
|
||||
import DataFlowImplCommonPublic
|
||||
deprecated import FlowStateString
|
||||
private import codeql.util.Unit
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* A configuration of interprocedural data flow analysis. This defines
|
||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
||||
* use of the global data flow library must define its own unique extension
|
||||
* of this abstract class. To create a configuration, extend this class with
|
||||
* a subclass whose characteristic predicate is a unique singleton string.
|
||||
* For example, write
|
||||
*
|
||||
* ```ql
|
||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
* // Optionally override `isBarrier`.
|
||||
* // Optionally override `isAdditionalFlowStep`.
|
||||
* }
|
||||
* ```
|
||||
* Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and
|
||||
* the edges are those data-flow steps that preserve the value of the node
|
||||
* along with any additional edges defined by `isAdditionalFlowStep`.
|
||||
* Specifying nodes in `isBarrier` will remove those nodes from the graph, and
|
||||
* specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going
|
||||
* and/or out-going edges from those nodes, respectively.
|
||||
*
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
* Multiple configurations can coexist, but two classes extending
|
||||
* `DataFlow::Configuration` should never depend on each other. One of them
|
||||
* should instead depend on a `DataFlow2::Configuration`, a
|
||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
|
||||
*/
|
||||
abstract deprecated class Configuration extends string {
|
||||
bindingset[this]
|
||||
Configuration() { any() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source.
|
||||
*/
|
||||
predicate isSource(Node source) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source with the given initial
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSource(Node source, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink.
|
||||
*/
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
||||
*/
|
||||
predicate isSink(Node sink, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited. This completely removes
|
||||
* `node` from the data flow graph.
|
||||
*/
|
||||
predicate isBarrier(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isBarrier(Node node, FlowState state) { none() }
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
predicate isBarrierIn(Node node) { none() }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
int fieldFlowBranchLimit() { result = 2 }
|
||||
|
||||
/**
|
||||
* Gets a data flow configuration feature to add restrictions to the set of
|
||||
* valid flow paths.
|
||||
*
|
||||
* - `FeatureHasSourceCallContext`:
|
||||
* Assume that sources have some existing call context to disallow
|
||||
* conflicting return-flow directly following the source.
|
||||
* - `FeatureHasSinkCallContext`:
|
||||
* Assume that sinks have some existing call context to disallow
|
||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
||||
* - `FeatureEqualSourceSinkCallContext`:
|
||||
* Implies both of the above and additionally ensures that the entire flow
|
||||
* path preserves the call context.
|
||||
*
|
||||
* These features are generally not relevant for typical end-to-end data flow
|
||||
* queries, but should only be used for constructing paths that need to
|
||||
* somehow be pluggable in another path context.
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlow(Node source, Node sink) { hasFlow(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (for example in a `path-problem` query).
|
||||
*/
|
||||
predicate includeHiddenNodes() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* This class exists to prevent mutual recursion between the user-overridden
|
||||
* member predicates of `Configuration` and the rest of the data-flow library.
|
||||
* Good performance cannot be guaranteed in the presence of such recursion, so
|
||||
* it should be replaced by using more than one copy of the data flow library.
|
||||
*/
|
||||
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
|
||||
bindingset[this]
|
||||
ConfigurationRecursionPrevention() { any() }
|
||||
|
||||
override predicate hasFlow(Node source, Node sink) {
|
||||
strictcount(Node n | this.isSource(n)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSource(n, _)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSink(n)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSink(n, _)) < 0
|
||||
or
|
||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
|
||||
or
|
||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0
|
||||
or
|
||||
super.hasFlow(source, sink)
|
||||
}
|
||||
}
|
||||
|
||||
deprecated private FlowState relevantState(Configuration config) {
|
||||
config.isSource(_, result) or
|
||||
config.isSink(_, result) or
|
||||
config.isBarrier(_, result) or
|
||||
config.isAdditionalFlowStep(_, result, _, _) or
|
||||
config.isAdditionalFlowStep(_, _, _, result)
|
||||
}
|
||||
|
||||
private newtype TConfigState =
|
||||
deprecated TMkConfigState(Configuration config, FlowState state) {
|
||||
state = relevantState(config) or state instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
|
||||
|
||||
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
|
||||
|
||||
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
|
||||
|
||||
deprecated private module Config implements FullStateConfigSig {
|
||||
class FlowState = TConfigState;
|
||||
|
||||
predicate isSource(Node source, FlowState state) {
|
||||
getConfig(state).isSource(source, getState(state))
|
||||
or
|
||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
predicate isSink(Node sink, FlowState state) {
|
||||
getConfig(state).isSink(sink, getState(state))
|
||||
or
|
||||
getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isBarrier(Node node) { none() }
|
||||
|
||||
predicate isBarrier(Node node, FlowState state) {
|
||||
getConfig(state).isBarrier(node, getState(state)) or
|
||||
getConfig(state).isBarrier(node)
|
||||
}
|
||||
|
||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
||||
|
||||
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
|
||||
|
||||
predicate isBarrierIn(Node node, FlowState state) { none() }
|
||||
|
||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
||||
singleConfiguration() and
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2) and
|
||||
model = ""
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
Node node1, FlowState state1, Node node2, FlowState state2, string model
|
||||
) {
|
||||
getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and
|
||||
getConfig(state2) = getConfig(state1) and
|
||||
model = ""
|
||||
or
|
||||
not singleConfiguration() and
|
||||
getConfig(state1).isAdditionalFlowStep(node1, node2) and
|
||||
state2 = state1 and
|
||||
model = ""
|
||||
}
|
||||
|
||||
predicate allowImplicitRead(Node node, ContentSet c) {
|
||||
any(Configuration config).allowImplicitRead(node, c)
|
||||
}
|
||||
|
||||
predicate neverSkip(Node node) { none() }
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
int accessPathLimit() { result = 5 }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { none() }
|
||||
}
|
||||
|
||||
deprecated private import Impl<Config> as I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
||||
*/
|
||||
deprecated class PathNode instanceof I::PathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
final string toString() { result = super.toString() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
final string toStringWithContext() { result = super.toStringWithContext() }
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
final predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
final Node getNode() { result = super.getNode() }
|
||||
|
||||
/** Gets the `FlowState` of this node. */
|
||||
deprecated final FlowState getState() { result = getState(super.getState()) }
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() { result = super.getASuccessor() }
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { super.isSourceGroup(group) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
deprecated module PathGraph = I::PathGraph;
|
||||
|
||||
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
source0.getNode() = source and
|
||||
sink0.getNode() = sink
|
||||
)
|
||||
}
|
||||
|
||||
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
deprecated predicate flowsTo = hasFlow/3;
|
||||
@@ -729,41 +729,39 @@ private predicate exprToDefinitionByReferenceStep(Expr exprIn, Expr argOut) {
|
||||
|
||||
private module FieldFlow {
|
||||
private import DataFlowImplCommon
|
||||
private import DataFlowImplLocal
|
||||
private import DataFlowPrivate
|
||||
private import semmle.code.cpp.dataflow.DataFlow
|
||||
|
||||
/**
|
||||
* A configuration for finding local-only flow through fields. This uses the
|
||||
* `Configuration` class in the dedicated `DataFlowImplLocal` copy of the
|
||||
* shared library that's not user-exposed directly.
|
||||
* A configuration for finding local-only flow through fields.
|
||||
*
|
||||
* To keep the flow local to a single function, we put barriers on parameters
|
||||
* and return statements. Sources and sinks are the values that go into and
|
||||
* out of fields, respectively.
|
||||
*/
|
||||
private class FieldConfiguration extends Configuration {
|
||||
FieldConfiguration() { this = "FieldConfiguration" }
|
||||
|
||||
override predicate isSource(Node source) {
|
||||
private module FieldConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(Node source) {
|
||||
storeStep(source, _, _)
|
||||
or
|
||||
// Also mark `foo(a.b);` as a source when `a.b` may be overwritten by `foo`.
|
||||
readStep(_, _, any(Node node | node.asExpr() = source.asDefiningArgument()))
|
||||
}
|
||||
|
||||
override predicate isSink(Node sink) { readStep(_, _, sink) }
|
||||
predicate isSink(Node sink) { readStep(_, _, sink) }
|
||||
|
||||
override predicate isBarrier(Node node) { node instanceof ParameterNode }
|
||||
predicate isBarrier(Node node) { node instanceof ParameterNode }
|
||||
|
||||
override predicate isBarrierOut(Node node) {
|
||||
predicate isBarrierOut(Node node) {
|
||||
node.asExpr().getParent() instanceof ReturnStmt
|
||||
or
|
||||
node.asExpr().getParent() instanceof ThrowExpr
|
||||
}
|
||||
}
|
||||
|
||||
private module Flow = DataFlow::Global<FieldConfig>;
|
||||
|
||||
predicate fieldFlow(Node node1, Node node2) {
|
||||
exists(FieldConfiguration cfg | cfg.hasFlow(node1, node2)) and
|
||||
Flow::flow(node1, node2) and
|
||||
// This configuration should not be able to cross function boundaries, but
|
||||
// we double-check here just to be sure.
|
||||
getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2)
|
||||
|
||||
@@ -1,168 +0,0 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* Provides an implementation of global (interprocedural) taint tracking.
|
||||
* This file re-exports the local (intraprocedural) taint-tracking analysis
|
||||
* from `TaintTrackingParameter::Public` and adds a global analysis, mainly
|
||||
* exposed through the `Configuration` class. For some languages, this file
|
||||
* exists in several identical copies, allowing queries to use multiple
|
||||
* `Configuration` classes that depend on each other without introducing
|
||||
* mutual recursion among those configurations.
|
||||
*/
|
||||
|
||||
import TaintTrackingParameter::Public
|
||||
private import TaintTrackingParameter::Private
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* A configuration of interprocedural taint tracking analysis. This defines
|
||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
||||
* use of the taint tracking library must define its own unique extension of
|
||||
* this abstract class.
|
||||
*
|
||||
* A taint-tracking configuration is a special data flow configuration
|
||||
* (`DataFlow::Configuration`) that allows for flow through nodes that do not
|
||||
* necessarily preserve values but are still relevant from a taint tracking
|
||||
* perspective. (For example, string concatenation, where one of the operands
|
||||
* is tainted.)
|
||||
*
|
||||
* To create a configuration, extend this class with a subclass whose
|
||||
* characteristic predicate is a unique singleton string. For example, write
|
||||
*
|
||||
* ```ql
|
||||
* class MyAnalysisConfiguration extends TaintTracking::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
* // Optionally override `isSanitizer`.
|
||||
* // Optionally override `isSanitizerIn`.
|
||||
* // Optionally override `isSanitizerOut`.
|
||||
* // Optionally override `isSanitizerGuard`.
|
||||
* // Optionally override `isAdditionalTaintStep`.
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
* Multiple configurations can coexist, but it is unsupported to depend on
|
||||
* another `TaintTracking::Configuration` or a `DataFlow::Configuration` in the
|
||||
* overridden predicates that define sources, sinks, or additional steps.
|
||||
* Instead, the dependency should go to a `TaintTracking2::Configuration` or a
|
||||
* `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc.
|
||||
*/
|
||||
abstract deprecated class Configuration extends DataFlow::Configuration {
|
||||
bindingset[this]
|
||||
Configuration() { any() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant taint source.
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSource(DataFlow::Node source) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant taint source with the given initial
|
||||
* `state`.
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant taint sink
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSink(DataFlow::Node sink) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant taint sink accepting `state`.
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { none() }
|
||||
|
||||
/** Holds if the node `node` is a taint sanitizer. */
|
||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrier(DataFlow::Node node) {
|
||||
this.isSanitizer(node) or
|
||||
defaultTaintSanitizer(node)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the node `node` is a taint sanitizer when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
||||
|
||||
final override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
|
||||
this.isSanitizer(node, state)
|
||||
}
|
||||
|
||||
/** Holds if taint propagation into `node` is prohibited. */
|
||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
||||
|
||||
/** Holds if taint propagation out of `node` is prohibited. */
|
||||
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||
|
||||
/**
|
||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
||||
*/
|
||||
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||
|
||||
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
this.isAdditionalTaintStep(node1, node2) or
|
||||
defaultAdditionalTaintStep(node1, node2, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalTaintStep(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
final override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
) {
|
||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||
}
|
||||
|
||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||
(
|
||||
this.isSink(node) or
|
||||
this.isSink(node, _) or
|
||||
this.isAdditionalTaintStep(node, _) or
|
||||
this.isAdditionalTaintStep(node, _, _, _)
|
||||
) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) {
|
||||
super.hasFlow(source, sink)
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.dataflow.internal.TaintTrackingUtil as Public
|
||||
|
||||
module Private {
|
||||
import semmle.code.cpp.dataflow.DataFlow::DataFlow as DataFlow
|
||||
import semmle.code.cpp.dataflow.internal.DataFlowImpl as DataFlowInternal
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* Provides an implementation of global (interprocedural) taint tracking.
|
||||
* This file re-exports the local (intraprocedural) taint-tracking analysis
|
||||
* from `TaintTrackingParameter::Public` and adds a global analysis, mainly
|
||||
* exposed through the `Configuration` class. For some languages, this file
|
||||
* exists in several identical copies, allowing queries to use multiple
|
||||
* `Configuration` classes that depend on each other without introducing
|
||||
* mutual recursion among those configurations.
|
||||
*/
|
||||
|
||||
import TaintTrackingParameter::Public
|
||||
private import TaintTrackingParameter::Private
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* A configuration of interprocedural taint tracking analysis. This defines
|
||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
||||
* use of the taint tracking library must define its own unique extension of
|
||||
* this abstract class.
|
||||
*
|
||||
* A taint-tracking configuration is a special data flow configuration
|
||||
* (`DataFlow::Configuration`) that allows for flow through nodes that do not
|
||||
* necessarily preserve values but are still relevant from a taint tracking
|
||||
* perspective. (For example, string concatenation, where one of the operands
|
||||
* is tainted.)
|
||||
*
|
||||
* To create a configuration, extend this class with a subclass whose
|
||||
* characteristic predicate is a unique singleton string. For example, write
|
||||
*
|
||||
* ```ql
|
||||
* class MyAnalysisConfiguration extends TaintTracking::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
* // Optionally override `isSanitizer`.
|
||||
* // Optionally override `isSanitizerIn`.
|
||||
* // Optionally override `isSanitizerOut`.
|
||||
* // Optionally override `isSanitizerGuard`.
|
||||
* // Optionally override `isAdditionalTaintStep`.
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
* Multiple configurations can coexist, but it is unsupported to depend on
|
||||
* another `TaintTracking::Configuration` or a `DataFlow::Configuration` in the
|
||||
* overridden predicates that define sources, sinks, or additional steps.
|
||||
* Instead, the dependency should go to a `TaintTracking2::Configuration` or a
|
||||
* `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc.
|
||||
*/
|
||||
abstract deprecated class Configuration extends DataFlow::Configuration {
|
||||
bindingset[this]
|
||||
Configuration() { any() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant taint source.
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSource(DataFlow::Node source) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant taint source with the given initial
|
||||
* `state`.
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant taint sink
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSink(DataFlow::Node sink) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant taint sink accepting `state`.
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { none() }
|
||||
|
||||
/** Holds if the node `node` is a taint sanitizer. */
|
||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrier(DataFlow::Node node) {
|
||||
this.isSanitizer(node) or
|
||||
defaultTaintSanitizer(node)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the node `node` is a taint sanitizer when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
||||
|
||||
final override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
|
||||
this.isSanitizer(node, state)
|
||||
}
|
||||
|
||||
/** Holds if taint propagation into `node` is prohibited. */
|
||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
||||
|
||||
/** Holds if taint propagation out of `node` is prohibited. */
|
||||
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||
|
||||
/**
|
||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
||||
*/
|
||||
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||
|
||||
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
this.isAdditionalTaintStep(node1, node2) or
|
||||
defaultAdditionalTaintStep(node1, node2, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalTaintStep(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
final override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
) {
|
||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||
}
|
||||
|
||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||
(
|
||||
this.isSink(node) or
|
||||
this.isSink(node, _) or
|
||||
this.isAdditionalTaintStep(node, _) or
|
||||
this.isAdditionalTaintStep(node, _, _, _)
|
||||
) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) {
|
||||
super.hasFlow(source, sink)
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.dataflow.internal.TaintTrackingUtil as Public
|
||||
|
||||
module Private {
|
||||
import semmle.code.cpp.dataflow.DataFlow2::DataFlow2 as DataFlow
|
||||
}
|
||||
@@ -29,5 +29,5 @@ module DataFlow {
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific
|
||||
private import codeql.dataflow.DataFlow
|
||||
import DataFlowMake<Location, CppDataFlow>
|
||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl1
|
||||
import Public
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
/**
|
||||
* Provides a `DataFlow2` module, which is a copy of the `DataFlow` module. Use
|
||||
* this class when data-flow configurations must depend on each other. Two
|
||||
* classes extending `DataFlow::Configuration` should never depend on each
|
||||
* other, but one of them should instead depend on a
|
||||
* `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a
|
||||
* `DataFlow4::Configuration`.
|
||||
*
|
||||
* See `semmle.code.cpp.dataflow.new.DataFlow` for the full documentation.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* Provides classes for performing local (intra-procedural) and
|
||||
* global (inter-procedural) data flow analyses.
|
||||
*/
|
||||
module DataFlow2 {
|
||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl2
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/**
|
||||
* Provides a `DataFlow3` module, which is a copy of the `DataFlow` module. Use
|
||||
* this class when data-flow configurations must depend on each other. Two
|
||||
* classes extending `DataFlow::Configuration` should never depend on each
|
||||
* other, but one of them should instead depend on a
|
||||
* `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a
|
||||
* `DataFlow4::Configuration`.
|
||||
*
|
||||
* See `semmle.code.cpp.dataflow.new.DataFlow` for the full documentation.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* Provides classes for performing local (intra-procedural) and
|
||||
* global (inter-procedural) data flow analyses.
|
||||
*/
|
||||
module DataFlow3 {
|
||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl3
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/**
|
||||
* Provides a `DataFlow4` module, which is a copy of the `DataFlow` module. Use
|
||||
* this class when data-flow configurations must depend on each other. Two
|
||||
* classes extending `DataFlow::Configuration` should never depend on each
|
||||
* other, but one of them should instead depend on a
|
||||
* `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a
|
||||
* `DataFlow4::Configuration`.
|
||||
*
|
||||
* See `semmle.code.cpp.dataflow.new.DataFlow` for the full documentation.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* Provides classes for performing local (intra-procedural) and
|
||||
* global (inter-procedural) data flow analyses.
|
||||
*/
|
||||
module DataFlow4 {
|
||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl4
|
||||
}
|
||||
@@ -16,18 +16,16 @@
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
import semmle.code.cpp.dataflow.new.DataFlow2
|
||||
|
||||
/**
|
||||
* Provides classes for performing local (intra-procedural) and
|
||||
* global (inter-procedural) taint-tracking analyses.
|
||||
*/
|
||||
module TaintTracking {
|
||||
import semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTrackingParameter::Public
|
||||
import semmle.code.cpp.ir.dataflow.internal.TaintTrackingUtil
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific
|
||||
private import semmle.code.cpp.ir.dataflow.internal.TaintTrackingImplSpecific
|
||||
private import codeql.dataflow.TaintTracking
|
||||
private import semmle.code.cpp.Location
|
||||
import TaintFlowMake<Location, CppDataFlow, CppTaintTracking>
|
||||
import semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTrackingImpl
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
/**
|
||||
* Provides a `TaintTracking2` module, which is a copy of the `TaintTracking`
|
||||
* module. Use this class when data-flow configurations or taint-tracking
|
||||
* configurations must depend on each other. Two classes extending
|
||||
* `DataFlow::Configuration` should never depend on each other, but one of them
|
||||
* should instead depend on a `DataFlow2::Configuration`, a
|
||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`. The
|
||||
* `TaintTracking::Configuration` class extends `DataFlow::Configuration`, and
|
||||
* `TaintTracking2::Configuration` extends `DataFlow2::Configuration`.
|
||||
*
|
||||
* See `semmle.code.cpp.dataflow.new.TaintTracking` for the full documentation.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Provides classes for performing local (intra-procedural) and
|
||||
* global (inter-procedural) taint-tracking analyses.
|
||||
*/
|
||||
module TaintTracking2 {
|
||||
import semmle.code.cpp.ir.dataflow.internal.tainttracking2.TaintTrackingImpl
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/**
|
||||
* Provides a `TaintTracking3` module, which is a copy of the `TaintTracking`
|
||||
* module. Use this class when data-flow configurations or taint-tracking
|
||||
* configurations must depend on each other. Two classes extending
|
||||
* `DataFlow::Configuration` should never depend on each other, but one of them
|
||||
* should instead depend on a `DataFlow2::Configuration`, a
|
||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`. The
|
||||
* `TaintTracking::Configuration` class extends `DataFlow::Configuration`, and
|
||||
* `TaintTracking2::Configuration` extends `DataFlow2::Configuration`.
|
||||
*
|
||||
* See `semmle.code.cpp.dataflow.new.TaintTracking` for the full documentation.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Provides classes for performing local (intra-procedural) and
|
||||
* global (inter-procedural) taint-tracking analyses.
|
||||
*/
|
||||
module TaintTracking3 {
|
||||
import semmle.code.cpp.ir.dataflow.internal.tainttracking3.TaintTrackingImpl
|
||||
}
|
||||
@@ -25,5 +25,5 @@ module DataFlow {
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific
|
||||
private import codeql.dataflow.DataFlow
|
||||
import DataFlowMake<Location, CppDataFlow>
|
||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl1
|
||||
import Public
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
/**
|
||||
* Provides a `DataFlow2` module, which is a copy of the `DataFlow` module. Use
|
||||
* this class when data-flow configurations must depend on each other. Two
|
||||
* classes extending `DataFlow::Configuration` should never depend on each
|
||||
* other, but one of them should instead depend on a
|
||||
* `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a
|
||||
* `DataFlow4::Configuration`.
|
||||
*
|
||||
* See `semmle.code.cpp.ir.dataflow.DataFlow` for the full documentation.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
module DataFlow2 {
|
||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl2
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
/**
|
||||
* Provides a `DataFlow3` module, which is a copy of the `DataFlow` module. Use
|
||||
* this class when data-flow configurations must depend on each other. Two
|
||||
* classes extending `DataFlow::Configuration` should never depend on each
|
||||
* other, but one of them should instead depend on a
|
||||
* `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a
|
||||
* `DataFlow4::Configuration`.
|
||||
*
|
||||
* See `semmle.code.cpp.ir.dataflow.DataFlow` for the full documentation.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
module DataFlow3 {
|
||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl3
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
/**
|
||||
* Provides a `DataFlow4` module, which is a copy of the `DataFlow` module. Use
|
||||
* this class when data-flow configurations must depend on each other. Two
|
||||
* classes extending `DataFlow::Configuration` should never depend on each
|
||||
* other, but one of them should instead depend on a
|
||||
* `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a
|
||||
* `DataFlow4::Configuration`.
|
||||
*
|
||||
* See `semmle.code.cpp.ir.dataflow.DataFlow` for the full documentation.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
module DataFlow4 {
|
||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl4
|
||||
}
|
||||
@@ -16,13 +16,11 @@
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
import semmle.code.cpp.ir.dataflow.DataFlow2
|
||||
|
||||
module TaintTracking {
|
||||
import semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTrackingParameter::Public
|
||||
import semmle.code.cpp.ir.dataflow.internal.TaintTrackingUtil
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific
|
||||
private import semmle.code.cpp.ir.dataflow.internal.TaintTrackingImplSpecific
|
||||
private import codeql.dataflow.TaintTracking
|
||||
import TaintFlowMake<Location, CppDataFlow, CppTaintTracking>
|
||||
import semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTrackingImpl
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
/**
|
||||
* Provides a `TaintTracking2` module, which is a copy of the `TaintTracking`
|
||||
* module. Use this class when data-flow configurations or taint-tracking
|
||||
* configurations must depend on each other. Two classes extending
|
||||
* `DataFlow::Configuration` should never depend on each other, but one of them
|
||||
* should instead depend on a `DataFlow2::Configuration`, a
|
||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`. The
|
||||
* `TaintTracking::Configuration` class extends `DataFlow::Configuration`, and
|
||||
* `TaintTracking2::Configuration` extends `DataFlow2::Configuration`.
|
||||
*
|
||||
* See `semmle.code.cpp.ir.dataflow.TaintTracking` for the full documentation.
|
||||
*/
|
||||
module TaintTracking2 {
|
||||
import semmle.code.cpp.ir.dataflow.internal.tainttracking2.TaintTrackingImpl
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
/**
|
||||
* Provides a `TaintTracking3` module, which is a copy of the `TaintTracking`
|
||||
* module. Use this class when data-flow configurations or taint-tracking
|
||||
* configurations must depend on each other. Two classes extending
|
||||
* `DataFlow::Configuration` should never depend on each other, but one of them
|
||||
* should instead depend on a `DataFlow2::Configuration`, a
|
||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`. The
|
||||
* `TaintTracking::Configuration` class extends `DataFlow::Configuration`, and
|
||||
* `TaintTracking2::Configuration` extends `DataFlow2::Configuration`.
|
||||
*
|
||||
* See `semmle.code.cpp.ir.dataflow.TaintTracking` for the full documentation.
|
||||
*/
|
||||
module TaintTracking3 {
|
||||
import semmle.code.cpp.ir.dataflow.internal.tainttracking3.TaintTrackingImpl
|
||||
}
|
||||
@@ -1,361 +0,0 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
||||
* flow library.
|
||||
*/
|
||||
|
||||
private import DataFlowImplCommon
|
||||
private import DataFlowImplSpecific::Private
|
||||
import DataFlowImplSpecific::Public
|
||||
private import DataFlowImpl
|
||||
import DataFlowImplCommonPublic
|
||||
deprecated import FlowStateString
|
||||
private import codeql.util.Unit
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* A configuration of interprocedural data flow analysis. This defines
|
||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
||||
* use of the global data flow library must define its own unique extension
|
||||
* of this abstract class. To create a configuration, extend this class with
|
||||
* a subclass whose characteristic predicate is a unique singleton string.
|
||||
* For example, write
|
||||
*
|
||||
* ```ql
|
||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
* // Optionally override `isBarrier`.
|
||||
* // Optionally override `isAdditionalFlowStep`.
|
||||
* }
|
||||
* ```
|
||||
* Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and
|
||||
* the edges are those data-flow steps that preserve the value of the node
|
||||
* along with any additional edges defined by `isAdditionalFlowStep`.
|
||||
* Specifying nodes in `isBarrier` will remove those nodes from the graph, and
|
||||
* specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going
|
||||
* and/or out-going edges from those nodes, respectively.
|
||||
*
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
* Multiple configurations can coexist, but two classes extending
|
||||
* `DataFlow::Configuration` should never depend on each other. One of them
|
||||
* should instead depend on a `DataFlow2::Configuration`, a
|
||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
|
||||
*/
|
||||
abstract deprecated class Configuration extends string {
|
||||
bindingset[this]
|
||||
Configuration() { any() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source.
|
||||
*/
|
||||
predicate isSource(Node source) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source with the given initial
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSource(Node source, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink.
|
||||
*/
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
||||
*/
|
||||
predicate isSink(Node sink, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited. This completely removes
|
||||
* `node` from the data flow graph.
|
||||
*/
|
||||
predicate isBarrier(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isBarrier(Node node, FlowState state) { none() }
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
predicate isBarrierIn(Node node) { none() }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
int fieldFlowBranchLimit() { result = 2 }
|
||||
|
||||
/**
|
||||
* Gets a data flow configuration feature to add restrictions to the set of
|
||||
* valid flow paths.
|
||||
*
|
||||
* - `FeatureHasSourceCallContext`:
|
||||
* Assume that sources have some existing call context to disallow
|
||||
* conflicting return-flow directly following the source.
|
||||
* - `FeatureHasSinkCallContext`:
|
||||
* Assume that sinks have some existing call context to disallow
|
||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
||||
* - `FeatureEqualSourceSinkCallContext`:
|
||||
* Implies both of the above and additionally ensures that the entire flow
|
||||
* path preserves the call context.
|
||||
*
|
||||
* These features are generally not relevant for typical end-to-end data flow
|
||||
* queries, but should only be used for constructing paths that need to
|
||||
* somehow be pluggable in another path context.
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlow(Node source, Node sink) { hasFlow(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (for example in a `path-problem` query).
|
||||
*/
|
||||
predicate includeHiddenNodes() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* This class exists to prevent mutual recursion between the user-overridden
|
||||
* member predicates of `Configuration` and the rest of the data-flow library.
|
||||
* Good performance cannot be guaranteed in the presence of such recursion, so
|
||||
* it should be replaced by using more than one copy of the data flow library.
|
||||
*/
|
||||
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
|
||||
bindingset[this]
|
||||
ConfigurationRecursionPrevention() { any() }
|
||||
|
||||
override predicate hasFlow(Node source, Node sink) {
|
||||
strictcount(Node n | this.isSource(n)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSource(n, _)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSink(n)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSink(n, _)) < 0
|
||||
or
|
||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
|
||||
or
|
||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0
|
||||
or
|
||||
super.hasFlow(source, sink)
|
||||
}
|
||||
}
|
||||
|
||||
deprecated private FlowState relevantState(Configuration config) {
|
||||
config.isSource(_, result) or
|
||||
config.isSink(_, result) or
|
||||
config.isBarrier(_, result) or
|
||||
config.isAdditionalFlowStep(_, result, _, _) or
|
||||
config.isAdditionalFlowStep(_, _, _, result)
|
||||
}
|
||||
|
||||
private newtype TConfigState =
|
||||
deprecated TMkConfigState(Configuration config, FlowState state) {
|
||||
state = relevantState(config) or state instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
|
||||
|
||||
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
|
||||
|
||||
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
|
||||
|
||||
deprecated private module Config implements FullStateConfigSig {
|
||||
class FlowState = TConfigState;
|
||||
|
||||
predicate isSource(Node source, FlowState state) {
|
||||
getConfig(state).isSource(source, getState(state))
|
||||
or
|
||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
predicate isSink(Node sink, FlowState state) {
|
||||
getConfig(state).isSink(sink, getState(state))
|
||||
or
|
||||
getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isBarrier(Node node) { none() }
|
||||
|
||||
predicate isBarrier(Node node, FlowState state) {
|
||||
getConfig(state).isBarrier(node, getState(state)) or
|
||||
getConfig(state).isBarrier(node)
|
||||
}
|
||||
|
||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
||||
|
||||
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
|
||||
|
||||
predicate isBarrierIn(Node node, FlowState state) { none() }
|
||||
|
||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
||||
singleConfiguration() and
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2) and
|
||||
model = ""
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
Node node1, FlowState state1, Node node2, FlowState state2, string model
|
||||
) {
|
||||
getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and
|
||||
getConfig(state2) = getConfig(state1) and
|
||||
model = ""
|
||||
or
|
||||
not singleConfiguration() and
|
||||
getConfig(state1).isAdditionalFlowStep(node1, node2) and
|
||||
state2 = state1 and
|
||||
model = ""
|
||||
}
|
||||
|
||||
predicate allowImplicitRead(Node node, ContentSet c) {
|
||||
any(Configuration config).allowImplicitRead(node, c)
|
||||
}
|
||||
|
||||
predicate neverSkip(Node node) { none() }
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
int accessPathLimit() { result = 5 }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { none() }
|
||||
}
|
||||
|
||||
deprecated private import Impl<Config> as I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
||||
*/
|
||||
deprecated class PathNode instanceof I::PathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
final string toString() { result = super.toString() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
final string toStringWithContext() { result = super.toStringWithContext() }
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
final predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
final Node getNode() { result = super.getNode() }
|
||||
|
||||
/** Gets the `FlowState` of this node. */
|
||||
deprecated final FlowState getState() { result = getState(super.getState()) }
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() { result = super.getASuccessor() }
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { super.isSourceGroup(group) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
deprecated module PathGraph = I::PathGraph;
|
||||
|
||||
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
source0.getNode() = source and
|
||||
sink0.getNode() = sink
|
||||
)
|
||||
}
|
||||
|
||||
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
deprecated predicate flowsTo = hasFlow/3;
|
||||
@@ -1,361 +0,0 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
||||
* flow library.
|
||||
*/
|
||||
|
||||
private import DataFlowImplCommon
|
||||
private import DataFlowImplSpecific::Private
|
||||
import DataFlowImplSpecific::Public
|
||||
private import DataFlowImpl
|
||||
import DataFlowImplCommonPublic
|
||||
deprecated import FlowStateString
|
||||
private import codeql.util.Unit
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* A configuration of interprocedural data flow analysis. This defines
|
||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
||||
* use of the global data flow library must define its own unique extension
|
||||
* of this abstract class. To create a configuration, extend this class with
|
||||
* a subclass whose characteristic predicate is a unique singleton string.
|
||||
* For example, write
|
||||
*
|
||||
* ```ql
|
||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
* // Optionally override `isBarrier`.
|
||||
* // Optionally override `isAdditionalFlowStep`.
|
||||
* }
|
||||
* ```
|
||||
* Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and
|
||||
* the edges are those data-flow steps that preserve the value of the node
|
||||
* along with any additional edges defined by `isAdditionalFlowStep`.
|
||||
* Specifying nodes in `isBarrier` will remove those nodes from the graph, and
|
||||
* specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going
|
||||
* and/or out-going edges from those nodes, respectively.
|
||||
*
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
* Multiple configurations can coexist, but two classes extending
|
||||
* `DataFlow::Configuration` should never depend on each other. One of them
|
||||
* should instead depend on a `DataFlow2::Configuration`, a
|
||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
|
||||
*/
|
||||
abstract deprecated class Configuration extends string {
|
||||
bindingset[this]
|
||||
Configuration() { any() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source.
|
||||
*/
|
||||
predicate isSource(Node source) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source with the given initial
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSource(Node source, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink.
|
||||
*/
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
||||
*/
|
||||
predicate isSink(Node sink, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited. This completely removes
|
||||
* `node` from the data flow graph.
|
||||
*/
|
||||
predicate isBarrier(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isBarrier(Node node, FlowState state) { none() }
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
predicate isBarrierIn(Node node) { none() }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
int fieldFlowBranchLimit() { result = 2 }
|
||||
|
||||
/**
|
||||
* Gets a data flow configuration feature to add restrictions to the set of
|
||||
* valid flow paths.
|
||||
*
|
||||
* - `FeatureHasSourceCallContext`:
|
||||
* Assume that sources have some existing call context to disallow
|
||||
* conflicting return-flow directly following the source.
|
||||
* - `FeatureHasSinkCallContext`:
|
||||
* Assume that sinks have some existing call context to disallow
|
||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
||||
* - `FeatureEqualSourceSinkCallContext`:
|
||||
* Implies both of the above and additionally ensures that the entire flow
|
||||
* path preserves the call context.
|
||||
*
|
||||
* These features are generally not relevant for typical end-to-end data flow
|
||||
* queries, but should only be used for constructing paths that need to
|
||||
* somehow be pluggable in another path context.
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlow(Node source, Node sink) { hasFlow(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (for example in a `path-problem` query).
|
||||
*/
|
||||
predicate includeHiddenNodes() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* This class exists to prevent mutual recursion between the user-overridden
|
||||
* member predicates of `Configuration` and the rest of the data-flow library.
|
||||
* Good performance cannot be guaranteed in the presence of such recursion, so
|
||||
* it should be replaced by using more than one copy of the data flow library.
|
||||
*/
|
||||
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
|
||||
bindingset[this]
|
||||
ConfigurationRecursionPrevention() { any() }
|
||||
|
||||
override predicate hasFlow(Node source, Node sink) {
|
||||
strictcount(Node n | this.isSource(n)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSource(n, _)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSink(n)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSink(n, _)) < 0
|
||||
or
|
||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
|
||||
or
|
||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0
|
||||
or
|
||||
super.hasFlow(source, sink)
|
||||
}
|
||||
}
|
||||
|
||||
deprecated private FlowState relevantState(Configuration config) {
|
||||
config.isSource(_, result) or
|
||||
config.isSink(_, result) or
|
||||
config.isBarrier(_, result) or
|
||||
config.isAdditionalFlowStep(_, result, _, _) or
|
||||
config.isAdditionalFlowStep(_, _, _, result)
|
||||
}
|
||||
|
||||
private newtype TConfigState =
|
||||
deprecated TMkConfigState(Configuration config, FlowState state) {
|
||||
state = relevantState(config) or state instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
|
||||
|
||||
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
|
||||
|
||||
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
|
||||
|
||||
deprecated private module Config implements FullStateConfigSig {
|
||||
class FlowState = TConfigState;
|
||||
|
||||
predicate isSource(Node source, FlowState state) {
|
||||
getConfig(state).isSource(source, getState(state))
|
||||
or
|
||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
predicate isSink(Node sink, FlowState state) {
|
||||
getConfig(state).isSink(sink, getState(state))
|
||||
or
|
||||
getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isBarrier(Node node) { none() }
|
||||
|
||||
predicate isBarrier(Node node, FlowState state) {
|
||||
getConfig(state).isBarrier(node, getState(state)) or
|
||||
getConfig(state).isBarrier(node)
|
||||
}
|
||||
|
||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
||||
|
||||
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
|
||||
|
||||
predicate isBarrierIn(Node node, FlowState state) { none() }
|
||||
|
||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
||||
singleConfiguration() and
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2) and
|
||||
model = ""
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
Node node1, FlowState state1, Node node2, FlowState state2, string model
|
||||
) {
|
||||
getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and
|
||||
getConfig(state2) = getConfig(state1) and
|
||||
model = ""
|
||||
or
|
||||
not singleConfiguration() and
|
||||
getConfig(state1).isAdditionalFlowStep(node1, node2) and
|
||||
state2 = state1 and
|
||||
model = ""
|
||||
}
|
||||
|
||||
predicate allowImplicitRead(Node node, ContentSet c) {
|
||||
any(Configuration config).allowImplicitRead(node, c)
|
||||
}
|
||||
|
||||
predicate neverSkip(Node node) { none() }
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
int accessPathLimit() { result = 5 }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { none() }
|
||||
}
|
||||
|
||||
deprecated private import Impl<Config> as I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
||||
*/
|
||||
deprecated class PathNode instanceof I::PathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
final string toString() { result = super.toString() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
final string toStringWithContext() { result = super.toStringWithContext() }
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
final predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
final Node getNode() { result = super.getNode() }
|
||||
|
||||
/** Gets the `FlowState` of this node. */
|
||||
deprecated final FlowState getState() { result = getState(super.getState()) }
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() { result = super.getASuccessor() }
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { super.isSourceGroup(group) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
deprecated module PathGraph = I::PathGraph;
|
||||
|
||||
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
source0.getNode() = source and
|
||||
sink0.getNode() = sink
|
||||
)
|
||||
}
|
||||
|
||||
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
deprecated predicate flowsTo = hasFlow/3;
|
||||
@@ -1,361 +0,0 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
||||
* flow library.
|
||||
*/
|
||||
|
||||
private import DataFlowImplCommon
|
||||
private import DataFlowImplSpecific::Private
|
||||
import DataFlowImplSpecific::Public
|
||||
private import DataFlowImpl
|
||||
import DataFlowImplCommonPublic
|
||||
deprecated import FlowStateString
|
||||
private import codeql.util.Unit
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* A configuration of interprocedural data flow analysis. This defines
|
||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
||||
* use of the global data flow library must define its own unique extension
|
||||
* of this abstract class. To create a configuration, extend this class with
|
||||
* a subclass whose characteristic predicate is a unique singleton string.
|
||||
* For example, write
|
||||
*
|
||||
* ```ql
|
||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
* // Optionally override `isBarrier`.
|
||||
* // Optionally override `isAdditionalFlowStep`.
|
||||
* }
|
||||
* ```
|
||||
* Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and
|
||||
* the edges are those data-flow steps that preserve the value of the node
|
||||
* along with any additional edges defined by `isAdditionalFlowStep`.
|
||||
* Specifying nodes in `isBarrier` will remove those nodes from the graph, and
|
||||
* specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going
|
||||
* and/or out-going edges from those nodes, respectively.
|
||||
*
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
* Multiple configurations can coexist, but two classes extending
|
||||
* `DataFlow::Configuration` should never depend on each other. One of them
|
||||
* should instead depend on a `DataFlow2::Configuration`, a
|
||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
|
||||
*/
|
||||
abstract deprecated class Configuration extends string {
|
||||
bindingset[this]
|
||||
Configuration() { any() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source.
|
||||
*/
|
||||
predicate isSource(Node source) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source with the given initial
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSource(Node source, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink.
|
||||
*/
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
||||
*/
|
||||
predicate isSink(Node sink, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited. This completely removes
|
||||
* `node` from the data flow graph.
|
||||
*/
|
||||
predicate isBarrier(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isBarrier(Node node, FlowState state) { none() }
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
predicate isBarrierIn(Node node) { none() }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
int fieldFlowBranchLimit() { result = 2 }
|
||||
|
||||
/**
|
||||
* Gets a data flow configuration feature to add restrictions to the set of
|
||||
* valid flow paths.
|
||||
*
|
||||
* - `FeatureHasSourceCallContext`:
|
||||
* Assume that sources have some existing call context to disallow
|
||||
* conflicting return-flow directly following the source.
|
||||
* - `FeatureHasSinkCallContext`:
|
||||
* Assume that sinks have some existing call context to disallow
|
||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
||||
* - `FeatureEqualSourceSinkCallContext`:
|
||||
* Implies both of the above and additionally ensures that the entire flow
|
||||
* path preserves the call context.
|
||||
*
|
||||
* These features are generally not relevant for typical end-to-end data flow
|
||||
* queries, but should only be used for constructing paths that need to
|
||||
* somehow be pluggable in another path context.
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlow(Node source, Node sink) { hasFlow(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (for example in a `path-problem` query).
|
||||
*/
|
||||
predicate includeHiddenNodes() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* This class exists to prevent mutual recursion between the user-overridden
|
||||
* member predicates of `Configuration` and the rest of the data-flow library.
|
||||
* Good performance cannot be guaranteed in the presence of such recursion, so
|
||||
* it should be replaced by using more than one copy of the data flow library.
|
||||
*/
|
||||
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
|
||||
bindingset[this]
|
||||
ConfigurationRecursionPrevention() { any() }
|
||||
|
||||
override predicate hasFlow(Node source, Node sink) {
|
||||
strictcount(Node n | this.isSource(n)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSource(n, _)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSink(n)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSink(n, _)) < 0
|
||||
or
|
||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
|
||||
or
|
||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0
|
||||
or
|
||||
super.hasFlow(source, sink)
|
||||
}
|
||||
}
|
||||
|
||||
deprecated private FlowState relevantState(Configuration config) {
|
||||
config.isSource(_, result) or
|
||||
config.isSink(_, result) or
|
||||
config.isBarrier(_, result) or
|
||||
config.isAdditionalFlowStep(_, result, _, _) or
|
||||
config.isAdditionalFlowStep(_, _, _, result)
|
||||
}
|
||||
|
||||
private newtype TConfigState =
|
||||
deprecated TMkConfigState(Configuration config, FlowState state) {
|
||||
state = relevantState(config) or state instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
|
||||
|
||||
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
|
||||
|
||||
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
|
||||
|
||||
deprecated private module Config implements FullStateConfigSig {
|
||||
class FlowState = TConfigState;
|
||||
|
||||
predicate isSource(Node source, FlowState state) {
|
||||
getConfig(state).isSource(source, getState(state))
|
||||
or
|
||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
predicate isSink(Node sink, FlowState state) {
|
||||
getConfig(state).isSink(sink, getState(state))
|
||||
or
|
||||
getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isBarrier(Node node) { none() }
|
||||
|
||||
predicate isBarrier(Node node, FlowState state) {
|
||||
getConfig(state).isBarrier(node, getState(state)) or
|
||||
getConfig(state).isBarrier(node)
|
||||
}
|
||||
|
||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
||||
|
||||
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
|
||||
|
||||
predicate isBarrierIn(Node node, FlowState state) { none() }
|
||||
|
||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
||||
singleConfiguration() and
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2) and
|
||||
model = ""
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
Node node1, FlowState state1, Node node2, FlowState state2, string model
|
||||
) {
|
||||
getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and
|
||||
getConfig(state2) = getConfig(state1) and
|
||||
model = ""
|
||||
or
|
||||
not singleConfiguration() and
|
||||
getConfig(state1).isAdditionalFlowStep(node1, node2) and
|
||||
state2 = state1 and
|
||||
model = ""
|
||||
}
|
||||
|
||||
predicate allowImplicitRead(Node node, ContentSet c) {
|
||||
any(Configuration config).allowImplicitRead(node, c)
|
||||
}
|
||||
|
||||
predicate neverSkip(Node node) { none() }
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
int accessPathLimit() { result = 5 }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { none() }
|
||||
}
|
||||
|
||||
deprecated private import Impl<Config> as I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
||||
*/
|
||||
deprecated class PathNode instanceof I::PathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
final string toString() { result = super.toString() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
final string toStringWithContext() { result = super.toStringWithContext() }
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
final predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
final Node getNode() { result = super.getNode() }
|
||||
|
||||
/** Gets the `FlowState` of this node. */
|
||||
deprecated final FlowState getState() { result = getState(super.getState()) }
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() { result = super.getASuccessor() }
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { super.isSourceGroup(group) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
deprecated module PathGraph = I::PathGraph;
|
||||
|
||||
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
source0.getNode() = source and
|
||||
sink0.getNode() = sink
|
||||
)
|
||||
}
|
||||
|
||||
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
deprecated predicate flowsTo = hasFlow/3;
|
||||
@@ -1,361 +0,0 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
||||
* flow library.
|
||||
*/
|
||||
|
||||
private import DataFlowImplCommon
|
||||
private import DataFlowImplSpecific::Private
|
||||
import DataFlowImplSpecific::Public
|
||||
private import DataFlowImpl
|
||||
import DataFlowImplCommonPublic
|
||||
deprecated import FlowStateString
|
||||
private import codeql.util.Unit
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* A configuration of interprocedural data flow analysis. This defines
|
||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
||||
* use of the global data flow library must define its own unique extension
|
||||
* of this abstract class. To create a configuration, extend this class with
|
||||
* a subclass whose characteristic predicate is a unique singleton string.
|
||||
* For example, write
|
||||
*
|
||||
* ```ql
|
||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
* // Optionally override `isBarrier`.
|
||||
* // Optionally override `isAdditionalFlowStep`.
|
||||
* }
|
||||
* ```
|
||||
* Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and
|
||||
* the edges are those data-flow steps that preserve the value of the node
|
||||
* along with any additional edges defined by `isAdditionalFlowStep`.
|
||||
* Specifying nodes in `isBarrier` will remove those nodes from the graph, and
|
||||
* specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going
|
||||
* and/or out-going edges from those nodes, respectively.
|
||||
*
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
* Multiple configurations can coexist, but two classes extending
|
||||
* `DataFlow::Configuration` should never depend on each other. One of them
|
||||
* should instead depend on a `DataFlow2::Configuration`, a
|
||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
|
||||
*/
|
||||
abstract deprecated class Configuration extends string {
|
||||
bindingset[this]
|
||||
Configuration() { any() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source.
|
||||
*/
|
||||
predicate isSource(Node source) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source with the given initial
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSource(Node source, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink.
|
||||
*/
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
||||
*/
|
||||
predicate isSink(Node sink, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited. This completely removes
|
||||
* `node` from the data flow graph.
|
||||
*/
|
||||
predicate isBarrier(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isBarrier(Node node, FlowState state) { none() }
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
predicate isBarrierIn(Node node) { none() }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
int fieldFlowBranchLimit() { result = 2 }
|
||||
|
||||
/**
|
||||
* Gets a data flow configuration feature to add restrictions to the set of
|
||||
* valid flow paths.
|
||||
*
|
||||
* - `FeatureHasSourceCallContext`:
|
||||
* Assume that sources have some existing call context to disallow
|
||||
* conflicting return-flow directly following the source.
|
||||
* - `FeatureHasSinkCallContext`:
|
||||
* Assume that sinks have some existing call context to disallow
|
||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
||||
* - `FeatureEqualSourceSinkCallContext`:
|
||||
* Implies both of the above and additionally ensures that the entire flow
|
||||
* path preserves the call context.
|
||||
*
|
||||
* These features are generally not relevant for typical end-to-end data flow
|
||||
* queries, but should only be used for constructing paths that need to
|
||||
* somehow be pluggable in another path context.
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlow(Node source, Node sink) { hasFlow(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (for example in a `path-problem` query).
|
||||
*/
|
||||
predicate includeHiddenNodes() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* This class exists to prevent mutual recursion between the user-overridden
|
||||
* member predicates of `Configuration` and the rest of the data-flow library.
|
||||
* Good performance cannot be guaranteed in the presence of such recursion, so
|
||||
* it should be replaced by using more than one copy of the data flow library.
|
||||
*/
|
||||
abstract deprecated private class ConfigurationRecursionPrevention extends Configuration {
|
||||
bindingset[this]
|
||||
ConfigurationRecursionPrevention() { any() }
|
||||
|
||||
override predicate hasFlow(Node source, Node sink) {
|
||||
strictcount(Node n | this.isSource(n)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSource(n, _)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSink(n)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSink(n, _)) < 0
|
||||
or
|
||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
|
||||
or
|
||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0
|
||||
or
|
||||
super.hasFlow(source, sink)
|
||||
}
|
||||
}
|
||||
|
||||
deprecated private FlowState relevantState(Configuration config) {
|
||||
config.isSource(_, result) or
|
||||
config.isSink(_, result) or
|
||||
config.isBarrier(_, result) or
|
||||
config.isAdditionalFlowStep(_, result, _, _) or
|
||||
config.isAdditionalFlowStep(_, _, _, result)
|
||||
}
|
||||
|
||||
private newtype TConfigState =
|
||||
deprecated TMkConfigState(Configuration config, FlowState state) {
|
||||
state = relevantState(config) or state instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
deprecated private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
|
||||
|
||||
deprecated private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
|
||||
|
||||
deprecated private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
|
||||
|
||||
deprecated private module Config implements FullStateConfigSig {
|
||||
class FlowState = TConfigState;
|
||||
|
||||
predicate isSource(Node source, FlowState state) {
|
||||
getConfig(state).isSource(source, getState(state))
|
||||
or
|
||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
predicate isSink(Node sink, FlowState state) {
|
||||
getConfig(state).isSink(sink, getState(state))
|
||||
or
|
||||
getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isBarrier(Node node) { none() }
|
||||
|
||||
predicate isBarrier(Node node, FlowState state) {
|
||||
getConfig(state).isBarrier(node, getState(state)) or
|
||||
getConfig(state).isBarrier(node)
|
||||
}
|
||||
|
||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
||||
|
||||
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
|
||||
|
||||
predicate isBarrierIn(Node node, FlowState state) { none() }
|
||||
|
||||
predicate isBarrierOut(Node node, FlowState state) { none() }
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
|
||||
singleConfiguration() and
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2) and
|
||||
model = ""
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
Node node1, FlowState state1, Node node2, FlowState state2, string model
|
||||
) {
|
||||
getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and
|
||||
getConfig(state2) = getConfig(state1) and
|
||||
model = ""
|
||||
or
|
||||
not singleConfiguration() and
|
||||
getConfig(state1).isAdditionalFlowStep(node1, node2) and
|
||||
state2 = state1 and
|
||||
model = ""
|
||||
}
|
||||
|
||||
predicate allowImplicitRead(Node node, ContentSet c) {
|
||||
any(Configuration config).allowImplicitRead(node, c)
|
||||
}
|
||||
|
||||
predicate neverSkip(Node node) { none() }
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
int accessPathLimit() { result = 5 }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { none() }
|
||||
}
|
||||
|
||||
deprecated private import Impl<Config> as I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
||||
*/
|
||||
deprecated class PathNode instanceof I::PathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
final string toString() { result = super.toString() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
final string toStringWithContext() { result = super.toStringWithContext() }
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
final predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
final Node getNode() { result = super.getNode() }
|
||||
|
||||
/** Gets the `FlowState` of this node. */
|
||||
deprecated final FlowState getState() { result = getState(super.getState()) }
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
deprecated final Configuration getConfiguration() { result = getConfig(super.getState()) }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() { result = super.getASuccessor() }
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { super.isSourceGroup(group) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
deprecated module PathGraph = I::PathGraph;
|
||||
|
||||
deprecated private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
source0.getNode() = source and
|
||||
sink0.getNode() = sink
|
||||
)
|
||||
}
|
||||
|
||||
deprecated private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
I::flowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
deprecated private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
deprecated predicate flowsTo = hasFlow/3;
|
||||
@@ -545,7 +545,7 @@ module ProductFlow {
|
||||
private predicate outImpl1(Flow1::PathNode pred1, Flow1::PathNode succ1, DataFlowCall call) {
|
||||
Flow1::PathGraph::edges(pred1, succ1, _, _) and
|
||||
exists(ReturnKindExt returnKind |
|
||||
succ1.getNode() = returnKind.getAnOutNode(call) and
|
||||
succ1.getNode() = getAnOutNodeExt(call, returnKind) and
|
||||
returnKind = getParamReturnPosition(_, pred1.asParameterReturnNode()).getKind()
|
||||
)
|
||||
}
|
||||
@@ -573,7 +573,7 @@ module ProductFlow {
|
||||
private predicate outImpl2(Flow2::PathNode pred2, Flow2::PathNode succ2, DataFlowCall call) {
|
||||
Flow2::PathGraph::edges(pred2, succ2, _, _) and
|
||||
exists(ReturnKindExt returnKind |
|
||||
succ2.getNode() = returnKind.getAnOutNode(call) and
|
||||
succ2.getNode() = getAnOutNodeExt(call, returnKind) and
|
||||
returnKind = getParamReturnPosition(_, pred2.asParameterReturnNode()).getKind()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,168 +0,0 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* Provides an implementation of global (interprocedural) taint tracking.
|
||||
* This file re-exports the local (intraprocedural) taint-tracking analysis
|
||||
* from `TaintTrackingParameter::Public` and adds a global analysis, mainly
|
||||
* exposed through the `Configuration` class. For some languages, this file
|
||||
* exists in several identical copies, allowing queries to use multiple
|
||||
* `Configuration` classes that depend on each other without introducing
|
||||
* mutual recursion among those configurations.
|
||||
*/
|
||||
|
||||
import TaintTrackingParameter::Public
|
||||
private import TaintTrackingParameter::Private
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* A configuration of interprocedural taint tracking analysis. This defines
|
||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
||||
* use of the taint tracking library must define its own unique extension of
|
||||
* this abstract class.
|
||||
*
|
||||
* A taint-tracking configuration is a special data flow configuration
|
||||
* (`DataFlow::Configuration`) that allows for flow through nodes that do not
|
||||
* necessarily preserve values but are still relevant from a taint tracking
|
||||
* perspective. (For example, string concatenation, where one of the operands
|
||||
* is tainted.)
|
||||
*
|
||||
* To create a configuration, extend this class with a subclass whose
|
||||
* characteristic predicate is a unique singleton string. For example, write
|
||||
*
|
||||
* ```ql
|
||||
* class MyAnalysisConfiguration extends TaintTracking::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
* // Optionally override `isSanitizer`.
|
||||
* // Optionally override `isSanitizerIn`.
|
||||
* // Optionally override `isSanitizerOut`.
|
||||
* // Optionally override `isSanitizerGuard`.
|
||||
* // Optionally override `isAdditionalTaintStep`.
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
* Multiple configurations can coexist, but it is unsupported to depend on
|
||||
* another `TaintTracking::Configuration` or a `DataFlow::Configuration` in the
|
||||
* overridden predicates that define sources, sinks, or additional steps.
|
||||
* Instead, the dependency should go to a `TaintTracking2::Configuration` or a
|
||||
* `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc.
|
||||
*/
|
||||
abstract deprecated class Configuration extends DataFlow::Configuration {
|
||||
bindingset[this]
|
||||
Configuration() { any() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant taint source.
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSource(DataFlow::Node source) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant taint source with the given initial
|
||||
* `state`.
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant taint sink
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSink(DataFlow::Node sink) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant taint sink accepting `state`.
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { none() }
|
||||
|
||||
/** Holds if the node `node` is a taint sanitizer. */
|
||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrier(DataFlow::Node node) {
|
||||
this.isSanitizer(node) or
|
||||
defaultTaintSanitizer(node)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the node `node` is a taint sanitizer when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
||||
|
||||
final override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
|
||||
this.isSanitizer(node, state)
|
||||
}
|
||||
|
||||
/** Holds if taint propagation into `node` is prohibited. */
|
||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
||||
|
||||
/** Holds if taint propagation out of `node` is prohibited. */
|
||||
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||
|
||||
/**
|
||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
||||
*/
|
||||
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||
|
||||
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
this.isAdditionalTaintStep(node1, node2) or
|
||||
defaultAdditionalTaintStep(node1, node2, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalTaintStep(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
final override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
) {
|
||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||
}
|
||||
|
||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||
(
|
||||
this.isSink(node) or
|
||||
this.isSink(node, _) or
|
||||
this.isAdditionalTaintStep(node, _) or
|
||||
this.isAdditionalTaintStep(node, _, _, _)
|
||||
) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) {
|
||||
super.hasFlow(source, sink)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
import semmle.code.cpp.ir.dataflow.internal.TaintTrackingUtil as Public
|
||||
|
||||
module Private {
|
||||
import semmle.code.cpp.ir.dataflow.DataFlow::DataFlow as DataFlow
|
||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl as DataFlowInternal
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* Provides an implementation of global (interprocedural) taint tracking.
|
||||
* This file re-exports the local (intraprocedural) taint-tracking analysis
|
||||
* from `TaintTrackingParameter::Public` and adds a global analysis, mainly
|
||||
* exposed through the `Configuration` class. For some languages, this file
|
||||
* exists in several identical copies, allowing queries to use multiple
|
||||
* `Configuration` classes that depend on each other without introducing
|
||||
* mutual recursion among those configurations.
|
||||
*/
|
||||
|
||||
import TaintTrackingParameter::Public
|
||||
private import TaintTrackingParameter::Private
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* A configuration of interprocedural taint tracking analysis. This defines
|
||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
||||
* use of the taint tracking library must define its own unique extension of
|
||||
* this abstract class.
|
||||
*
|
||||
* A taint-tracking configuration is a special data flow configuration
|
||||
* (`DataFlow::Configuration`) that allows for flow through nodes that do not
|
||||
* necessarily preserve values but are still relevant from a taint tracking
|
||||
* perspective. (For example, string concatenation, where one of the operands
|
||||
* is tainted.)
|
||||
*
|
||||
* To create a configuration, extend this class with a subclass whose
|
||||
* characteristic predicate is a unique singleton string. For example, write
|
||||
*
|
||||
* ```ql
|
||||
* class MyAnalysisConfiguration extends TaintTracking::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
* // Optionally override `isSanitizer`.
|
||||
* // Optionally override `isSanitizerIn`.
|
||||
* // Optionally override `isSanitizerOut`.
|
||||
* // Optionally override `isSanitizerGuard`.
|
||||
* // Optionally override `isAdditionalTaintStep`.
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
* Multiple configurations can coexist, but it is unsupported to depend on
|
||||
* another `TaintTracking::Configuration` or a `DataFlow::Configuration` in the
|
||||
* overridden predicates that define sources, sinks, or additional steps.
|
||||
* Instead, the dependency should go to a `TaintTracking2::Configuration` or a
|
||||
* `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc.
|
||||
*/
|
||||
abstract deprecated class Configuration extends DataFlow::Configuration {
|
||||
bindingset[this]
|
||||
Configuration() { any() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant taint source.
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSource(DataFlow::Node source) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant taint source with the given initial
|
||||
* `state`.
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant taint sink
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSink(DataFlow::Node sink) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant taint sink accepting `state`.
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { none() }
|
||||
|
||||
/** Holds if the node `node` is a taint sanitizer. */
|
||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrier(DataFlow::Node node) {
|
||||
this.isSanitizer(node) or
|
||||
defaultTaintSanitizer(node)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the node `node` is a taint sanitizer when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
||||
|
||||
final override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
|
||||
this.isSanitizer(node, state)
|
||||
}
|
||||
|
||||
/** Holds if taint propagation into `node` is prohibited. */
|
||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
||||
|
||||
/** Holds if taint propagation out of `node` is prohibited. */
|
||||
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||
|
||||
/**
|
||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
||||
*/
|
||||
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||
|
||||
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
this.isAdditionalTaintStep(node1, node2) or
|
||||
defaultAdditionalTaintStep(node1, node2, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalTaintStep(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
final override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
) {
|
||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||
}
|
||||
|
||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||
(
|
||||
this.isSink(node) or
|
||||
this.isSink(node, _) or
|
||||
this.isAdditionalTaintStep(node, _) or
|
||||
this.isAdditionalTaintStep(node, _, _, _)
|
||||
) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) {
|
||||
super.hasFlow(source, sink)
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import semmle.code.cpp.ir.dataflow.internal.TaintTrackingUtil as Public
|
||||
|
||||
module Private {
|
||||
import semmle.code.cpp.ir.dataflow.DataFlow2::DataFlow2 as DataFlow
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* Provides an implementation of global (interprocedural) taint tracking.
|
||||
* This file re-exports the local (intraprocedural) taint-tracking analysis
|
||||
* from `TaintTrackingParameter::Public` and adds a global analysis, mainly
|
||||
* exposed through the `Configuration` class. For some languages, this file
|
||||
* exists in several identical copies, allowing queries to use multiple
|
||||
* `Configuration` classes that depend on each other without introducing
|
||||
* mutual recursion among those configurations.
|
||||
*/
|
||||
|
||||
import TaintTrackingParameter::Public
|
||||
private import TaintTrackingParameter::Private
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `Global` and `GlobalWithState` instead.
|
||||
*
|
||||
* A configuration of interprocedural taint tracking analysis. This defines
|
||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
||||
* use of the taint tracking library must define its own unique extension of
|
||||
* this abstract class.
|
||||
*
|
||||
* A taint-tracking configuration is a special data flow configuration
|
||||
* (`DataFlow::Configuration`) that allows for flow through nodes that do not
|
||||
* necessarily preserve values but are still relevant from a taint tracking
|
||||
* perspective. (For example, string concatenation, where one of the operands
|
||||
* is tainted.)
|
||||
*
|
||||
* To create a configuration, extend this class with a subclass whose
|
||||
* characteristic predicate is a unique singleton string. For example, write
|
||||
*
|
||||
* ```ql
|
||||
* class MyAnalysisConfiguration extends TaintTracking::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
* // Optionally override `isSanitizer`.
|
||||
* // Optionally override `isSanitizerIn`.
|
||||
* // Optionally override `isSanitizerOut`.
|
||||
* // Optionally override `isSanitizerGuard`.
|
||||
* // Optionally override `isAdditionalTaintStep`.
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
* Multiple configurations can coexist, but it is unsupported to depend on
|
||||
* another `TaintTracking::Configuration` or a `DataFlow::Configuration` in the
|
||||
* overridden predicates that define sources, sinks, or additional steps.
|
||||
* Instead, the dependency should go to a `TaintTracking2::Configuration` or a
|
||||
* `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc.
|
||||
*/
|
||||
abstract deprecated class Configuration extends DataFlow::Configuration {
|
||||
bindingset[this]
|
||||
Configuration() { any() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant taint source.
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSource(DataFlow::Node source) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant taint source with the given initial
|
||||
* `state`.
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant taint sink
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSink(DataFlow::Node sink) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant taint sink accepting `state`.
|
||||
*
|
||||
* The smaller this predicate is, the faster `hasFlow()` will converge.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) { none() }
|
||||
|
||||
/** Holds if the node `node` is a taint sanitizer. */
|
||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrier(DataFlow::Node node) {
|
||||
this.isSanitizer(node) or
|
||||
defaultTaintSanitizer(node)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the node `node` is a taint sanitizer when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) { none() }
|
||||
|
||||
final override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
|
||||
this.isSanitizer(node, state)
|
||||
}
|
||||
|
||||
/** Holds if taint propagation into `node` is prohibited. */
|
||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
||||
|
||||
/** Holds if taint propagation out of `node` is prohibited. */
|
||||
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||
|
||||
/**
|
||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
||||
*/
|
||||
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||
|
||||
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
this.isAdditionalTaintStep(node1, node2) or
|
||||
defaultAdditionalTaintStep(node1, node2, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalTaintStep(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
final override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
) {
|
||||
this.isAdditionalTaintStep(node1, state1, node2, state2)
|
||||
}
|
||||
|
||||
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||
(
|
||||
this.isSink(node) or
|
||||
this.isSink(node, _) or
|
||||
this.isAdditionalTaintStep(node, _) or
|
||||
this.isAdditionalTaintStep(node, _, _, _)
|
||||
) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
// overridden to provide taint-tracking specific qldoc
|
||||
override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) {
|
||||
super.hasFlow(source, sink)
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import semmle.code.cpp.ir.dataflow.internal.TaintTrackingUtil as Public
|
||||
|
||||
module Private {
|
||||
import semmle.code.cpp.ir.dataflow.DataFlow3::DataFlow3 as DataFlow
|
||||
}
|
||||
@@ -546,4 +546,26 @@ module InstructionConsistency {
|
||||
"' has no associated variable, in function '$@'." and
|
||||
irFunc = getInstructionIRFunction(instr, irFuncText)
|
||||
}
|
||||
|
||||
query predicate nonBooleanOperand(
|
||||
Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText
|
||||
) {
|
||||
exists(Instruction unary |
|
||||
unary = instr.(LogicalNotInstruction).getUnary() and
|
||||
not unary.getResultIRType() instanceof IRBooleanType and
|
||||
irFunc = getInstructionIRFunction(instr, irFuncText) and
|
||||
message =
|
||||
"Logical Not instruction " + instr.toString() +
|
||||
" with non-Boolean operand, in function '$@'."
|
||||
)
|
||||
or
|
||||
exists(Instruction cond |
|
||||
cond = instr.(ConditionalBranchInstruction).getCondition() and
|
||||
not cond.getResultIRType() instanceof IRBooleanType and
|
||||
irFunc = getInstructionIRFunction(instr, irFuncText) and
|
||||
message =
|
||||
"Conditional branch instruction " + instr.toString() +
|
||||
" with non-Boolean condition, in function '$@'."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -546,4 +546,26 @@ module InstructionConsistency {
|
||||
"' has no associated variable, in function '$@'." and
|
||||
irFunc = getInstructionIRFunction(instr, irFuncText)
|
||||
}
|
||||
|
||||
query predicate nonBooleanOperand(
|
||||
Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText
|
||||
) {
|
||||
exists(Instruction unary |
|
||||
unary = instr.(LogicalNotInstruction).getUnary() and
|
||||
not unary.getResultIRType() instanceof IRBooleanType and
|
||||
irFunc = getInstructionIRFunction(instr, irFuncText) and
|
||||
message =
|
||||
"Logical Not instruction " + instr.toString() +
|
||||
" with non-Boolean operand, in function '$@'."
|
||||
)
|
||||
or
|
||||
exists(Instruction cond |
|
||||
cond = instr.(ConditionalBranchInstruction).getCondition() and
|
||||
not cond.getResultIRType() instanceof IRBooleanType and
|
||||
irFunc = getInstructionIRFunction(instr, irFuncText) and
|
||||
message =
|
||||
"Conditional branch instruction " + instr.toString() +
|
||||
" with non-Boolean condition, in function '$@'."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,10 +364,14 @@ class TranslatedFunctionCall extends TranslatedCallExpr, TranslatedDirectCall {
|
||||
|
||||
final override predicate mayThrowException() {
|
||||
expr.getTarget().(ThrowingFunction).mayThrowException(_)
|
||||
or
|
||||
expr.getTarget() instanceof AlwaysSehThrowingFunction
|
||||
}
|
||||
|
||||
final override predicate mustThrowException() {
|
||||
expr.getTarget().(ThrowingFunction).mayThrowException(true)
|
||||
or
|
||||
expr.getTarget() instanceof AlwaysSehThrowingFunction
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -546,4 +546,26 @@ module InstructionConsistency {
|
||||
"' has no associated variable, in function '$@'." and
|
||||
irFunc = getInstructionIRFunction(instr, irFuncText)
|
||||
}
|
||||
|
||||
query predicate nonBooleanOperand(
|
||||
Instruction instr, string message, OptionalIRFunction irFunc, string irFuncText
|
||||
) {
|
||||
exists(Instruction unary |
|
||||
unary = instr.(LogicalNotInstruction).getUnary() and
|
||||
not unary.getResultIRType() instanceof IRBooleanType and
|
||||
irFunc = getInstructionIRFunction(instr, irFuncText) and
|
||||
message =
|
||||
"Logical Not instruction " + instr.toString() +
|
||||
" with non-Boolean operand, in function '$@'."
|
||||
)
|
||||
or
|
||||
exists(Instruction cond |
|
||||
cond = instr.(ConditionalBranchInstruction).getCondition() and
|
||||
not cond.getResultIRType() instanceof IRBooleanType and
|
||||
irFunc = getInstructionIRFunction(instr, irFuncText) and
|
||||
message =
|
||||
"Conditional branch instruction " + instr.toString() +
|
||||
" with non-Boolean condition, in function '$@'."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,3 +49,4 @@ private import implementations.PostgreSql
|
||||
private import implementations.System
|
||||
private import implementations.StructuredExceptionHandling
|
||||
private import implementations.ZMQ
|
||||
private import implementations.Win32CommandExecution
|
||||
|
||||
@@ -16,7 +16,7 @@ import semmle.code.cpp.models.interfaces.NonThrowing
|
||||
* `__builtin___memcpy_chk`.
|
||||
*/
|
||||
private class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffectFunction,
|
||||
AliasFunction, NonThrowingFunction
|
||||
AliasFunction, NonCppThrowingFunction
|
||||
{
|
||||
MemcpyFunction() {
|
||||
// memcpy(dest, src, num)
|
||||
|
||||
@@ -11,7 +11,7 @@ import semmle.code.cpp.models.interfaces.SideEffect
|
||||
import semmle.code.cpp.models.interfaces.NonThrowing
|
||||
|
||||
private class MemsetFunctionModel extends ArrayFunction, DataFlowFunction, AliasFunction,
|
||||
SideEffectFunction, NonThrowingFunction
|
||||
SideEffectFunction, NonCppThrowingFunction
|
||||
{
|
||||
MemsetFunctionModel() {
|
||||
this.hasGlobalOrStdOrBslName("memset")
|
||||
|
||||
@@ -6,6 +6,6 @@ import semmle.code.cpp.models.interfaces.NonThrowing
|
||||
*
|
||||
* Note: The `throw` specifier was deprecated in C++11 and removed in C++17.
|
||||
*/
|
||||
class NoexceptFunction extends NonThrowingFunction {
|
||||
class NoexceptFunction extends NonCppThrowingFunction {
|
||||
NoexceptFunction() { this.isNoExcept() or this.isNoThrow() }
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import semmle.code.cpp.models.interfaces.NonThrowing
|
||||
/**
|
||||
* The standard functions `printf`, `wprintf` and their glib variants.
|
||||
*/
|
||||
private class Printf extends FormattingFunction, AliasFunction, NonThrowingFunction {
|
||||
private class Printf extends FormattingFunction, AliasFunction, NonCppThrowingFunction {
|
||||
Printf() {
|
||||
this instanceof TopLevelFunction and
|
||||
(
|
||||
@@ -37,7 +37,7 @@ private class Printf extends FormattingFunction, AliasFunction, NonThrowingFunct
|
||||
/**
|
||||
* The standard functions `fprintf`, `fwprintf` and their glib variants.
|
||||
*/
|
||||
private class Fprintf extends FormattingFunction, NonThrowingFunction {
|
||||
private class Fprintf extends FormattingFunction, NonCppThrowingFunction {
|
||||
Fprintf() {
|
||||
this instanceof TopLevelFunction and
|
||||
(
|
||||
@@ -55,7 +55,7 @@ private class Fprintf extends FormattingFunction, NonThrowingFunction {
|
||||
/**
|
||||
* The standard function `sprintf` and its Microsoft and glib variants.
|
||||
*/
|
||||
private class Sprintf extends FormattingFunction, NonThrowingFunction {
|
||||
private class Sprintf extends FormattingFunction, NonCppThrowingFunction {
|
||||
Sprintf() {
|
||||
this instanceof TopLevelFunction and
|
||||
(
|
||||
@@ -98,7 +98,9 @@ private class Sprintf extends FormattingFunction, NonThrowingFunction {
|
||||
/**
|
||||
* Implements `Snprintf`.
|
||||
*/
|
||||
private class SnprintfImpl extends Snprintf, AliasFunction, SideEffectFunction, NonThrowingFunction {
|
||||
private class SnprintfImpl extends Snprintf, AliasFunction, SideEffectFunction,
|
||||
NonCppThrowingFunction
|
||||
{
|
||||
SnprintfImpl() {
|
||||
this instanceof TopLevelFunction and
|
||||
(
|
||||
@@ -205,7 +207,7 @@ private class StringCchPrintf extends FormattingFunction {
|
||||
/**
|
||||
* The standard function `syslog`.
|
||||
*/
|
||||
private class Syslog extends FormattingFunction, NonThrowingFunction {
|
||||
private class Syslog extends FormattingFunction, NonCppThrowingFunction {
|
||||
Syslog() {
|
||||
this instanceof TopLevelFunction and
|
||||
this.hasGlobalName("syslog") and
|
||||
|
||||
@@ -15,7 +15,7 @@ import semmle.code.cpp.models.interfaces.NonThrowing
|
||||
* Does not include `strlcat`, which is covered by `StrlcatFunction`
|
||||
*/
|
||||
class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, SideEffectFunction,
|
||||
NonThrowingFunction
|
||||
NonCppThrowingFunction
|
||||
{
|
||||
StrcatFunction() {
|
||||
this.hasGlobalOrStdOrBslName([
|
||||
|
||||
@@ -13,7 +13,7 @@ import semmle.code.cpp.models.interfaces.NonThrowing
|
||||
* The standard function `strcpy` and its wide, sized, and Microsoft variants.
|
||||
*/
|
||||
class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, SideEffectFunction,
|
||||
NonThrowingFunction
|
||||
NonCppThrowingFunction
|
||||
{
|
||||
StrcpyFunction() {
|
||||
this.hasGlobalOrStdOrBslName([
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import semmle.code.cpp.models.interfaces.Throwing
|
||||
|
||||
class WindowsDriverFunction extends ThrowingFunction {
|
||||
WindowsDriverFunction() {
|
||||
class WindowsDriverExceptionAnnotation extends AlwaysSehThrowingFunction {
|
||||
WindowsDriverExceptionAnnotation() {
|
||||
this.hasGlobalName(["RaiseException", "ExRaiseAccessViolation", "ExRaiseDatatypeMisalignment"])
|
||||
}
|
||||
|
||||
final override predicate mayThrowException(boolean unconditional) { unconditional = true }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
private import semmle.code.cpp.models.interfaces.CommandExecution
|
||||
|
||||
/** The `ShellExecute` family of functions from Win32. */
|
||||
class ShellExecute extends Function {
|
||||
ShellExecute() { this.hasGlobalName("ShellExecute" + ["", "A", "W"]) }
|
||||
}
|
||||
|
||||
private class ShellExecuteModel extends ShellExecute, CommandExecutionFunction {
|
||||
override predicate hasCommandArgument(FunctionInput input) { input.isParameterDeref(2) }
|
||||
}
|
||||
|
||||
/** The `WinExec` function from Win32. */
|
||||
class WinExec extends Function {
|
||||
WinExec() { this.hasGlobalName("WinExec") }
|
||||
}
|
||||
|
||||
private class WinExecModel extends WinExec, CommandExecutionFunction {
|
||||
override predicate hasCommandArgument(FunctionInput input) { input.isParameterDeref(0) }
|
||||
}
|
||||
|
||||
/** The `CreateProcess` family of functions from Win32. */
|
||||
class CreateProcess extends Function {
|
||||
CreateProcess() { this.hasGlobalName("CreateProcess" + ["", "A", "W"]) }
|
||||
}
|
||||
|
||||
private class CreateProcessModel extends CreateProcess, CommandExecutionFunction {
|
||||
override predicate hasCommandArgument(FunctionInput input) { input.isParameterDeref(0) }
|
||||
}
|
||||
|
||||
/** The `CreateProcessAsUser` family of functions from Win32. */
|
||||
class CreateProcessAsUser extends Function {
|
||||
CreateProcessAsUser() { this.hasGlobalName("CreateProcessAsUser" + ["", "A", "W"]) }
|
||||
}
|
||||
|
||||
private class CreateProcessAsUserModel extends CreateProcessAsUser, CommandExecutionFunction {
|
||||
override predicate hasCommandArgument(FunctionInput input) { input.isParameterDeref(1) }
|
||||
}
|
||||
|
||||
/** The `CreateProcessWithLogonW` function from Win32. */
|
||||
class CreateProcessWithLogonW extends Function {
|
||||
CreateProcessWithLogonW() { this.hasGlobalName("CreateProcessWithLogonW") }
|
||||
}
|
||||
|
||||
private class CreateProcessWithLogonModel extends CreateProcessWithLogonW, CommandExecutionFunction {
|
||||
override predicate hasCommandArgument(FunctionInput input) { input.isParameterDeref(4) }
|
||||
}
|
||||
|
||||
/** The `CreateProcessWithTokenW` function from Win32. */
|
||||
class CreateProcessWithTokenW extends Function {
|
||||
CreateProcessWithTokenW() { this.hasGlobalName("CreateProcessWithTokenW") }
|
||||
}
|
||||
|
||||
private class CreateProcessWithTokenWModel extends CreateProcessWithTokenW, CommandExecutionFunction
|
||||
{
|
||||
override predicate hasCommandArgument(FunctionInput input) { input.isParameterDeref(2) }
|
||||
}
|
||||
@@ -6,6 +6,15 @@ import semmle.code.cpp.Function
|
||||
import semmle.code.cpp.models.Models
|
||||
|
||||
/**
|
||||
* A function that is guaranteed to never throw.
|
||||
* A function that is guaranteed to never throw a C++ exception
|
||||
*
|
||||
* The function may still raise a structured exception handling (SEH) exception.
|
||||
*/
|
||||
abstract class NonThrowingFunction extends Function { }
|
||||
abstract class NonCppThrowingFunction extends Function { }
|
||||
|
||||
/**
|
||||
* A function that is guaranteed to never throw.
|
||||
*
|
||||
* DEPRECATED: use `NonCppThrowingFunction` instead.
|
||||
*/
|
||||
deprecated class NonThrowingFunction = NonCppThrowingFunction;
|
||||
|
||||
@@ -11,7 +11,7 @@ import semmle.code.cpp.models.Models
|
||||
import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs
|
||||
|
||||
/**
|
||||
* A class that models the exceptional behavior of a function.
|
||||
* A function that is known to raise an exception.
|
||||
*/
|
||||
abstract class ThrowingFunction extends Function {
|
||||
/**
|
||||
@@ -20,3 +20,8 @@ abstract class ThrowingFunction extends Function {
|
||||
*/
|
||||
abstract predicate mayThrowException(boolean unconditional);
|
||||
}
|
||||
|
||||
/**
|
||||
* A function that unconditionally raises a structured exception handling (SEH) exception.
|
||||
*/
|
||||
abstract class AlwaysSehThrowingFunction extends Function { }
|
||||
|
||||
@@ -46,6 +46,22 @@ compilation_args(
|
||||
string arg : string ref
|
||||
);
|
||||
|
||||
/**
|
||||
* Optionally, record the build mode for each compilation.
|
||||
*/
|
||||
compilation_build_mode(
|
||||
unique int id : @compilation ref,
|
||||
int mode : int ref
|
||||
);
|
||||
|
||||
/*
|
||||
case @compilation_build_mode.mode of
|
||||
0 = @build_mode_none
|
||||
| 1 = @build_mode_manual
|
||||
| 2 = @build_mode_auto
|
||||
;
|
||||
*/
|
||||
|
||||
/**
|
||||
* The source files that are compiled by a compiler invocation.
|
||||
* If `id` is for the compiler invocation
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Implement compilation_build_mode/2
|
||||
compatibility: backwards
|
||||
@@ -1,18 +1,28 @@
|
||||
<!DOCTYPE qhelp SYSTEM "qhelp.dtd">
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>The <code>free</code> function, which deallocates heap memory, may accept a NULL pointer and take no action. Therefore, it is unnecessary to check its argument for the value of NULL before a function call to <code>free</code>. As such, these guards may hinder performance and readability.</p>
|
||||
<p>The <code>free</code> function, which deallocates heap memory, may accept a NULL pointer and take no action. Therefore, it is unnecessary to check the argument for the value of NULL before a function call to <code>free</code>. As such, these guards may hinder performance and readability.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>A function call to <code>free</code> should not depend upon the value of its argument. Delete the <code>if</code> condition preceeding a function call to <code>free</code> when its only purpose is to check the value of the pointer to be freed.</p>
|
||||
<p>A function call to <code>free</code> should not depend upon the value of its argument. Delete the condition preceding a function call to <code>free</code> when its only purpose is to check the value of the pointer to be freed.</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<sample src = "GuardedFree.cpp" />
|
||||
|
||||
<p>In this example, the condition checking the value of <code>foo</code> can be deleted.</p>
|
||||
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
The Open Group Base Specifications Issue 7, 2018 Edition:
|
||||
<a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html">free - free allocated memory</a>
|
||||
<a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html">free - free allocated memory</a>.
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
|
||||
</qhelp>
|
||||
47
cpp/ql/src/Best Practices/GuardedFree.ql
Normal file
47
cpp/ql/src/Best Practices/GuardedFree.ql
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* @name Guarded Free
|
||||
* @description NULL-condition guards before function calls to the memory-deallocation
|
||||
* function free(3) are unnecessary, because passing NULL to free(3) is a no-op.
|
||||
* @kind problem
|
||||
* @problem.severity recommendation
|
||||
* @precision very-high
|
||||
* @id cpp/guarded-free
|
||||
* @tags maintainability
|
||||
* readability
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.Guards
|
||||
|
||||
class FreeCall extends FunctionCall {
|
||||
FreeCall() { this.getTarget().hasGlobalName("free") }
|
||||
}
|
||||
|
||||
predicate blockContainsPreprocessorBranches(BasicBlock bb) {
|
||||
exists(PreprocessorBranch ppb, Location bbLoc, Location ppbLoc |
|
||||
bbLoc = bb.(Stmt).getLocation() and ppbLoc = ppb.getLocation()
|
||||
|
|
||||
bbLoc.getFile() = ppb.getFile() and
|
||||
bbLoc.getStartLine() < ppbLoc.getStartLine() and
|
||||
ppbLoc.getEndLine() < bbLoc.getEndLine()
|
||||
)
|
||||
}
|
||||
|
||||
from GuardCondition gc, FreeCall fc, Variable v, BasicBlock bb
|
||||
where
|
||||
gc.ensuresEq(v.getAnAccess(), 0, bb, false) and
|
||||
fc.getArgument(0) = v.getAnAccess() and
|
||||
bb = fc.getBasicBlock() and
|
||||
(
|
||||
// No block statement: if (x) free(x);
|
||||
bb = fc.getEnclosingStmt()
|
||||
or
|
||||
// Block statement with a single nested statement: if (x) { free(x); }
|
||||
strictcount(bb.(BlockStmt).getAStmt()) = 1
|
||||
) and
|
||||
strictcount(BasicBlock bb2 | gc.ensuresEq(_, 0, bb2, _) | bb2) = 1 and
|
||||
not fc.isInMacroExpansion() and
|
||||
not blockContainsPreprocessorBranches(bb) and
|
||||
not (gc instanceof BinaryOperation and not gc instanceof ComparisonOperation) and
|
||||
not exists(CommaExpr c | c.getAChild*() = fc)
|
||||
select gc, "unnecessary NULL check before call to $@", fc, "free"
|
||||
@@ -1,3 +1,17 @@
|
||||
## 1.3.0
|
||||
|
||||
### New Queries
|
||||
|
||||
* Added a new high-precision quality query, `cpp/guarded-free`, which detects useless NULL pointer checks before calls to `free`. A variation of this query was originally contributed as an [experimental query by @mario-campos](https://github.com/github/codeql/pull/16331).
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The "Call to function with fewer arguments than declared parameters" query (`cpp/too-few-arguments`) query no longer produces results if the function has been implicitly declared.
|
||||
|
||||
## 1.2.7
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.2.6
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<p>
|
||||
This rule finds accesses through a pointer of a memory location that has already been freed (i.e. through a dangling pointer).
|
||||
Such memory blocks have already been released to the dynamic memory manager, and modifying them can lead to anything
|
||||
from a segfault to memory corruption that would cause subsequent calls to the dynamic memory manger to behave
|
||||
from a segfault to memory corruption that would cause subsequent calls to the dynamic memory manager to behave
|
||||
erratically, to a possible security vulnerability.
|
||||
</p>
|
||||
|
||||
|
||||
@@ -51,5 +51,7 @@ predicate tooFewArguments(FunctionCall fc, Function f) {
|
||||
hasDefiniteNumberOfParameters(fde)
|
||||
|
|
||||
fde.getNumberOfParameters() > fc.getNumberOfArguments()
|
||||
)
|
||||
) and
|
||||
// Don't report on implicit function declarations, as these are likely extraction errors.
|
||||
not f.getADeclarationEntry().isImplicit()
|
||||
}
|
||||
|
||||
@@ -40,4 +40,5 @@ select count(Instruction i | IRConsistency::missingOperand(i, _, _, _) | i) as m
|
||||
count(Instruction i | IRConsistency::nonUniqueEnclosingIRFunction(i, _, _, _) | i) as nonUniqueEnclosingIRFunction,
|
||||
count(FieldAddressInstruction i | IRConsistency::fieldAddressOnNonPointer(i, _, _, _) | i) as fieldAddressOnNonPointer,
|
||||
count(Instruction i | IRConsistency::thisArgumentIsNonPointer(i, _, _, _) | i) as thisArgumentIsNonPointer,
|
||||
count(Instruction i | IRConsistency::nonUniqueIRVariable(i, _, _, _) | i) as nonUniqueIRVariable
|
||||
count(Instruction i | IRConsistency::nonUniqueIRVariable(i, _, _, _) | i) as nonUniqueIRVariable,
|
||||
count(Instruction i | IRConsistency::nonBooleanOperand(i, _, _, _) | i) as nonBooleanOperand
|
||||
|
||||
@@ -19,7 +19,6 @@ import semmle.code.cpp.security.Security
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
import semmle.code.cpp.ir.IR
|
||||
import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||
import semmle.code.cpp.ir.dataflow.TaintTracking2
|
||||
import semmle.code.cpp.security.FlowSources
|
||||
import semmle.code.cpp.models.implementations.Strcat
|
||||
import ExecTaint::PathGraph
|
||||
|
||||
@@ -45,7 +45,7 @@ predicate deleteMayThrow(DeleteOrDeleteArrayExpr deleteExpr) {
|
||||
* like it might throw an exception, and the function does not have a `noexcept` or `throw()` specifier.
|
||||
*/
|
||||
predicate functionMayThrow(Function f) {
|
||||
not f instanceof NonThrowingFunction and
|
||||
not f instanceof NonCppThrowingFunction and
|
||||
(not exists(f.getBlock()) or stmtMayThrow(f.getBlock()))
|
||||
}
|
||||
|
||||
|
||||
3
cpp/ql/src/change-notes/released/1.2.7.md
Normal file
3
cpp/ql/src/change-notes/released/1.2.7.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.2.7
|
||||
|
||||
No user-facing changes.
|
||||
9
cpp/ql/src/change-notes/released/1.3.0.md
Normal file
9
cpp/ql/src/change-notes/released/1.3.0.md
Normal file
@@ -0,0 +1,9 @@
|
||||
## 1.3.0
|
||||
|
||||
### New Queries
|
||||
|
||||
* Added a new high-precision quality query, `cpp/guarded-free`, which detects useless NULL pointer checks before calls to `free`. A variation of this query was originally contributed as an [experimental query by @mario-campos](https://github.com/github/codeql/pull/16331).
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The "Call to function with fewer arguments than declared parameters" query (`cpp/too-few-arguments`) query no longer produces results if the function has been implicitly declared.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.2.6
|
||||
lastReleaseVersion: 1.3.0
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user