mirror of
https://github.com/github/codeql.git
synced 2026-05-26 17:11:24 +02:00
Compare commits
1387 Commits
smowton/ad
...
felicityma
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba78b76fe1 | ||
|
|
5d03892943 | ||
|
|
174fbf672f | ||
|
|
3e0702f904 | ||
|
|
0c362ca812 | ||
|
|
cd2c8061f2 | ||
|
|
8eeba92a47 | ||
|
|
7f5df4fc0e | ||
|
|
04450c5173 | ||
|
|
42259ef8d1 | ||
|
|
2ac06b8db9 | ||
|
|
8f065e9483 | ||
|
|
cb4a7e22f0 | ||
|
|
1eec067474 | ||
|
|
3d4f64f168 | ||
|
|
efdfc361be | ||
|
|
3fbe089f65 | ||
|
|
2b52a44024 | ||
|
|
146d2460b7 | ||
|
|
357c823b92 | ||
|
|
b9694eb09a | ||
|
|
d03817ce2d | ||
|
|
2684b3f396 | ||
|
|
277b5b483d | ||
|
|
582cfb9330 | ||
|
|
950c4c811c | ||
|
|
9ee36215bd | ||
|
|
ee0811df26 | ||
|
|
f9215ec5ca | ||
|
|
72999c7af1 | ||
|
|
3c3442d8f0 | ||
|
|
ef837f72e4 | ||
|
|
8042edb6a9 | ||
|
|
33216f3867 | ||
|
|
311614c5e6 | ||
|
|
19b5f64a11 | ||
|
|
2eb6b1adb3 | ||
|
|
ac7063ba09 | ||
|
|
876add5214 | ||
|
|
dcd082e955 | ||
|
|
bc6a41c1e6 | ||
|
|
d401be1845 | ||
|
|
686a1cbafe | ||
|
|
8f3731fd42 | ||
|
|
1c17d854d8 | ||
|
|
6cfa89e1db | ||
|
|
a1bffff0b0 | ||
|
|
28c32fc78e | ||
|
|
3b69821630 | ||
|
|
a55c56feed | ||
|
|
40c2b3c43b | ||
|
|
093ff4061d | ||
|
|
7644ecad52 | ||
|
|
0a91ee1019 | ||
|
|
df7f0cf9a9 | ||
|
|
c06b8a68e5 | ||
|
|
c663da5be6 | ||
|
|
4bd7e24b5f | ||
|
|
605c7113a2 | ||
|
|
e2240abc78 | ||
|
|
e16bdc4d07 | ||
|
|
556d68aeed | ||
|
|
545c2f67e9 | ||
|
|
d345cec339 | ||
|
|
4ad7d2d822 | ||
|
|
24c413fbf9 | ||
|
|
8f02463411 | ||
|
|
a2ac1384cb | ||
|
|
92ee0aa7ae | ||
|
|
2e1a78e1bf | ||
|
|
5866af413f | ||
|
|
04a68f8d52 | ||
|
|
b281cc88ff | ||
|
|
9195b73d84 | ||
|
|
80e71b202a | ||
|
|
9342e3ba76 | ||
|
|
e01df3ea7c | ||
|
|
18be30d177 | ||
|
|
1b30cf8eca | ||
|
|
158ea26dd1 | ||
|
|
f67219965e | ||
|
|
b2267c0e49 | ||
|
|
06386b2cdd | ||
|
|
1667fbad88 | ||
|
|
43f4dd8bc4 | ||
|
|
ed841aee30 | ||
|
|
84faf49bf0 | ||
|
|
d876acde4c | ||
|
|
d799466e9d | ||
|
|
ef270232dc | ||
|
|
949cfb758d | ||
|
|
10c602d9fb | ||
|
|
15aa8b62b8 | ||
|
|
313767539a | ||
|
|
e70eb3a3ee | ||
|
|
29055f7709 | ||
|
|
8a73675483 | ||
|
|
c2ac60fc34 | ||
|
|
9e2ec9d12f | ||
|
|
6c33ddcd47 | ||
|
|
af367a5fdf | ||
|
|
76ceb49841 | ||
|
|
53ba22ab5c | ||
|
|
3b7ce0680d | ||
|
|
999e8ed0d0 | ||
|
|
b1db390200 | ||
|
|
9c792902c7 | ||
|
|
64707f4f7b | ||
|
|
937365141f | ||
|
|
e28f1ffe18 | ||
|
|
4f08000a2e | ||
|
|
16a76853f4 | ||
|
|
f12e15b46b | ||
|
|
7e80a57724 | ||
|
|
b4661f4a59 | ||
|
|
01dcf6a9ac | ||
|
|
a385e87273 | ||
|
|
5000a14451 | ||
|
|
fcd9dd0be4 | ||
|
|
8f4eb7107a | ||
|
|
57a7f89485 | ||
|
|
57656d0a7e | ||
|
|
f50778ae26 | ||
|
|
a9c95a3230 | ||
|
|
4af8d5769a | ||
|
|
24a973e545 | ||
|
|
af58329931 | ||
|
|
d189ba52c0 | ||
|
|
78ad9ba60f | ||
|
|
f7fc61e39d | ||
|
|
6f52fe81d1 | ||
|
|
0d89f57680 | ||
|
|
2fac505221 | ||
|
|
61de07e53f | ||
|
|
e7ed056b6f | ||
|
|
8c9431d278 | ||
|
|
752bc2e980 | ||
|
|
aa2c7426ad | ||
|
|
b6dd388bdb | ||
|
|
2809c3a77c | ||
|
|
26866a7337 | ||
|
|
1dbcf8eb10 | ||
|
|
41e8170d59 | ||
|
|
a69524f7b4 | ||
|
|
a964325724 | ||
|
|
a97570be63 | ||
|
|
aaa96b20ed | ||
|
|
4478ac2c17 | ||
|
|
ef6b85fa77 | ||
|
|
b748ed8f43 | ||
|
|
6dcdf8c71f | ||
|
|
aeb7b0d050 | ||
|
|
8f5af3fca6 | ||
|
|
2cd58817d7 | ||
|
|
07969260c8 | ||
|
|
f589ba8b9c | ||
|
|
d79eed533b | ||
|
|
3cdfed9483 | ||
|
|
e777934290 | ||
|
|
5b14ebf22a | ||
|
|
2cf302f9df | ||
|
|
7c091fa6cd | ||
|
|
23dc977d48 | ||
|
|
16a84bd94a | ||
|
|
e76ab8c78c | ||
|
|
468a879c1f | ||
|
|
ba2734909f | ||
|
|
3635db8244 | ||
|
|
635b8772d7 | ||
|
|
e491b61e09 | ||
|
|
a7ba693ccb | ||
|
|
a4e5d752e1 | ||
|
|
d5ec781d4c | ||
|
|
a5a244fc53 | ||
|
|
e83cc59cba | ||
|
|
29c47ad515 | ||
|
|
cf34dbd276 | ||
|
|
8b332778e3 | ||
|
|
0deb2d4c5f | ||
|
|
63fcbb5969 | ||
|
|
0219c2b02b | ||
|
|
80b2f0d3cd | ||
|
|
d45c35a02e | ||
|
|
47f07d83b8 | ||
|
|
e13eb79f5b | ||
|
|
2bd151ba9c | ||
|
|
7c74350d5e | ||
|
|
e105c13e77 | ||
|
|
ac54da7d93 | ||
|
|
4073d77635 | ||
|
|
ab15a19028 | ||
|
|
166a3688f8 | ||
|
|
1a65a27fde | ||
|
|
71aeeee7c8 | ||
|
|
f2e2c02db6 | ||
|
|
1718ef88be | ||
|
|
736435adda | ||
|
|
50210a9d24 | ||
|
|
83a3af2fff | ||
|
|
10ed4ad3df | ||
|
|
1ee5d3e80e | ||
|
|
e5829201e1 | ||
|
|
282699e5b5 | ||
|
|
c768f04e32 | ||
|
|
dae60c9deb | ||
|
|
811426c586 | ||
|
|
9f13cdadcb | ||
|
|
254a5b0928 | ||
|
|
bbcef98e06 | ||
|
|
d8b5a04f97 | ||
|
|
c92989ca04 | ||
|
|
659f86cecf | ||
|
|
95fdea8b77 | ||
|
|
11188304a7 | ||
|
|
780297152c | ||
|
|
5ab77600b8 | ||
|
|
45d4318e0e | ||
|
|
ba894e21e8 | ||
|
|
a7dc29bad4 | ||
|
|
49f476d3b4 | ||
|
|
8ed8161d5c | ||
|
|
81348049df | ||
|
|
de2ebe3618 | ||
|
|
a6f6936719 | ||
|
|
baaafadeb0 | ||
|
|
19261ecfbf | ||
|
|
2717b9a47d | ||
|
|
b70a9d172b | ||
|
|
ae38d5d8b7 | ||
|
|
2796c46598 | ||
|
|
1c69a1f012 | ||
|
|
27df44f5ad | ||
|
|
d6c5132f39 | ||
|
|
dfc72edba2 | ||
|
|
ad7c0f9ebc | ||
|
|
a3ff83595a | ||
|
|
b4b8649fd6 | ||
|
|
8b6bf910ba | ||
|
|
983851fc60 | ||
|
|
e4b0d8dbf3 | ||
|
|
3894fad54d | ||
|
|
7cab6b5491 | ||
|
|
7d9ce53080 | ||
|
|
a9023d06d0 | ||
|
|
9f2d89c903 | ||
|
|
fc614ad4d0 | ||
|
|
b6978128b1 | ||
|
|
63e9ae3b93 | ||
|
|
67b6a82cf1 | ||
|
|
c9241cc933 | ||
|
|
0d70b5c776 | ||
|
|
c42663723f | ||
|
|
5f6f72ba8e | ||
|
|
c1be93a34c | ||
|
|
e547be5e9a | ||
|
|
48c37a2c0f | ||
|
|
35078738bc | ||
|
|
d6a395ba37 | ||
|
|
6c0bef7e6e | ||
|
|
7a0e248096 | ||
|
|
782c82a2d3 | ||
|
|
127888f3c1 | ||
|
|
54a6f066b3 | ||
|
|
468a6f2a70 | ||
|
|
266a0874b5 | ||
|
|
91b7798be8 | ||
|
|
76c6943159 | ||
|
|
25b32860ba | ||
|
|
fe49e41d7b | ||
|
|
9eaeaf7322 | ||
|
|
7331363618 | ||
|
|
6bfaf3b2f7 | ||
|
|
20c4699478 | ||
|
|
78c9fb3d76 | ||
|
|
67e8ec1a5f | ||
|
|
bfb0ca7968 | ||
|
|
f0c3d039a1 | ||
|
|
94bca4399a | ||
|
|
f2222d32db | ||
|
|
f71359c81d | ||
|
|
de082260d8 | ||
|
|
7d4ea47611 | ||
|
|
8bf0bbb715 | ||
|
|
798b03f29d | ||
|
|
bafb9ae020 | ||
|
|
55dc929a1f | ||
|
|
cc960377ac | ||
|
|
255123cbf9 | ||
|
|
7ae41ff165 | ||
|
|
6d465aaf52 | ||
|
|
63f715e650 | ||
|
|
dd4e1d0ac3 | ||
|
|
10a3b3bd14 | ||
|
|
359d703ded | ||
|
|
f48b57c95a | ||
|
|
e6dd3673a1 | ||
|
|
b4216767ad | ||
|
|
775a5507a6 | ||
|
|
c085c1f3ad | ||
|
|
0bce1894ae | ||
|
|
92190e5095 | ||
|
|
706858e211 | ||
|
|
85fe226256 | ||
|
|
3d21f89f1d | ||
|
|
0d9e28012e | ||
|
|
3d11e5bb32 | ||
|
|
c91e20c6b5 | ||
|
|
a3d33e27e2 | ||
|
|
3ebb7cfa1b | ||
|
|
88a0c4053b | ||
|
|
784475dd66 | ||
|
|
84cb59b942 | ||
|
|
0c14759e86 | ||
|
|
6d1421a6f9 | ||
|
|
307d2d5dc1 | ||
|
|
acab8e8632 | ||
|
|
d4f3e38062 | ||
|
|
ac85d2eb3e | ||
|
|
de833d620e | ||
|
|
ed3270fb04 | ||
|
|
2e2fcd49bf | ||
|
|
762ebad66e | ||
|
|
d0521f15f1 | ||
|
|
d2c0250b41 | ||
|
|
9f357837fa | ||
|
|
5cfc494e16 | ||
|
|
155b64d3fc | ||
|
|
b7e14311be | ||
|
|
27681ac987 | ||
|
|
c70f3d35d0 | ||
|
|
ec04f0c88f | ||
|
|
8cb68b79c1 | ||
|
|
b0b5761a8c | ||
|
|
364336e22a | ||
|
|
1f90f7dd4d | ||
|
|
d4c6f873af | ||
|
|
65567fa1ce | ||
|
|
e98d1df5f4 | ||
|
|
a8973c1147 | ||
|
|
75ef5b1b0b | ||
|
|
30c66303ba | ||
|
|
09b669a584 | ||
|
|
52e5d541ef | ||
|
|
fccb581765 | ||
|
|
cb7d9d5f3f | ||
|
|
8db8f14f99 | ||
|
|
b42482c960 | ||
|
|
710b215c38 | ||
|
|
fc078a47fd | ||
|
|
092e019de9 | ||
|
|
2ffb4b6480 | ||
|
|
88750a7000 | ||
|
|
f069802abb | ||
|
|
eb2f1ff559 | ||
|
|
6f4fd3ef72 | ||
|
|
0ce4500b48 | ||
|
|
d79c722d95 | ||
|
|
98176007d8 | ||
|
|
cec5045b52 | ||
|
|
f6255e497b | ||
|
|
68e513c6a4 | ||
|
|
56b207e41f | ||
|
|
da7788dd64 | ||
|
|
89a8ccb828 | ||
|
|
0570610765 | ||
|
|
8109a7b67a | ||
|
|
e5e3bb3705 | ||
|
|
f7b5a4d170 | ||
|
|
8ca004fde1 | ||
|
|
563a56af9d | ||
|
|
635391eae8 | ||
|
|
c2171c01e1 | ||
|
|
65c1e239eb | ||
|
|
dc440aaee6 | ||
|
|
9887e2b53b | ||
|
|
4b9b35d1c2 | ||
|
|
8d9b106be1 | ||
|
|
dff7b475fb | ||
|
|
67f31ffdf0 | ||
|
|
bd78e73131 | ||
|
|
81a1fa167a | ||
|
|
32f60fd112 | ||
|
|
8d854e0a6b | ||
|
|
dc2cd994d4 | ||
|
|
a749212707 | ||
|
|
e886b53a94 | ||
|
|
98bf3adc72 | ||
|
|
7ca32ee2b5 | ||
|
|
ec3578364e | ||
|
|
eda028721e | ||
|
|
9ecff0723c | ||
|
|
6b7612fed7 | ||
|
|
b47723d607 | ||
|
|
9d7e7735d5 | ||
|
|
3260c81397 | ||
|
|
5ea03b1ded | ||
|
|
5bbdaad0e5 | ||
|
|
10fff4e2ef | ||
|
|
b59a9bc95c | ||
|
|
a4acea9adf | ||
|
|
c029048306 | ||
|
|
d5b066636f | ||
|
|
b737bdbca0 | ||
|
|
20254dfc08 | ||
|
|
af1470de07 | ||
|
|
d2857006cf | ||
|
|
855eddab80 | ||
|
|
99636ba344 | ||
|
|
324e0e8f90 | ||
|
|
7bf55c5846 | ||
|
|
5791e8b9a2 | ||
|
|
07de92cdb6 | ||
|
|
f2888dcb1e | ||
|
|
3ef7f3f44d | ||
|
|
3e6eedec30 | ||
|
|
2bcf9b86cf | ||
|
|
5f18484fa9 | ||
|
|
b028d72d51 | ||
|
|
61149f297c | ||
|
|
fab2d30f38 | ||
|
|
1e6ef99a50 | ||
|
|
5460004223 | ||
|
|
b242bd6468 | ||
|
|
847ecd1eec | ||
|
|
c80fbff648 | ||
|
|
b20f8fc8c9 | ||
|
|
52bd140213 | ||
|
|
c03eab2410 | ||
|
|
a21db3b3c2 | ||
|
|
87ee979a12 | ||
|
|
16ba5b1bb5 | ||
|
|
3afd895d41 | ||
|
|
83b3312467 | ||
|
|
0dadf0bbb4 | ||
|
|
dd525a4f9b | ||
|
|
d19bde8cb1 | ||
|
|
b5400f6dc9 | ||
|
|
3514694cdf | ||
|
|
5c109cdef1 | ||
|
|
fea4b816af | ||
|
|
f92d836607 | ||
|
|
b5c7d6bfcd | ||
|
|
d49015a7e6 | ||
|
|
e69d003d8f | ||
|
|
a08253b6d0 | ||
|
|
a8a7a59ae8 | ||
|
|
ce1fb4c018 | ||
|
|
38acdaabfa | ||
|
|
edaf64c254 | ||
|
|
2291f18695 | ||
|
|
7d54b542b5 | ||
|
|
b540eb094c | ||
|
|
ddbcdcb4ba | ||
|
|
7f790432cc | ||
|
|
eb14348153 | ||
|
|
7b6cb70cc8 | ||
|
|
afbd05d41a | ||
|
|
d3ff4908e6 | ||
|
|
612624d241 | ||
|
|
3816361c15 | ||
|
|
131fc986b4 | ||
|
|
b5b69e9357 | ||
|
|
3e5e695325 | ||
|
|
d567ab3569 | ||
|
|
6dfa57a7b1 | ||
|
|
f659ee3e0b | ||
|
|
be60a871a3 | ||
|
|
3bb5505063 | ||
|
|
41977d1dbb | ||
|
|
3de650e19d | ||
|
|
fc98fd3094 | ||
|
|
85233b3cbf | ||
|
|
e3ebf1c668 | ||
|
|
4b7a89e754 | ||
|
|
176405cd7c | ||
|
|
5dec08b9a3 | ||
|
|
8147d2048e | ||
|
|
25ac3499c2 | ||
|
|
ef50e57317 | ||
|
|
887062d339 | ||
|
|
03a479fd60 | ||
|
|
ab42521906 | ||
|
|
b60504f404 | ||
|
|
6d9745e5c3 | ||
|
|
313f600432 | ||
|
|
ba00a0f370 | ||
|
|
23e29e993b | ||
|
|
ecd8921dcd | ||
|
|
dcebe930e7 | ||
|
|
88f703af1f | ||
|
|
e00f87045e | ||
|
|
fac839f481 | ||
|
|
a6b8f4b674 | ||
|
|
2fb78565a7 | ||
|
|
d0dfb4926b | ||
|
|
4caaa3a396 | ||
|
|
90382c4d1c | ||
|
|
866e92558c | ||
|
|
f5b198b8b7 | ||
|
|
fbb2dcf7a8 | ||
|
|
88dc65cb3c | ||
|
|
04d042308b | ||
|
|
bda4b52395 | ||
|
|
f7c55a3258 | ||
|
|
20f76e50c3 | ||
|
|
887d1893e7 | ||
|
|
458fb3a4a2 | ||
|
|
30bbae3c22 | ||
|
|
2a26c8f340 | ||
|
|
d97682991d | ||
|
|
b91b3148a4 | ||
|
|
a54853d3b4 | ||
|
|
6a816ba700 | ||
|
|
c5bb32d6d2 | ||
|
|
62f5d10d03 | ||
|
|
724a31b746 | ||
|
|
a2c0d47e9c | ||
|
|
676327d9e4 | ||
|
|
012fb28e25 | ||
|
|
b209cac2e2 | ||
|
|
e18b2cfa39 | ||
|
|
23ff3769ac | ||
|
|
511fb97273 | ||
|
|
5b9e89acd3 | ||
|
|
e26e0ec809 | ||
|
|
0337ccb93a | ||
|
|
5a15558355 | ||
|
|
e18442069b | ||
|
|
3d17c8f1ab | ||
|
|
7f36f65ab0 | ||
|
|
62a0bcddd9 | ||
|
|
5d2ab8adfb | ||
|
|
54958fd502 | ||
|
|
8041542f92 | ||
|
|
7d473fb265 | ||
|
|
2f12ccc803 | ||
|
|
a2ce764c82 | ||
|
|
9b5318876d | ||
|
|
91aa75da0e | ||
|
|
ce8ab0e66e | ||
|
|
0e7179ca85 | ||
|
|
9d34ce9776 | ||
|
|
decfcdd82a | ||
|
|
d6ae1ef6f2 | ||
|
|
4cb82ad5a7 | ||
|
|
62603dd2bc | ||
|
|
2011685e89 | ||
|
|
ceef9cf276 | ||
|
|
5b9ae5e6db | ||
|
|
8352925257 | ||
|
|
9f783b018d | ||
|
|
8a0f00a5c9 | ||
|
|
0c09f78142 | ||
|
|
84743ec87d | ||
|
|
5b65f5c185 | ||
|
|
8c1de5958b | ||
|
|
b80c533fb0 | ||
|
|
937404892f | ||
|
|
39ee1e28cf | ||
|
|
dc79ed8192 | ||
|
|
d1b8bef248 | ||
|
|
62de3e4ab6 | ||
|
|
716d6aeeee | ||
|
|
96414034f9 | ||
|
|
efe802dac0 | ||
|
|
52f69f77bc | ||
|
|
b8922b0270 | ||
|
|
0caee16eb0 | ||
|
|
0cfd7787f4 | ||
|
|
3b109db2d1 | ||
|
|
3a5d06272f | ||
|
|
9ccff656bd | ||
|
|
8bc92320d4 | ||
|
|
309b6e0810 | ||
|
|
f22e1db33f | ||
|
|
207191f987 | ||
|
|
0cab131c51 | ||
|
|
bdc569feea | ||
|
|
ac32f27fdc | ||
|
|
de8e7b0f27 | ||
|
|
d229d6a7cb | ||
|
|
53f1985e77 | ||
|
|
31a1667fda | ||
|
|
c9d34947b7 | ||
|
|
eea062d357 | ||
|
|
9c6875ec0f | ||
|
|
56f8100f16 | ||
|
|
edfecddca1 | ||
|
|
9f31ef851f | ||
|
|
4a98ef064e | ||
|
|
2b5e2ed282 | ||
|
|
72a26865b5 | ||
|
|
ee02265ac2 | ||
|
|
e7576fdd1a | ||
|
|
28c9d6b6b5 | ||
|
|
06f619875b | ||
|
|
2f9f1f73b7 | ||
|
|
a8ed6bad34 | ||
|
|
4d7aeced3f | ||
|
|
24ba51d11e | ||
|
|
d7bbf74e49 | ||
|
|
3b9ec2b9eb | ||
|
|
f795025f13 | ||
|
|
a8e6dc7a54 | ||
|
|
dbcdc2209e | ||
|
|
b6532fa9a0 | ||
|
|
243980ef73 | ||
|
|
6cb01a210f | ||
|
|
88de299e12 | ||
|
|
eb2a487433 | ||
|
|
0d9aa0cdac | ||
|
|
c8c53cb424 | ||
|
|
cfde7e9edc | ||
|
|
fd6ae3a216 | ||
|
|
0ccf81e67c | ||
|
|
1a062823ee | ||
|
|
e2bdef2fba | ||
|
|
611ed93e39 | ||
|
|
d35e5ac752 | ||
|
|
4770ad3177 | ||
|
|
83291f378b | ||
|
|
df2e259944 | ||
|
|
5f8e7e67b4 | ||
|
|
151f12ef5e | ||
|
|
199b3f4d71 | ||
|
|
db20e7d143 | ||
|
|
07f50e275d | ||
|
|
859dc7beb7 | ||
|
|
5ba694e909 | ||
|
|
a05706d89d | ||
|
|
57e31c11da | ||
|
|
57ad491356 | ||
|
|
8d51aaa403 | ||
|
|
7e522770f6 | ||
|
|
1b9653827f | ||
|
|
b3b7711149 | ||
|
|
ade83b3cfe | ||
|
|
fc4f93c87a | ||
|
|
5940f17b83 | ||
|
|
53917e506e | ||
|
|
97e939ae2b | ||
|
|
f0b09ee16c | ||
|
|
b3b13bdd43 | ||
|
|
50c2683be0 | ||
|
|
ad7fc34efd | ||
|
|
c537c80ed6 | ||
|
|
dacbf4e798 | ||
|
|
4ee6ae67d6 | ||
|
|
a1fa424ec1 | ||
|
|
9d4a208c0d | ||
|
|
235181fb21 | ||
|
|
7bcee6e9a8 | ||
|
|
aede9c3467 | ||
|
|
484dc4ad3a | ||
|
|
8756989b4b | ||
|
|
c8b7eccc6f | ||
|
|
23add8a72b | ||
|
|
e0bcfe2afb | ||
|
|
73ad1307ae | ||
|
|
c95a6ea5d1 | ||
|
|
ac5a1d68ea | ||
|
|
138a16f0b3 | ||
|
|
694d987365 | ||
|
|
f4b2af730d | ||
|
|
b399d8df7e | ||
|
|
cfbaf5e53b | ||
|
|
af9ad7b699 | ||
|
|
ac14b6d685 | ||
|
|
13decd38d9 | ||
|
|
bada986433 | ||
|
|
b99a1d2cd9 | ||
|
|
e49c5213ca | ||
|
|
0e93e71127 | ||
|
|
695d6f0e4e | ||
|
|
5402001362 | ||
|
|
be548c13e1 | ||
|
|
5dcd3b2c0f | ||
|
|
32f7348d30 | ||
|
|
eb30e8fe9e | ||
|
|
81ad10bab5 | ||
|
|
5b089bbb9c | ||
|
|
91491d9a7b | ||
|
|
50d638d1b6 | ||
|
|
f6f26fe6c5 | ||
|
|
037a05cd66 | ||
|
|
6ba7449df7 | ||
|
|
6545cff0ef | ||
|
|
833c5edf06 | ||
|
|
25436fe555 | ||
|
|
32b140045e | ||
|
|
53b7584a90 | ||
|
|
7939b84380 | ||
|
|
fadbdc1f63 | ||
|
|
6a5f37b1b7 | ||
|
|
c1727ba005 | ||
|
|
107cbb29b1 | ||
|
|
8b11e98d42 | ||
|
|
43769ad464 | ||
|
|
a9ff0bdbbf | ||
|
|
cbae72d9da | ||
|
|
9ee4f8b388 | ||
|
|
4cdcebf022 | ||
|
|
00d3ff8a18 | ||
|
|
d8889f2d1f | ||
|
|
865d0ca64a | ||
|
|
04575674db | ||
|
|
0b04505e04 | ||
|
|
d3a458ef1a | ||
|
|
271de66f01 | ||
|
|
e674759860 | ||
|
|
8e546e8496 | ||
|
|
a60f510c85 | ||
|
|
6fb021a5bc | ||
|
|
f1b5ed1cba | ||
|
|
2bef82babc | ||
|
|
c8426776fc | ||
|
|
eef4fc3a0a | ||
|
|
d325a42890 | ||
|
|
3f2f328d87 | ||
|
|
d93bda21c2 | ||
|
|
096469c6fe | ||
|
|
fa2d58adff | ||
|
|
42004d93f0 | ||
|
|
22d7f3cfe5 | ||
|
|
d9b3104c78 | ||
|
|
4f05f083a5 | ||
|
|
609c7cf84d | ||
|
|
25b4296045 | ||
|
|
2b8b6d3dc3 | ||
|
|
e9c4cb227f | ||
|
|
680b7a16fb | ||
|
|
e9da5eecf2 | ||
|
|
24c8f1d8b5 | ||
|
|
b62a4aae1a | ||
|
|
433f4e0cb5 | ||
|
|
288bdc2ee9 | ||
|
|
b39cf7ea11 | ||
|
|
1574e855eb | ||
|
|
62c26f8f27 | ||
|
|
e01cbb2ffa | ||
|
|
e669754d0b | ||
|
|
be05b807cd | ||
|
|
0dcb5546a1 | ||
|
|
c5285acb04 | ||
|
|
552c5249ac | ||
|
|
f0554fcdee | ||
|
|
edde3defed | ||
|
|
4895daba85 | ||
|
|
69f5879384 | ||
|
|
d813590780 | ||
|
|
c61a9c5911 | ||
|
|
44e94f6615 | ||
|
|
9731048836 | ||
|
|
fda9d19a97 | ||
|
|
8d3e6ff8a7 | ||
|
|
450a4a04af | ||
|
|
fef922e417 | ||
|
|
d6fb6bf036 | ||
|
|
e17bc6c581 | ||
|
|
92e8f059c8 | ||
|
|
4411852e59 | ||
|
|
2aa528852e | ||
|
|
7585541514 | ||
|
|
d37ed02e79 | ||
|
|
66291d3575 | ||
|
|
f0b9ca4bf9 | ||
|
|
a75c50620c | ||
|
|
e00585ca24 | ||
|
|
37a69b4569 | ||
|
|
c794fef9cb | ||
|
|
d1848194eb | ||
|
|
38abd389eb | ||
|
|
b1679df3d2 | ||
|
|
b077fc5e91 | ||
|
|
0d4a2239fc | ||
|
|
072edad0fd | ||
|
|
c82410fd16 | ||
|
|
7ba0682297 | ||
|
|
c86f597153 | ||
|
|
21adcca065 | ||
|
|
8c8f1418d5 | ||
|
|
03aa8df8e2 | ||
|
|
d392cdaab6 | ||
|
|
ef967b6a21 | ||
|
|
7c515bbef7 | ||
|
|
d72ea52f68 | ||
|
|
55a7adff20 | ||
|
|
b911556896 | ||
|
|
c6c4a7b14f | ||
|
|
cfb0ff2618 | ||
|
|
8b33e6d175 | ||
|
|
3f871a08e2 | ||
|
|
418a245ea9 | ||
|
|
f20bfacc5a | ||
|
|
0b3d55e6ab | ||
|
|
ed305d2699 | ||
|
|
5766ff21d0 | ||
|
|
a887ff4f09 | ||
|
|
577f1a588b | ||
|
|
7a8e7150f0 | ||
|
|
f2d980b132 | ||
|
|
860c3c443c | ||
|
|
40e4359173 | ||
|
|
3432e814c5 | ||
|
|
af922702c7 | ||
|
|
dddf550593 | ||
|
|
c89016b181 | ||
|
|
c733648dc6 | ||
|
|
618438642a | ||
|
|
4f11e2d25f | ||
|
|
05605480ae | ||
|
|
1aeaefca7f | ||
|
|
5fbcbbc584 | ||
|
|
2b139924cd | ||
|
|
f5daee2483 | ||
|
|
09275a56c1 | ||
|
|
5ec22bc180 | ||
|
|
edc5d8d644 | ||
|
|
645906a7d7 | ||
|
|
a213e9e55d | ||
|
|
d67235b3c1 | ||
|
|
69df9f9daa | ||
|
|
f991991474 | ||
|
|
4d50543d70 | ||
|
|
2737255705 | ||
|
|
a39cefe40f | ||
|
|
82277d8f56 | ||
|
|
268a990aa6 | ||
|
|
a1e0bf022e | ||
|
|
be808deb59 | ||
|
|
33b1c8471c | ||
|
|
eb365c1d24 | ||
|
|
aad3e06027 | ||
|
|
6a0a81b3be | ||
|
|
830be92f1d | ||
|
|
f8e80f96ff | ||
|
|
53055bc8b6 | ||
|
|
2a22c69a64 | ||
|
|
1756feae71 | ||
|
|
9d55cd7658 | ||
|
|
b30a6d36b5 | ||
|
|
b94066acd8 | ||
|
|
63dc0445a8 | ||
|
|
16c3da3a27 | ||
|
|
7b62bed9db | ||
|
|
e877967a62 | ||
|
|
d999c1d3dd | ||
|
|
334d5b1b17 | ||
|
|
1cd30847f6 | ||
|
|
27e1a8bd7a | ||
|
|
68face8d46 | ||
|
|
d62e3f6bc2 | ||
|
|
99ca28ea9b | ||
|
|
587aa93f6d | ||
|
|
4e8d8a4de1 | ||
|
|
7d927a7396 | ||
|
|
fb5b344427 | ||
|
|
44e70afa85 | ||
|
|
d4b018f242 | ||
|
|
fc38bf0429 | ||
|
|
291027ad82 | ||
|
|
3b1feeef6d | ||
|
|
25f0382fce | ||
|
|
af5a378572 | ||
|
|
9a38e31baa | ||
|
|
ff20908bbd | ||
|
|
40032f295a | ||
|
|
25dd8db423 | ||
|
|
5fa49b3319 | ||
|
|
8b85744d3e | ||
|
|
bc5b7455cf | ||
|
|
b8e1aa67d8 | ||
|
|
fca754bddd | ||
|
|
8344d5a376 | ||
|
|
60ac031db4 | ||
|
|
013b7eff1c | ||
|
|
508327235a | ||
|
|
5198ad7612 | ||
|
|
b32f4b844a | ||
|
|
9992ecc317 | ||
|
|
e9e94dcb0f | ||
|
|
833041c62e | ||
|
|
2aa4651534 | ||
|
|
74c8bfff4f | ||
|
|
e60c016fc6 | ||
|
|
cbf81b8839 | ||
|
|
300456cd3e | ||
|
|
c0cc754fb5 | ||
|
|
a4939b91e7 | ||
|
|
08bbe596a2 | ||
|
|
d7f1491f41 | ||
|
|
649c3af98a | ||
|
|
53e83ff048 | ||
|
|
13aad99194 | ||
|
|
a77fc96067 | ||
|
|
530b29ccdf | ||
|
|
9cf3284371 | ||
|
|
5aee96d907 | ||
|
|
a11de9b145 | ||
|
|
20bebba1ff | ||
|
|
58c0e65542 | ||
|
|
c07db098a7 | ||
|
|
610bbeee97 | ||
|
|
8fd4041511 | ||
|
|
98f4c29913 | ||
|
|
418d632738 | ||
|
|
c7da814bca | ||
|
|
0370d1a1ba | ||
|
|
d218572c72 | ||
|
|
05bf86acb6 | ||
|
|
0260ecfbdb | ||
|
|
0b9588bf9e | ||
|
|
3e863a539a | ||
|
|
95835b8297 | ||
|
|
def9b5e2ce | ||
|
|
265838aa2c | ||
|
|
fadc278485 | ||
|
|
476bbfbdb7 | ||
|
|
cbbff0c401 | ||
|
|
87f7b65052 | ||
|
|
91b33f72b5 | ||
|
|
a1dba82360 | ||
|
|
828d187198 | ||
|
|
545dd8b8d8 | ||
|
|
ca04779dfc | ||
|
|
fe27e09a07 | ||
|
|
05dd161d76 | ||
|
|
7976d746b6 | ||
|
|
35a4d31519 | ||
|
|
f558e858e7 | ||
|
|
2bec4479e7 | ||
|
|
47289a4d33 | ||
|
|
ec87a932b8 | ||
|
|
d580722164 | ||
|
|
187ece610b | ||
|
|
366b94addc | ||
|
|
e0d7e277fb | ||
|
|
be1129e782 | ||
|
|
fec4d1992d | ||
|
|
f0b5058760 | ||
|
|
c82d8cbacc | ||
|
|
daa4e99a2f | ||
|
|
3c07ff592a | ||
|
|
fdde84ac35 | ||
|
|
858ae3dab4 | ||
|
|
20147e87b2 | ||
|
|
2f8dcdd602 | ||
|
|
587e6739d9 | ||
|
|
231f2238c1 | ||
|
|
4cfe11c319 | ||
|
|
331b8c0144 | ||
|
|
4ae90e35d5 | ||
|
|
472a10fd54 | ||
|
|
3c8fb0520e | ||
|
|
cee06140e2 | ||
|
|
990a898cc7 | ||
|
|
d11bca0cdc | ||
|
|
e432e6576a | ||
|
|
5acfc22442 | ||
|
|
afb604ee5f | ||
|
|
44e4cf6556 | ||
|
|
43af1e4b42 | ||
|
|
8fa6140a0d | ||
|
|
f181d66003 | ||
|
|
7be79290e8 | ||
|
|
eb27e8acc5 | ||
|
|
ac47b56566 | ||
|
|
e6a8019c2b | ||
|
|
4972839b69 | ||
|
|
2a0c3636c7 | ||
|
|
4b649e0bad | ||
|
|
3c02d614fa | ||
|
|
3a8efb3db1 | ||
|
|
d69d289020 | ||
|
|
86cbf1b82c | ||
|
|
910eebcf5d | ||
|
|
e0eb820ef9 | ||
|
|
a1d798b817 | ||
|
|
cc9dafffde | ||
|
|
7c9fffc201 | ||
|
|
75f30a8f9c | ||
|
|
a6b1806e66 | ||
|
|
c8cb30f76e | ||
|
|
faf10294ed | ||
|
|
4702271102 | ||
|
|
24f0eeb6df | ||
|
|
6dc51edb4c | ||
|
|
472ece45e7 | ||
|
|
a7ecdef2a6 | ||
|
|
924f999aa8 | ||
|
|
1f51bd4594 | ||
|
|
fdd7d76ffd | ||
|
|
16cb4c5aaa | ||
|
|
70561cabaf | ||
|
|
1711efcc47 | ||
|
|
a533c95640 | ||
|
|
d3488da0c2 | ||
|
|
cc87d2e38b | ||
|
|
1ea87020c4 | ||
|
|
0e67100cad | ||
|
|
12ab95668c | ||
|
|
8060b30cce | ||
|
|
5918e0184c | ||
|
|
1ca7c5b97d | ||
|
|
96ec54e5be | ||
|
|
b5666888b1 | ||
|
|
83a8b1afb8 | ||
|
|
6891b52216 | ||
|
|
a42f3fdfbc | ||
|
|
7ce4629b12 | ||
|
|
dd264c6dfb | ||
|
|
ad0b36a0c9 | ||
|
|
c60d071239 | ||
|
|
da67b1059c | ||
|
|
7c577ae1d1 | ||
|
|
3e1819f25d | ||
|
|
fe138dc0a1 | ||
|
|
0c6957ea78 | ||
|
|
f4047e016c | ||
|
|
dc6f60a501 | ||
|
|
83caf01778 | ||
|
|
3159b3d9a1 | ||
|
|
f9195d194b | ||
|
|
c9fcef2608 | ||
|
|
1ec204987d | ||
|
|
fc811bd33d | ||
|
|
978ed03e9c | ||
|
|
44b0f1921f | ||
|
|
3d24e0a2eb | ||
|
|
28b7f0884f | ||
|
|
7b599f5fef | ||
|
|
5c905c42b2 | ||
|
|
655b4a4d17 | ||
|
|
94e864e933 | ||
|
|
0f1b3486de | ||
|
|
a195ea942e | ||
|
|
8502939b65 | ||
|
|
cf4a3e0bbe | ||
|
|
fe8945b5c9 | ||
|
|
01f3150a70 | ||
|
|
bd2a065562 | ||
|
|
fbcdb53d72 | ||
|
|
f3741ff1e4 | ||
|
|
7e0a7d8b71 | ||
|
|
73131cef9e | ||
|
|
4e3fcc3235 | ||
|
|
499f20f6e8 | ||
|
|
3317223e19 | ||
|
|
46631d6eaf | ||
|
|
8e240a2e84 | ||
|
|
8eee450c65 | ||
|
|
15be488c53 | ||
|
|
a475e5758d | ||
|
|
7cad4b7918 | ||
|
|
e48dfcc5b1 | ||
|
|
197be69425 | ||
|
|
3b015eef51 | ||
|
|
b59cb778ef | ||
|
|
bac573bbed | ||
|
|
f6484e6e6b | ||
|
|
27d2dc6d9e | ||
|
|
eefda61445 | ||
|
|
c2339b1203 | ||
|
|
285ff54853 | ||
|
|
60fe5d6428 | ||
|
|
cad268476c | ||
|
|
d704795d90 | ||
|
|
d700fddfdd | ||
|
|
2c517a3237 | ||
|
|
99764450b3 | ||
|
|
bc65d358f2 | ||
|
|
6ce6d9dc37 | ||
|
|
08909e5c69 | ||
|
|
17012c1a45 | ||
|
|
e6d4685109 | ||
|
|
37869e816b | ||
|
|
1d3f4826a9 | ||
|
|
6bc12e8f2b | ||
|
|
727b5aebd1 | ||
|
|
8786c700c2 | ||
|
|
45320d91d1 | ||
|
|
39520e54ea | ||
|
|
3acd4486a3 | ||
|
|
9998752147 | ||
|
|
145e2093f3 | ||
|
|
1e3adcd14e | ||
|
|
f603d96f48 | ||
|
|
f3e7d8778c | ||
|
|
33cca29a8e | ||
|
|
fa762d9952 | ||
|
|
5b5dd07d60 | ||
|
|
c4b750002e | ||
|
|
e8549a413b | ||
|
|
a7cc8fced5 | ||
|
|
ec5ac17f87 | ||
|
|
556c199a89 | ||
|
|
2d5b9c12a6 | ||
|
|
759ffc4743 | ||
|
|
79aba19dde | ||
|
|
780ea72b3b | ||
|
|
82998ce3a3 | ||
|
|
57a616262f | ||
|
|
0d9ecfc4de | ||
|
|
6e370beb92 | ||
|
|
e6f91b91e0 | ||
|
|
85e99feb49 | ||
|
|
d87117f623 | ||
|
|
851d53d56b | ||
|
|
08bc14f598 | ||
|
|
28b7ab7fbe | ||
|
|
c15f63ce62 | ||
|
|
15416a9c86 | ||
|
|
78e35e2f29 | ||
|
|
3d1f75221b | ||
|
|
44bf8184fe | ||
|
|
ce1092c33d | ||
|
|
4910bf12e9 | ||
|
|
04a47093ee | ||
|
|
9d5e5e3ee7 | ||
|
|
1a702bfd50 | ||
|
|
49c4c554c4 | ||
|
|
ee9163aa40 | ||
|
|
a191edfbd5 | ||
|
|
d061df2e12 | ||
|
|
640b0ce093 | ||
|
|
8be4d47178 | ||
|
|
1d6db8db9a | ||
|
|
6f3ca40fed | ||
|
|
e8f9429b92 | ||
|
|
8fd6424db9 | ||
|
|
84c754e007 | ||
|
|
aba87a139d | ||
|
|
f623ea0a55 | ||
|
|
fe408cfb41 | ||
|
|
ab963fef82 | ||
|
|
8b39059d3a | ||
|
|
a1edd65542 | ||
|
|
c3577b2256 | ||
|
|
7d80c5c7f7 | ||
|
|
4edef874d6 | ||
|
|
84a7fddd95 | ||
|
|
ff2a5e8c27 | ||
|
|
2619f3f667 | ||
|
|
f5c2ed9e45 | ||
|
|
a7ebbfb139 | ||
|
|
5e5160d4fc | ||
|
|
994c033c62 | ||
|
|
91972d1d1f | ||
|
|
222c9a6357 | ||
|
|
caa56c9cad | ||
|
|
23db9c573f | ||
|
|
59284739dd | ||
|
|
b43cbf7f95 | ||
|
|
80ea2b8c5e | ||
|
|
003866621f | ||
|
|
067704a59a | ||
|
|
2783668092 | ||
|
|
86e81f523c | ||
|
|
6b5deee9a8 | ||
|
|
d3934c97ed | ||
|
|
7c4df8c81f | ||
|
|
7d0beeafad | ||
|
|
b1d9f9f9d5 | ||
|
|
abe9258943 | ||
|
|
83afc2a0ad | ||
|
|
21600c612d | ||
|
|
e356720c73 | ||
|
|
ab4e341e65 | ||
|
|
9da5ec79c5 | ||
|
|
e549f15b1c | ||
|
|
056b1e8d63 | ||
|
|
d959630991 | ||
|
|
9be2512050 | ||
|
|
b4b34cc994 | ||
|
|
12ce46e4b1 | ||
|
|
38955d1761 | ||
|
|
9f59b6b439 | ||
|
|
0a8f39fe96 | ||
|
|
ff02ba5965 | ||
|
|
017157820a | ||
|
|
b29ac5249e | ||
|
|
4ed61c13f8 | ||
|
|
b632e21ba0 | ||
|
|
3911f3b202 | ||
|
|
76a330d4b9 | ||
|
|
723ca8ed88 | ||
|
|
a53c2104d1 | ||
|
|
5369ba1d83 | ||
|
|
b62ede1544 | ||
|
|
c11d63e4d2 | ||
|
|
ca586b4f3d | ||
|
|
0dd8f574a7 | ||
|
|
c161bb5e95 | ||
|
|
ead0844174 | ||
|
|
2b395985e6 | ||
|
|
e62acb1e8c | ||
|
|
7237362feb | ||
|
|
46c7ee0e4f | ||
|
|
80debe19e0 | ||
|
|
4cd0f1ca66 | ||
|
|
0dd63c007e | ||
|
|
fd61a5253d | ||
|
|
3f403f0f87 | ||
|
|
fc2112831c | ||
|
|
b370497f96 | ||
|
|
3573e211cc | ||
|
|
b6e4f472d1 | ||
|
|
6d321e0151 | ||
|
|
5c66d87ed6 | ||
|
|
0c6c135967 | ||
|
|
8266a22332 | ||
|
|
85790fcade | ||
|
|
d9744c81b7 | ||
|
|
84427e132e | ||
|
|
840b74dbb5 | ||
|
|
f122005aaf | ||
|
|
2402504a4c | ||
|
|
b4d939a620 | ||
|
|
1914a114a2 | ||
|
|
d6e2f5f4a8 | ||
|
|
1e1c9f639c | ||
|
|
24f87ac963 | ||
|
|
2796d60d79 | ||
|
|
648c2d09f9 | ||
|
|
baf7986cfa | ||
|
|
a04c78ab94 | ||
|
|
06ec03de74 | ||
|
|
046e669c78 | ||
|
|
77d1788619 | ||
|
|
2546d09fe2 | ||
|
|
515b8366d2 | ||
|
|
c8f7519cee | ||
|
|
1f644a9c1d | ||
|
|
436cc60138 | ||
|
|
156964bfc9 | ||
|
|
67772bbc43 | ||
|
|
8976ba5583 | ||
|
|
49425e6c2a | ||
|
|
cf9c3afc86 | ||
|
|
d745381ebe | ||
|
|
803a97df7f | ||
|
|
841340b266 | ||
|
|
1e3060598f | ||
|
|
bb9205226a | ||
|
|
3dcdc739de | ||
|
|
366410ee9e | ||
|
|
48b0cc0229 | ||
|
|
81701547b2 | ||
|
|
f387eb21eb | ||
|
|
382c08e3cd | ||
|
|
15d5369bdd | ||
|
|
0a7e797090 | ||
|
|
946720f414 | ||
|
|
e8fdff7a3b | ||
|
|
6577281bed | ||
|
|
c1b2561598 | ||
|
|
0f34752f8f | ||
|
|
7d8c0c663f | ||
|
|
609a4cfd42 | ||
|
|
39081e9c1c | ||
|
|
368ce69198 | ||
|
|
9df8edcb1c | ||
|
|
cd34686967 | ||
|
|
ca7b48c3d5 | ||
|
|
5e781f24b6 | ||
|
|
4ec527a9ea | ||
|
|
6e8446b6ae | ||
|
|
ef260db76e | ||
|
|
71d703f2a5 | ||
|
|
cb37a0e835 | ||
|
|
3dea1d6a60 | ||
|
|
0454642220 | ||
|
|
9f260853ac | ||
|
|
b389d50943 | ||
|
|
f40eefce57 | ||
|
|
65f7474110 | ||
|
|
45a4cd89a6 | ||
|
|
b1da636be0 | ||
|
|
6f646be733 | ||
|
|
23b572e9b7 | ||
|
|
1bfdfc954b | ||
|
|
b3f29b0a53 | ||
|
|
420c35d4a2 | ||
|
|
21e7e27e1f | ||
|
|
1e80fa118c | ||
|
|
18dd0f650c | ||
|
|
408c7bebe5 | ||
|
|
e8f55b9f0d | ||
|
|
c0ac29db16 | ||
|
|
4b7cb706f6 | ||
|
|
0d2e7d43b9 | ||
|
|
5179a99abb | ||
|
|
c4b2519e6c | ||
|
|
1a1245343d | ||
|
|
c742a09def | ||
|
|
d569f93e78 | ||
|
|
09829d7f7a | ||
|
|
8bc0a64863 | ||
|
|
eb69b98dff | ||
|
|
2ee23f004e | ||
|
|
4c8e0a7648 | ||
|
|
aafef382dc | ||
|
|
ac4cac889f | ||
|
|
65add15416 | ||
|
|
aab1e1f5b4 | ||
|
|
4422327c00 | ||
|
|
6feff7e3ed | ||
|
|
345e4e0e8f | ||
|
|
9ebcaf80e7 | ||
|
|
c13e8e4f48 | ||
|
|
7797211118 | ||
|
|
b7f360647e | ||
|
|
e5982f19fa | ||
|
|
0678b06a9b | ||
|
|
25241276b0 | ||
|
|
429bd5fbd8 | ||
|
|
961e5c72a3 | ||
|
|
4df0fbcce1 | ||
|
|
dc8b62baa0 | ||
|
|
ff557a287f | ||
|
|
383b8a84e9 | ||
|
|
55bda34a45 | ||
|
|
5f39888a2d | ||
|
|
58754982ce | ||
|
|
ad13fbaeb6 | ||
|
|
651afaf11b | ||
|
|
0051ba1596 | ||
|
|
bb4bc55c6a | ||
|
|
f09e3bd3ac | ||
|
|
d4919d04ba | ||
|
|
f222cc1f3e | ||
|
|
6de1abcb0e | ||
|
|
a2b924bbdf | ||
|
|
dbf2673a91 | ||
|
|
46627a737e | ||
|
|
2714c7fdcf | ||
|
|
da218fdbf1 | ||
|
|
0334470f33 | ||
|
|
47030df8ac | ||
|
|
6eb58d832c | ||
|
|
c61f23baae | ||
|
|
2daa3457d7 | ||
|
|
e0f0d554cb | ||
|
|
bcb506b637 | ||
|
|
bfbb6db436 | ||
|
|
37d85587e0 | ||
|
|
0fc4a33d43 | ||
|
|
01c2a8cbba | ||
|
|
29de0c6748 | ||
|
|
3e8748e639 | ||
|
|
26f4abf12b | ||
|
|
e64825ff7a | ||
|
|
b6a8c27d48 | ||
|
|
bd76b1fcc0 | ||
|
|
0c2cff253f | ||
|
|
3cc7f143b2 | ||
|
|
f5a2fef7a3 | ||
|
|
b0af9f936c | ||
|
|
b7123c17f8 | ||
|
|
cdac0e2b52 | ||
|
|
c414ee0e25 | ||
|
|
5e2ef66014 | ||
|
|
ac707198d5 | ||
|
|
8ffd2522e7 | ||
|
|
d3b1a04c13 | ||
|
|
7de9c05c9d | ||
|
|
75794ec7a7 | ||
|
|
7d94590d79 | ||
|
|
9eb45c3787 | ||
|
|
657e1e62ca | ||
|
|
3643c9e658 | ||
|
|
9b7df354e6 | ||
|
|
0220f0aa5c | ||
|
|
b64a1b7c42 | ||
|
|
cadb948d57 | ||
|
|
d427e55507 | ||
|
|
557dd10896 | ||
|
|
0d5da42ddd | ||
|
|
75422dfa72 | ||
|
|
99b90789e5 | ||
|
|
b16b3c0394 | ||
|
|
ae7e6ef701 | ||
|
|
dcdff7a995 | ||
|
|
5fb44e9dd8 | ||
|
|
fedf8fc575 | ||
|
|
843fce4bcd | ||
|
|
460eddd781 |
@@ -1,24 +0,0 @@
|
||||
---
|
||||
name: LGTM.com - false positive
|
||||
about: Tell us about an alert that shouldn't be reported
|
||||
title: LGTM.com - false positive
|
||||
labels: false-positive
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Description of the false positive**
|
||||
|
||||
<!-- Please explain briefly why you think it shouldn't be included. -->
|
||||
|
||||
**URL to the alert on the project page on LGTM.com**
|
||||
|
||||
<!--
|
||||
1. Open the project on LGTM.com.
|
||||
For example, https://lgtm.com/projects/g/pallets/click/.
|
||||
2. Switch to the `Alerts` tab. For example, https://lgtm.com/projects/g/pallets/click/alerts/.
|
||||
3. Scroll to the alert that you would like to report.
|
||||
4. Click on the right most icon `View this alert within the complete file`.
|
||||
5. A new browser tab opens. Copy and paste the page URL here.
|
||||
For example, https://lgtm.com/projects/g/pallets/click/snapshot/719fb7d8322b0767cdd1e5903ba3eb3233ba8dd5/files/click/_winconsole.py#xa08d213ab3289f87:1.
|
||||
-->
|
||||
36
.github/ISSUE_TEMPLATE/ql--false-positive.md
vendored
Normal file
36
.github/ISSUE_TEMPLATE/ql--false-positive.md
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
---
|
||||
name: CodeQL False positive
|
||||
about: Report CodeQL alerts that you think should not have been detected (not applicable, not exploitable, etc.)
|
||||
title: False positive
|
||||
labels: false-positive
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Description of the false positive**
|
||||
|
||||
<!-- Please explain briefly why you think it shouldn't be included. -->
|
||||
|
||||
**Code samples or links to source code**
|
||||
|
||||
<!--
|
||||
For open source code: file links with line numbers on GitHub, for example:
|
||||
https://github.com/github/codeql/blob/dc440aaee6695deb0d9676b87e06ea984e1b4ae5/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/exec-sh2.js#L10
|
||||
|
||||
For closed source code: (redacted) code samples that illustrate the problem, for example:
|
||||
|
||||
```
|
||||
function execSh(command, options) {
|
||||
return cp.spawn(getShell(), ["-c", command], options) // <- command line injection
|
||||
};
|
||||
```
|
||||
-->
|
||||
|
||||
**URL to the alert on GitHub code scanning (optional)**
|
||||
|
||||
<!--
|
||||
1. Open the project on GitHub.com.
|
||||
2. Switch to the `Security` tab.
|
||||
3. Browse to the alert that you would like to report.
|
||||
4. Copy and paste the page URL here.
|
||||
-->
|
||||
61
.github/actions/cache-query-compilation/action.yml
vendored
Normal file
61
.github/actions/cache-query-compilation/action.yml
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
name: Cache query compilation
|
||||
description: Caches CodeQL compilation caches - should be run both on PRs and pushes to main.
|
||||
|
||||
inputs:
|
||||
key:
|
||||
description: 'The cache key to use - should be unique to the workflow'
|
||||
required: true
|
||||
|
||||
outputs:
|
||||
cache-dir:
|
||||
description: "The directory where the cache was stored"
|
||||
value: ${{ steps.fill-compilation-dir.outputs.compdir }}
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
# Cache the query compilation caches.
|
||||
# calculate the merge-base with main, in a way that works both on PRs and pushes to main.
|
||||
- name: Calculate merge-base
|
||||
shell: bash
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
env:
|
||||
BASE_BRANCH: ${{ github.base_ref }}
|
||||
run: |
|
||||
MERGE_BASE=$(git cat-file commit $GITHUB_SHA | grep '^parent ' | head -1 | cut -f 2 -d " ")
|
||||
echo "merge_base=$MERGE_BASE" >> $GITHUB_ENV
|
||||
- name: Read CodeQL query compilation - PR
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
uses: erik-krogh/actions-cache@a88d0603fe5fb5606db9f002dfcadeb32b5f84c6
|
||||
with:
|
||||
path: '**/.cache'
|
||||
read-only: true
|
||||
key: codeql-compile-${{ inputs.key }}-pr-${{ github.sha }} # deliberately not using the `compile-compile-main` keys here.
|
||||
restore-keys: |
|
||||
codeql-compile-${{ inputs.key }}-${{ github.base_ref }}-${{ env.merge_base }}
|
||||
codeql-compile-${{ inputs.key }}-${{ github.base_ref }}-
|
||||
codeql-compile-${{ inputs.key }}-main-
|
||||
- name: Fill CodeQL query compilation cache - main
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
uses: erik-krogh/actions-cache@a88d0603fe5fb5606db9f002dfcadeb32b5f84c6
|
||||
with:
|
||||
path: '**/.cache'
|
||||
key: codeql-compile-${{ inputs.key }}-${{ github.ref_name }}-${{ github.sha }} # just fill on main
|
||||
restore-keys: | # restore from another random commit, to speed up compilation.
|
||||
codeql-compile-${{ inputs.key }}-${{ github.ref_name }}-
|
||||
codeql-compile-${{ inputs.key }}-main-
|
||||
- name: Fill compilation cache directory
|
||||
id: fill-compilation-dir
|
||||
shell: bash
|
||||
run: |
|
||||
# Move all the existing cache into another folder, so we only preserve the cache for the current queries.
|
||||
mkdir -p ${COMBINED_CACHE_DIR}
|
||||
rm -f **/.cache/{lock,size} # -f to avoid errors if the cache is empty.
|
||||
# copy the contents of the .cache folders into the combined cache folder.
|
||||
cp -r **/.cache/* ${COMBINED_CACHE_DIR}/ || : # ignore missing files
|
||||
# clean up the .cache folders
|
||||
rm -rf **/.cache/*
|
||||
|
||||
echo "compdir=${COMBINED_CACHE_DIR}" >> $GITHUB_OUTPUT
|
||||
env:
|
||||
COMBINED_CACHE_DIR: ${{ github.workspace }}/compilation-dir
|
||||
18
.github/actions/fetch-codeql/action.yml
vendored
18
.github/actions/fetch-codeql/action.yml
vendored
@@ -1,14 +1,22 @@
|
||||
name: Fetch CodeQL
|
||||
description: Fetches the latest version of CodeQL
|
||||
|
||||
inputs:
|
||||
channel:
|
||||
description: 'The CodeQL channel to use'
|
||||
required: false
|
||||
default: 'nightly'
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Fetch CodeQL
|
||||
shell: bash
|
||||
run: |
|
||||
gh extension install github/gh-codeql
|
||||
gh codeql set-channel nightly
|
||||
gh codeql version
|
||||
gh codeql version --format=json | jq -r .unpackedLocation >> "${GITHUB_PATH}"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
CHANNEL: ${{ inputs.channel }}
|
||||
run: |
|
||||
gh extension install github/gh-codeql
|
||||
gh codeql set-channel "$CHANNEL"
|
||||
gh codeql version
|
||||
gh codeql version --format=json | jq -r .unpackedLocation >> "${GITHUB_PATH}"
|
||||
|
||||
3
.github/labeler.yml
vendored
3
.github/labeler.yml
vendored
@@ -51,3 +51,6 @@ documentation:
|
||||
- "java/ql/lib/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll"
|
||||
- "java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll"
|
||||
- "java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll"
|
||||
|
||||
"ATM":
|
||||
- javascript/ql/experimental/adaptivethreatmodeling/**/*
|
||||
|
||||
93
.github/workflows/atm-check-query-suite.yml
vendored
Normal file
93
.github/workflows/atm-check-query-suite.yml
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
name: "ATM - Check query suite"
|
||||
|
||||
env:
|
||||
QUERY_PACK: javascript/ql/experimental/adaptivethreatmodeling/src
|
||||
QUERY_SUITE: codeql-suites/javascript-atm-code-scanning.qls
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/atm-check-query-suite.yml"
|
||||
- "javascript/ql/experimental/adaptivethreatmodeling/**"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
atm-check-query-suite:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup CodeQL
|
||||
uses: ./.github/actions/fetch-codeql
|
||||
with:
|
||||
channel: release
|
||||
|
||||
- name: Install ATM model
|
||||
run: |
|
||||
set -exu
|
||||
|
||||
# Install dependencies of ATM query pack, i.e. the ATM model
|
||||
codeql pack install "${QUERY_PACK}"
|
||||
|
||||
# Retrieve model checksum
|
||||
model_checksum=$(codeql resolve extensions "${QUERY_PACK}/${QUERY_SUITE}" | jq -r '.models[0].checksum')
|
||||
|
||||
# Trust the model so that we can use it in the ATM boosted queries
|
||||
mkdir -p "$HOME/.config/codeql"
|
||||
echo "--insecurely-execute-ml-model-checksums ${model_checksum}" >> "$HOME/.config/codeql/config"
|
||||
|
||||
- name: Create test DB
|
||||
run: |
|
||||
DB_PATH="${RUNNER_TEMP}/db"
|
||||
echo "DB_PATH=${DB_PATH}" >> "${GITHUB_ENV}"
|
||||
|
||||
codeql database create "${DB_PATH}" --source-root config/atm --language javascript
|
||||
|
||||
- name: Run ATM query suite
|
||||
run: |
|
||||
SARIF_PATH="${RUNNER_TEMP}/sarif.json"
|
||||
echo "SARIF_PATH=${SARIF_PATH}" >> "${GITHUB_ENV}"
|
||||
|
||||
codeql database analyze \
|
||||
--format sarif-latest \
|
||||
--output "${SARIF_PATH}" \
|
||||
--sarif-group-rules-by-pack \
|
||||
-vv \
|
||||
-- \
|
||||
"${DB_PATH}" \
|
||||
"${QUERY_PACK}/${QUERY_SUITE}"
|
||||
|
||||
- name: Upload SARIF
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: javascript-ml-powered-queries.sarif
|
||||
path: "${{ env.SARIF_PATH }}"
|
||||
retention-days: 5
|
||||
|
||||
- name: Check results
|
||||
run: |
|
||||
# We should run at least the ML-powered queries in `expected_rules`.
|
||||
expected_rules="js/ml-powered/nosql-injection js/ml-powered/path-injection js/ml-powered/sql-injection js/ml-powered/xss"
|
||||
|
||||
for rule in ${expected_rules}; do
|
||||
found_rule=$(jq --arg rule "${rule}" '[.runs[0].tool.extensions[].rules | select(. != null) |
|
||||
flatten | .[].id] | any(. == $rule)' "${SARIF_PATH}")
|
||||
if [[ "${found_rule}" != "true" ]]; then
|
||||
echo "Expected SARIF output to contain rule '${rule}', but found no such rule."
|
||||
exit 1
|
||||
else
|
||||
echo "Found rule '${rule}'."
|
||||
fi
|
||||
done
|
||||
|
||||
# We should have at least one alert from an ML-powered query.
|
||||
num_alerts=$(jq '[.runs[0].results[] |
|
||||
select(.properties.score != null and (.rule.id | startswith("js/ml-powered/")))] | length' \
|
||||
"${SARIF_PATH}")
|
||||
if [[ "${num_alerts}" -eq 0 ]]; then
|
||||
echo "Expected to find at least one alert from an ML-powered query but found ${num_alerts}."
|
||||
exit 1
|
||||
else
|
||||
echo "Found ${num_alerts} alerts from ML-powered queries.";
|
||||
fi
|
||||
@@ -1,6 +1,5 @@
|
||||
name: ATM Check Queries Run
|
||||
name: ATM Model Integration Tests
|
||||
|
||||
# This check is required, therefore we must run it on all PRs, even if only Markdown has changed.
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
39
.github/workflows/compile-queries.yml
vendored
Normal file
39
.github/workflows/compile-queries.yml
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
name: "Compile all queries using the latest stable CodeQL CLI"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: # makes sure the cache gets populated - running on the branches people tend to merge into.
|
||||
- main
|
||||
- "rc/*"
|
||||
- "codeql-cli-*"
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
compile-queries:
|
||||
runs-on: ubuntu-latest-xl
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup CodeQL
|
||||
uses: ./.github/actions/fetch-codeql
|
||||
with:
|
||||
channel: 'release'
|
||||
- name: Cache compilation cache
|
||||
id: query-cache
|
||||
uses: ./.github/actions/cache-query-compilation
|
||||
with:
|
||||
key: all-queries
|
||||
- name: check formatting
|
||||
run: find */ql -type f \( -name "*.qll" -o -name "*.ql" \) -print0 | xargs -0 codeql query format --check-only
|
||||
- name: compile queries - check-only
|
||||
# run with --check-only if running in a PR (github.sha != main)
|
||||
if : ${{ github.event_name == 'pull_request' }}
|
||||
shell: bash
|
||||
run: codeql query compile -j0 */ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
- 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 -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
env:
|
||||
COMBINED_CACHE_DIR: ${{ github.workspace }}/compilation-dir
|
||||
86
.github/workflows/csharp-qltest.yml
vendored
Normal file
86
.github/workflows/csharp-qltest.yml
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
name: "C#: Run QL Tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "csharp/**"
|
||||
- "shared/**"
|
||||
- .github/actions/fetch-codeql/action.yml
|
||||
- codeql-workspace.yml
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
pull_request:
|
||||
paths:
|
||||
- "csharp/**"
|
||||
- "shared/**"
|
||||
- .github/workflows/csharp-qltest.yml
|
||||
- .github/actions/fetch-codeql/action.yml
|
||||
- codeql-workspace.yml
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: csharp
|
||||
|
||||
jobs:
|
||||
qlupgrade:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- name: Check DB upgrade scripts
|
||||
run: |
|
||||
echo >empty.trap
|
||||
codeql dataset import -S ql/lib/upgrades/initial/semmlecode.csharp.dbscheme testdb empty.trap
|
||||
codeql dataset upgrade testdb --additional-packs ql/lib
|
||||
diff -q testdb/semmlecode.csharp.dbscheme ql/lib/semmlecode.csharp.dbscheme
|
||||
- name: Check DB downgrade scripts
|
||||
run: |
|
||||
echo >empty.trap
|
||||
rm -rf testdb; codeql dataset import -S ql/lib/semmlecode.csharp.dbscheme testdb empty.trap
|
||||
codeql resolve upgrades --format=lines --allow-downgrades --additional-packs downgrades \
|
||||
--dbscheme=ql/lib/semmlecode.csharp.dbscheme --target-dbscheme=downgrades/initial/semmlecode.csharp.dbscheme |
|
||||
xargs codeql execute upgrades testdb
|
||||
diff -q testdb/semmlecode.csharp.dbscheme downgrades/initial/semmlecode.csharp.dbscheme
|
||||
qltest:
|
||||
runs-on: ubuntu-latest-xl
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
slice: ["1/2", "2/2"]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- uses: ./csharp/actions/create-extractor-pack
|
||||
- name: Cache compilation cache
|
||||
id: query-cache
|
||||
uses: ./.github/actions/cache-query-compilation
|
||||
with:
|
||||
key: csharp-qltest-${{ matrix.slice }}
|
||||
- name: Run QL tests
|
||||
run: |
|
||||
CODEQL_PATH=$(gh codeql version --format=json | jq -r .unpackedLocation)
|
||||
# The legacy ASP extractor is not in this repo, so take the one from the nightly build
|
||||
mv "$CODEQL_PATH/csharp/tools/extractor-asp.jar" "${{ github.workspace }}/csharp/extractor-pack/tools"
|
||||
# Safe guard against using the bundled extractor
|
||||
rm -rf "$CODEQL_PATH/csharp"
|
||||
codeql test run --threads=0 --ram 52000 --slice ${{ matrix.slice }} --search-path "${{ github.workspace }}/csharp/extractor-pack" --check-databases --check-undefined-labels --check-repeated-labels --check-redefined-labels --consistency-queries ql/consistency-queries ql/test --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
unit-tests:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 6.0.202
|
||||
- name: Extractor unit tests
|
||||
run: |
|
||||
dotnet test -p:RuntimeFrameworkVersion=6.0.4 "${{ github.workspace }}/csharp/extractor/Semmle.Util.Tests"
|
||||
dotnet test -p:RuntimeFrameworkVersion=6.0.4 "${{ github.workspace }}/csharp/extractor/Semmle.Extraction.Tests"
|
||||
dotnet test -p:RuntimeFrameworkVersion=6.0.4 "${{ github.workspace }}/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests"
|
||||
dotnet test -p:RuntimeFrameworkVersion=6.0.4 "${{ github.workspace }}/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests"
|
||||
13
.github/workflows/js-ml-tests.yml
vendored
13
.github/workflows/js-ml-tests.yml
vendored
@@ -23,19 +23,6 @@ defaults:
|
||||
working-directory: javascript/ql/experimental/adaptivethreatmodeling
|
||||
|
||||
jobs:
|
||||
qlformat:
|
||||
name: Check QL formatting
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
|
||||
- name: Check QL formatting
|
||||
run: |
|
||||
find . "(" -name "*.ql" -or -name "*.qll" ")" -print0 | \
|
||||
xargs -0 codeql query format --check-only
|
||||
|
||||
qlcompile:
|
||||
name: Check QL compilation
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
8
.github/workflows/ql-for-ql-build.yml
vendored
8
.github/workflows/ql-for-ql-build.yml
vendored
@@ -24,13 +24,13 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Find codeql
|
||||
id: find-codeql
|
||||
uses: github/codeql-action/init@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
|
||||
uses: github/codeql-action/init@77a8d2d10c0b403a8b4aadbd223dc489ecd22683
|
||||
with:
|
||||
languages: javascript # does not matter
|
||||
- name: Get CodeQL version
|
||||
id: get-codeql-version
|
||||
run: |
|
||||
echo "::set-output name=version::$("${CODEQL}" --version | head -n 1 | rev | cut -d " " -f 1 | rev)"
|
||||
echo "version=$("${CODEQL}" --version | head -n 1 | rev | cut -d " " -f 1 | rev)" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
env:
|
||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||
@@ -133,7 +133,7 @@ jobs:
|
||||
env:
|
||||
CONF: ./ql-for-ql-config.yml
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
|
||||
uses: github/codeql-action/init@77a8d2d10c0b403a8b4aadbd223dc489ecd22683
|
||||
with:
|
||||
languages: ql
|
||||
db-location: ${{ runner.temp }}/db
|
||||
@@ -145,7 +145,7 @@ jobs:
|
||||
PACK: ${{ runner.temp }}/pack
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
|
||||
uses: github/codeql-action/analyze@77a8d2d10c0b403a8b4aadbd223dc489ecd22683
|
||||
with:
|
||||
category: "ql-for-ql"
|
||||
- name: Copy sarif file to CWD
|
||||
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
|
||||
- name: Find codeql
|
||||
id: find-codeql
|
||||
uses: github/codeql-action/init@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
|
||||
uses: github/codeql-action/init@77a8d2d10c0b403a8b4aadbd223dc489ecd22683
|
||||
with:
|
||||
languages: javascript # does not matter
|
||||
- uses: actions/cache@v3
|
||||
|
||||
7
.github/workflows/ql-for-ql-tests.yml
vendored
7
.github/workflows/ql-for-ql-tests.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Find codeql
|
||||
id: find-codeql
|
||||
uses: github/codeql-action/init@71a8b35ff4c80fcfcd05bc1cd932fe3c08f943ca
|
||||
uses: github/codeql-action/init@77a8d2d10c0b403a8b4aadbd223dc489ecd22683
|
||||
with:
|
||||
languages: javascript # does not matter
|
||||
- uses: actions/cache@v3
|
||||
@@ -47,8 +47,3 @@ jobs:
|
||||
find ql/ql/src "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 "${CODEQL}" query format --check-only
|
||||
env:
|
||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||
- name: Check QL compilation
|
||||
run: |
|
||||
"${CODEQL}" query compile --check-only --threads=4 --warnings=error --search-path "${{ github.workspace }}/ql/extractor-pack" "ql/ql/src" "ql/ql/examples"
|
||||
env:
|
||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||
|
||||
17
.github/workflows/ruby-build.yml
vendored
17
.github/workflows/ruby-build.yml
vendored
@@ -86,19 +86,24 @@ jobs:
|
||||
ruby/target/release/ruby-extractor.exe
|
||||
retention-days: 1
|
||||
compile-queries:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CODEQL_THREADS: 4 # TODO: remove this once it's set by the CLI
|
||||
runs-on: ubuntu-latest-xl
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Fetch CodeQL
|
||||
uses: ./.github/actions/fetch-codeql
|
||||
- name: Cache compilation cache
|
||||
id: query-cache
|
||||
uses: ./.github/actions/cache-query-compilation
|
||||
with:
|
||||
key: ruby-build
|
||||
- name: Build Query Pack
|
||||
run: |
|
||||
rm -rf target/packs
|
||||
codeql pack create ../shared/ssa --output target/packs
|
||||
codeql pack create ../misc/suite-helpers --output target/packs
|
||||
codeql pack create ../shared/regex --output target/packs
|
||||
codeql pack create ql/lib --output target/packs
|
||||
codeql pack install ql/src
|
||||
codeql pack create ql/src --output target/packs
|
||||
codeql pack create -j0 ql/src --output target/packs --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
PACK_FOLDER=$(readlink -f target/packs/codeql/ruby-queries/*)
|
||||
codeql generate query-help --format=sarifv2.1.0 --output="${PACK_FOLDER}/rules.sarif" ql/src
|
||||
(cd ql/src; find queries \( -name '*.qhelp' -o -name '*.rb' -o -name '*.erb' \) -exec bash -c 'mkdir -p "'"${PACK_FOLDER}"'/$(dirname "{}")"' \; -exec cp "{}" "${PACK_FOLDER}/{}" \;)
|
||||
@@ -202,7 +207,7 @@ jobs:
|
||||
echo 'name: sample-tests
|
||||
version: 0.0.0
|
||||
dependencies:
|
||||
codeql/ruby-all: 0.0.1
|
||||
codeql/ruby-all: "*"
|
||||
extractor: ruby
|
||||
tests: .
|
||||
' > qlpack.yml
|
||||
|
||||
30
.github/workflows/ruby-qltest.yml
vendored
30
.github/workflows/ruby-qltest.yml
vendored
@@ -4,7 +4,7 @@ on:
|
||||
push:
|
||||
paths:
|
||||
- "ruby/**"
|
||||
- .github/workflows/ruby-qltest.yml
|
||||
- .github/workflows/ruby-build.yml
|
||||
- .github/actions/fetch-codeql/action.yml
|
||||
- codeql-workspace.yml
|
||||
branches:
|
||||
@@ -28,23 +28,6 @@ defaults:
|
||||
working-directory: ruby
|
||||
|
||||
jobs:
|
||||
qlformat:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- name: Check QL formatting
|
||||
run: find ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 codeql query format --check-only
|
||||
qlcompile:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- name: Check QL compilation
|
||||
run: |
|
||||
codeql query compile --check-only --threads=0 --ram 5000 --warnings=error "ql/src" "ql/examples"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
qlupgrade:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -65,17 +48,20 @@ jobs:
|
||||
xargs codeql execute upgrades testdb
|
||||
diff -q testdb/ruby.dbscheme downgrades/initial/ruby.dbscheme
|
||||
qltest:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-latest-xl
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
slice: ["1/2", "2/2"]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- uses: ./ruby/actions/create-extractor-pack
|
||||
- name: Cache compilation cache
|
||||
id: query-cache
|
||||
uses: ./.github/actions/cache-query-compilation
|
||||
with:
|
||||
key: ruby-qltest
|
||||
- name: Run QL tests
|
||||
run: |
|
||||
codeql test run --threads=0 --ram 5000 --slice ${{ matrix.slice }} --search-path "${{ github.workspace }}/ruby/extractor-pack" --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --consistency-queries ql/consistency-queries ql/test
|
||||
codeql test run --threads=0 --ram 52000 --search-path "${{ github.workspace }}/ruby/extractor-pack" --check-databases --check-undefined-labels --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --consistency-queries ql/consistency-queries ql/test --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
|
||||
27
.github/workflows/swift-autobuilder.yml
vendored
27
.github/workflows/swift-autobuilder.yml
vendored
@@ -1,27 +0,0 @@
|
||||
name: "Swift: Build and test Xcode autobuilder"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "swift/xcode-autobuilder/**"
|
||||
- "misc/bazel/**"
|
||||
- "*.bazel*"
|
||||
- .github/workflows/swift-autobuilder.yml
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
autobuilder:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: bazelbuild/setup-bazelisk@v2
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version-file: 'swift/.python-version'
|
||||
- name: Build the Xcode autobuilder
|
||||
run: |
|
||||
bazel build //swift/xcode-autobuilder
|
||||
- name: Test the Xcode autobuilder
|
||||
run: |
|
||||
bazel test //swift/xcode-autobuilder/tests
|
||||
44
.github/workflows/swift-codegen.yml
vendored
44
.github/workflows/swift-codegen.yml
vendored
@@ -1,44 +0,0 @@
|
||||
name: "Swift: Check code generation"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "swift/**"
|
||||
- "misc/bazel/**"
|
||||
- "*.bazel*"
|
||||
- .github/workflows/swift-codegen.yml
|
||||
- .github/actions/fetch-codeql/action.yml
|
||||
branches:
|
||||
- main
|
||||
defaults:
|
||||
run:
|
||||
working-directory: swift
|
||||
|
||||
jobs:
|
||||
codegen:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- uses: bazelbuild/setup-bazelisk@v2
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version-file: 'swift/.python-version'
|
||||
- uses: pre-commit/action@v3.0.0
|
||||
name: Check that python code is properly formatted
|
||||
with:
|
||||
extra_args: autopep8 --all-files
|
||||
- name: Run unit tests
|
||||
run: |
|
||||
bazel test //swift/codegen/test --test_output=errors
|
||||
- uses: pre-commit/action@v3.0.0
|
||||
name: Check that QL generated code was checked in
|
||||
with:
|
||||
extra_args: swift-codegen --all-files
|
||||
- name: Generate C++ files
|
||||
run: |
|
||||
bazel run //swift/codegen:codegen -- --generate=trap,cpp --cpp-output=$PWD/swift-generated-cpp-files
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: swift-generated-cpp-files
|
||||
path: swift-generated-cpp-files/**
|
||||
47
.github/workflows/swift-integration-tests.yml
vendored
47
.github/workflows/swift-integration-tests.yml
vendored
@@ -1,47 +0,0 @@
|
||||
name: "Swift: Run Integration Tests"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "swift/**"
|
||||
- "misc/bazel/**"
|
||||
- "*.bazel*"
|
||||
- .github/workflows/swift-integration-tests.yml
|
||||
- .github/actions/fetch-codeql/action.yml
|
||||
- codeql-workspace.yml
|
||||
branches:
|
||||
- main
|
||||
defaults:
|
||||
run:
|
||||
working-directory: swift
|
||||
|
||||
jobs:
|
||||
integration-tests:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-20.04
|
||||
# - macos-latest TODO
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- uses: bazelbuild/setup-bazelisk@v2
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version-file: 'swift/.python-version'
|
||||
- name: Build Swift extractor
|
||||
run: |
|
||||
bazel run //swift:create-extractor-pack
|
||||
- name: Get Swift version
|
||||
id: get_swift_version
|
||||
run: |
|
||||
VERSION=$(bazel run //swift/extractor -- --version | sed -ne 's/.*version \(\S*\).*/\1/p')
|
||||
echo "::set-output name=version::$VERSION"
|
||||
- uses: swift-actions/setup-swift@v1
|
||||
with:
|
||||
swift-version: "${{steps.get_swift_version.outputs.version}}"
|
||||
- name: Run integration tests
|
||||
run: |
|
||||
python integration-tests/runner.py
|
||||
57
.github/workflows/swift-qltest.yml
vendored
57
.github/workflows/swift-qltest.yml
vendored
@@ -1,57 +0,0 @@
|
||||
name: "Swift: Run QL Tests"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "swift/**"
|
||||
- "misc/bazel/**"
|
||||
- "*.bazel*"
|
||||
- .github/workflows/swift-qltest.yml
|
||||
- .github/actions/fetch-codeql/action.yml
|
||||
- codeql-workspace.yml
|
||||
branches:
|
||||
- main
|
||||
defaults:
|
||||
run:
|
||||
working-directory: swift
|
||||
|
||||
jobs:
|
||||
qlformat:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- name: Check QL formatting
|
||||
run: find ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 codeql query format --check-only
|
||||
qltest-test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: bazelbuild/setup-bazelisk@v2
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version-file: 'swift/.python-version'
|
||||
- name: Test qltest.sh
|
||||
run: |
|
||||
bazel test //swift/tools/test/qltest
|
||||
qltest:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ ubuntu-20.04, macos-latest ]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- uses: bazelbuild/setup-bazelisk@v2
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version-file: 'swift/.python-version'
|
||||
- name: Build Swift extractor
|
||||
run: |
|
||||
bazel run //swift:create-extractor-pack
|
||||
- name: Run QL tests
|
||||
run: |
|
||||
codeql test run --threads=0 --ram 5000 --search-path "${{ github.workspace }}/swift/extractor-pack" --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition ql/test
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
121
.github/workflows/swift.yml
vendored
Normal file
121
.github/workflows/swift.yml
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
name: "Swift"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "swift/**"
|
||||
- "misc/bazel/**"
|
||||
- "*.bazel*"
|
||||
- .github/workflows/swift.yml
|
||||
- .github/actions/fetch-codeql/action.yml
|
||||
- codeql-workspace.yml
|
||||
- .pre-commit-config.yaml
|
||||
- "!**/*.md"
|
||||
- "!**/*.qhelp"
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
codegen: ${{ steps.filter.outputs.codegen }}
|
||||
ql: ${{ steps.filter.outputs.ql }}
|
||||
steps:
|
||||
- uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
codegen:
|
||||
- '.github/workflows/swift.yml'
|
||||
- "misc/bazel/**"
|
||||
- "*.bazel*"
|
||||
- 'swift/actions/setup-env/**'
|
||||
- '.pre-commit-config.yaml'
|
||||
- 'swift/codegen/**'
|
||||
- 'swift/schema.py'
|
||||
- 'swift/**/*.dbscheme'
|
||||
- 'swift/ql/lib/codeql/swift/elements.qll'
|
||||
- 'swift/ql/lib/codeql/swift/elements/**'
|
||||
- 'swift/ql/lib/codeql/swift/generated/**'
|
||||
- 'swift/ql/test/extractor-tests/generated/**'
|
||||
- 'swift/ql/.generated.list'
|
||||
ql:
|
||||
- 'github/workflows/swift.yml'
|
||||
- 'swift/**/*.ql'
|
||||
- 'swift/**/*.qll'
|
||||
# not using a matrix as you cannot depend on a specific job in a matrix, and we want to start linux checks
|
||||
# without waiting for the macOS build
|
||||
build-and-test-macos:
|
||||
runs-on: macos-12-xl
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./swift/actions/create-extractor-pack
|
||||
- uses: ./swift/actions/run-quick-tests
|
||||
- uses: ./swift/actions/print-unextracted
|
||||
build-and-test-linux:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./swift/actions/create-extractor-pack
|
||||
- uses: ./swift/actions/run-quick-tests
|
||||
- uses: ./swift/actions/print-unextracted
|
||||
qltests-linux:
|
||||
needs: build-and-test-linux
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./swift/actions/run-ql-tests
|
||||
qltests-macos:
|
||||
needs: build-and-test-macos
|
||||
runs-on: macos-12-xl
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
slice: ["1/2", "2/2"]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./swift/actions/run-ql-tests
|
||||
with:
|
||||
flags: --slice ${{ matrix.slice }}
|
||||
integration-tests-linux:
|
||||
needs: build-and-test-linux
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./swift/actions/run-integration-tests
|
||||
integration-tests-macos:
|
||||
needs: build-and-test-macos
|
||||
runs-on: macos-12-xl
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./swift/actions/run-integration-tests
|
||||
codegen:
|
||||
runs-on: ubuntu-latest
|
||||
needs: changes
|
||||
if: ${{ needs.changes.outputs.codegen == 'true' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./swift/actions/setup-env
|
||||
- uses: pre-commit/action@v3.0.0
|
||||
name: Check that python code is properly formatted
|
||||
with:
|
||||
extra_args: autopep8 --all-files
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- uses: pre-commit/action@v3.0.0
|
||||
name: Check that QL generated code was checked in
|
||||
with:
|
||||
extra_args: swift-codegen --all-files
|
||||
- name: Generate C++ files
|
||||
run: |
|
||||
bazel run //swift/codegen:codegen -- --generate=trap,cpp --cpp-output=$PWD/generated-cpp-files
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: swift-generated-cpp-files
|
||||
path: generated-cpp-files/**
|
||||
database-upgrade-scripts:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/fetch-codeql
|
||||
- uses: ./swift/actions/database-upgrade-scripts
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -27,8 +27,6 @@
|
||||
# It's useful (though not required) to be able to unpack codeql in the ql checkout itself
|
||||
/codeql/
|
||||
|
||||
csharp/extractor/Semmle.Extraction.CSharp.Driver/Properties/launchSettings.json
|
||||
|
||||
# Avoid committing cached package components
|
||||
.codeql
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ repos:
|
||||
rev: v1.6.0
|
||||
hooks:
|
||||
- id: autopep8
|
||||
files: ^swift/codegen/.*\.py
|
||||
files: ^swift/.*\.py
|
||||
|
||||
- repo: local
|
||||
hooks:
|
||||
@@ -31,7 +31,7 @@ repos:
|
||||
|
||||
- id: sync-files
|
||||
name: Fix files required to be identical
|
||||
files: \.(qll?|qhelp|swift)$
|
||||
files: \.(qll?|qhelp|swift)$|^config/identical-files\.json$
|
||||
language: system
|
||||
entry: python3 config/sync-files.py --latest
|
||||
pass_filenames: false
|
||||
@@ -44,7 +44,7 @@ repos:
|
||||
|
||||
- id: swift-codegen
|
||||
name: Run Swift checked in code generation
|
||||
files: ^swift/(codegen/|.*/generated/|ql/lib/(swift\.dbscheme$|codeql/swift/elements))
|
||||
files: ^swift/(schema.py$|codegen/|.*/generated/|ql/lib/(swift\.dbscheme$|codeql/swift/elements)|ql/\.generated.list)
|
||||
language: system
|
||||
entry: bazel run //swift/codegen -- --quiet
|
||||
pass_filenames: false
|
||||
|
||||
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@@ -1,3 +1,5 @@
|
||||
{
|
||||
"omnisharp.autoStart": false
|
||||
"omnisharp.autoStart": false,
|
||||
"cmake.sourceDirectory": "${workspaceFolder}/swift",
|
||||
"cmake.buildDirectory": "${workspaceFolder}/bazel-cmake-build"
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
/javascript/ @github/codeql-javascript
|
||||
/python/ @github/codeql-python
|
||||
/ruby/ @github/codeql-ruby
|
||||
/swift/ @github/codeql-c
|
||||
/swift/ @github/codeql-swift
|
||||
/java/kotlin-extractor/ @github/codeql-kotlin
|
||||
/java/kotlin-explorer/ @github/codeql-kotlin
|
||||
|
||||
@@ -40,8 +40,9 @@ WORKSPACE.bazel @github/codeql-ci-reviewers
|
||||
|
||||
# Workflows
|
||||
/.github/workflows/ @github/codeql-ci-reviewers
|
||||
/.github/workflows/atm-* @github/codeql-ml-powered-queries-reviewers
|
||||
/.github/workflows/go-* @github/codeql-go
|
||||
/.github/workflows/js-ml-tests.yml @github/codeql-ml-powered-queries-reviewers
|
||||
/.github/workflows/ql-for-ql-* @github/codeql-ql-for-ql-reviewers
|
||||
/.github/workflows/ruby-* @github/codeql-ruby
|
||||
/.github/workflows/swift-* @github/codeql-c
|
||||
/.github/workflows/swift.yml @github/codeql-swift
|
||||
|
||||
@@ -17,6 +17,7 @@ provide:
|
||||
# - "javascript/ql/experimental/adaptivethreatmodeling/model/qlpack.yml"
|
||||
- "javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/qlpack.yml"
|
||||
- "javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml"
|
||||
- "javascript/ql/experimental/adaptivethreatmodeling/test/qlpack.yml"
|
||||
- "csharp/ql/campaigns/Solorigate/lib/qlpack.yml"
|
||||
- "csharp/ql/campaigns/Solorigate/src/qlpack.yml"
|
||||
- "csharp/ql/campaigns/Solorigate/test/qlpack.yml"
|
||||
@@ -24,7 +25,7 @@ provide:
|
||||
- "misc/suite-helpers/qlpack.yml"
|
||||
- "ruby/extractor-pack/codeql-extractor.yml"
|
||||
- "swift/extractor-pack/codeql-extractor.yml"
|
||||
- "ql/extractor-pack/codeql-extractor.ym"
|
||||
- "ql/extractor-pack/codeql-extractor.yml"
|
||||
|
||||
versionPolicies:
|
||||
default:
|
||||
|
||||
21
config/atm/ml-powered-queries-repo/add-note.js
Normal file
21
config/atm/ml-powered-queries-repo/add-note.js
Normal file
@@ -0,0 +1,21 @@
|
||||
const mongoose = require('mongoose');
|
||||
|
||||
Logger = require('./logger').Logger;
|
||||
Note = require('./models/note').Note;
|
||||
|
||||
(async () => {
|
||||
if (process.argv.length != 5) {
|
||||
Logger.log("Creates a private note. Usage: node add-note.js <token> <title> <body>")
|
||||
return;
|
||||
}
|
||||
|
||||
// Open the default mongoose connection
|
||||
await mongoose.connect('mongodb://localhost:27017/notes', { useFindAndModify: false });
|
||||
|
||||
const [userToken, title, body] = process.argv.slice(2);
|
||||
await Note.create({ title, body, userToken });
|
||||
|
||||
Logger.log(`Created private note with title ${title} and body ${body} belonging to user with token ${userToken}.`);
|
||||
|
||||
await mongoose.connection.close();
|
||||
})();
|
||||
68
config/atm/ml-powered-queries-repo/app.js
Normal file
68
config/atm/ml-powered-queries-repo/app.js
Normal file
@@ -0,0 +1,68 @@
|
||||
const bodyParser = require('body-parser');
|
||||
const express = require('express');
|
||||
const mongoose = require('mongoose');
|
||||
|
||||
const notesApi = require('./notes-api');
|
||||
const usersApi = require('./users-api');
|
||||
|
||||
const addSampleData = module.exports.addSampleData = async () => {
|
||||
const [userA, userB] = await User.create([
|
||||
{
|
||||
name: "A",
|
||||
token: "tokenA"
|
||||
},
|
||||
{
|
||||
name: "B",
|
||||
token: "tokenB"
|
||||
}
|
||||
]);
|
||||
|
||||
await Note.create([
|
||||
{
|
||||
title: "Public note belonging to A",
|
||||
body: "This is a public note belonging to A",
|
||||
isPublic: true,
|
||||
ownerToken: userA.token
|
||||
},
|
||||
{
|
||||
title: "Public note belonging to B",
|
||||
body: "This is a public note belonging to B",
|
||||
isPublic: true,
|
||||
ownerToken: userB.token
|
||||
},
|
||||
{
|
||||
title: "Private note belonging to A",
|
||||
body: "This is a private note belonging to A",
|
||||
ownerToken: userA.token
|
||||
},
|
||||
{
|
||||
title: "Private note belonging to B",
|
||||
body: "This is a private note belonging to B",
|
||||
ownerToken: userB.token
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
module.exports.startApp = async () => {
|
||||
// Open the default mongoose connection
|
||||
await mongoose.connect('mongodb://mongo:27017/notes', { useFindAndModify: false });
|
||||
// Drop contents of DB
|
||||
mongoose.connection.dropDatabase();
|
||||
// Add some sample data
|
||||
await addSampleData();
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(bodyParser.json());
|
||||
app.use(bodyParser.urlencoded());
|
||||
|
||||
app.get('/', async (_req, res) => {
|
||||
res.send('Hello World');
|
||||
});
|
||||
|
||||
app.use('/api/notes', notesApi.router);
|
||||
app.use('/api/users', usersApi.router);
|
||||
|
||||
app.listen(3000);
|
||||
Logger.log('Express started on port 3000');
|
||||
};
|
||||
7
config/atm/ml-powered-queries-repo/index.js
Normal file
7
config/atm/ml-powered-queries-repo/index.js
Normal file
@@ -0,0 +1,7 @@
|
||||
const startApp = require('./app').startApp;
|
||||
|
||||
Logger = require('./logger').Logger;
|
||||
Note = require('./models/note').Note;
|
||||
User = require('./models/user').User;
|
||||
|
||||
startApp();
|
||||
5
config/atm/ml-powered-queries-repo/logger.js
Normal file
5
config/atm/ml-powered-queries-repo/logger.js
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports.Logger = class {
|
||||
log(message, ...objs) {
|
||||
console.log(message, objs);
|
||||
}
|
||||
};
|
||||
8
config/atm/ml-powered-queries-repo/models/note.js
Normal file
8
config/atm/ml-powered-queries-repo/models/note.js
Normal file
@@ -0,0 +1,8 @@
|
||||
const mongoose = require('mongoose');
|
||||
|
||||
module.exports.Note = mongoose.model('Note', new mongoose.Schema({
|
||||
title: String,
|
||||
body: String,
|
||||
ownerToken: String,
|
||||
isPublic: Boolean
|
||||
}));
|
||||
6
config/atm/ml-powered-queries-repo/models/user.js
Normal file
6
config/atm/ml-powered-queries-repo/models/user.js
Normal file
@@ -0,0 +1,6 @@
|
||||
const mongoose = require('mongoose');
|
||||
|
||||
module.exports.User = mongoose.model('User', new mongoose.Schema({
|
||||
name: String,
|
||||
token: String
|
||||
}));
|
||||
44
config/atm/ml-powered-queries-repo/notes-api.js
Normal file
44
config/atm/ml-powered-queries-repo/notes-api.js
Normal file
@@ -0,0 +1,44 @@
|
||||
const express = require('express')
|
||||
|
||||
const router = module.exports.router = express.Router();
|
||||
|
||||
function serializeNote(note) {
|
||||
return {
|
||||
title: note.title,
|
||||
body: note.body
|
||||
};
|
||||
}
|
||||
|
||||
router.post('/find', async (req, res) => {
|
||||
const notes = await Note.find({
|
||||
ownerToken: req.body.token
|
||||
}).exec();
|
||||
res.json({
|
||||
notes: notes.map(serializeNote)
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/findPublic', async (_req, res) => {
|
||||
const notes = await Note.find({
|
||||
isPublic: true
|
||||
}).exec();
|
||||
res.json({
|
||||
notes: notes.map(serializeNote)
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/findVisible', async (req, res) => {
|
||||
const notes = await Note.find({
|
||||
$or: [
|
||||
{
|
||||
isPublic: true
|
||||
},
|
||||
{
|
||||
ownerToken: req.body.token
|
||||
}
|
||||
]
|
||||
}).exec();
|
||||
res.json({
|
||||
notes: notes.map(serializeNote)
|
||||
});
|
||||
});
|
||||
37
config/atm/ml-powered-queries-repo/read-notes.js
Normal file
37
config/atm/ml-powered-queries-repo/read-notes.js
Normal file
@@ -0,0 +1,37 @@
|
||||
const mongoose = require('mongoose');
|
||||
|
||||
Logger = require('./logger').Logger;
|
||||
Note = require('./models/note').Note;
|
||||
User = require('./models/user').User;
|
||||
|
||||
(async () => {
|
||||
if (process.argv.length != 3) {
|
||||
Logger.log("Outputs all notes visible to a user. Usage: node read-notes.js <token>")
|
||||
return;
|
||||
}
|
||||
|
||||
// Open the default mongoose connection
|
||||
await mongoose.connect('mongodb://localhost:27017/notes', { useFindAndModify: false });
|
||||
|
||||
const ownerToken = process.argv[2];
|
||||
|
||||
const user = await User.findOne({
|
||||
token: ownerToken
|
||||
}).exec();
|
||||
|
||||
const notes = await Note.find({
|
||||
$or: [
|
||||
{ isPublic: true },
|
||||
{ ownerToken }
|
||||
]
|
||||
}).exec();
|
||||
|
||||
notes.map(note => {
|
||||
Logger.log("Title:" + note.title);
|
||||
Logger.log("By:" + user.name);
|
||||
Logger.log("Body:" + note.body);
|
||||
Logger.log();
|
||||
});
|
||||
|
||||
await mongoose.connection.close();
|
||||
})();
|
||||
25
config/atm/ml-powered-queries-repo/users-api.js
Normal file
25
config/atm/ml-powered-queries-repo/users-api.js
Normal file
@@ -0,0 +1,25 @@
|
||||
const express = require('express')
|
||||
|
||||
Logger = require('./logger').Logger;
|
||||
const router = module.exports.router = express.Router();
|
||||
|
||||
router.post('/updateName', async (req, res) => {
|
||||
Logger.log("/updateName called with new name", req.body.name);
|
||||
await User.findOneAndUpdate({
|
||||
token: req.body.token
|
||||
}, {
|
||||
name: req.body.name
|
||||
}).exec();
|
||||
res.json({
|
||||
name: req.body.name
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/getName', async (req, res) => {
|
||||
const user = await User.findOne({
|
||||
token: req.body.token
|
||||
}).exec();
|
||||
res.json({
|
||||
name: user.name
|
||||
});
|
||||
});
|
||||
@@ -94,8 +94,8 @@
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll"
|
||||
],
|
||||
"Model as Data Generation Java/C# - CaptureModels": [
|
||||
"java/ql/src/utils/model-generator/internal/CaptureModels.qll",
|
||||
"csharp/ql/src/utils/model-generator/internal/CaptureModels.qll"
|
||||
"java/ql/src/utils/modelgenerator/internal/CaptureModels.qll",
|
||||
"csharp/ql/src/utils/modelgenerator/internal/CaptureModels.qll"
|
||||
],
|
||||
"Sign Java/C#": [
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/Sign.qll",
|
||||
@@ -486,40 +486,6 @@
|
||||
"python/ql/lib/semmle/python/security/internal/SensitiveDataHeuristics.qll",
|
||||
"ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll"
|
||||
],
|
||||
"ReDoS Util Python/JS/Ruby/Java": [
|
||||
"javascript/ql/lib/semmle/javascript/security/regexp/NfaUtils.qll",
|
||||
"python/ql/lib/semmle/python/security/regexp/NfaUtils.qll",
|
||||
"ruby/ql/lib/codeql/ruby/security/regexp/NfaUtils.qll",
|
||||
"java/ql/lib/semmle/code/java/security/regexp/NfaUtils.qll"
|
||||
],
|
||||
"ReDoS Exponential Python/JS/Ruby/Java": [
|
||||
"javascript/ql/lib/semmle/javascript/security/regexp/ExponentialBackTracking.qll",
|
||||
"python/ql/lib/semmle/python/security/regexp/ExponentialBackTracking.qll",
|
||||
"ruby/ql/lib/codeql/ruby/security/regexp/ExponentialBackTracking.qll",
|
||||
"java/ql/lib/semmle/code/java/security/regexp/ExponentialBackTracking.qll"
|
||||
],
|
||||
"ReDoS Polynomial Python/JS/Ruby/Java": [
|
||||
"javascript/ql/lib/semmle/javascript/security/regexp/SuperlinearBackTracking.qll",
|
||||
"python/ql/lib/semmle/python/security/regexp/SuperlinearBackTracking.qll",
|
||||
"ruby/ql/lib/codeql/ruby/security/regexp/SuperlinearBackTracking.qll",
|
||||
"java/ql/lib/semmle/code/java/security/regexp/SuperlinearBackTracking.qll"
|
||||
],
|
||||
"RegexpMatching Python/JS/Ruby": [
|
||||
"javascript/ql/lib/semmle/javascript/security/regexp/RegexpMatching.qll",
|
||||
"python/ql/lib/semmle/python/security/regexp/RegexpMatching.qll",
|
||||
"ruby/ql/lib/codeql/ruby/security/regexp/RegexpMatching.qll"
|
||||
],
|
||||
"BadTagFilterQuery Python/JS/Ruby": [
|
||||
"javascript/ql/lib/semmle/javascript/security/BadTagFilterQuery.qll",
|
||||
"python/ql/lib/semmle/python/security/BadTagFilterQuery.qll",
|
||||
"ruby/ql/lib/codeql/ruby/security/BadTagFilterQuery.qll"
|
||||
],
|
||||
"OverlyLargeRange Python/JS/Ruby/Java": [
|
||||
"javascript/ql/lib/semmle/javascript/security/OverlyLargeRangeQuery.qll",
|
||||
"python/ql/lib/semmle/python/security/OverlyLargeRangeQuery.qll",
|
||||
"ruby/ql/lib/codeql/ruby/security/OverlyLargeRangeQuery.qll",
|
||||
"java/ql/lib/semmle/code/java/security/OverlyLargeRangeQuery.qll"
|
||||
],
|
||||
"CFG": [
|
||||
"csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll",
|
||||
"ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImplShared.qll",
|
||||
@@ -600,8 +566,12 @@
|
||||
"swift/ql/test/extractor-tests/patterns/patterns.swift",
|
||||
"swift/ql/test/library-tests/ast/patterns.swift"
|
||||
],
|
||||
"Swift control flow test file": [
|
||||
"swift/ql/test/library-tests/controlflow/graph/cfg.swift",
|
||||
"swift/ql/test/library-tests/ast/cfg.swift"
|
||||
],
|
||||
"IncompleteMultiCharacterSanitization JS/Ruby": [
|
||||
"javascript/ql/lib/semmle/javascript/security/IncompleteMultiCharacterSanitizationQuery.qll",
|
||||
"ruby/ql/lib/codeql/ruby/security/IncompleteMultiCharacterSanitizationQuery.qll"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,11 +257,11 @@ namespace Semmle.Autobuild.Cpp.Tests
|
||||
Actions.GetCurrentDirectory = cwd;
|
||||
Actions.IsWindows = isWindows;
|
||||
|
||||
var options = new AutobuildOptions(Actions, Language.Cpp);
|
||||
var options = new CppAutobuildOptions(Actions);
|
||||
return new CppAutobuilder(Actions, options);
|
||||
}
|
||||
|
||||
void TestAutobuilderScript(Autobuilder autobuilder, int expectedOutput, int commandsRun)
|
||||
void TestAutobuilderScript(CppAutobuilder autobuilder, int expectedOutput, int commandsRun)
|
||||
{
|
||||
Assert.Equal(expectedOutput, autobuilder.GetBuildScript().Run(Actions, StartCallback, EndCallback));
|
||||
|
||||
@@ -299,7 +299,7 @@ namespace Semmle.Autobuild.Cpp.Tests
|
||||
{
|
||||
Actions.RunProcess[@"cmd.exe /C nuget restore C:\Project\test.sln -DisableParallelProcessing"] = 1;
|
||||
Actions.RunProcess[@"cmd.exe /C C:\Project\.nuget\nuget.exe restore C:\Project\test.sln -DisableParallelProcessing"] = 0;
|
||||
Actions.RunProcess[@"cmd.exe /C CALL ^""C:\Program Files ^(x86^)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat^"" && set Platform=&& type NUL && C:\odasa\tools\odasa index --auto msbuild C:\Project\test.sln /t:rebuild /p:Platform=""x86"" /p:Configuration=""Release"" /p:MvcBuildViews=true"] = 0;
|
||||
Actions.RunProcess[@"cmd.exe /C CALL ^""C:\Program Files ^(x86^)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat^"" && set Platform=&& type NUL && msbuild C:\Project\test.sln /t:rebuild /p:Platform=""x86"" /p:Configuration=""Release"""] = 0;
|
||||
Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = "";
|
||||
Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = 1;
|
||||
Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = 0;
|
||||
|
||||
@@ -11,11 +11,12 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.IO.FileSystem" Version="4.3.0" />
|
||||
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
|
||||
<PackageReference Include="xunit" Version="2.4.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -2,9 +2,26 @@
|
||||
|
||||
namespace Semmle.Autobuild.Cpp
|
||||
{
|
||||
public class CppAutobuilder : Autobuilder
|
||||
/// <summary>
|
||||
/// Encapsulates C++ build options.
|
||||
/// </summary>
|
||||
public class CppAutobuildOptions : AutobuildOptionsShared
|
||||
{
|
||||
public CppAutobuilder(IBuildActions actions, AutobuildOptions options) : base(actions, options) { }
|
||||
public override Language Language => Language.Cpp;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Reads options from environment variables.
|
||||
/// Throws ArgumentOutOfRangeException for invalid arguments.
|
||||
/// </summary>
|
||||
public CppAutobuildOptions(IBuildActions actions) : base(actions)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class CppAutobuilder : Autobuilder<CppAutobuildOptions>
|
||||
{
|
||||
public CppAutobuilder(IBuildActions actions, CppAutobuildOptions options) : base(actions, options) { }
|
||||
|
||||
public override BuildScript GetBuildScript()
|
||||
{
|
||||
|
||||
@@ -11,14 +11,14 @@ namespace Semmle.Autobuild.Cpp
|
||||
try
|
||||
{
|
||||
var actions = SystemBuildActions.Instance;
|
||||
var options = new AutobuildOptions(actions, Language.Cpp);
|
||||
var options = new CppAutobuildOptions(actions);
|
||||
try
|
||||
{
|
||||
Console.WriteLine("CodeQL C++ autobuilder");
|
||||
var builder = new CppAutobuilder(actions, options);
|
||||
return builder.AttemptBuild();
|
||||
}
|
||||
catch(InvalidEnvironmentException ex)
|
||||
catch (InvalidEnvironmentException ex)
|
||||
{
|
||||
Console.WriteLine("The environment is invalid: {0}", ex.Message);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Build" Version="16.11.0" />
|
||||
<PackageReference Include="Microsoft.Build" Version="17.3.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -3,4 +3,4 @@ groups:
|
||||
- cpp
|
||||
- examples
|
||||
dependencies:
|
||||
codeql/cpp-all: "*"
|
||||
codeql/cpp-all: ${workspace}
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
## 0.4.4
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.3
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Fixed bugs in the `FormatLiteral` class that were causing `getMaxConvertedLength` and related predicates to return no results when the format literal was `%e`, `%f` or `%g` and an explicit precision was specified.
|
||||
|
||||
## 0.4.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
6
cpp/ql/lib/change-notes/2022-11-14-deprecate-ast-gvn.md
Normal file
6
cpp/ql/lib/change-notes/2022-11-14-deprecate-ast-gvn.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: deprecated
|
||||
---
|
||||
|
||||
|
||||
* Deprecated `semmle.code.cpp.valuenumbering.GlobalValueNumberingImpl`. Use `semmle.code.cpp.valuenumbering.GlobalValueNumbering`, which exposes the same API.
|
||||
4
cpp/ql/lib/change-notes/2022-11-16-must-flow.md
Normal file
4
cpp/ql/lib/change-notes/2022-11-16-must-flow.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: breaking
|
||||
---
|
||||
The predicates in the `MustFlow::Configuration` class used by the `MustFlow` library (`semmle.code.cpp.ir.dataflow.MustFlow`) have changed to be defined directly in terms of the C++ IR instead of IR dataflow nodes.
|
||||
4
cpp/ql/lib/change-notes/2022-11-17-deleted-deps.md
Normal file
4
cpp/ql/lib/change-notes/2022-11-17-deleted-deps.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Deleted the deprecated `getName` and `getShortName` predicates from the `Folder` class.
|
||||
@@ -1,4 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
## 0.4.3
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Fixed bugs in the `FormatLiteral` class that were causing `getMaxConvertedLength` and related predicates to return no results when the format literal was `%e`, `%f` or `%g` and an explicit precision was specified.
|
||||
3
cpp/ql/lib/change-notes/released/0.4.4.md
Normal file
3
cpp/ql/lib/change-notes/released/0.4.4.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.4.4
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.4.2
|
||||
lastReleaseVersion: 0.4.4
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2629,6 +2635,7 @@ private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration
|
||||
/**
|
||||
* Gets the number of `AccessPath`s that correspond to `apa`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
private int countAps(AccessPathApprox apa, Configuration config) {
|
||||
evalUnfold(apa, false, config) and
|
||||
result = 1 and
|
||||
@@ -2647,6 +2654,7 @@ private int countAps(AccessPathApprox apa, Configuration config) {
|
||||
* that it is expanded to a precise head-tail representation.
|
||||
*/
|
||||
language[monotonicAggregates]
|
||||
pragma[assume_small_delta]
|
||||
private int countPotentialAps(AccessPathApprox apa, Configuration config) {
|
||||
apa instanceof AccessPathApproxNil and result = 1
|
||||
or
|
||||
@@ -2681,6 +2689,7 @@ private newtype TAccessPath =
|
||||
}
|
||||
|
||||
private newtype TPathNode =
|
||||
pragma[assume_small_delta]
|
||||
TPathNodeMid(
|
||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||
) {
|
||||
@@ -2709,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2778,6 +2799,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
|
||||
|
||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override AccessPathApproxCons getApprox() {
|
||||
result = TConsNil(head, tail.(AccessPathNil).getType())
|
||||
or
|
||||
@@ -2786,6 +2808,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
|
||||
result = TCons1(head, this.length())
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override int length() { result = 1 + tail.length() }
|
||||
|
||||
private string toStringImpl(boolean needsSuffix) {
|
||||
@@ -2874,54 +2897,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 are generated.
|
||||
*/
|
||||
class PathNode extends TPathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() { none() }
|
||||
|
||||
/**
|
||||
* 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/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
|
||||
|
||||
abstract private class PathNodeImpl extends TPathNode {
|
||||
/** Gets the `FlowState` of this node. */
|
||||
FlowState getState() { none() }
|
||||
abstract FlowState getState();
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
|
||||
reach(this) and
|
||||
reach(result)
|
||||
}
|
||||
abstract Configuration getConfiguration();
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
predicate isSource() { none() }
|
||||
}
|
||||
abstract predicate isSource();
|
||||
|
||||
abstract private class PathNodeImpl extends PathNode {
|
||||
abstract PathNodeImpl getASuccessorImpl();
|
||||
|
||||
private PathNodeImpl getASuccessorIfHidden() {
|
||||
@@ -2953,6 +2938,22 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2967,13 +2968,23 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
|
||||
}
|
||||
|
||||
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
|
||||
override string toStringWithContext() {
|
||||
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
|
||||
}
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
/**
|
||||
* 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/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
@@ -2982,18 +2993,71 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
|
||||
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
|
||||
}
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
class PathNode instanceof PathNodeImpl {
|
||||
PathNode() { reach(this) }
|
||||
|
||||
/** 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() { super.getNodeEx().projectToNode() = result }
|
||||
|
||||
/** Gets the `FlowState` of this node. */
|
||||
final FlowState getState() { result = super.getState() }
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
final Configuration getConfiguration() { result = super.getConfiguration() }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
|
||||
|
||||
/** 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) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||
@@ -3004,7 +3068,7 @@ module PathGraph {
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3013,11 +3077,7 @@ module PathGraph {
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
|
||||
Subpaths::subpaths(arg, par, ret, out) and
|
||||
reach(arg) and
|
||||
reach(par) and
|
||||
reach(ret) and
|
||||
reach(out)
|
||||
Subpaths::subpaths(arg, par, ret, out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3118,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3142,6 +3259,7 @@ private predicate pathNode(
|
||||
* Holds if data may flow from `mid` to `node`. The last step in or out of
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate pathStep(
|
||||
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap
|
||||
@@ -3399,7 +3517,7 @@ private module Subpaths {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths02(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, FlowState sout, AccessPath apout
|
||||
) {
|
||||
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
|
||||
@@ -3407,14 +3525,14 @@ private module Subpaths {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
|
||||
private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths03(
|
||||
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
|
||||
PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
|
||||
) {
|
||||
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
|
||||
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
|
||||
@@ -3444,7 +3562,7 @@ private module Subpaths {
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
|
||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
|
||||
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||
@@ -3460,7 +3578,7 @@ private module Subpaths {
|
||||
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
|
||||
*/
|
||||
predicate retReach(PathNodeImpl n) {
|
||||
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
or
|
||||
exists(PathNodeImpl mid |
|
||||
retReach(mid) and
|
||||
@@ -3476,12 +3594,22 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
) {
|
||||
flowsource.isSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
|
||||
flowsource.getNodeEx().asNode() = source and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.getNodeEx().asNode() = sink
|
||||
}
|
||||
@@ -3504,14 +3632,14 @@ private predicate finalStats(
|
||||
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
|
||||
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
|
||||
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
|
||||
tuples = count(PathNode pn)
|
||||
tuples = count(PathNodeImpl pn)
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
|
||||
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
|
||||
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
|
||||
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
|
||||
tuples = count(PathNode pn | reach(pn))
|
||||
tuples = count(PathNode pn)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2629,6 +2635,7 @@ private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration
|
||||
/**
|
||||
* Gets the number of `AccessPath`s that correspond to `apa`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
private int countAps(AccessPathApprox apa, Configuration config) {
|
||||
evalUnfold(apa, false, config) and
|
||||
result = 1 and
|
||||
@@ -2647,6 +2654,7 @@ private int countAps(AccessPathApprox apa, Configuration config) {
|
||||
* that it is expanded to a precise head-tail representation.
|
||||
*/
|
||||
language[monotonicAggregates]
|
||||
pragma[assume_small_delta]
|
||||
private int countPotentialAps(AccessPathApprox apa, Configuration config) {
|
||||
apa instanceof AccessPathApproxNil and result = 1
|
||||
or
|
||||
@@ -2681,6 +2689,7 @@ private newtype TAccessPath =
|
||||
}
|
||||
|
||||
private newtype TPathNode =
|
||||
pragma[assume_small_delta]
|
||||
TPathNodeMid(
|
||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||
) {
|
||||
@@ -2709,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2778,6 +2799,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
|
||||
|
||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override AccessPathApproxCons getApprox() {
|
||||
result = TConsNil(head, tail.(AccessPathNil).getType())
|
||||
or
|
||||
@@ -2786,6 +2808,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
|
||||
result = TCons1(head, this.length())
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override int length() { result = 1 + tail.length() }
|
||||
|
||||
private string toStringImpl(boolean needsSuffix) {
|
||||
@@ -2874,54 +2897,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 are generated.
|
||||
*/
|
||||
class PathNode extends TPathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() { none() }
|
||||
|
||||
/**
|
||||
* 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/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
|
||||
|
||||
abstract private class PathNodeImpl extends TPathNode {
|
||||
/** Gets the `FlowState` of this node. */
|
||||
FlowState getState() { none() }
|
||||
abstract FlowState getState();
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
|
||||
reach(this) and
|
||||
reach(result)
|
||||
}
|
||||
abstract Configuration getConfiguration();
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
predicate isSource() { none() }
|
||||
}
|
||||
abstract predicate isSource();
|
||||
|
||||
abstract private class PathNodeImpl extends PathNode {
|
||||
abstract PathNodeImpl getASuccessorImpl();
|
||||
|
||||
private PathNodeImpl getASuccessorIfHidden() {
|
||||
@@ -2953,6 +2938,22 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2967,13 +2968,23 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
|
||||
}
|
||||
|
||||
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
|
||||
override string toStringWithContext() {
|
||||
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
|
||||
}
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
/**
|
||||
* 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/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
@@ -2982,18 +2993,71 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
|
||||
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
|
||||
}
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
class PathNode instanceof PathNodeImpl {
|
||||
PathNode() { reach(this) }
|
||||
|
||||
/** 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() { super.getNodeEx().projectToNode() = result }
|
||||
|
||||
/** Gets the `FlowState` of this node. */
|
||||
final FlowState getState() { result = super.getState() }
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
final Configuration getConfiguration() { result = super.getConfiguration() }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
|
||||
|
||||
/** 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) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||
@@ -3004,7 +3068,7 @@ module PathGraph {
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3013,11 +3077,7 @@ module PathGraph {
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
|
||||
Subpaths::subpaths(arg, par, ret, out) and
|
||||
reach(arg) and
|
||||
reach(par) and
|
||||
reach(ret) and
|
||||
reach(out)
|
||||
Subpaths::subpaths(arg, par, ret, out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3118,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3142,6 +3259,7 @@ private predicate pathNode(
|
||||
* Holds if data may flow from `mid` to `node`. The last step in or out of
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate pathStep(
|
||||
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap
|
||||
@@ -3399,7 +3517,7 @@ private module Subpaths {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths02(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, FlowState sout, AccessPath apout
|
||||
) {
|
||||
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
|
||||
@@ -3407,14 +3525,14 @@ private module Subpaths {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
|
||||
private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths03(
|
||||
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
|
||||
PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
|
||||
) {
|
||||
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
|
||||
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
|
||||
@@ -3444,7 +3562,7 @@ private module Subpaths {
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
|
||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
|
||||
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||
@@ -3460,7 +3578,7 @@ private module Subpaths {
|
||||
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
|
||||
*/
|
||||
predicate retReach(PathNodeImpl n) {
|
||||
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
or
|
||||
exists(PathNodeImpl mid |
|
||||
retReach(mid) and
|
||||
@@ -3476,12 +3594,22 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
) {
|
||||
flowsource.isSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
|
||||
flowsource.getNodeEx().asNode() = source and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.getNodeEx().asNode() = sink
|
||||
}
|
||||
@@ -3504,14 +3632,14 @@ private predicate finalStats(
|
||||
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
|
||||
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
|
||||
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
|
||||
tuples = count(PathNode pn)
|
||||
tuples = count(PathNodeImpl pn)
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
|
||||
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
|
||||
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
|
||||
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
|
||||
tuples = count(PathNode pn | reach(pn))
|
||||
tuples = count(PathNode pn)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2629,6 +2635,7 @@ private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration
|
||||
/**
|
||||
* Gets the number of `AccessPath`s that correspond to `apa`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
private int countAps(AccessPathApprox apa, Configuration config) {
|
||||
evalUnfold(apa, false, config) and
|
||||
result = 1 and
|
||||
@@ -2647,6 +2654,7 @@ private int countAps(AccessPathApprox apa, Configuration config) {
|
||||
* that it is expanded to a precise head-tail representation.
|
||||
*/
|
||||
language[monotonicAggregates]
|
||||
pragma[assume_small_delta]
|
||||
private int countPotentialAps(AccessPathApprox apa, Configuration config) {
|
||||
apa instanceof AccessPathApproxNil and result = 1
|
||||
or
|
||||
@@ -2681,6 +2689,7 @@ private newtype TAccessPath =
|
||||
}
|
||||
|
||||
private newtype TPathNode =
|
||||
pragma[assume_small_delta]
|
||||
TPathNodeMid(
|
||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||
) {
|
||||
@@ -2709,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2778,6 +2799,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
|
||||
|
||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override AccessPathApproxCons getApprox() {
|
||||
result = TConsNil(head, tail.(AccessPathNil).getType())
|
||||
or
|
||||
@@ -2786,6 +2808,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
|
||||
result = TCons1(head, this.length())
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override int length() { result = 1 + tail.length() }
|
||||
|
||||
private string toStringImpl(boolean needsSuffix) {
|
||||
@@ -2874,54 +2897,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 are generated.
|
||||
*/
|
||||
class PathNode extends TPathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() { none() }
|
||||
|
||||
/**
|
||||
* 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/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
|
||||
|
||||
abstract private class PathNodeImpl extends TPathNode {
|
||||
/** Gets the `FlowState` of this node. */
|
||||
FlowState getState() { none() }
|
||||
abstract FlowState getState();
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
|
||||
reach(this) and
|
||||
reach(result)
|
||||
}
|
||||
abstract Configuration getConfiguration();
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
predicate isSource() { none() }
|
||||
}
|
||||
abstract predicate isSource();
|
||||
|
||||
abstract private class PathNodeImpl extends PathNode {
|
||||
abstract PathNodeImpl getASuccessorImpl();
|
||||
|
||||
private PathNodeImpl getASuccessorIfHidden() {
|
||||
@@ -2953,6 +2938,22 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2967,13 +2968,23 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
|
||||
}
|
||||
|
||||
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
|
||||
override string toStringWithContext() {
|
||||
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
|
||||
}
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
/**
|
||||
* 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/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
@@ -2982,18 +2993,71 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
|
||||
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
|
||||
}
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
class PathNode instanceof PathNodeImpl {
|
||||
PathNode() { reach(this) }
|
||||
|
||||
/** 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() { super.getNodeEx().projectToNode() = result }
|
||||
|
||||
/** Gets the `FlowState` of this node. */
|
||||
final FlowState getState() { result = super.getState() }
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
final Configuration getConfiguration() { result = super.getConfiguration() }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
|
||||
|
||||
/** 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) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||
@@ -3004,7 +3068,7 @@ module PathGraph {
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3013,11 +3077,7 @@ module PathGraph {
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
|
||||
Subpaths::subpaths(arg, par, ret, out) and
|
||||
reach(arg) and
|
||||
reach(par) and
|
||||
reach(ret) and
|
||||
reach(out)
|
||||
Subpaths::subpaths(arg, par, ret, out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3118,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3142,6 +3259,7 @@ private predicate pathNode(
|
||||
* Holds if data may flow from `mid` to `node`. The last step in or out of
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate pathStep(
|
||||
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap
|
||||
@@ -3399,7 +3517,7 @@ private module Subpaths {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths02(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, FlowState sout, AccessPath apout
|
||||
) {
|
||||
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
|
||||
@@ -3407,14 +3525,14 @@ private module Subpaths {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
|
||||
private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths03(
|
||||
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
|
||||
PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
|
||||
) {
|
||||
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
|
||||
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
|
||||
@@ -3444,7 +3562,7 @@ private module Subpaths {
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
|
||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
|
||||
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||
@@ -3460,7 +3578,7 @@ private module Subpaths {
|
||||
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
|
||||
*/
|
||||
predicate retReach(PathNodeImpl n) {
|
||||
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
or
|
||||
exists(PathNodeImpl mid |
|
||||
retReach(mid) and
|
||||
@@ -3476,12 +3594,22 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
) {
|
||||
flowsource.isSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
|
||||
flowsource.getNodeEx().asNode() = source and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.getNodeEx().asNode() = sink
|
||||
}
|
||||
@@ -3504,14 +3632,14 @@ private predicate finalStats(
|
||||
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
|
||||
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
|
||||
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
|
||||
tuples = count(PathNode pn)
|
||||
tuples = count(PathNodeImpl pn)
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
|
||||
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
|
||||
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
|
||||
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
|
||||
tuples = count(PathNode pn | reach(pn))
|
||||
tuples = count(PathNode pn)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2629,6 +2635,7 @@ private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration
|
||||
/**
|
||||
* Gets the number of `AccessPath`s that correspond to `apa`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
private int countAps(AccessPathApprox apa, Configuration config) {
|
||||
evalUnfold(apa, false, config) and
|
||||
result = 1 and
|
||||
@@ -2647,6 +2654,7 @@ private int countAps(AccessPathApprox apa, Configuration config) {
|
||||
* that it is expanded to a precise head-tail representation.
|
||||
*/
|
||||
language[monotonicAggregates]
|
||||
pragma[assume_small_delta]
|
||||
private int countPotentialAps(AccessPathApprox apa, Configuration config) {
|
||||
apa instanceof AccessPathApproxNil and result = 1
|
||||
or
|
||||
@@ -2681,6 +2689,7 @@ private newtype TAccessPath =
|
||||
}
|
||||
|
||||
private newtype TPathNode =
|
||||
pragma[assume_small_delta]
|
||||
TPathNodeMid(
|
||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||
) {
|
||||
@@ -2709,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2778,6 +2799,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
|
||||
|
||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override AccessPathApproxCons getApprox() {
|
||||
result = TConsNil(head, tail.(AccessPathNil).getType())
|
||||
or
|
||||
@@ -2786,6 +2808,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
|
||||
result = TCons1(head, this.length())
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override int length() { result = 1 + tail.length() }
|
||||
|
||||
private string toStringImpl(boolean needsSuffix) {
|
||||
@@ -2874,54 +2897,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 are generated.
|
||||
*/
|
||||
class PathNode extends TPathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() { none() }
|
||||
|
||||
/**
|
||||
* 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/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
|
||||
|
||||
abstract private class PathNodeImpl extends TPathNode {
|
||||
/** Gets the `FlowState` of this node. */
|
||||
FlowState getState() { none() }
|
||||
abstract FlowState getState();
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
|
||||
reach(this) and
|
||||
reach(result)
|
||||
}
|
||||
abstract Configuration getConfiguration();
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
predicate isSource() { none() }
|
||||
}
|
||||
abstract predicate isSource();
|
||||
|
||||
abstract private class PathNodeImpl extends PathNode {
|
||||
abstract PathNodeImpl getASuccessorImpl();
|
||||
|
||||
private PathNodeImpl getASuccessorIfHidden() {
|
||||
@@ -2953,6 +2938,22 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2967,13 +2968,23 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
|
||||
}
|
||||
|
||||
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
|
||||
override string toStringWithContext() {
|
||||
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
|
||||
}
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
/**
|
||||
* 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/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
@@ -2982,18 +2993,71 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
|
||||
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
|
||||
}
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
class PathNode instanceof PathNodeImpl {
|
||||
PathNode() { reach(this) }
|
||||
|
||||
/** 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() { super.getNodeEx().projectToNode() = result }
|
||||
|
||||
/** Gets the `FlowState` of this node. */
|
||||
final FlowState getState() { result = super.getState() }
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
final Configuration getConfiguration() { result = super.getConfiguration() }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
|
||||
|
||||
/** 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) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||
@@ -3004,7 +3068,7 @@ module PathGraph {
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3013,11 +3077,7 @@ module PathGraph {
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
|
||||
Subpaths::subpaths(arg, par, ret, out) and
|
||||
reach(arg) and
|
||||
reach(par) and
|
||||
reach(ret) and
|
||||
reach(out)
|
||||
Subpaths::subpaths(arg, par, ret, out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3118,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3142,6 +3259,7 @@ private predicate pathNode(
|
||||
* Holds if data may flow from `mid` to `node`. The last step in or out of
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate pathStep(
|
||||
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap
|
||||
@@ -3399,7 +3517,7 @@ private module Subpaths {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths02(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, FlowState sout, AccessPath apout
|
||||
) {
|
||||
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
|
||||
@@ -3407,14 +3525,14 @@ private module Subpaths {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
|
||||
private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths03(
|
||||
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
|
||||
PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
|
||||
) {
|
||||
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
|
||||
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
|
||||
@@ -3444,7 +3562,7 @@ private module Subpaths {
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
|
||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
|
||||
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||
@@ -3460,7 +3578,7 @@ private module Subpaths {
|
||||
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
|
||||
*/
|
||||
predicate retReach(PathNodeImpl n) {
|
||||
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
or
|
||||
exists(PathNodeImpl mid |
|
||||
retReach(mid) and
|
||||
@@ -3476,12 +3594,22 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
) {
|
||||
flowsource.isSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
|
||||
flowsource.getNodeEx().asNode() = source and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.getNodeEx().asNode() = sink
|
||||
}
|
||||
@@ -3504,14 +3632,14 @@ private predicate finalStats(
|
||||
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
|
||||
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
|
||||
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
|
||||
tuples = count(PathNode pn)
|
||||
tuples = count(PathNodeImpl pn)
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
|
||||
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
|
||||
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
|
||||
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
|
||||
tuples = count(PathNode pn | reach(pn))
|
||||
tuples = count(PathNode pn)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -136,6 +136,18 @@ module Consistency {
|
||||
msg = "Local flow step does not preserve enclosing callable."
|
||||
}
|
||||
|
||||
query predicate readStepIsLocal(Node n1, Node n2, string msg) {
|
||||
readStep(n1, _, n2) and
|
||||
nodeGetEnclosingCallable(n1) != nodeGetEnclosingCallable(n2) and
|
||||
msg = "Read step does not preserve enclosing callable."
|
||||
}
|
||||
|
||||
query predicate storeStepIsLocal(Node n1, Node n2, string msg) {
|
||||
storeStep(n1, _, n2) and
|
||||
nodeGetEnclosingCallable(n1) != nodeGetEnclosingCallable(n2) and
|
||||
msg = "Store step does not preserve enclosing callable."
|
||||
}
|
||||
|
||||
private DataFlowType typeRepr() { result = getNodeType(_) }
|
||||
|
||||
query predicate compatibleTypesReflexive(DataFlowType t, string msg) {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
name: codeql/cpp-all
|
||||
version: 0.4.3-dev
|
||||
version: 0.4.5-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
library: true
|
||||
upgrades: upgrades
|
||||
dependencies:
|
||||
codeql/ssa: 0.0.1
|
||||
codeql/ssa: ${workspace}
|
||||
|
||||
@@ -189,18 +189,6 @@ class Folder extends Container, @folder {
|
||||
* Gets the URL of this folder.
|
||||
*/
|
||||
deprecated override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `getAbsolutePath` instead.
|
||||
* Gets the name of this folder.
|
||||
*/
|
||||
deprecated string getName() { folders(underlyingElement(this), result) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `getBaseName` instead.
|
||||
* Gets the last part of the folder name.
|
||||
*/
|
||||
deprecated string getShortName() { result = this.getBaseName() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2629,6 +2635,7 @@ private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration
|
||||
/**
|
||||
* Gets the number of `AccessPath`s that correspond to `apa`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
private int countAps(AccessPathApprox apa, Configuration config) {
|
||||
evalUnfold(apa, false, config) and
|
||||
result = 1 and
|
||||
@@ -2647,6 +2654,7 @@ private int countAps(AccessPathApprox apa, Configuration config) {
|
||||
* that it is expanded to a precise head-tail representation.
|
||||
*/
|
||||
language[monotonicAggregates]
|
||||
pragma[assume_small_delta]
|
||||
private int countPotentialAps(AccessPathApprox apa, Configuration config) {
|
||||
apa instanceof AccessPathApproxNil and result = 1
|
||||
or
|
||||
@@ -2681,6 +2689,7 @@ private newtype TAccessPath =
|
||||
}
|
||||
|
||||
private newtype TPathNode =
|
||||
pragma[assume_small_delta]
|
||||
TPathNodeMid(
|
||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||
) {
|
||||
@@ -2709,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2778,6 +2799,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
|
||||
|
||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override AccessPathApproxCons getApprox() {
|
||||
result = TConsNil(head, tail.(AccessPathNil).getType())
|
||||
or
|
||||
@@ -2786,6 +2808,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
|
||||
result = TCons1(head, this.length())
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override int length() { result = 1 + tail.length() }
|
||||
|
||||
private string toStringImpl(boolean needsSuffix) {
|
||||
@@ -2874,54 +2897,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 are generated.
|
||||
*/
|
||||
class PathNode extends TPathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() { none() }
|
||||
|
||||
/**
|
||||
* 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/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
|
||||
|
||||
abstract private class PathNodeImpl extends TPathNode {
|
||||
/** Gets the `FlowState` of this node. */
|
||||
FlowState getState() { none() }
|
||||
abstract FlowState getState();
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
|
||||
reach(this) and
|
||||
reach(result)
|
||||
}
|
||||
abstract Configuration getConfiguration();
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
predicate isSource() { none() }
|
||||
}
|
||||
abstract predicate isSource();
|
||||
|
||||
abstract private class PathNodeImpl extends PathNode {
|
||||
abstract PathNodeImpl getASuccessorImpl();
|
||||
|
||||
private PathNodeImpl getASuccessorIfHidden() {
|
||||
@@ -2953,6 +2938,22 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2967,13 +2968,23 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
|
||||
}
|
||||
|
||||
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
|
||||
override string toStringWithContext() {
|
||||
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
|
||||
}
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
/**
|
||||
* 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/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
@@ -2982,18 +2993,71 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
|
||||
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
|
||||
}
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
class PathNode instanceof PathNodeImpl {
|
||||
PathNode() { reach(this) }
|
||||
|
||||
/** 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() { super.getNodeEx().projectToNode() = result }
|
||||
|
||||
/** Gets the `FlowState` of this node. */
|
||||
final FlowState getState() { result = super.getState() }
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
final Configuration getConfiguration() { result = super.getConfiguration() }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
|
||||
|
||||
/** 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) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||
@@ -3004,7 +3068,7 @@ module PathGraph {
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3013,11 +3077,7 @@ module PathGraph {
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
|
||||
Subpaths::subpaths(arg, par, ret, out) and
|
||||
reach(arg) and
|
||||
reach(par) and
|
||||
reach(ret) and
|
||||
reach(out)
|
||||
Subpaths::subpaths(arg, par, ret, out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3118,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3142,6 +3259,7 @@ private predicate pathNode(
|
||||
* Holds if data may flow from `mid` to `node`. The last step in or out of
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate pathStep(
|
||||
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap
|
||||
@@ -3399,7 +3517,7 @@ private module Subpaths {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths02(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, FlowState sout, AccessPath apout
|
||||
) {
|
||||
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
|
||||
@@ -3407,14 +3525,14 @@ private module Subpaths {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
|
||||
private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths03(
|
||||
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
|
||||
PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
|
||||
) {
|
||||
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
|
||||
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
|
||||
@@ -3444,7 +3562,7 @@ private module Subpaths {
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
|
||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
|
||||
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||
@@ -3460,7 +3578,7 @@ private module Subpaths {
|
||||
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
|
||||
*/
|
||||
predicate retReach(PathNodeImpl n) {
|
||||
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
or
|
||||
exists(PathNodeImpl mid |
|
||||
retReach(mid) and
|
||||
@@ -3476,12 +3594,22 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
) {
|
||||
flowsource.isSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
|
||||
flowsource.getNodeEx().asNode() = source and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.getNodeEx().asNode() = sink
|
||||
}
|
||||
@@ -3504,14 +3632,14 @@ private predicate finalStats(
|
||||
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
|
||||
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
|
||||
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
|
||||
tuples = count(PathNode pn)
|
||||
tuples = count(PathNodeImpl pn)
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
|
||||
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
|
||||
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
|
||||
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
|
||||
tuples = count(PathNode pn | reach(pn))
|
||||
tuples = count(PathNode pn)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2629,6 +2635,7 @@ private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration
|
||||
/**
|
||||
* Gets the number of `AccessPath`s that correspond to `apa`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
private int countAps(AccessPathApprox apa, Configuration config) {
|
||||
evalUnfold(apa, false, config) and
|
||||
result = 1 and
|
||||
@@ -2647,6 +2654,7 @@ private int countAps(AccessPathApprox apa, Configuration config) {
|
||||
* that it is expanded to a precise head-tail representation.
|
||||
*/
|
||||
language[monotonicAggregates]
|
||||
pragma[assume_small_delta]
|
||||
private int countPotentialAps(AccessPathApprox apa, Configuration config) {
|
||||
apa instanceof AccessPathApproxNil and result = 1
|
||||
or
|
||||
@@ -2681,6 +2689,7 @@ private newtype TAccessPath =
|
||||
}
|
||||
|
||||
private newtype TPathNode =
|
||||
pragma[assume_small_delta]
|
||||
TPathNodeMid(
|
||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||
) {
|
||||
@@ -2709,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2778,6 +2799,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
|
||||
|
||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override AccessPathApproxCons getApprox() {
|
||||
result = TConsNil(head, tail.(AccessPathNil).getType())
|
||||
or
|
||||
@@ -2786,6 +2808,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
|
||||
result = TCons1(head, this.length())
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override int length() { result = 1 + tail.length() }
|
||||
|
||||
private string toStringImpl(boolean needsSuffix) {
|
||||
@@ -2874,54 +2897,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 are generated.
|
||||
*/
|
||||
class PathNode extends TPathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() { none() }
|
||||
|
||||
/**
|
||||
* 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/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
|
||||
|
||||
abstract private class PathNodeImpl extends TPathNode {
|
||||
/** Gets the `FlowState` of this node. */
|
||||
FlowState getState() { none() }
|
||||
abstract FlowState getState();
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
|
||||
reach(this) and
|
||||
reach(result)
|
||||
}
|
||||
abstract Configuration getConfiguration();
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
predicate isSource() { none() }
|
||||
}
|
||||
abstract predicate isSource();
|
||||
|
||||
abstract private class PathNodeImpl extends PathNode {
|
||||
abstract PathNodeImpl getASuccessorImpl();
|
||||
|
||||
private PathNodeImpl getASuccessorIfHidden() {
|
||||
@@ -2953,6 +2938,22 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2967,13 +2968,23 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
|
||||
}
|
||||
|
||||
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
|
||||
override string toStringWithContext() {
|
||||
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
|
||||
}
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
/**
|
||||
* 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/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
@@ -2982,18 +2993,71 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
|
||||
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
|
||||
}
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
class PathNode instanceof PathNodeImpl {
|
||||
PathNode() { reach(this) }
|
||||
|
||||
/** 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() { super.getNodeEx().projectToNode() = result }
|
||||
|
||||
/** Gets the `FlowState` of this node. */
|
||||
final FlowState getState() { result = super.getState() }
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
final Configuration getConfiguration() { result = super.getConfiguration() }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
|
||||
|
||||
/** 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) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||
@@ -3004,7 +3068,7 @@ module PathGraph {
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3013,11 +3077,7 @@ module PathGraph {
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
|
||||
Subpaths::subpaths(arg, par, ret, out) and
|
||||
reach(arg) and
|
||||
reach(par) and
|
||||
reach(ret) and
|
||||
reach(out)
|
||||
Subpaths::subpaths(arg, par, ret, out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3118,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3142,6 +3259,7 @@ private predicate pathNode(
|
||||
* Holds if data may flow from `mid` to `node`. The last step in or out of
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate pathStep(
|
||||
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap
|
||||
@@ -3399,7 +3517,7 @@ private module Subpaths {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths02(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, FlowState sout, AccessPath apout
|
||||
) {
|
||||
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
|
||||
@@ -3407,14 +3525,14 @@ private module Subpaths {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
|
||||
private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths03(
|
||||
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
|
||||
PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
|
||||
) {
|
||||
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
|
||||
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
|
||||
@@ -3444,7 +3562,7 @@ private module Subpaths {
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
|
||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
|
||||
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||
@@ -3460,7 +3578,7 @@ private module Subpaths {
|
||||
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
|
||||
*/
|
||||
predicate retReach(PathNodeImpl n) {
|
||||
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
or
|
||||
exists(PathNodeImpl mid |
|
||||
retReach(mid) and
|
||||
@@ -3476,12 +3594,22 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
) {
|
||||
flowsource.isSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
|
||||
flowsource.getNodeEx().asNode() = source and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.getNodeEx().asNode() = sink
|
||||
}
|
||||
@@ -3504,14 +3632,14 @@ private predicate finalStats(
|
||||
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
|
||||
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
|
||||
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
|
||||
tuples = count(PathNode pn)
|
||||
tuples = count(PathNodeImpl pn)
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
|
||||
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
|
||||
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
|
||||
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
|
||||
tuples = count(PathNode pn | reach(pn))
|
||||
tuples = count(PathNode pn)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2629,6 +2635,7 @@ private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration
|
||||
/**
|
||||
* Gets the number of `AccessPath`s that correspond to `apa`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
private int countAps(AccessPathApprox apa, Configuration config) {
|
||||
evalUnfold(apa, false, config) and
|
||||
result = 1 and
|
||||
@@ -2647,6 +2654,7 @@ private int countAps(AccessPathApprox apa, Configuration config) {
|
||||
* that it is expanded to a precise head-tail representation.
|
||||
*/
|
||||
language[monotonicAggregates]
|
||||
pragma[assume_small_delta]
|
||||
private int countPotentialAps(AccessPathApprox apa, Configuration config) {
|
||||
apa instanceof AccessPathApproxNil and result = 1
|
||||
or
|
||||
@@ -2681,6 +2689,7 @@ private newtype TAccessPath =
|
||||
}
|
||||
|
||||
private newtype TPathNode =
|
||||
pragma[assume_small_delta]
|
||||
TPathNodeMid(
|
||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||
) {
|
||||
@@ -2709,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2778,6 +2799,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
|
||||
|
||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override AccessPathApproxCons getApprox() {
|
||||
result = TConsNil(head, tail.(AccessPathNil).getType())
|
||||
or
|
||||
@@ -2786,6 +2808,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
|
||||
result = TCons1(head, this.length())
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override int length() { result = 1 + tail.length() }
|
||||
|
||||
private string toStringImpl(boolean needsSuffix) {
|
||||
@@ -2874,54 +2897,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 are generated.
|
||||
*/
|
||||
class PathNode extends TPathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() { none() }
|
||||
|
||||
/**
|
||||
* 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/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
|
||||
|
||||
abstract private class PathNodeImpl extends TPathNode {
|
||||
/** Gets the `FlowState` of this node. */
|
||||
FlowState getState() { none() }
|
||||
abstract FlowState getState();
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
|
||||
reach(this) and
|
||||
reach(result)
|
||||
}
|
||||
abstract Configuration getConfiguration();
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
predicate isSource() { none() }
|
||||
}
|
||||
abstract predicate isSource();
|
||||
|
||||
abstract private class PathNodeImpl extends PathNode {
|
||||
abstract PathNodeImpl getASuccessorImpl();
|
||||
|
||||
private PathNodeImpl getASuccessorIfHidden() {
|
||||
@@ -2953,6 +2938,22 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2967,13 +2968,23 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
|
||||
}
|
||||
|
||||
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
|
||||
override string toStringWithContext() {
|
||||
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
|
||||
}
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
/**
|
||||
* 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/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
@@ -2982,18 +2993,71 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
|
||||
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
|
||||
}
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
class PathNode instanceof PathNodeImpl {
|
||||
PathNode() { reach(this) }
|
||||
|
||||
/** 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() { super.getNodeEx().projectToNode() = result }
|
||||
|
||||
/** Gets the `FlowState` of this node. */
|
||||
final FlowState getState() { result = super.getState() }
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
final Configuration getConfiguration() { result = super.getConfiguration() }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
|
||||
|
||||
/** 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) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||
@@ -3004,7 +3068,7 @@ module PathGraph {
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3013,11 +3077,7 @@ module PathGraph {
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
|
||||
Subpaths::subpaths(arg, par, ret, out) and
|
||||
reach(arg) and
|
||||
reach(par) and
|
||||
reach(ret) and
|
||||
reach(out)
|
||||
Subpaths::subpaths(arg, par, ret, out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3118,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3142,6 +3259,7 @@ private predicate pathNode(
|
||||
* Holds if data may flow from `mid` to `node`. The last step in or out of
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate pathStep(
|
||||
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap
|
||||
@@ -3399,7 +3517,7 @@ private module Subpaths {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths02(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, FlowState sout, AccessPath apout
|
||||
) {
|
||||
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
|
||||
@@ -3407,14 +3525,14 @@ private module Subpaths {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
|
||||
private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths03(
|
||||
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
|
||||
PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
|
||||
) {
|
||||
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
|
||||
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
|
||||
@@ -3444,7 +3562,7 @@ private module Subpaths {
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
|
||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
|
||||
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||
@@ -3460,7 +3578,7 @@ private module Subpaths {
|
||||
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
|
||||
*/
|
||||
predicate retReach(PathNodeImpl n) {
|
||||
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
or
|
||||
exists(PathNodeImpl mid |
|
||||
retReach(mid) and
|
||||
@@ -3476,12 +3594,22 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
) {
|
||||
flowsource.isSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
|
||||
flowsource.getNodeEx().asNode() = source and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.getNodeEx().asNode() = sink
|
||||
}
|
||||
@@ -3504,14 +3632,14 @@ private predicate finalStats(
|
||||
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
|
||||
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
|
||||
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
|
||||
tuples = count(PathNode pn)
|
||||
tuples = count(PathNodeImpl pn)
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
|
||||
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
|
||||
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
|
||||
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
|
||||
tuples = count(PathNode pn | reach(pn))
|
||||
tuples = count(PathNode pn)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2629,6 +2635,7 @@ private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration
|
||||
/**
|
||||
* Gets the number of `AccessPath`s that correspond to `apa`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
private int countAps(AccessPathApprox apa, Configuration config) {
|
||||
evalUnfold(apa, false, config) and
|
||||
result = 1 and
|
||||
@@ -2647,6 +2654,7 @@ private int countAps(AccessPathApprox apa, Configuration config) {
|
||||
* that it is expanded to a precise head-tail representation.
|
||||
*/
|
||||
language[monotonicAggregates]
|
||||
pragma[assume_small_delta]
|
||||
private int countPotentialAps(AccessPathApprox apa, Configuration config) {
|
||||
apa instanceof AccessPathApproxNil and result = 1
|
||||
or
|
||||
@@ -2681,6 +2689,7 @@ private newtype TAccessPath =
|
||||
}
|
||||
|
||||
private newtype TPathNode =
|
||||
pragma[assume_small_delta]
|
||||
TPathNodeMid(
|
||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||
) {
|
||||
@@ -2709,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2778,6 +2799,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
|
||||
|
||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override AccessPathApproxCons getApprox() {
|
||||
result = TConsNil(head, tail.(AccessPathNil).getType())
|
||||
or
|
||||
@@ -2786,6 +2808,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
|
||||
result = TCons1(head, this.length())
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override int length() { result = 1 + tail.length() }
|
||||
|
||||
private string toStringImpl(boolean needsSuffix) {
|
||||
@@ -2874,54 +2897,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 are generated.
|
||||
*/
|
||||
class PathNode extends TPathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() { none() }
|
||||
|
||||
/**
|
||||
* 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/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
|
||||
|
||||
abstract private class PathNodeImpl extends TPathNode {
|
||||
/** Gets the `FlowState` of this node. */
|
||||
FlowState getState() { none() }
|
||||
abstract FlowState getState();
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
|
||||
reach(this) and
|
||||
reach(result)
|
||||
}
|
||||
abstract Configuration getConfiguration();
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
predicate isSource() { none() }
|
||||
}
|
||||
abstract predicate isSource();
|
||||
|
||||
abstract private class PathNodeImpl extends PathNode {
|
||||
abstract PathNodeImpl getASuccessorImpl();
|
||||
|
||||
private PathNodeImpl getASuccessorIfHidden() {
|
||||
@@ -2953,6 +2938,22 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2967,13 +2968,23 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
|
||||
}
|
||||
|
||||
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
|
||||
override string toStringWithContext() {
|
||||
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
|
||||
}
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
/**
|
||||
* 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/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
@@ -2982,18 +2993,71 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
|
||||
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
|
||||
}
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
class PathNode instanceof PathNodeImpl {
|
||||
PathNode() { reach(this) }
|
||||
|
||||
/** 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() { super.getNodeEx().projectToNode() = result }
|
||||
|
||||
/** Gets the `FlowState` of this node. */
|
||||
final FlowState getState() { result = super.getState() }
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
final Configuration getConfiguration() { result = super.getConfiguration() }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
|
||||
|
||||
/** 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) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||
@@ -3004,7 +3068,7 @@ module PathGraph {
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3013,11 +3077,7 @@ module PathGraph {
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
|
||||
Subpaths::subpaths(arg, par, ret, out) and
|
||||
reach(arg) and
|
||||
reach(par) and
|
||||
reach(ret) and
|
||||
reach(out)
|
||||
Subpaths::subpaths(arg, par, ret, out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3118,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3142,6 +3259,7 @@ private predicate pathNode(
|
||||
* Holds if data may flow from `mid` to `node`. The last step in or out of
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate pathStep(
|
||||
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap
|
||||
@@ -3399,7 +3517,7 @@ private module Subpaths {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths02(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, FlowState sout, AccessPath apout
|
||||
) {
|
||||
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
|
||||
@@ -3407,14 +3525,14 @@ private module Subpaths {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
|
||||
private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths03(
|
||||
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
|
||||
PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
|
||||
) {
|
||||
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
|
||||
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
|
||||
@@ -3444,7 +3562,7 @@ private module Subpaths {
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
|
||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
|
||||
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||
@@ -3460,7 +3578,7 @@ private module Subpaths {
|
||||
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
|
||||
*/
|
||||
predicate retReach(PathNodeImpl n) {
|
||||
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
or
|
||||
exists(PathNodeImpl mid |
|
||||
retReach(mid) and
|
||||
@@ -3476,12 +3594,22 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
) {
|
||||
flowsource.isSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
|
||||
flowsource.getNodeEx().asNode() = source and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.getNodeEx().asNode() = sink
|
||||
}
|
||||
@@ -3504,14 +3632,14 @@ private predicate finalStats(
|
||||
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
|
||||
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
|
||||
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
|
||||
tuples = count(PathNode pn)
|
||||
tuples = count(PathNodeImpl pn)
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
|
||||
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
|
||||
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
|
||||
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
|
||||
tuples = count(PathNode pn | reach(pn))
|
||||
tuples = count(PathNode pn)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -136,6 +136,18 @@ module Consistency {
|
||||
msg = "Local flow step does not preserve enclosing callable."
|
||||
}
|
||||
|
||||
query predicate readStepIsLocal(Node n1, Node n2, string msg) {
|
||||
readStep(n1, _, n2) and
|
||||
nodeGetEnclosingCallable(n1) != nodeGetEnclosingCallable(n2) and
|
||||
msg = "Read step does not preserve enclosing callable."
|
||||
}
|
||||
|
||||
query predicate storeStepIsLocal(Node n1, Node n2, string msg) {
|
||||
storeStep(n1, _, n2) and
|
||||
nodeGetEnclosingCallable(n1) != nodeGetEnclosingCallable(n2) and
|
||||
msg = "Store step does not preserve enclosing callable."
|
||||
}
|
||||
|
||||
private DataFlowType typeRepr() { result = getNodeType(_) }
|
||||
|
||||
query predicate compatibleTypesReflexive(DataFlowType t, string msg) {
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2629,6 +2635,7 @@ private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration
|
||||
/**
|
||||
* Gets the number of `AccessPath`s that correspond to `apa`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
private int countAps(AccessPathApprox apa, Configuration config) {
|
||||
evalUnfold(apa, false, config) and
|
||||
result = 1 and
|
||||
@@ -2647,6 +2654,7 @@ private int countAps(AccessPathApprox apa, Configuration config) {
|
||||
* that it is expanded to a precise head-tail representation.
|
||||
*/
|
||||
language[monotonicAggregates]
|
||||
pragma[assume_small_delta]
|
||||
private int countPotentialAps(AccessPathApprox apa, Configuration config) {
|
||||
apa instanceof AccessPathApproxNil and result = 1
|
||||
or
|
||||
@@ -2681,6 +2689,7 @@ private newtype TAccessPath =
|
||||
}
|
||||
|
||||
private newtype TPathNode =
|
||||
pragma[assume_small_delta]
|
||||
TPathNodeMid(
|
||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||
) {
|
||||
@@ -2709,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2778,6 +2799,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
|
||||
|
||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override AccessPathApproxCons getApprox() {
|
||||
result = TConsNil(head, tail.(AccessPathNil).getType())
|
||||
or
|
||||
@@ -2786,6 +2808,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
|
||||
result = TCons1(head, this.length())
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override int length() { result = 1 + tail.length() }
|
||||
|
||||
private string toStringImpl(boolean needsSuffix) {
|
||||
@@ -2874,54 +2897,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 are generated.
|
||||
*/
|
||||
class PathNode extends TPathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() { none() }
|
||||
|
||||
/**
|
||||
* 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/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
|
||||
|
||||
abstract private class PathNodeImpl extends TPathNode {
|
||||
/** Gets the `FlowState` of this node. */
|
||||
FlowState getState() { none() }
|
||||
abstract FlowState getState();
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
|
||||
reach(this) and
|
||||
reach(result)
|
||||
}
|
||||
abstract Configuration getConfiguration();
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
predicate isSource() { none() }
|
||||
}
|
||||
abstract predicate isSource();
|
||||
|
||||
abstract private class PathNodeImpl extends PathNode {
|
||||
abstract PathNodeImpl getASuccessorImpl();
|
||||
|
||||
private PathNodeImpl getASuccessorIfHidden() {
|
||||
@@ -2953,6 +2938,22 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2967,13 +2968,23 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
|
||||
}
|
||||
|
||||
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
|
||||
override string toStringWithContext() {
|
||||
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
|
||||
}
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
/**
|
||||
* 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/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
@@ -2982,18 +2993,71 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
|
||||
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
|
||||
}
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
class PathNode instanceof PathNodeImpl {
|
||||
PathNode() { reach(this) }
|
||||
|
||||
/** 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() { super.getNodeEx().projectToNode() = result }
|
||||
|
||||
/** Gets the `FlowState` of this node. */
|
||||
final FlowState getState() { result = super.getState() }
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
final Configuration getConfiguration() { result = super.getConfiguration() }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
|
||||
|
||||
/** 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) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||
@@ -3004,7 +3068,7 @@ module PathGraph {
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3013,11 +3077,7 @@ module PathGraph {
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
|
||||
Subpaths::subpaths(arg, par, ret, out) and
|
||||
reach(arg) and
|
||||
reach(par) and
|
||||
reach(ret) and
|
||||
reach(out)
|
||||
Subpaths::subpaths(arg, par, ret, out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3118,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3142,6 +3259,7 @@ private predicate pathNode(
|
||||
* Holds if data may flow from `mid` to `node`. The last step in or out of
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate pathStep(
|
||||
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap
|
||||
@@ -3399,7 +3517,7 @@ private module Subpaths {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths02(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, FlowState sout, AccessPath apout
|
||||
) {
|
||||
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
|
||||
@@ -3407,14 +3525,14 @@ private module Subpaths {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
|
||||
private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths03(
|
||||
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
|
||||
PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
|
||||
) {
|
||||
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
|
||||
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
|
||||
@@ -3444,7 +3562,7 @@ private module Subpaths {
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
|
||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
|
||||
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||
@@ -3460,7 +3578,7 @@ private module Subpaths {
|
||||
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
|
||||
*/
|
||||
predicate retReach(PathNodeImpl n) {
|
||||
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
or
|
||||
exists(PathNodeImpl mid |
|
||||
retReach(mid) and
|
||||
@@ -3476,12 +3594,22 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
) {
|
||||
flowsource.isSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
|
||||
flowsource.getNodeEx().asNode() = source and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.getNodeEx().asNode() = sink
|
||||
}
|
||||
@@ -3504,14 +3632,14 @@ private predicate finalStats(
|
||||
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
|
||||
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
|
||||
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
|
||||
tuples = count(PathNode pn)
|
||||
tuples = count(PathNodeImpl pn)
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
|
||||
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
|
||||
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
|
||||
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
|
||||
tuples = count(PathNode pn | reach(pn))
|
||||
tuples = count(PathNode pn)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
*/
|
||||
|
||||
private import cpp
|
||||
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
private import semmle.code.cpp.ir.IR
|
||||
|
||||
/**
|
||||
@@ -25,18 +24,18 @@ abstract class MustFlowConfiguration extends string {
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source.
|
||||
*/
|
||||
abstract predicate isSource(DataFlow::Node source);
|
||||
abstract predicate isSource(Instruction source);
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink.
|
||||
*/
|
||||
abstract predicate isSink(DataFlow::Node sink);
|
||||
abstract predicate isSink(Operand sink);
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||
predicate isAdditionalFlowStep(Operand node1, Instruction node2) { none() }
|
||||
|
||||
/** Holds if this configuration allows flow from arguments to parameters. */
|
||||
predicate allowInterproceduralFlow() { any() }
|
||||
@@ -48,17 +47,17 @@ abstract class MustFlowConfiguration extends string {
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
final predicate hasFlowPath(MustFlowPathNode source, MustFlowPathSink sink) {
|
||||
this.isSource(source.getNode()) and
|
||||
this.isSource(source.getInstruction()) and
|
||||
source.getASuccessor+() = sink
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if `node` flows from a source. */
|
||||
pragma[nomagic]
|
||||
private predicate flowsFromSource(DataFlow::Node node, MustFlowConfiguration config) {
|
||||
private predicate flowsFromSource(Instruction node, MustFlowConfiguration config) {
|
||||
config.isSource(node)
|
||||
or
|
||||
exists(DataFlow::Node mid |
|
||||
exists(Instruction mid |
|
||||
step(mid, node, config) and
|
||||
flowsFromSource(mid, pragma[only_bind_into](config))
|
||||
)
|
||||
@@ -66,12 +65,12 @@ private predicate flowsFromSource(DataFlow::Node node, MustFlowConfiguration con
|
||||
|
||||
/** Holds if `node` flows to a sink. */
|
||||
pragma[nomagic]
|
||||
private predicate flowsToSink(DataFlow::Node node, MustFlowConfiguration config) {
|
||||
private predicate flowsToSink(Instruction node, MustFlowConfiguration config) {
|
||||
flowsFromSource(node, pragma[only_bind_into](config)) and
|
||||
(
|
||||
config.isSink(node)
|
||||
config.isSink(node.getAUse())
|
||||
or
|
||||
exists(DataFlow::Node mid |
|
||||
exists(Instruction mid |
|
||||
step(node, mid, config) and
|
||||
flowsToSink(mid, pragma[only_bind_into](config))
|
||||
)
|
||||
@@ -198,12 +197,13 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
instructionToOperandStep(nodeFrom.asInstruction(), nodeTo.asOperand())
|
||||
predicate step(Instruction nodeFrom, Instruction nodeTo) {
|
||||
exists(Operand mid |
|
||||
instructionToOperandStep(nodeFrom, mid) and
|
||||
operandToInstructionStep(mid, nodeTo)
|
||||
)
|
||||
or
|
||||
flowThroughCallable(nodeFrom.asInstruction(), nodeTo.asInstruction())
|
||||
or
|
||||
operandToInstructionStep(nodeFrom.asOperand(), nodeTo.asInstruction())
|
||||
flowThroughCallable(nodeFrom, nodeTo)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,12 +213,12 @@ private module Cached {
|
||||
* way around.
|
||||
*/
|
||||
pragma[inline]
|
||||
private Declaration getEnclosingCallable(DataFlow::Node n) {
|
||||
pragma[only_bind_into](result) = pragma[only_bind_out](n).getEnclosingCallable()
|
||||
private IRFunction getEnclosingCallable(Instruction n) {
|
||||
pragma[only_bind_into](result) = pragma[only_bind_out](n).getEnclosingIRFunction()
|
||||
}
|
||||
|
||||
/** Holds if `nodeFrom` flows to `nodeTo`. */
|
||||
private predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, MustFlowConfiguration config) {
|
||||
private predicate step(Instruction nodeFrom, Instruction nodeTo, MustFlowConfiguration config) {
|
||||
exists(config) and
|
||||
Cached::step(pragma[only_bind_into](nodeFrom), pragma[only_bind_into](nodeTo)) and
|
||||
(
|
||||
@@ -227,37 +227,37 @@ private predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, MustFlowC
|
||||
getEnclosingCallable(nodeFrom) = getEnclosingCallable(nodeTo)
|
||||
)
|
||||
or
|
||||
config.isAdditionalFlowStep(nodeFrom, nodeTo)
|
||||
config.isAdditionalFlowStep(nodeFrom.getAUse(), nodeTo)
|
||||
}
|
||||
|
||||
private newtype TLocalPathNode =
|
||||
MkLocalPathNode(DataFlow::Node n, MustFlowConfiguration config) {
|
||||
MkLocalPathNode(Instruction n, MustFlowConfiguration config) {
|
||||
flowsToSink(n, config) and
|
||||
(
|
||||
config.isSource(n)
|
||||
or
|
||||
exists(MustFlowPathNode mid | step(mid.getNode(), n, config))
|
||||
exists(MustFlowPathNode mid | step(mid.getInstruction(), n, config))
|
||||
)
|
||||
}
|
||||
|
||||
/** A `Node` that is in a path from a source to a sink. */
|
||||
class MustFlowPathNode extends TLocalPathNode {
|
||||
DataFlow::Node n;
|
||||
Instruction n;
|
||||
|
||||
MustFlowPathNode() { this = MkLocalPathNode(n, _) }
|
||||
|
||||
/** Gets the underlying node. */
|
||||
DataFlow::Node getNode() { result = n }
|
||||
Instruction getInstruction() { result = n }
|
||||
|
||||
/** Gets a textual representation of this node. */
|
||||
string toString() { result = n.toString() }
|
||||
string toString() { result = n.getAst().toString() }
|
||||
|
||||
/** Gets the location of this element. */
|
||||
Location getLocation() { result = n.getLocation() }
|
||||
|
||||
/** Gets a successor node, if any. */
|
||||
MustFlowPathNode getASuccessor() {
|
||||
step(this.getNode(), result.getNode(), this.getConfiguration())
|
||||
step(this.getInstruction(), result.getInstruction(), this.getConfiguration())
|
||||
}
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
@@ -265,7 +265,7 @@ class MustFlowPathNode extends TLocalPathNode {
|
||||
}
|
||||
|
||||
private class MustFlowPathSink extends MustFlowPathNode {
|
||||
MustFlowPathSink() { this.getConfiguration().isSink(this.getNode()) }
|
||||
MustFlowPathSink() { this.getConfiguration().isSink(this.getInstruction().getAUse()) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2629,6 +2635,7 @@ private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration
|
||||
/**
|
||||
* Gets the number of `AccessPath`s that correspond to `apa`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
private int countAps(AccessPathApprox apa, Configuration config) {
|
||||
evalUnfold(apa, false, config) and
|
||||
result = 1 and
|
||||
@@ -2647,6 +2654,7 @@ private int countAps(AccessPathApprox apa, Configuration config) {
|
||||
* that it is expanded to a precise head-tail representation.
|
||||
*/
|
||||
language[monotonicAggregates]
|
||||
pragma[assume_small_delta]
|
||||
private int countPotentialAps(AccessPathApprox apa, Configuration config) {
|
||||
apa instanceof AccessPathApproxNil and result = 1
|
||||
or
|
||||
@@ -2681,6 +2689,7 @@ private newtype TAccessPath =
|
||||
}
|
||||
|
||||
private newtype TPathNode =
|
||||
pragma[assume_small_delta]
|
||||
TPathNodeMid(
|
||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||
) {
|
||||
@@ -2709,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2778,6 +2799,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
|
||||
|
||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override AccessPathApproxCons getApprox() {
|
||||
result = TConsNil(head, tail.(AccessPathNil).getType())
|
||||
or
|
||||
@@ -2786,6 +2808,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
|
||||
result = TCons1(head, this.length())
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override int length() { result = 1 + tail.length() }
|
||||
|
||||
private string toStringImpl(boolean needsSuffix) {
|
||||
@@ -2874,54 +2897,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 are generated.
|
||||
*/
|
||||
class PathNode extends TPathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() { none() }
|
||||
|
||||
/**
|
||||
* 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/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
|
||||
|
||||
abstract private class PathNodeImpl extends TPathNode {
|
||||
/** Gets the `FlowState` of this node. */
|
||||
FlowState getState() { none() }
|
||||
abstract FlowState getState();
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
|
||||
reach(this) and
|
||||
reach(result)
|
||||
}
|
||||
abstract Configuration getConfiguration();
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
predicate isSource() { none() }
|
||||
}
|
||||
abstract predicate isSource();
|
||||
|
||||
abstract private class PathNodeImpl extends PathNode {
|
||||
abstract PathNodeImpl getASuccessorImpl();
|
||||
|
||||
private PathNodeImpl getASuccessorIfHidden() {
|
||||
@@ -2953,6 +2938,22 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2967,13 +2968,23 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
|
||||
}
|
||||
|
||||
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
|
||||
override string toStringWithContext() {
|
||||
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
|
||||
}
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
/**
|
||||
* 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/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
@@ -2982,18 +2993,71 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
|
||||
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
|
||||
}
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
class PathNode instanceof PathNodeImpl {
|
||||
PathNode() { reach(this) }
|
||||
|
||||
/** 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() { super.getNodeEx().projectToNode() = result }
|
||||
|
||||
/** Gets the `FlowState` of this node. */
|
||||
final FlowState getState() { result = super.getState() }
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
final Configuration getConfiguration() { result = super.getConfiguration() }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
|
||||
|
||||
/** 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) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||
@@ -3004,7 +3068,7 @@ module PathGraph {
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3013,11 +3077,7 @@ module PathGraph {
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
|
||||
Subpaths::subpaths(arg, par, ret, out) and
|
||||
reach(arg) and
|
||||
reach(par) and
|
||||
reach(ret) and
|
||||
reach(out)
|
||||
Subpaths::subpaths(arg, par, ret, out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3118,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3142,6 +3259,7 @@ private predicate pathNode(
|
||||
* Holds if data may flow from `mid` to `node`. The last step in or out of
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate pathStep(
|
||||
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap
|
||||
@@ -3399,7 +3517,7 @@ private module Subpaths {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths02(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, FlowState sout, AccessPath apout
|
||||
) {
|
||||
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
|
||||
@@ -3407,14 +3525,14 @@ private module Subpaths {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
|
||||
private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths03(
|
||||
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
|
||||
PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
|
||||
) {
|
||||
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
|
||||
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
|
||||
@@ -3444,7 +3562,7 @@ private module Subpaths {
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
|
||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
|
||||
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||
@@ -3460,7 +3578,7 @@ private module Subpaths {
|
||||
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
|
||||
*/
|
||||
predicate retReach(PathNodeImpl n) {
|
||||
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
or
|
||||
exists(PathNodeImpl mid |
|
||||
retReach(mid) and
|
||||
@@ -3476,12 +3594,22 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
) {
|
||||
flowsource.isSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
|
||||
flowsource.getNodeEx().asNode() = source and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.getNodeEx().asNode() = sink
|
||||
}
|
||||
@@ -3504,14 +3632,14 @@ private predicate finalStats(
|
||||
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
|
||||
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
|
||||
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
|
||||
tuples = count(PathNode pn)
|
||||
tuples = count(PathNodeImpl pn)
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
|
||||
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
|
||||
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
|
||||
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
|
||||
tuples = count(PathNode pn | reach(pn))
|
||||
tuples = count(PathNode pn)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2629,6 +2635,7 @@ private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration
|
||||
/**
|
||||
* Gets the number of `AccessPath`s that correspond to `apa`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
private int countAps(AccessPathApprox apa, Configuration config) {
|
||||
evalUnfold(apa, false, config) and
|
||||
result = 1 and
|
||||
@@ -2647,6 +2654,7 @@ private int countAps(AccessPathApprox apa, Configuration config) {
|
||||
* that it is expanded to a precise head-tail representation.
|
||||
*/
|
||||
language[monotonicAggregates]
|
||||
pragma[assume_small_delta]
|
||||
private int countPotentialAps(AccessPathApprox apa, Configuration config) {
|
||||
apa instanceof AccessPathApproxNil and result = 1
|
||||
or
|
||||
@@ -2681,6 +2689,7 @@ private newtype TAccessPath =
|
||||
}
|
||||
|
||||
private newtype TPathNode =
|
||||
pragma[assume_small_delta]
|
||||
TPathNodeMid(
|
||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||
) {
|
||||
@@ -2709,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2778,6 +2799,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
|
||||
|
||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override AccessPathApproxCons getApprox() {
|
||||
result = TConsNil(head, tail.(AccessPathNil).getType())
|
||||
or
|
||||
@@ -2786,6 +2808,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
|
||||
result = TCons1(head, this.length())
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override int length() { result = 1 + tail.length() }
|
||||
|
||||
private string toStringImpl(boolean needsSuffix) {
|
||||
@@ -2874,54 +2897,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 are generated.
|
||||
*/
|
||||
class PathNode extends TPathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() { none() }
|
||||
|
||||
/**
|
||||
* 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/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
|
||||
|
||||
abstract private class PathNodeImpl extends TPathNode {
|
||||
/** Gets the `FlowState` of this node. */
|
||||
FlowState getState() { none() }
|
||||
abstract FlowState getState();
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
|
||||
reach(this) and
|
||||
reach(result)
|
||||
}
|
||||
abstract Configuration getConfiguration();
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
predicate isSource() { none() }
|
||||
}
|
||||
abstract predicate isSource();
|
||||
|
||||
abstract private class PathNodeImpl extends PathNode {
|
||||
abstract PathNodeImpl getASuccessorImpl();
|
||||
|
||||
private PathNodeImpl getASuccessorIfHidden() {
|
||||
@@ -2953,6 +2938,22 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2967,13 +2968,23 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
|
||||
}
|
||||
|
||||
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
|
||||
override string toStringWithContext() {
|
||||
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
|
||||
}
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
/**
|
||||
* 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/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
@@ -2982,18 +2993,71 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
|
||||
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
|
||||
}
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
class PathNode instanceof PathNodeImpl {
|
||||
PathNode() { reach(this) }
|
||||
|
||||
/** 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() { super.getNodeEx().projectToNode() = result }
|
||||
|
||||
/** Gets the `FlowState` of this node. */
|
||||
final FlowState getState() { result = super.getState() }
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
final Configuration getConfiguration() { result = super.getConfiguration() }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
|
||||
|
||||
/** 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) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||
@@ -3004,7 +3068,7 @@ module PathGraph {
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3013,11 +3077,7 @@ module PathGraph {
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
|
||||
Subpaths::subpaths(arg, par, ret, out) and
|
||||
reach(arg) and
|
||||
reach(par) and
|
||||
reach(ret) and
|
||||
reach(out)
|
||||
Subpaths::subpaths(arg, par, ret, out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3118,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3142,6 +3259,7 @@ private predicate pathNode(
|
||||
* Holds if data may flow from `mid` to `node`. The last step in or out of
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate pathStep(
|
||||
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap
|
||||
@@ -3399,7 +3517,7 @@ private module Subpaths {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths02(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, FlowState sout, AccessPath apout
|
||||
) {
|
||||
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
|
||||
@@ -3407,14 +3525,14 @@ private module Subpaths {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
|
||||
private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths03(
|
||||
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
|
||||
PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
|
||||
) {
|
||||
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
|
||||
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
|
||||
@@ -3444,7 +3562,7 @@ private module Subpaths {
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
|
||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
|
||||
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||
@@ -3460,7 +3578,7 @@ private module Subpaths {
|
||||
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
|
||||
*/
|
||||
predicate retReach(PathNodeImpl n) {
|
||||
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
or
|
||||
exists(PathNodeImpl mid |
|
||||
retReach(mid) and
|
||||
@@ -3476,12 +3594,22 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
) {
|
||||
flowsource.isSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
|
||||
flowsource.getNodeEx().asNode() = source and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.getNodeEx().asNode() = sink
|
||||
}
|
||||
@@ -3504,14 +3632,14 @@ private predicate finalStats(
|
||||
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
|
||||
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
|
||||
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
|
||||
tuples = count(PathNode pn)
|
||||
tuples = count(PathNodeImpl pn)
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
|
||||
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
|
||||
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
|
||||
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
|
||||
tuples = count(PathNode pn | reach(pn))
|
||||
tuples = count(PathNode pn)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2629,6 +2635,7 @@ private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration
|
||||
/**
|
||||
* Gets the number of `AccessPath`s that correspond to `apa`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
private int countAps(AccessPathApprox apa, Configuration config) {
|
||||
evalUnfold(apa, false, config) and
|
||||
result = 1 and
|
||||
@@ -2647,6 +2654,7 @@ private int countAps(AccessPathApprox apa, Configuration config) {
|
||||
* that it is expanded to a precise head-tail representation.
|
||||
*/
|
||||
language[monotonicAggregates]
|
||||
pragma[assume_small_delta]
|
||||
private int countPotentialAps(AccessPathApprox apa, Configuration config) {
|
||||
apa instanceof AccessPathApproxNil and result = 1
|
||||
or
|
||||
@@ -2681,6 +2689,7 @@ private newtype TAccessPath =
|
||||
}
|
||||
|
||||
private newtype TPathNode =
|
||||
pragma[assume_small_delta]
|
||||
TPathNodeMid(
|
||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||
) {
|
||||
@@ -2709,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2778,6 +2799,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
|
||||
|
||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override AccessPathApproxCons getApprox() {
|
||||
result = TConsNil(head, tail.(AccessPathNil).getType())
|
||||
or
|
||||
@@ -2786,6 +2808,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
|
||||
result = TCons1(head, this.length())
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override int length() { result = 1 + tail.length() }
|
||||
|
||||
private string toStringImpl(boolean needsSuffix) {
|
||||
@@ -2874,54 +2897,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 are generated.
|
||||
*/
|
||||
class PathNode extends TPathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() { none() }
|
||||
|
||||
/**
|
||||
* 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/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
|
||||
|
||||
abstract private class PathNodeImpl extends TPathNode {
|
||||
/** Gets the `FlowState` of this node. */
|
||||
FlowState getState() { none() }
|
||||
abstract FlowState getState();
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
|
||||
reach(this) and
|
||||
reach(result)
|
||||
}
|
||||
abstract Configuration getConfiguration();
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
predicate isSource() { none() }
|
||||
}
|
||||
abstract predicate isSource();
|
||||
|
||||
abstract private class PathNodeImpl extends PathNode {
|
||||
abstract PathNodeImpl getASuccessorImpl();
|
||||
|
||||
private PathNodeImpl getASuccessorIfHidden() {
|
||||
@@ -2953,6 +2938,22 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2967,13 +2968,23 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
|
||||
}
|
||||
|
||||
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
|
||||
override string toStringWithContext() {
|
||||
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
|
||||
}
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
/**
|
||||
* 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/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
@@ -2982,18 +2993,71 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
|
||||
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
|
||||
}
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
class PathNode instanceof PathNodeImpl {
|
||||
PathNode() { reach(this) }
|
||||
|
||||
/** 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() { super.getNodeEx().projectToNode() = result }
|
||||
|
||||
/** Gets the `FlowState` of this node. */
|
||||
final FlowState getState() { result = super.getState() }
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
final Configuration getConfiguration() { result = super.getConfiguration() }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
|
||||
|
||||
/** 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) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||
@@ -3004,7 +3068,7 @@ module PathGraph {
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3013,11 +3077,7 @@ module PathGraph {
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
|
||||
Subpaths::subpaths(arg, par, ret, out) and
|
||||
reach(arg) and
|
||||
reach(par) and
|
||||
reach(ret) and
|
||||
reach(out)
|
||||
Subpaths::subpaths(arg, par, ret, out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3118,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3142,6 +3259,7 @@ private predicate pathNode(
|
||||
* Holds if data may flow from `mid` to `node`. The last step in or out of
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate pathStep(
|
||||
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap
|
||||
@@ -3399,7 +3517,7 @@ private module Subpaths {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths02(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, FlowState sout, AccessPath apout
|
||||
) {
|
||||
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
|
||||
@@ -3407,14 +3525,14 @@ private module Subpaths {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
|
||||
private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths03(
|
||||
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
|
||||
PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
|
||||
) {
|
||||
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
|
||||
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
|
||||
@@ -3444,7 +3562,7 @@ private module Subpaths {
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
|
||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
|
||||
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||
@@ -3460,7 +3578,7 @@ private module Subpaths {
|
||||
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
|
||||
*/
|
||||
predicate retReach(PathNodeImpl n) {
|
||||
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
or
|
||||
exists(PathNodeImpl mid |
|
||||
retReach(mid) and
|
||||
@@ -3476,12 +3594,22 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
) {
|
||||
flowsource.isSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
|
||||
flowsource.getNodeEx().asNode() = source and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.getNodeEx().asNode() = sink
|
||||
}
|
||||
@@ -3504,14 +3632,14 @@ private predicate finalStats(
|
||||
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
|
||||
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
|
||||
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
|
||||
tuples = count(PathNode pn)
|
||||
tuples = count(PathNodeImpl pn)
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
|
||||
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
|
||||
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
|
||||
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
|
||||
tuples = count(PathNode pn | reach(pn))
|
||||
tuples = count(PathNode pn)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2629,6 +2635,7 @@ private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration
|
||||
/**
|
||||
* Gets the number of `AccessPath`s that correspond to `apa`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
private int countAps(AccessPathApprox apa, Configuration config) {
|
||||
evalUnfold(apa, false, config) and
|
||||
result = 1 and
|
||||
@@ -2647,6 +2654,7 @@ private int countAps(AccessPathApprox apa, Configuration config) {
|
||||
* that it is expanded to a precise head-tail representation.
|
||||
*/
|
||||
language[monotonicAggregates]
|
||||
pragma[assume_small_delta]
|
||||
private int countPotentialAps(AccessPathApprox apa, Configuration config) {
|
||||
apa instanceof AccessPathApproxNil and result = 1
|
||||
or
|
||||
@@ -2681,6 +2689,7 @@ private newtype TAccessPath =
|
||||
}
|
||||
|
||||
private newtype TPathNode =
|
||||
pragma[assume_small_delta]
|
||||
TPathNodeMid(
|
||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap, Configuration config
|
||||
) {
|
||||
@@ -2709,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2778,6 +2799,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
|
||||
|
||||
override AccessPathFrontHead getFront() { result = TFrontHead(head) }
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override AccessPathApproxCons getApprox() {
|
||||
result = TConsNil(head, tail.(AccessPathNil).getType())
|
||||
or
|
||||
@@ -2786,6 +2808,7 @@ private class AccessPathCons extends AccessPath, TAccessPathCons {
|
||||
result = TCons1(head, this.length())
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override int length() { result = 1 + tail.length() }
|
||||
|
||||
private string toStringImpl(boolean needsSuffix) {
|
||||
@@ -2874,54 +2897,16 @@ private class AccessPathCons1 extends AccessPath, TAccessPathCons1 {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 are generated.
|
||||
*/
|
||||
class PathNode extends TPathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() { none() }
|
||||
|
||||
/**
|
||||
* 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/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
final Node getNode() { this.(PathNodeImpl).getNodeEx().projectToNode() = result }
|
||||
|
||||
abstract private class PathNodeImpl extends TPathNode {
|
||||
/** Gets the `FlowState` of this node. */
|
||||
FlowState getState() { none() }
|
||||
abstract FlowState getState();
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() {
|
||||
result = this.(PathNodeImpl).getANonHiddenSuccessor() and
|
||||
reach(this) and
|
||||
reach(result)
|
||||
}
|
||||
abstract Configuration getConfiguration();
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
predicate isSource() { none() }
|
||||
}
|
||||
abstract predicate isSource();
|
||||
|
||||
abstract private class PathNodeImpl extends PathNode {
|
||||
abstract PathNodeImpl getASuccessorImpl();
|
||||
|
||||
private PathNodeImpl getASuccessorIfHidden() {
|
||||
@@ -2953,6 +2938,22 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2967,13 +2968,23 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
|
||||
}
|
||||
|
||||
override string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = this.getNodeEx().toString() + this.ppAp() }
|
||||
|
||||
override string toStringWithContext() {
|
||||
result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx()
|
||||
}
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() { result = this.getNodeEx().toString() + this.ppAp() + this.ppCtx() }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
/**
|
||||
* 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/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.getNodeEx().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
@@ -2982,18 +2993,71 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
private predicate reach(PathNode n) { directReach(n) or Subpaths::retReach(n) }
|
||||
private predicate reach(PathNodeImpl n) { directReach(n) or Subpaths::retReach(n) }
|
||||
|
||||
/** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNode n2) {
|
||||
private predicate pathSucc(PathNodeImpl n1, PathNodeImpl n2) {
|
||||
n1.getANonHiddenSuccessor() = n2 and directReach(n2)
|
||||
}
|
||||
|
||||
private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
private predicate pathSuccPlus(PathNodeImpl n1, PathNodeImpl n2) = fastTC(pathSucc/2)(n1, n2)
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
class PathNode instanceof PathNodeImpl {
|
||||
PathNode() { reach(this) }
|
||||
|
||||
/** 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() { super.getNodeEx().projectToNode() = result }
|
||||
|
||||
/** Gets the `FlowState` of this node. */
|
||||
final FlowState getState() { result = super.getState() }
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
final Configuration getConfiguration() { result = super.getConfiguration() }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() { result = super.getANonHiddenSuccessor() }
|
||||
|
||||
/** 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) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||
@@ -3004,7 +3068,7 @@ module PathGraph {
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3013,11 +3077,7 @@ module PathGraph {
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
|
||||
Subpaths::subpaths(arg, par, ret, out) and
|
||||
reach(arg) and
|
||||
reach(par) and
|
||||
reach(ret) and
|
||||
reach(out)
|
||||
Subpaths::subpaths(arg, par, ret, out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3118,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3142,6 +3259,7 @@ private predicate pathNode(
|
||||
* Holds if data may flow from `mid` to `node`. The last step in or out of
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate pathStep(
|
||||
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, AccessPath ap
|
||||
@@ -3399,7 +3517,7 @@ private module Subpaths {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths02(
|
||||
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
|
||||
NodeEx out, FlowState sout, AccessPath apout
|
||||
) {
|
||||
subpaths01(arg, par, sc, innercc, kind, out, sout, apout) and
|
||||
@@ -3407,14 +3525,14 @@ private module Subpaths {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Configuration getPathNodeConf(PathNode n) { result = n.getConfiguration() }
|
||||
private Configuration getPathNodeConf(PathNodeImpl n) { result = n.getConfiguration() }
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate subpaths03(
|
||||
PathNode arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
|
||||
PathNodeImpl arg, ParamNodeEx par, PathNodeMid ret, NodeEx out, FlowState sout, AccessPath apout
|
||||
) {
|
||||
exists(SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind, RetNodeEx retnode |
|
||||
subpaths02(arg, par, sc, innercc, kind, out, sout, apout) and
|
||||
@@ -3444,7 +3562,7 @@ private module Subpaths {
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNode out) {
|
||||
predicate subpaths(PathNodeImpl arg, PathNodeImpl par, PathNodeImpl ret, PathNodeImpl out) {
|
||||
exists(ParamNodeEx p, NodeEx o, FlowState sout, AccessPath apout, PathNodeMid out0 |
|
||||
pragma[only_bind_into](arg).getANonHiddenSuccessor() = pragma[only_bind_into](out0) and
|
||||
subpaths03(pragma[only_bind_into](arg), p, localStepToHidden*(ret), o, sout, apout) and
|
||||
@@ -3460,7 +3578,7 @@ private module Subpaths {
|
||||
* Holds if `n` can reach a return node in a summarized subpath that can reach a sink.
|
||||
*/
|
||||
predicate retReach(PathNodeImpl n) {
|
||||
exists(PathNode out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
exists(PathNodeImpl out | subpaths(_, _, n, out) | directReach(out) or retReach(out))
|
||||
or
|
||||
exists(PathNodeImpl mid |
|
||||
retReach(mid) and
|
||||
@@ -3476,12 +3594,22 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNode flowsource, PathNodeSink flowsink, Node source, Node sink, Configuration configuration
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
) {
|
||||
flowsource.isSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
flowsource.(PathNodeImpl).getNodeEx().asNode() = source and
|
||||
flowsource.getNodeEx().asNode() = source and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.getNodeEx().asNode() = sink
|
||||
}
|
||||
@@ -3504,14 +3632,14 @@ private predicate finalStats(
|
||||
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0)) and
|
||||
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap)) and
|
||||
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state)) and
|
||||
tuples = count(PathNode pn)
|
||||
tuples = count(PathNodeImpl pn)
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx n0 | exists(PathNodeImpl pn | pn.getNodeEx() = n0 and reach(pn))) and
|
||||
fields = count(TypedContent f0 | exists(PathNodeMid pn | pn.getAp().getHead() = f0 and reach(pn))) and
|
||||
conscand = count(AccessPath ap | exists(PathNodeMid pn | pn.getAp() = ap and reach(pn))) and
|
||||
states = count(FlowState state | exists(PathNodeMid pn | pn.getState() = state and reach(pn))) and
|
||||
tuples = count(PathNode pn | reach(pn))
|
||||
tuples = count(PathNode pn)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -136,6 +136,18 @@ module Consistency {
|
||||
msg = "Local flow step does not preserve enclosing callable."
|
||||
}
|
||||
|
||||
query predicate readStepIsLocal(Node n1, Node n2, string msg) {
|
||||
readStep(n1, _, n2) and
|
||||
nodeGetEnclosingCallable(n1) != nodeGetEnclosingCallable(n2) and
|
||||
msg = "Read step does not preserve enclosing callable."
|
||||
}
|
||||
|
||||
query predicate storeStepIsLocal(Node n1, Node n2, string msg) {
|
||||
storeStep(n1, _, n2) and
|
||||
nodeGetEnclosingCallable(n1) != nodeGetEnclosingCallable(n2) and
|
||||
msg = "Store step does not preserve enclosing callable."
|
||||
}
|
||||
|
||||
private DataFlowType typeRepr() { result = getNodeType(_) }
|
||||
|
||||
query predicate compatibleTypesReflexive(DataFlowType t, string msg) {
|
||||
|
||||
@@ -98,16 +98,16 @@ class ParameterPosition = Position;
|
||||
/** An argument position represented by an integer. */
|
||||
class ArgumentPosition = Position;
|
||||
|
||||
class Position extends TPosition {
|
||||
abstract class Position extends TPosition {
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
class DirectPosition extends TDirectPosition {
|
||||
class DirectPosition extends Position, TDirectPosition {
|
||||
int index;
|
||||
|
||||
DirectPosition() { this = TDirectPosition(index) }
|
||||
|
||||
string toString() {
|
||||
override string toString() {
|
||||
index = -1 and
|
||||
result = "this"
|
||||
or
|
||||
@@ -118,12 +118,12 @@ class DirectPosition extends TDirectPosition {
|
||||
int getIndex() { result = index }
|
||||
}
|
||||
|
||||
class IndirectionPosition extends TIndirectionPosition {
|
||||
class IndirectionPosition extends Position, TIndirectionPosition {
|
||||
int index;
|
||||
|
||||
IndirectionPosition() { this = TIndirectionPosition(index) }
|
||||
|
||||
string toString() {
|
||||
override string toString() {
|
||||
index = -1 and
|
||||
result = "this"
|
||||
or
|
||||
|
||||
@@ -16,21 +16,23 @@ private class StdBasicString extends ClassTemplateInstantiation {
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional model for `std::string` constructors that reference the character
|
||||
* type of the container, or an iterator. For example construction from
|
||||
* iterators:
|
||||
* ```
|
||||
* std::string b(a.begin(), a.end());
|
||||
* ```
|
||||
* The `std::basic_string::iterator` declaration.
|
||||
*/
|
||||
private class StdStringConstructor extends Constructor, TaintFunction {
|
||||
StdStringConstructor() { this.getDeclaringType() instanceof StdBasicString }
|
||||
private class StdBasicStringIterator extends Iterator, Type {
|
||||
StdBasicStringIterator() {
|
||||
this.getEnclosingElement() instanceof StdBasicString and this.hasName("iterator")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `std::string` function for which taint should be propagated.
|
||||
*/
|
||||
abstract private class StdStringTaintFunction extends TaintFunction {
|
||||
/**
|
||||
* Gets the index of a parameter to this function that is a string (or
|
||||
* character).
|
||||
*/
|
||||
int getAStringParameterIndex() {
|
||||
final int getAStringParameterIndex() {
|
||||
exists(Type paramType | paramType = this.getParameter(result).getUnspecifiedType() |
|
||||
// e.g. `std::basic_string::CharT *`
|
||||
paramType instanceof PointerType
|
||||
@@ -41,15 +43,28 @@ private class StdStringConstructor extends Constructor, TaintFunction {
|
||||
this.getDeclaringType().getTemplateArgument(2).(Type).getUnspecifiedType()
|
||||
or
|
||||
// i.e. `std::basic_string::CharT`
|
||||
this.getParameter(result).getUnspecifiedType() =
|
||||
this.getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType()
|
||||
paramType = this.getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of a parameter to this function that is an iterator.
|
||||
*/
|
||||
int getAnIteratorParameterIndex() { this.getParameter(result).getType() instanceof Iterator }
|
||||
final int getAnIteratorParameterIndex() {
|
||||
this.getParameter(result).getType() instanceof Iterator
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional model for `std::string` constructors that reference the character
|
||||
* type of the container, or an iterator. For example construction from
|
||||
* iterators:
|
||||
* ```
|
||||
* std::string b(a.begin(), a.end());
|
||||
* ```
|
||||
*/
|
||||
private class StdStringConstructor extends Constructor, StdStringTaintFunction {
|
||||
StdStringConstructor() { this.getDeclaringType() instanceof StdBasicString }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// taint flow from any parameter of the value type to the returned object
|
||||
@@ -68,7 +83,7 @@ private class StdStringConstructor extends Constructor, TaintFunction {
|
||||
/**
|
||||
* The `std::string` function `c_str`.
|
||||
*/
|
||||
private class StdStringCStr extends TaintFunction {
|
||||
private class StdStringCStr extends StdStringTaintFunction {
|
||||
StdStringCStr() { this.getClassAndName("c_str") instanceof StdBasicString }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -81,7 +96,7 @@ private class StdStringCStr extends TaintFunction {
|
||||
/**
|
||||
* The `std::string` function `data`.
|
||||
*/
|
||||
private class StdStringData extends TaintFunction {
|
||||
private class StdStringData extends StdStringTaintFunction {
|
||||
StdStringData() { this.getClassAndName("data") instanceof StdBasicString }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -99,7 +114,7 @@ private class StdStringData extends TaintFunction {
|
||||
/**
|
||||
* The `std::string` function `push_back`.
|
||||
*/
|
||||
private class StdStringPush extends TaintFunction {
|
||||
private class StdStringPush extends StdStringTaintFunction {
|
||||
StdStringPush() { this.getClassAndName("push_back") instanceof StdBasicString }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -112,7 +127,7 @@ private class StdStringPush extends TaintFunction {
|
||||
/**
|
||||
* The `std::string` functions `front` and `back`.
|
||||
*/
|
||||
private class StdStringFrontBack extends TaintFunction {
|
||||
private class StdStringFrontBack extends StdStringTaintFunction {
|
||||
StdStringFrontBack() { this.getClassAndName(["front", "back"]) instanceof StdBasicString }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -125,7 +140,7 @@ private class StdStringFrontBack extends TaintFunction {
|
||||
/**
|
||||
* The (non-member) `std::string` function `operator+`.
|
||||
*/
|
||||
private class StdStringPlus extends TaintFunction {
|
||||
private class StdStringPlus extends StdStringTaintFunction {
|
||||
StdStringPlus() {
|
||||
this.hasQualifiedName(["std", "bsl"], "operator+") and
|
||||
this.getUnspecifiedType() instanceof StdBasicString
|
||||
@@ -142,31 +157,15 @@ private class StdStringPlus extends TaintFunction {
|
||||
}
|
||||
|
||||
/**
|
||||
* The `std::string` functions `operator+=`, `append`, `insert` and
|
||||
* `replace`. All of these functions combine the existing string
|
||||
* with a new string (or character) from one of the arguments.
|
||||
* The `std::string` functions `operator+=`, `append` and `replace`.
|
||||
* All of these functions combine the existing string with a new
|
||||
* string (or character) from one of the arguments.
|
||||
*/
|
||||
private class StdStringAppend extends TaintFunction {
|
||||
private class StdStringAppend extends StdStringTaintFunction {
|
||||
StdStringAppend() {
|
||||
this.getClassAndName(["operator+=", "append", "insert", "replace"]) instanceof StdBasicString
|
||||
this.getClassAndName(["operator+=", "append", "replace"]) instanceof StdBasicString
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of a parameter to this function that is a string (or
|
||||
* character).
|
||||
*/
|
||||
int getAStringParameterIndex() {
|
||||
this.getParameter(result).getType() instanceof PointerType or // e.g. `std::basic_string::CharT *`
|
||||
this.getParameter(result).getType() instanceof ReferenceType or // e.g. `std::basic_string &`
|
||||
this.getParameter(result).getUnspecifiedType() =
|
||||
this.getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. `std::basic_string::CharT`
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of a parameter to this function that is an iterator.
|
||||
*/
|
||||
int getAnIteratorParameterIndex() { this.getParameter(result).getType() instanceof Iterator }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from string and parameter to string (qualifier) and return value
|
||||
(
|
||||
@@ -186,28 +185,44 @@ private class StdStringAppend extends TaintFunction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `std::string` function `insert`.
|
||||
*/
|
||||
private class StdStringInsert extends StdStringTaintFunction {
|
||||
StdStringInsert() { this.getClassAndName("insert") instanceof StdBasicString }
|
||||
|
||||
/**
|
||||
* Holds if the return type is an iterator.
|
||||
*/
|
||||
predicate hasIteratorReturnValue() { this.getType() instanceof Iterator }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from string and parameter to string (qualifier) and return value
|
||||
(
|
||||
input.isQualifierObject() or
|
||||
input.isParameterDeref(this.getAStringParameterIndex()) or
|
||||
input.isParameter(this.getAnIteratorParameterIndex())
|
||||
) and
|
||||
(
|
||||
output.isQualifierObject()
|
||||
or
|
||||
if this.hasIteratorReturnValue() then output.isReturnValue() else output.isReturnValueDeref()
|
||||
)
|
||||
or
|
||||
// reverse flow from returned reference to the qualifier (for writes to
|
||||
// the result)
|
||||
not this.hasIteratorReturnValue() and
|
||||
input.isReturnValueDeref() and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard function `std::string.assign`.
|
||||
*/
|
||||
private class StdStringAssign extends TaintFunction {
|
||||
private class StdStringAssign extends StdStringTaintFunction {
|
||||
StdStringAssign() { this.getClassAndName("assign") instanceof StdBasicString }
|
||||
|
||||
/**
|
||||
* Gets the index of a parameter to this function that is a string (or
|
||||
* character).
|
||||
*/
|
||||
int getAStringParameterIndex() {
|
||||
this.getParameter(result).getType() instanceof PointerType or // e.g. `std::basic_string::CharT *`
|
||||
this.getParameter(result).getType() instanceof ReferenceType or // e.g. `std::basic_string &`
|
||||
this.getParameter(result).getUnspecifiedType() =
|
||||
this.getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. `std::basic_string::CharT`
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of a parameter to this function that is an iterator.
|
||||
*/
|
||||
int getAnIteratorParameterIndex() { this.getParameter(result).getType() instanceof Iterator }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from parameter to string itself (qualifier) and return value
|
||||
(
|
||||
@@ -229,7 +244,7 @@ private class StdStringAssign extends TaintFunction {
|
||||
/**
|
||||
* The standard function `std::string.copy`.
|
||||
*/
|
||||
private class StdStringCopy extends TaintFunction {
|
||||
private class StdStringCopy extends StdStringTaintFunction {
|
||||
StdStringCopy() { this.getClassAndName("copy") instanceof StdBasicString }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -242,7 +257,7 @@ private class StdStringCopy extends TaintFunction {
|
||||
/**
|
||||
* The standard function `std::string.substr`.
|
||||
*/
|
||||
private class StdStringSubstr extends TaintFunction {
|
||||
private class StdStringSubstr extends StdStringTaintFunction {
|
||||
StdStringSubstr() { this.getClassAndName("substr") instanceof StdBasicString }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -255,7 +270,7 @@ private class StdStringSubstr extends TaintFunction {
|
||||
/**
|
||||
* The `std::string` functions `at` and `operator[]`.
|
||||
*/
|
||||
private class StdStringAt extends TaintFunction {
|
||||
private class StdStringAt extends StdStringTaintFunction {
|
||||
StdStringAt() { this.getClassAndName(["at", "operator[]"]) instanceof StdBasicString }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
|
||||
@@ -50,19 +50,18 @@ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, Sid
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
this.getName() = ["strncat", "wcsncat", "_mbsncat", "_mbsncat_l"] and
|
||||
input.isParameter(2) and
|
||||
output.isParameterDeref(0)
|
||||
or
|
||||
this.getName() = ["_mbsncat_l", "_mbsnbcat_l"] and
|
||||
input.isParameter(3) and
|
||||
output.isParameterDeref(0)
|
||||
or
|
||||
input.isParameterDeref(0) and
|
||||
output.isParameterDeref(0)
|
||||
or
|
||||
input.isParameterDeref(1) and
|
||||
output.isParameterDeref(0)
|
||||
(
|
||||
this.getName() = ["strncat", "wcsncat", "_mbsncat", "_mbsncat_l"] and
|
||||
input.isParameter(2)
|
||||
or
|
||||
this.getName() = ["_mbsncat_l", "_mbsnbcat_l"] and
|
||||
input.isParameter(3)
|
||||
or
|
||||
input.isParameterDeref(0)
|
||||
or
|
||||
input.isParameterDeref(1)
|
||||
) and
|
||||
(output.isParameterDeref(0) or output.isReturnValueDeref())
|
||||
}
|
||||
|
||||
override predicate hasArrayInput(int param) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/**
|
||||
* Support for tracking tainted data through the program. This is an alias for
|
||||
* `semmle.code.cpp.ir.dataflow.DefaultTaintTracking` provided for backwards
|
||||
* compatibility.
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
/**
|
||||
* DEPRECATED: This library has been replaced with a newer version which
|
||||
* provides better performance and precision. Use
|
||||
* `semmle.code.cpp.valuenumbering.GlobalValueNumbering` instead.
|
||||
*
|
||||
* Provides an implementation of Global Value Numbering.
|
||||
* See https://en.wikipedia.org/wiki/Global_value_numbering
|
||||
*
|
||||
@@ -221,7 +225,7 @@ private newtype GvnBase =
|
||||
* expression with this `GVN` and using its `toString` and `getLocation`
|
||||
* methods.
|
||||
*/
|
||||
class GVN extends GvnBase {
|
||||
deprecated class GVN extends GvnBase {
|
||||
GVN() { this instanceof GvnBase }
|
||||
|
||||
/** Gets an expression that has this GVN. */
|
||||
@@ -503,7 +507,7 @@ private predicate mk_Deref(GVN p, ControlFlowNode dominator, PointerDereferenceE
|
||||
|
||||
/** Gets the global value number of expression `e`. */
|
||||
cached
|
||||
GVN globalValueNumber(Expr e) {
|
||||
deprecated GVN globalValueNumber(Expr e) {
|
||||
exists(int val, Type t |
|
||||
mk_IntConst(val, t, e) and
|
||||
result = GVN_IntConst(val, t)
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
## 0.4.4
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.3
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Fixed a bug in `cpp/jsf/av-rule-76` that caused the query to miss results when an implicitly-defined copy constructor or copy assignment operator was generated.
|
||||
|
||||
## 0.4.2
|
||||
|
||||
### New Queries
|
||||
|
||||
@@ -13,11 +13,18 @@
|
||||
|
||||
import cpp
|
||||
|
||||
from FormatLiteral fl, FormattingFunctionCall ffc, int expected, int given
|
||||
from FormatLiteral fl, FormattingFunctionCall ffc, int expected, int given, string ffcName
|
||||
where
|
||||
ffc = fl.getUse() and
|
||||
expected = fl.getNumArgNeeded() and
|
||||
given = ffc.getNumFormatArgument() and
|
||||
expected < given and
|
||||
fl.specsAreKnown()
|
||||
select ffc, "Format expects " + expected.toString() + " arguments but given " + given.toString()
|
||||
fl.specsAreKnown() and
|
||||
(
|
||||
if ffc.isInMacroExpansion()
|
||||
then ffcName = ffc.getTarget().getName() + " (in a macro expansion)"
|
||||
else ffcName = ffc.getTarget().getName()
|
||||
)
|
||||
select ffc,
|
||||
"Format for " + ffcName + " expects " + expected.toString() + " arguments but given " +
|
||||
given.toString()
|
||||
|
||||
@@ -16,11 +16,18 @@
|
||||
|
||||
import cpp
|
||||
|
||||
from FormatLiteral fl, FormattingFunctionCall ffc, int expected, int given
|
||||
from FormatLiteral fl, FormattingFunctionCall ffc, int expected, int given, string ffcName
|
||||
where
|
||||
ffc = fl.getUse() and
|
||||
expected = fl.getNumArgNeeded() and
|
||||
given = ffc.getNumFormatArgument() and
|
||||
expected > given and
|
||||
fl.specsAreKnown()
|
||||
select ffc, "Format expects " + expected.toString() + " arguments but given " + given.toString()
|
||||
fl.specsAreKnown() and
|
||||
(
|
||||
if ffc.isInMacroExpansion()
|
||||
then ffcName = ffc.getTarget().getName() + " (in a macro expansion)"
|
||||
else ffcName = ffc.getTarget().getName()
|
||||
)
|
||||
select ffc,
|
||||
"Format for " + ffcName + " expects " + expected.toString() + " arguments but given " +
|
||||
given.toString()
|
||||
|
||||
@@ -26,11 +26,11 @@ predicate intentionallyReturnsStackPointer(Function f) {
|
||||
class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
|
||||
ReturnStackAllocatedMemoryConfig() { this = "ReturnStackAllocatedMemoryConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
override predicate isSource(Instruction source) {
|
||||
// Holds if `source` is a node that represents the use of a stack variable
|
||||
exists(VariableAddressInstruction var, Function func |
|
||||
var = source.asInstruction() and
|
||||
func = var.getEnclosingFunction() and
|
||||
var = source and
|
||||
func = source.getEnclosingFunction() and
|
||||
var.getAstVariable() instanceof StackVariable and
|
||||
// Pointer-to-member types aren't properly handled in the dbscheme.
|
||||
not var.getResultType() instanceof PointerToMemberType and
|
||||
@@ -40,7 +40,7 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
override predicate isSink(Operand sink) {
|
||||
// Holds if `sink` is a node that represents the `StoreInstruction` that is subsequently used in
|
||||
// a `ReturnValueInstruction`.
|
||||
// We use the `StoreInstruction` instead of the instruction that defines the
|
||||
@@ -48,7 +48,7 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
|
||||
exists(StoreInstruction store |
|
||||
store.getDestinationAddress().(VariableAddressInstruction).getIRVariable() instanceof
|
||||
IRReturnVariable and
|
||||
sink.asOperand() = store.getSourceValueOperand()
|
||||
sink = store.getSourceValueOperand()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -77,10 +77,10 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
node2.asInstruction().(FieldAddressInstruction).getObjectAddressOperand() = node1.asOperand()
|
||||
override predicate isAdditionalFlowStep(Operand node1, Instruction node2) {
|
||||
node2.(FieldAddressInstruction).getObjectAddressOperand() = node1
|
||||
or
|
||||
node2.asInstruction().(PointerOffsetInstruction).getLeftOperand() = node1.asOperand()
|
||||
node2.(PointerOffsetInstruction).getLeftOperand() = node1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,6 +89,6 @@ from
|
||||
ReturnStackAllocatedMemoryConfig conf
|
||||
where
|
||||
conf.hasFlowPath(pragma[only_bind_into](source), pragma[only_bind_into](sink)) and
|
||||
source.getNode().asInstruction() = var
|
||||
select sink.getNode(), source, sink, "May return stack-allocated memory from $@.", var.getAst(),
|
||||
var.getAst().toString()
|
||||
source.getInstruction() = var
|
||||
select sink.getInstruction(), source, sink, "May return stack-allocated memory from $@.",
|
||||
var.getAst(), var.getAst().toString()
|
||||
|
||||
@@ -22,37 +22,40 @@ import PathGraph
|
||||
class UnsafeUseOfThisConfig extends MustFlowConfiguration {
|
||||
UnsafeUseOfThisConfig() { this = "UnsafeUseOfThisConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { isSource(source, _, _) }
|
||||
override predicate isSource(Instruction source) { isSource(source, _, _) }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { isSink(sink, _) }
|
||||
override predicate isSink(Operand sink) { isSink(sink, _) }
|
||||
}
|
||||
|
||||
/** Holds if `instr` is a `this` pointer used by the call instruction `call`. */
|
||||
predicate isSink(DataFlow::Node sink, CallInstruction call) {
|
||||
/** Holds if `sink` is a `this` pointer used by the call instruction `call`. */
|
||||
predicate isSink(Operand sink, CallInstruction call) {
|
||||
exists(PureVirtualFunction func |
|
||||
call.getStaticCallTarget() = func and
|
||||
call.getThisArgument() = sink.asInstruction() and
|
||||
call.getThisArgumentOperand() = sink and
|
||||
// Weed out implicit calls to destructors of a base class
|
||||
not func instanceof Destructor
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `init` initializes the `this` pointer in class `c`. */
|
||||
predicate isSource(DataFlow::Node source, string msg, Class c) {
|
||||
exists(InitializeParameterInstruction init | init = source.asInstruction() |
|
||||
(
|
||||
exists(Constructor func |
|
||||
not func instanceof CopyConstructor and
|
||||
not func instanceof MoveConstructor and
|
||||
func = init.getEnclosingFunction() and
|
||||
msg = "construction"
|
||||
)
|
||||
or
|
||||
init.getEnclosingFunction() instanceof Destructor and msg = "destruction"
|
||||
) and
|
||||
init.getIRVariable() instanceof IRThisVariable and
|
||||
init.getEnclosingFunction().getDeclaringType() = c
|
||||
)
|
||||
/**
|
||||
* Holds if `source` initializes the `this` pointer in class `c`.
|
||||
*
|
||||
* The string `msg` describes whether the enclosing function is a
|
||||
* constructor or destructor.
|
||||
*/
|
||||
predicate isSource(InitializeParameterInstruction source, string msg, Class c) {
|
||||
(
|
||||
exists(Constructor func |
|
||||
not func instanceof CopyConstructor and
|
||||
not func instanceof MoveConstructor and
|
||||
func = source.getEnclosingFunction() and
|
||||
msg = "construction"
|
||||
)
|
||||
or
|
||||
source.getEnclosingFunction() instanceof Destructor and msg = "destruction"
|
||||
) and
|
||||
source.getIRVariable() instanceof IRThisVariable and
|
||||
source.getEnclosingFunction().getDeclaringType() = c
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,8 +71,8 @@ predicate flows(
|
||||
) {
|
||||
exists(UnsafeUseOfThisConfig conf |
|
||||
conf.hasFlowPath(source, sink) and
|
||||
isSource(source.getNode(), msg, sourceClass) and
|
||||
isSink(sink.getNode(), call)
|
||||
isSource(source.getInstruction(), msg, sourceClass) and
|
||||
isSink(sink.getInstruction().getAUse(), call)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
5
cpp/ql/src/change-notes/released/0.4.3.md
Normal file
5
cpp/ql/src/change-notes/released/0.4.3.md
Normal file
@@ -0,0 +1,5 @@
|
||||
## 0.4.3
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Fixed a bug in `cpp/jsf/av-rule-76` that caused the query to miss results when an implicitly-defined copy constructor or copy assignment operator was generated.
|
||||
3
cpp/ql/src/change-notes/released/0.4.4.md
Normal file
3
cpp/ql/src/change-notes/released/0.4.4.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.4.4
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.4.2
|
||||
lastReleaseVersion: 0.4.4
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/**
|
||||
* Common functions for implementing naming conventions
|
||||
*
|
||||
* Naming rules are the following:
|
||||
|
||||
@@ -38,9 +38,9 @@ predicate hasNontrivialDestructor(Class c) {
|
||||
from Class c
|
||||
where
|
||||
(hasPointerMember(c) or hasNontrivialDestructor(c)) and
|
||||
not (
|
||||
c.getAMemberFunction() instanceof CopyConstructor and
|
||||
c.getAMemberFunction() instanceof CopyAssignmentOperator
|
||||
(
|
||||
c.hasImplicitCopyAssignmentOperator() or
|
||||
c.hasImplicitCopyConstructor()
|
||||
) and
|
||||
not c instanceof Struct
|
||||
select c,
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 0.4.3-dev
|
||||
version: 0.4.5-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
dependencies:
|
||||
codeql/cpp-all: "*"
|
||||
codeql/suite-helpers: "*"
|
||||
codeql/cpp-all: ${workspace}
|
||||
codeql/suite-helpers: ${workspace}
|
||||
suites: codeql-suites
|
||||
extractor: cpp
|
||||
defaultSuiteFile: codeql-suites/cpp-code-scanning.qls
|
||||
|
||||
@@ -2,43 +2,21 @@ edges
|
||||
| test.cpp:4:15:4:20 | call to malloc | test.cpp:5:15:5:15 | Load |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | ... + ... |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | ... + ... |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | ... + ... |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | ... + ... |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | Store |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | Store |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | Store |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:5:15:5:22 | Store |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:6:15:6:15 | Load |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:6:15:6:15 | Load |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:6:15:6:15 | Load |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:6:15:6:15 | Load |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:7:16:7:16 | Load |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:7:16:7:16 | Load |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:7:16:7:16 | Load |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:7:16:7:16 | Load |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:16 | Load |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:16 | Load |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:16 | Load |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:16 | Load |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:20 | ... + ... |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:20 | ... + ... |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:20 | ... + ... |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:8:16:8:20 | ... + ... |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:9:16:9:16 | Load |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:9:16:9:16 | Load |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:9:16:9:16 | Load |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:9:16:9:16 | Load |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:10:16:10:16 | Load |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:10:16:10:16 | Load |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:10:16:10:16 | Load |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:10:16:10:16 | Load |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:11:16:11:16 | Load |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:11:16:11:16 | Load |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:11:16:11:16 | Load |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:11:16:11:16 | Load |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:12:16:12:16 | Load |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:12:16:12:16 | Load |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:12:16:12:16 | Load |
|
||||
| test.cpp:5:15:5:15 | Load | test.cpp:12:16:12:16 | Load |
|
||||
| test.cpp:5:15:5:22 | ... + ... | test.cpp:5:15:5:22 | Store |
|
||||
| test.cpp:5:15:5:22 | ... + ... | test.cpp:5:15:5:22 | Store |
|
||||
@@ -116,7 +94,6 @@ edges
|
||||
| test.cpp:8:16:8:16 | Load | test.cpp:11:16:11:16 | Load |
|
||||
| test.cpp:8:16:8:16 | Load | test.cpp:12:16:12:16 | Load |
|
||||
| test.cpp:8:16:8:20 | ... + ... | test.cpp:8:14:8:21 | Load: * ... |
|
||||
| test.cpp:8:16:8:20 | ... + ... | test.cpp:8:14:8:21 | Load: * ... |
|
||||
| test.cpp:9:16:9:16 | Load | test.cpp:6:14:6:15 | Load: * ... |
|
||||
| test.cpp:9:16:9:16 | Load | test.cpp:6:14:6:15 | Load: * ... |
|
||||
| test.cpp:9:16:9:16 | Load | test.cpp:8:14:8:21 | Load: * ... |
|
||||
@@ -139,62 +116,30 @@ edges
|
||||
| test.cpp:11:16:11:16 | Load | test.cpp:8:14:8:21 | Load: * ... |
|
||||
| test.cpp:11:16:11:16 | Load | test.cpp:12:16:12:16 | Load |
|
||||
| test.cpp:12:16:12:16 | Load | test.cpp:6:14:6:15 | Load: * ... |
|
||||
| test.cpp:12:16:12:16 | Load | test.cpp:6:14:6:15 | Load: * ... |
|
||||
| test.cpp:12:16:12:16 | Load | test.cpp:8:14:8:21 | Load: * ... |
|
||||
| test.cpp:12:16:12:16 | Load | test.cpp:8:14:8:21 | Load: * ... |
|
||||
| test.cpp:16:15:16:20 | call to malloc | test.cpp:17:15:17:15 | Load |
|
||||
| test.cpp:17:15:17:15 | Load | test.cpp:17:15:17:22 | ... + ... |
|
||||
| test.cpp:17:15:17:15 | Load | test.cpp:17:15:17:22 | ... + ... |
|
||||
| test.cpp:17:15:17:15 | Load | test.cpp:17:15:17:22 | ... + ... |
|
||||
| test.cpp:17:15:17:15 | Load | test.cpp:17:15:17:22 | ... + ... |
|
||||
| test.cpp:17:15:17:15 | Load | test.cpp:20:16:20:20 | ... + ... |
|
||||
| test.cpp:17:15:17:15 | Load | test.cpp:20:16:20:20 | ... + ... |
|
||||
| test.cpp:17:15:17:15 | Load | test.cpp:20:16:20:20 | ... + ... |
|
||||
| test.cpp:17:15:17:15 | Load | test.cpp:20:16:20:20 | ... + ... |
|
||||
| test.cpp:17:15:17:22 | ... + ... | test.cpp:20:14:20:21 | Load: * ... |
|
||||
| test.cpp:17:15:17:22 | ... + ... | test.cpp:20:14:20:21 | Load: * ... |
|
||||
| test.cpp:20:16:20:20 | ... + ... | test.cpp:20:14:20:21 | Load: * ... |
|
||||
| test.cpp:20:16:20:20 | ... + ... | test.cpp:20:14:20:21 | Load: * ... |
|
||||
| test.cpp:28:15:28:20 | call to malloc | test.cpp:29:15:29:15 | Load |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | ... + ... |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | ... + ... |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | ... + ... |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | ... + ... |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | Store |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | Store |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | Store |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:29:15:29:28 | Store |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:30:15:30:15 | Load |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:30:15:30:15 | Load |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:30:15:30:15 | Load |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:30:15:30:15 | Load |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:31:16:31:16 | Load |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:31:16:31:16 | Load |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:31:16:31:16 | Load |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:31:16:31:16 | Load |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:16 | Load |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:16 | Load |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:16 | Load |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:16 | Load |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:20 | ... + ... |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:20 | ... + ... |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:20 | ... + ... |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:32:16:32:20 | ... + ... |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:33:16:33:16 | Load |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:33:16:33:16 | Load |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:33:16:33:16 | Load |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:33:16:33:16 | Load |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:34:16:34:16 | Load |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:34:16:34:16 | Load |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:34:16:34:16 | Load |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:34:16:34:16 | Load |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:35:16:35:16 | Load |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:35:16:35:16 | Load |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:35:16:35:16 | Load |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:35:16:35:16 | Load |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:36:16:36:16 | Load |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:36:16:36:16 | Load |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:36:16:36:16 | Load |
|
||||
| test.cpp:29:15:29:15 | Load | test.cpp:36:16:36:16 | Load |
|
||||
| test.cpp:29:15:29:28 | ... + ... | test.cpp:29:15:29:28 | Store |
|
||||
| test.cpp:29:15:29:28 | ... + ... | test.cpp:29:15:29:28 | Store |
|
||||
@@ -272,7 +217,6 @@ edges
|
||||
| test.cpp:32:16:32:16 | Load | test.cpp:35:16:35:16 | Load |
|
||||
| test.cpp:32:16:32:16 | Load | test.cpp:36:16:36:16 | Load |
|
||||
| test.cpp:32:16:32:20 | ... + ... | test.cpp:32:14:32:21 | Load: * ... |
|
||||
| test.cpp:32:16:32:20 | ... + ... | test.cpp:32:14:32:21 | Load: * ... |
|
||||
| test.cpp:33:16:33:16 | Load | test.cpp:30:14:30:15 | Load: * ... |
|
||||
| test.cpp:33:16:33:16 | Load | test.cpp:30:14:30:15 | Load: * ... |
|
||||
| test.cpp:33:16:33:16 | Load | test.cpp:32:14:32:21 | Load: * ... |
|
||||
@@ -295,49 +239,25 @@ edges
|
||||
| test.cpp:35:16:35:16 | Load | test.cpp:32:14:32:21 | Load: * ... |
|
||||
| test.cpp:35:16:35:16 | Load | test.cpp:36:16:36:16 | Load |
|
||||
| test.cpp:36:16:36:16 | Load | test.cpp:30:14:30:15 | Load: * ... |
|
||||
| test.cpp:36:16:36:16 | Load | test.cpp:30:14:30:15 | Load: * ... |
|
||||
| test.cpp:36:16:36:16 | Load | test.cpp:32:14:32:21 | Load: * ... |
|
||||
| test.cpp:36:16:36:16 | Load | test.cpp:32:14:32:21 | Load: * ... |
|
||||
| test.cpp:40:15:40:20 | call to malloc | test.cpp:41:15:41:15 | Load |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | ... + ... |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | ... + ... |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | ... + ... |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | ... + ... |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | Store |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | Store |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | Store |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:41:15:41:28 | Store |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:42:15:42:15 | Load |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:42:15:42:15 | Load |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:42:15:42:15 | Load |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:42:15:42:15 | Load |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:43:16:43:16 | Load |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:43:16:43:16 | Load |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:43:16:43:16 | Load |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:43:16:43:16 | Load |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:16 | Load |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:16 | Load |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:16 | Load |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:16 | Load |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:20 | ... + ... |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:20 | ... + ... |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:20 | ... + ... |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:44:16:44:20 | ... + ... |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:45:16:45:16 | Load |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:45:16:45:16 | Load |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:45:16:45:16 | Load |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:45:16:45:16 | Load |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:46:16:46:16 | Load |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:46:16:46:16 | Load |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:46:16:46:16 | Load |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:46:16:46:16 | Load |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:47:16:47:16 | Load |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:47:16:47:16 | Load |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:47:16:47:16 | Load |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:47:16:47:16 | Load |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:48:16:48:16 | Load |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:48:16:48:16 | Load |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:48:16:48:16 | Load |
|
||||
| test.cpp:41:15:41:15 | Load | test.cpp:48:16:48:16 | Load |
|
||||
| test.cpp:41:15:41:28 | ... + ... | test.cpp:41:15:41:28 | Store |
|
||||
| test.cpp:41:15:41:28 | ... + ... | test.cpp:41:15:41:28 | Store |
|
||||
@@ -415,7 +335,6 @@ edges
|
||||
| test.cpp:44:16:44:16 | Load | test.cpp:47:16:47:16 | Load |
|
||||
| test.cpp:44:16:44:16 | Load | test.cpp:48:16:48:16 | Load |
|
||||
| test.cpp:44:16:44:20 | ... + ... | test.cpp:44:14:44:21 | Load: * ... |
|
||||
| test.cpp:44:16:44:20 | ... + ... | test.cpp:44:14:44:21 | Load: * ... |
|
||||
| test.cpp:45:16:45:16 | Load | test.cpp:42:14:42:15 | Load: * ... |
|
||||
| test.cpp:45:16:45:16 | Load | test.cpp:42:14:42:15 | Load: * ... |
|
||||
| test.cpp:45:16:45:16 | Load | test.cpp:44:14:44:21 | Load: * ... |
|
||||
@@ -438,8 +357,6 @@ edges
|
||||
| test.cpp:47:16:47:16 | Load | test.cpp:44:14:44:21 | Load: * ... |
|
||||
| test.cpp:47:16:47:16 | Load | test.cpp:48:16:48:16 | Load |
|
||||
| test.cpp:48:16:48:16 | Load | test.cpp:42:14:42:15 | Load: * ... |
|
||||
| test.cpp:48:16:48:16 | Load | test.cpp:42:14:42:15 | Load: * ... |
|
||||
| test.cpp:48:16:48:16 | Load | test.cpp:44:14:44:21 | Load: * ... |
|
||||
| test.cpp:48:16:48:16 | Load | test.cpp:44:14:44:21 | Load: * ... |
|
||||
| test.cpp:51:7:51:14 | VariableAddress indirection | test.cpp:62:39:62:39 | Load |
|
||||
| test.cpp:51:7:51:14 | VariableAddress indirection | test.cpp:66:39:66:39 | Load |
|
||||
@@ -449,18 +366,13 @@ edges
|
||||
| test.cpp:52:19:52:24 | call to malloc | test.cpp:53:12:53:16 | Load |
|
||||
| test.cpp:53:5:53:23 | Store | test.cpp:51:33:51:35 | Load indirection |
|
||||
| test.cpp:53:12:53:16 | Load | test.cpp:53:5:53:23 | Store |
|
||||
| test.cpp:53:12:53:16 | Load | test.cpp:53:5:53:23 | Store |
|
||||
| test.cpp:53:12:53:16 | Load | test.cpp:53:12:53:23 | ... + ... |
|
||||
| test.cpp:53:12:53:16 | Load | test.cpp:53:12:53:23 | ... + ... |
|
||||
| test.cpp:53:12:53:23 | ... + ... | test.cpp:51:33:51:35 | Load indirection |
|
||||
| test.cpp:60:34:60:37 | mk_array output argument | test.cpp:62:32:62:34 | Load |
|
||||
| test.cpp:60:34:60:37 | mk_array output argument | test.cpp:66:32:66:34 | Load |
|
||||
| test.cpp:60:34:60:37 | mk_array output argument | test.cpp:70:31:70:33 | Load |
|
||||
| test.cpp:62:32:62:34 | Load | test.cpp:67:9:67:14 | Store: ... = ... |
|
||||
| test.cpp:62:32:62:34 | Load | test.cpp:67:9:67:14 | Store: ... = ... |
|
||||
| test.cpp:66:32:66:34 | Load | test.cpp:67:9:67:14 | Store: ... = ... |
|
||||
| test.cpp:66:32:66:34 | Load | test.cpp:67:9:67:14 | Store: ... = ... |
|
||||
| test.cpp:70:31:70:33 | Load | test.cpp:67:9:67:14 | Store: ... = ... |
|
||||
| test.cpp:70:31:70:33 | Load | test.cpp:67:9:67:14 | Store: ... = ... |
|
||||
| test.cpp:80:9:80:16 | VariableAddress indirection [begin] | test.cpp:91:20:91:22 | arr indirection [begin] |
|
||||
| test.cpp:80:9:80:16 | VariableAddress indirection [begin] | test.cpp:95:20:95:22 | arr indirection [begin] |
|
||||
@@ -479,8 +391,6 @@ edges
|
||||
| test.cpp:83:15:83:17 | arr indirection [begin] | test.cpp:83:19:83:23 | begin |
|
||||
| test.cpp:83:15:83:30 | ... + ... | test.cpp:83:5:83:30 | Store |
|
||||
| test.cpp:83:19:83:23 | Load | test.cpp:83:5:83:30 | Store |
|
||||
| test.cpp:83:19:83:23 | Load | test.cpp:83:5:83:30 | Store |
|
||||
| test.cpp:83:19:83:23 | Load | test.cpp:83:15:83:30 | ... + ... |
|
||||
| test.cpp:83:19:83:23 | Load | test.cpp:83:15:83:30 | ... + ... |
|
||||
| test.cpp:83:19:83:23 | begin | test.cpp:83:19:83:23 | Load |
|
||||
| test.cpp:91:20:91:22 | arr indirection [begin] | test.cpp:91:24:91:28 | begin |
|
||||
@@ -488,21 +398,18 @@ edges
|
||||
| test.cpp:91:24:91:28 | begin | test.cpp:91:47:91:47 | Load |
|
||||
| test.cpp:91:36:91:38 | arr indirection [end] | test.cpp:91:40:91:42 | end |
|
||||
| test.cpp:91:40:91:42 | Load | test.cpp:96:9:96:14 | Store: ... = ... |
|
||||
| test.cpp:91:40:91:42 | Load | test.cpp:96:9:96:14 | Store: ... = ... |
|
||||
| test.cpp:91:40:91:42 | end | test.cpp:91:40:91:42 | Load |
|
||||
| test.cpp:95:20:95:22 | arr indirection [begin] | test.cpp:95:24:95:28 | begin |
|
||||
| test.cpp:95:20:95:22 | arr indirection [begin] | test.cpp:95:47:95:47 | Load |
|
||||
| test.cpp:95:24:95:28 | begin | test.cpp:95:47:95:47 | Load |
|
||||
| test.cpp:95:36:95:38 | arr indirection [end] | test.cpp:95:40:95:42 | end |
|
||||
| test.cpp:95:40:95:42 | Load | test.cpp:96:9:96:14 | Store: ... = ... |
|
||||
| test.cpp:95:40:95:42 | Load | test.cpp:96:9:96:14 | Store: ... = ... |
|
||||
| test.cpp:95:40:95:42 | end | test.cpp:95:40:95:42 | Load |
|
||||
| test.cpp:99:20:99:22 | arr indirection [begin] | test.cpp:99:24:99:28 | begin |
|
||||
| test.cpp:99:20:99:22 | arr indirection [begin] | test.cpp:99:46:99:46 | Load |
|
||||
| test.cpp:99:24:99:28 | begin | test.cpp:99:46:99:46 | Load |
|
||||
| test.cpp:99:35:99:37 | arr indirection [end] | test.cpp:99:39:99:41 | end |
|
||||
| test.cpp:99:39:99:41 | Load | test.cpp:96:9:96:14 | Store: ... = ... |
|
||||
| test.cpp:99:39:99:41 | Load | test.cpp:96:9:96:14 | Store: ... = ... |
|
||||
| test.cpp:99:39:99:41 | end | test.cpp:99:39:99:41 | Load |
|
||||
| test.cpp:104:27:104:29 | arr [begin] | test.cpp:105:20:105:22 | arr indirection [begin] |
|
||||
| test.cpp:104:27:104:29 | arr [begin] | test.cpp:109:20:109:22 | arr indirection [begin] |
|
||||
@@ -515,21 +422,18 @@ edges
|
||||
| test.cpp:105:24:105:28 | begin | test.cpp:105:47:105:47 | Load |
|
||||
| test.cpp:105:36:105:38 | arr indirection [end] | test.cpp:105:40:105:42 | end |
|
||||
| test.cpp:105:40:105:42 | Load | test.cpp:110:9:110:14 | Store: ... = ... |
|
||||
| test.cpp:105:40:105:42 | Load | test.cpp:110:9:110:14 | Store: ... = ... |
|
||||
| test.cpp:105:40:105:42 | end | test.cpp:105:40:105:42 | Load |
|
||||
| test.cpp:109:20:109:22 | arr indirection [begin] | test.cpp:109:24:109:28 | begin |
|
||||
| test.cpp:109:20:109:22 | arr indirection [begin] | test.cpp:109:47:109:47 | Load |
|
||||
| test.cpp:109:24:109:28 | begin | test.cpp:109:47:109:47 | Load |
|
||||
| test.cpp:109:36:109:38 | arr indirection [end] | test.cpp:109:40:109:42 | end |
|
||||
| test.cpp:109:40:109:42 | Load | test.cpp:110:9:110:14 | Store: ... = ... |
|
||||
| test.cpp:109:40:109:42 | Load | test.cpp:110:9:110:14 | Store: ... = ... |
|
||||
| test.cpp:109:40:109:42 | end | test.cpp:109:40:109:42 | Load |
|
||||
| test.cpp:113:20:113:22 | arr indirection [begin] | test.cpp:113:24:113:28 | begin |
|
||||
| test.cpp:113:20:113:22 | arr indirection [begin] | test.cpp:113:46:113:46 | Load |
|
||||
| test.cpp:113:24:113:28 | begin | test.cpp:113:46:113:46 | Load |
|
||||
| test.cpp:113:35:113:37 | arr indirection [end] | test.cpp:113:39:113:41 | end |
|
||||
| test.cpp:113:39:113:41 | Load | test.cpp:110:9:110:14 | Store: ... = ... |
|
||||
| test.cpp:113:39:113:41 | Load | test.cpp:110:9:110:14 | Store: ... = ... |
|
||||
| test.cpp:113:39:113:41 | end | test.cpp:113:39:113:41 | Load |
|
||||
| test.cpp:119:18:119:25 | call to mk_array [begin] | test.cpp:104:27:104:29 | arr [begin] |
|
||||
| test.cpp:119:18:119:25 | call to mk_array [end] | test.cpp:104:27:104:29 | arr [end] |
|
||||
@@ -558,8 +462,6 @@ edges
|
||||
| test.cpp:144:16:144:18 | Load indirection [begin] | test.cpp:144:21:144:25 | begin |
|
||||
| test.cpp:144:16:144:32 | ... + ... | test.cpp:144:5:144:32 | Store |
|
||||
| test.cpp:144:21:144:25 | Load | test.cpp:144:5:144:32 | Store |
|
||||
| test.cpp:144:21:144:25 | Load | test.cpp:144:5:144:32 | Store |
|
||||
| test.cpp:144:21:144:25 | Load | test.cpp:144:16:144:32 | ... + ... |
|
||||
| test.cpp:144:21:144:25 | Load | test.cpp:144:16:144:32 | ... + ... |
|
||||
| test.cpp:144:21:144:25 | begin | test.cpp:144:21:144:25 | Load |
|
||||
| test.cpp:150:20:150:29 | Call indirection [begin] | test.cpp:152:20:152:22 | Load indirection [begin] |
|
||||
@@ -574,7 +476,6 @@ edges
|
||||
| test.cpp:156:25:156:29 | begin | test.cpp:156:49:156:49 | Load |
|
||||
| test.cpp:156:37:156:39 | Load indirection [end] | test.cpp:156:42:156:44 | end |
|
||||
| test.cpp:156:42:156:44 | Load | test.cpp:157:9:157:14 | Store: ... = ... |
|
||||
| test.cpp:156:42:156:44 | Load | test.cpp:157:9:157:14 | Store: ... = ... |
|
||||
| test.cpp:156:42:156:44 | end | test.cpp:156:42:156:44 | Load |
|
||||
| test.cpp:160:20:160:22 | Load indirection [begin] | test.cpp:160:25:160:29 | begin |
|
||||
| test.cpp:160:20:160:22 | Load indirection [begin] | test.cpp:160:48:160:48 | Load |
|
||||
@@ -590,21 +491,18 @@ edges
|
||||
| test.cpp:166:25:166:29 | begin | test.cpp:166:49:166:49 | Load |
|
||||
| test.cpp:166:37:166:39 | Load indirection [end] | test.cpp:166:42:166:44 | end |
|
||||
| test.cpp:166:42:166:44 | Load | test.cpp:171:9:171:14 | Store: ... = ... |
|
||||
| test.cpp:166:42:166:44 | Load | test.cpp:171:9:171:14 | Store: ... = ... |
|
||||
| test.cpp:166:42:166:44 | end | test.cpp:166:42:166:44 | Load |
|
||||
| test.cpp:170:20:170:22 | Load indirection [begin] | test.cpp:170:25:170:29 | begin |
|
||||
| test.cpp:170:20:170:22 | Load indirection [begin] | test.cpp:170:49:170:49 | Load |
|
||||
| test.cpp:170:25:170:29 | begin | test.cpp:170:49:170:49 | Load |
|
||||
| test.cpp:170:37:170:39 | Load indirection [end] | test.cpp:170:42:170:44 | end |
|
||||
| test.cpp:170:42:170:44 | Load | test.cpp:171:9:171:14 | Store: ... = ... |
|
||||
| test.cpp:170:42:170:44 | Load | test.cpp:171:9:171:14 | Store: ... = ... |
|
||||
| test.cpp:170:42:170:44 | end | test.cpp:170:42:170:44 | Load |
|
||||
| test.cpp:174:20:174:22 | Load indirection [begin] | test.cpp:174:25:174:29 | begin |
|
||||
| test.cpp:174:20:174:22 | Load indirection [begin] | test.cpp:174:48:174:48 | Load |
|
||||
| test.cpp:174:25:174:29 | begin | test.cpp:174:48:174:48 | Load |
|
||||
| test.cpp:174:36:174:38 | Load indirection [end] | test.cpp:174:41:174:43 | end |
|
||||
| test.cpp:174:41:174:43 | Load | test.cpp:171:9:171:14 | Store: ... = ... |
|
||||
| test.cpp:174:41:174:43 | Load | test.cpp:171:9:171:14 | Store: ... = ... |
|
||||
| test.cpp:174:41:174:43 | end | test.cpp:174:41:174:43 | Load |
|
||||
| test.cpp:180:19:180:28 | call to mk_array_p indirection [begin] | test.cpp:165:29:165:31 | arr indirection [begin] |
|
||||
| test.cpp:180:19:180:28 | call to mk_array_p indirection [end] | test.cpp:165:29:165:31 | arr indirection [end] |
|
||||
@@ -614,19 +512,9 @@ edges
|
||||
| test.cpp:194:23:194:28 | call to malloc | test.cpp:201:5:201:5 | Load |
|
||||
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | ... + ... |
|
||||
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | ... + ... |
|
||||
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | ... + ... |
|
||||
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | ... + ... |
|
||||
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | Store |
|
||||
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | Store |
|
||||
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | Store |
|
||||
| test.cpp:195:17:195:17 | Load | test.cpp:195:17:195:23 | Store |
|
||||
| test.cpp:195:17:195:17 | Load | test.cpp:197:20:197:22 | Load |
|
||||
| test.cpp:195:17:195:17 | Load | test.cpp:197:20:197:22 | Load |
|
||||
| test.cpp:195:17:195:17 | Load | test.cpp:197:20:197:22 | Load |
|
||||
| test.cpp:195:17:195:17 | Load | test.cpp:197:20:197:22 | Load |
|
||||
| test.cpp:195:17:195:17 | Load | test.cpp:201:5:201:12 | access to array |
|
||||
| test.cpp:195:17:195:17 | Load | test.cpp:201:5:201:12 | access to array |
|
||||
| test.cpp:195:17:195:17 | Load | test.cpp:201:5:201:12 | access to array |
|
||||
| test.cpp:195:17:195:17 | Load | test.cpp:201:5:201:12 | access to array |
|
||||
| test.cpp:195:17:195:23 | ... + ... | test.cpp:195:17:195:23 | Store |
|
||||
| test.cpp:195:17:195:23 | ... + ... | test.cpp:195:17:195:23 | Store |
|
||||
@@ -637,29 +525,15 @@ edges
|
||||
| test.cpp:195:17:195:23 | Store | test.cpp:201:5:201:19 | Store: ... = ... |
|
||||
| test.cpp:195:17:195:23 | Store | test.cpp:201:5:201:19 | Store: ... = ... |
|
||||
| test.cpp:197:20:197:22 | Load | test.cpp:201:5:201:19 | Store: ... = ... |
|
||||
| test.cpp:197:20:197:22 | Load | test.cpp:201:5:201:19 | Store: ... = ... |
|
||||
| test.cpp:201:5:201:12 | access to array | test.cpp:201:5:201:19 | Store: ... = ... |
|
||||
| test.cpp:201:5:201:12 | access to array | test.cpp:201:5:201:19 | Store: ... = ... |
|
||||
| test.cpp:205:23:205:28 | call to malloc | test.cpp:206:17:206:17 | Load |
|
||||
| test.cpp:205:23:205:28 | call to malloc | test.cpp:208:15:208:15 | Load |
|
||||
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | ... + ... |
|
||||
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | ... + ... |
|
||||
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | ... + ... |
|
||||
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | ... + ... |
|
||||
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | Store |
|
||||
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | Store |
|
||||
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | Store |
|
||||
| test.cpp:206:17:206:17 | Load | test.cpp:206:17:206:23 | Store |
|
||||
| test.cpp:206:17:206:17 | Load | test.cpp:209:12:209:14 | Load |
|
||||
| test.cpp:206:17:206:17 | Load | test.cpp:209:12:209:14 | Load |
|
||||
| test.cpp:206:17:206:17 | Load | test.cpp:209:12:209:14 | Load |
|
||||
| test.cpp:206:17:206:17 | Load | test.cpp:209:12:209:14 | Load |
|
||||
| test.cpp:206:17:206:17 | Load | test.cpp:213:5:213:6 | * ... |
|
||||
| test.cpp:206:17:206:17 | Load | test.cpp:213:5:213:6 | * ... |
|
||||
| test.cpp:206:17:206:17 | Load | test.cpp:213:5:213:6 | * ... |
|
||||
| test.cpp:206:17:206:17 | Load | test.cpp:213:5:213:6 | * ... |
|
||||
| test.cpp:206:17:206:17 | Load | test.cpp:213:6:213:6 | Load |
|
||||
| test.cpp:206:17:206:17 | Load | test.cpp:213:6:213:6 | Load |
|
||||
| test.cpp:206:17:206:17 | Load | test.cpp:213:6:213:6 | Load |
|
||||
| test.cpp:206:17:206:17 | Load | test.cpp:213:6:213:6 | Load |
|
||||
| test.cpp:206:17:206:23 | ... + ... | test.cpp:206:17:206:23 | Store |
|
||||
@@ -671,8 +545,6 @@ edges
|
||||
| test.cpp:206:17:206:23 | Store | test.cpp:213:5:213:13 | Store: ... = ... |
|
||||
| test.cpp:206:17:206:23 | Store | test.cpp:213:5:213:13 | Store: ... = ... |
|
||||
| test.cpp:209:12:209:14 | Load | test.cpp:213:5:213:13 | Store: ... = ... |
|
||||
| test.cpp:209:12:209:14 | Load | test.cpp:213:5:213:13 | Store: ... = ... |
|
||||
| test.cpp:213:5:213:6 | * ... | test.cpp:213:5:213:13 | Store: ... = ... |
|
||||
| test.cpp:213:5:213:6 | * ... | test.cpp:213:5:213:13 | Store: ... = ... |
|
||||
| test.cpp:213:6:213:6 | Load | test.cpp:213:5:213:6 | * ... |
|
||||
| test.cpp:213:6:213:6 | Load | test.cpp:213:5:213:13 | Store: ... = ... |
|
||||
|
||||
@@ -6,6 +6,8 @@ uniqueNodeToString
|
||||
missingToString
|
||||
parameterCallable
|
||||
localFlowIsLocal
|
||||
readStepIsLocal
|
||||
storeStepIsLocal
|
||||
compatibleTypesReflexive
|
||||
unreachableNodeCCtx
|
||||
localCallNodes
|
||||
@@ -87,4 +89,7 @@ postWithInFlow
|
||||
| test.cpp:465:3:465:4 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:465:4:465:4 | p [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:470:22:470:22 | x [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:499:3:499:4 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:499:4:499:4 | p [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:505:35:505:35 | x [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
viableImplInCallContextTooLarge
|
||||
|
||||
@@ -21,6 +21,8 @@ uniqueNodeToString
|
||||
missingToString
|
||||
parameterCallable
|
||||
localFlowIsLocal
|
||||
readStepIsLocal
|
||||
storeStepIsLocal
|
||||
compatibleTypesReflexive
|
||||
unreachableNodeCCtx
|
||||
localCallNodes
|
||||
@@ -582,6 +584,13 @@ postWithInFlow
|
||||
| test.cpp:489:7:489:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:491:5:491:5 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:494:5:494:5 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:499:3:499:4 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:499:4:499:4 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:499:4:499:4 | p [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:504:7:504:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:505:34:505:35 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:505:34:505:35 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:505:35:505:35 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| true_upon_entry.cpp:9:7:9:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| true_upon_entry.cpp:10:12:10:12 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| true_upon_entry.cpp:10:27:10:27 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
|
||||
@@ -87,7 +87,7 @@ Top *identity(Top *top) {
|
||||
|
||||
void callIdentityFunctions(Top *top, Bottom *bottom) {
|
||||
identity(bottom)->isSink(source()); // $ MISSING: ast,ir
|
||||
identity(top)->isSink(source()); // now flow
|
||||
identity(top)->isSink(source()); // no flow
|
||||
}
|
||||
|
||||
using SinkFunctionType = void (*)(int);
|
||||
|
||||
@@ -329,21 +329,21 @@ namespace NestedTests {
|
||||
namespace FlowThroughGlobals {
|
||||
int globalVar;
|
||||
|
||||
int taintGlobal() {
|
||||
void taintGlobal() {
|
||||
globalVar = source();
|
||||
}
|
||||
|
||||
int f() {
|
||||
void f() {
|
||||
sink(globalVar); // $ ir=333:17 ir=347:17 // tainted or clean? Not sure.
|
||||
taintGlobal();
|
||||
sink(globalVar); // $ ir=333:17 ir=347:17 MISSING: ast
|
||||
}
|
||||
|
||||
int calledAfterTaint() {
|
||||
void calledAfterTaint() {
|
||||
sink(globalVar); // $ ir=333:17 ir=347:17 MISSING: ast
|
||||
}
|
||||
|
||||
int taintAndCall() {
|
||||
void taintAndCall() {
|
||||
globalVar = source();
|
||||
calledAfterTaint();
|
||||
sink(globalVar); // $ ast ir=333:17 ir=347:17
|
||||
@@ -494,3 +494,14 @@ void regression_with_phi_flow(int clean1) {
|
||||
x = source();
|
||||
}
|
||||
}
|
||||
|
||||
int intOutparamSourceMissingReturn(int *p) {
|
||||
*p = source();
|
||||
// return deliberately omitted to test IR dataflow behavior
|
||||
}
|
||||
|
||||
void viaOutparamMissingReturn() {
|
||||
int x = 0;
|
||||
intOutparamSourceMissingReturn(&x);
|
||||
sink(x); // $ ast,ir
|
||||
}
|
||||
|
||||
@@ -77,27 +77,9 @@ module IRTest {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
|
||||
exists(GlobalOrNamespaceVariable var | var.getName().matches("flowTestGlobal%") |
|
||||
writesVariable(n1.asInstruction(), var) and
|
||||
var = n2.asVariable()
|
||||
or
|
||||
readsVariable(n2.asInstruction(), var) and
|
||||
var = n1.asVariable()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isBarrier(DataFlow::Node barrier) {
|
||||
barrier.asExpr().(VariableAccess).getTarget().hasName("barrier") or
|
||||
barrier = DataFlow::InstructionBarrierGuard<testBarrierGuard/3>::getABarrierNode()
|
||||
}
|
||||
}
|
||||
|
||||
private predicate readsVariable(LoadInstruction load, Variable var) {
|
||||
load.getSourceAddress().(VariableAddressInstruction).getAstVariable() = var
|
||||
}
|
||||
|
||||
private predicate writesVariable(StoreInstruction store, Variable var) {
|
||||
store.getDestinationAddress().(VariableAddressInstruction).getAstVariable() = var
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ int source();
|
||||
void sink(...);
|
||||
bool random();
|
||||
|
||||
int test1() {
|
||||
void test1() {
|
||||
int x = source();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
x = 0;
|
||||
@@ -13,7 +13,7 @@ int test1() {
|
||||
sink(x); // $ SPURIOUS: ir
|
||||
}
|
||||
|
||||
int test2(int iterations) {
|
||||
void test2(int iterations) {
|
||||
int x = source();
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
x = 0;
|
||||
@@ -21,7 +21,7 @@ int test2(int iterations) {
|
||||
sink(x); // $ ast,ir
|
||||
}
|
||||
|
||||
int test3() {
|
||||
void test3() {
|
||||
int x = 0;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
x = source();
|
||||
@@ -29,7 +29,7 @@ int test3() {
|
||||
sink(x); // $ ast,ir
|
||||
}
|
||||
|
||||
int test4() {
|
||||
void test4() {
|
||||
int x = source();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (random())
|
||||
@@ -39,7 +39,7 @@ int test4() {
|
||||
sink(x); // $ ast,ir
|
||||
}
|
||||
|
||||
int test5() {
|
||||
void test5() {
|
||||
int x = source();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (random())
|
||||
@@ -49,7 +49,7 @@ int test5() {
|
||||
sink(x); // $ ast,ir
|
||||
}
|
||||
|
||||
int test6() {
|
||||
void test6() {
|
||||
int y;
|
||||
int x = source();
|
||||
for (int i = 0; i < 10 && (y = 1); i++) {
|
||||
@@ -57,7 +57,7 @@ int test6() {
|
||||
sink(x); // $ ast,ir
|
||||
}
|
||||
|
||||
int test7() {
|
||||
void test7() {
|
||||
int y;
|
||||
int x = source();
|
||||
for (int i = 0; i < 10 && (y = 1); i++) {
|
||||
@@ -66,7 +66,7 @@ int test7() {
|
||||
sink(x); // $ SPURIOUS: ir
|
||||
}
|
||||
|
||||
int test8() {
|
||||
void test8() {
|
||||
int x = source();
|
||||
// It appears to the analysis that the condition can exit after `i < 10`
|
||||
// without having assigned to `x`. That is an effect of how the
|
||||
@@ -78,7 +78,7 @@ int test8() {
|
||||
sink(x); // $ SPURIOUS: ast,ir
|
||||
}
|
||||
|
||||
int test9() {
|
||||
void test9() {
|
||||
int y;
|
||||
int x = source();
|
||||
for (int i = 0; (y = 1) && i < 10; i++) {
|
||||
@@ -86,21 +86,21 @@ int test9() {
|
||||
sink(x); // $ ast,ir
|
||||
}
|
||||
|
||||
int test10() {
|
||||
void test10() {
|
||||
int x = source();
|
||||
for (int i = 0; (x = 1) && i < 10; i++) {
|
||||
}
|
||||
sink(x); // no flow
|
||||
}
|
||||
|
||||
int test10(int b, int d) {
|
||||
void test10(int b, int d) {
|
||||
int i = 0;
|
||||
int x = source();
|
||||
if (b)
|
||||
goto L;
|
||||
for (; i < 10; i += d) {
|
||||
x = 0;
|
||||
L:
|
||||
L: ;
|
||||
}
|
||||
sink(x); // $ ir MISSING: ast
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ uniqueNodeToString
|
||||
missingToString
|
||||
parameterCallable
|
||||
localFlowIsLocal
|
||||
readStepIsLocal
|
||||
storeStepIsLocal
|
||||
compatibleTypesReflexive
|
||||
unreachableNodeCCtx
|
||||
localCallNodes
|
||||
|
||||
@@ -15,6 +15,8 @@ uniqueNodeToString
|
||||
missingToString
|
||||
parameterCallable
|
||||
localFlowIsLocal
|
||||
readStepIsLocal
|
||||
storeStepIsLocal
|
||||
compatibleTypesReflexive
|
||||
unreachableNodeCCtx
|
||||
localCallNodes
|
||||
|
||||
@@ -9,7 +9,7 @@ struct sockaddr {
|
||||
char* sa_data;
|
||||
};
|
||||
|
||||
int accept(int, const sockaddr*, int*);
|
||||
int accept(int, sockaddr*, int*);
|
||||
|
||||
void sink(sockaddr);
|
||||
|
||||
@@ -20,5 +20,5 @@ void test_accept() {
|
||||
int a = accept(s, &addr, &size);
|
||||
|
||||
sink(a); // $ ast=17:11 ir SPURIOUS: ast=18:12
|
||||
sink(addr); // $ ast,ir
|
||||
sink(addr); // $ ast=17:11 ir SPURIOUS: ast=18:12
|
||||
}
|
||||
|
||||
@@ -142,9 +142,14 @@
|
||||
| bsd.cpp:19:14:19:29 | sizeof(sockaddr) | bsd.cpp:20:29:20:32 | size | |
|
||||
| bsd.cpp:20:11:20:16 | call to accept | bsd.cpp:22:8:22:8 | a | |
|
||||
| bsd.cpp:20:18:20:18 | s | bsd.cpp:20:11:20:16 | call to accept | TAINT |
|
||||
| bsd.cpp:20:18:20:18 | s | bsd.cpp:20:21:20:25 | ref arg & ... | TAINT |
|
||||
| bsd.cpp:20:21:20:25 | & ... | bsd.cpp:20:11:20:16 | call to accept | TAINT |
|
||||
| bsd.cpp:20:21:20:25 | & ... | bsd.cpp:20:21:20:25 | ref arg & ... | TAINT |
|
||||
| bsd.cpp:20:21:20:25 | ref arg & ... | bsd.cpp:20:22:20:25 | addr [inner post update] | |
|
||||
| bsd.cpp:20:21:20:25 | ref arg & ... | bsd.cpp:23:8:23:11 | addr | |
|
||||
| bsd.cpp:20:22:20:25 | addr | bsd.cpp:20:11:20:16 | call to accept | TAINT |
|
||||
| bsd.cpp:20:22:20:25 | addr | bsd.cpp:20:21:20:25 | & ... | |
|
||||
| bsd.cpp:20:22:20:25 | addr | bsd.cpp:20:21:20:25 | ref arg & ... | TAINT |
|
||||
| bsd.cpp:20:28:20:32 | ref arg & ... | bsd.cpp:20:29:20:32 | size [inner post update] | |
|
||||
| bsd.cpp:20:29:20:32 | size | bsd.cpp:20:28:20:32 | & ... | |
|
||||
| constructor_delegation.cpp:8:2:8:8 | this | constructor_delegation.cpp:8:20:8:24 | constructor init of field x [pre-this] | |
|
||||
@@ -5964,6 +5969,7 @@
|
||||
| taint.cpp:172:10:172:15 | buffer | taint.cpp:172:3:172:8 | call to strcat | |
|
||||
| taint.cpp:172:10:172:15 | buffer | taint.cpp:172:10:172:15 | ref arg buffer | TAINT |
|
||||
| taint.cpp:172:10:172:15 | ref arg buffer | taint.cpp:173:8:173:13 | buffer | |
|
||||
| taint.cpp:172:18:172:24 | tainted | taint.cpp:172:3:172:8 | call to strcat | TAINT |
|
||||
| taint.cpp:172:18:172:24 | tainted | taint.cpp:172:10:172:15 | ref arg buffer | TAINT |
|
||||
| taint.cpp:180:19:180:19 | p | taint.cpp:180:19:180:19 | p | |
|
||||
| taint.cpp:180:19:180:19 | p | taint.cpp:181:9:181:9 | p | |
|
||||
@@ -6373,12 +6379,14 @@
|
||||
| taint.cpp:561:9:561:13 | dest1 | taint.cpp:561:9:561:13 | ref arg dest1 | TAINT |
|
||||
| taint.cpp:561:9:561:13 | ref arg dest1 | taint.cpp:560:24:560:28 | dest1 | |
|
||||
| taint.cpp:561:9:561:13 | ref arg dest1 | taint.cpp:562:7:562:11 | dest1 | |
|
||||
| taint.cpp:561:16:561:21 | source | taint.cpp:561:2:561:7 | call to strcat | TAINT |
|
||||
| taint.cpp:561:16:561:21 | source | taint.cpp:561:9:561:13 | ref arg dest1 | TAINT |
|
||||
| taint.cpp:562:7:562:11 | ref arg dest1 | taint.cpp:560:24:560:28 | dest1 | |
|
||||
| taint.cpp:564:9:564:13 | dest2 | taint.cpp:564:2:564:7 | call to strcat | |
|
||||
| taint.cpp:564:9:564:13 | dest2 | taint.cpp:564:9:564:13 | ref arg dest2 | TAINT |
|
||||
| taint.cpp:564:9:564:13 | ref arg dest2 | taint.cpp:560:37:560:41 | dest2 | |
|
||||
| taint.cpp:564:9:564:13 | ref arg dest2 | taint.cpp:565:7:565:11 | dest2 | |
|
||||
| taint.cpp:564:16:564:20 | clean | taint.cpp:564:2:564:7 | call to strcat | TAINT |
|
||||
| taint.cpp:564:16:564:20 | clean | taint.cpp:564:9:564:13 | ref arg dest2 | TAINT |
|
||||
| taint.cpp:565:7:565:11 | ref arg dest2 | taint.cpp:560:37:560:41 | dest2 | |
|
||||
| taint.cpp:572:37:572:41 | dest1 | taint.cpp:572:37:572:41 | dest1 | |
|
||||
@@ -6405,9 +6413,12 @@
|
||||
| taint.cpp:574:36:574:40 | ref arg dest1 | taint.cpp:572:37:572:41 | dest1 | |
|
||||
| taint.cpp:574:36:574:40 | ref arg dest1 | taint.cpp:575:7:575:11 | dest1 | |
|
||||
| taint.cpp:574:36:574:40 | ref arg dest1 | taint.cpp:576:8:576:12 | dest1 | |
|
||||
| taint.cpp:574:43:574:45 | ptr | taint.cpp:574:25:574:34 | call to _mbsncat_l | TAINT |
|
||||
| taint.cpp:574:43:574:45 | ptr | taint.cpp:574:36:574:40 | ref arg dest1 | TAINT |
|
||||
| taint.cpp:574:48:574:48 | n | taint.cpp:574:25:574:34 | call to _mbsncat_l | TAINT |
|
||||
| taint.cpp:574:48:574:48 | n | taint.cpp:574:36:574:40 | ref arg dest1 | TAINT |
|
||||
| taint.cpp:574:51:574:56 | ref arg source | taint.cpp:573:49:573:54 | source | |
|
||||
| taint.cpp:574:51:574:56 | source | taint.cpp:574:25:574:34 | call to _mbsncat_l | TAINT |
|
||||
| taint.cpp:574:51:574:56 | source | taint.cpp:574:36:574:40 | ref arg dest1 | TAINT |
|
||||
| taint.cpp:575:7:575:11 | ref arg dest1 | taint.cpp:572:37:572:41 | dest1 | |
|
||||
| taint.cpp:575:7:575:11 | ref arg dest1 | taint.cpp:576:8:576:12 | dest1 | |
|
||||
@@ -6421,8 +6432,11 @@
|
||||
| taint.cpp:580:36:580:40 | ref arg dest3 | taint.cpp:572:85:572:89 | dest3 | |
|
||||
| taint.cpp:580:36:580:40 | ref arg dest3 | taint.cpp:581:7:581:11 | dest3 | |
|
||||
| taint.cpp:580:36:580:40 | ref arg dest3 | taint.cpp:582:8:582:12 | dest3 | |
|
||||
| taint.cpp:580:43:580:45 | ptr | taint.cpp:580:25:580:34 | call to _mbsncat_l | TAINT |
|
||||
| taint.cpp:580:43:580:45 | ptr | taint.cpp:580:36:580:40 | ref arg dest3 | TAINT |
|
||||
| taint.cpp:580:48:580:48 | n | taint.cpp:580:25:580:34 | call to _mbsncat_l | TAINT |
|
||||
| taint.cpp:580:48:580:48 | n | taint.cpp:580:36:580:40 | ref arg dest3 | TAINT |
|
||||
| taint.cpp:580:51:580:55 | clean | taint.cpp:580:25:580:34 | call to _mbsncat_l | TAINT |
|
||||
| taint.cpp:580:51:580:55 | clean | taint.cpp:580:36:580:40 | ref arg dest3 | TAINT |
|
||||
| taint.cpp:580:51:580:55 | ref arg clean | taint.cpp:573:32:573:36 | clean | |
|
||||
| taint.cpp:581:7:581:11 | ref arg dest3 | taint.cpp:572:85:572:89 | dest3 | |
|
||||
|
||||
@@ -574,8 +574,8 @@ void test__mbsncat_l(unsigned char* dest1, unsigned const char* ptr, unsigned ch
|
||||
unsigned char* dest2 = _mbsncat_l(dest1, ptr, n, source);
|
||||
sink(dest1); // $ SPURIOUS: ast,ir
|
||||
sink(*dest1); // $ ast,ir
|
||||
sink(dest2); // $ SPURIOUS: ir
|
||||
sink(*dest2); // $ ir
|
||||
sink(dest2); // $ SPURIOUS: ast,ir
|
||||
sink(*dest2); // $ ast,ir
|
||||
|
||||
unsigned char* dest4 = _mbsncat_l(dest3, ptr, n, clean);
|
||||
sink(dest3);
|
||||
|
||||
@@ -95,16 +95,7 @@ module IRTest {
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(FunctionCall call |
|
||||
call.getTarget().getName() = "sink" and
|
||||
sink.asConvertedExpr() = call.getAnArgument()
|
||||
or
|
||||
call.getTarget().getName() = "sink" and
|
||||
sink.asExpr() = call.getAnArgument() and
|
||||
sink.asConvertedExpr() instanceof ReferenceDereferenceExpr
|
||||
)
|
||||
or
|
||||
exists(ReadSideEffectInstruction read |
|
||||
read.getSideEffectOperand() = sink.asOperand() and
|
||||
read.getPrimaryInstruction().(CallInstruction).getStaticCallTarget().hasName("sink")
|
||||
sink.asExpr() = call.getAnArgument()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -52,6 +52,8 @@ uniqueNodeToString
|
||||
missingToString
|
||||
parameterCallable
|
||||
localFlowIsLocal
|
||||
readStepIsLocal
|
||||
storeStepIsLocal
|
||||
compatibleTypesReflexive
|
||||
unreachableNodeCCtx
|
||||
localCallNodes
|
||||
|
||||
@@ -1463,6 +1463,8 @@ uniqueNodeToString
|
||||
missingToString
|
||||
parameterCallable
|
||||
localFlowIsLocal
|
||||
readStepIsLocal
|
||||
storeStepIsLocal
|
||||
compatibleTypesReflexive
|
||||
unreachableNodeCCtx
|
||||
localCallNodes
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
WARNING: Type GVN has been deprecated and may be removed in future (ast_gvn.ql:4,6-9)
|
||||
| test.cpp:5:3:5:3 | x | 5:c3-c3 6:c3-c3 |
|
||||
| test.cpp:5:7:5:8 | p0 | 5:c7-c8 6:c7-c8 |
|
||||
| test.cpp:5:7:5:13 | ... + ... | 5:c7-c13 6:c7-c13 7:c7-c7 |
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
WARNING: Predicate globalValueNumber has been deprecated and may be removed in future (ast_uniqueness.ql:7,13-30)
|
||||
WARNING: Predicate globalValueNumber has been deprecated and may be removed in future (ast_uniqueness.ql:8,30-47)
|
||||
WARNING: Type GVN has been deprecated and may be removed in future (ast_uniqueness.ql:8,18-21)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user