mirror of
https://github.com/github/codeql.git
synced 2026-05-18 05:07:06 +02:00
Compare commits
747 Commits
codeql-cli
...
codeql-cli
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34e25624e0 | ||
|
|
c7a79a51fe | ||
|
|
119872d8a4 | ||
|
|
257fc7459d | ||
|
|
b495e1efab | ||
|
|
0bfeba5251 | ||
|
|
f681d584bd | ||
|
|
0f83722767 | ||
|
|
58fe81db2e | ||
|
|
c5ef57c408 | ||
|
|
a889316003 | ||
|
|
343f4e442f | ||
|
|
9e84b756f7 | ||
|
|
668841cefa | ||
|
|
b422a972bf | ||
|
|
98558c7c59 | ||
|
|
36962b8438 | ||
|
|
cd059eb965 | ||
|
|
fa98443bb7 | ||
|
|
b565e3de91 | ||
|
|
07ca09ef90 | ||
|
|
3415b64229 | ||
|
|
84e9229386 | ||
|
|
eae7bccaad | ||
|
|
c6a69e1d6e | ||
|
|
6e1ee07e90 | ||
|
|
d9079e34e3 | ||
|
|
79feb3b689 | ||
|
|
18ac2596d0 | ||
|
|
3b117f5218 | ||
|
|
42c4b22ea1 | ||
|
|
98c1aa5298 | ||
|
|
0732f200e8 | ||
|
|
752c911a22 | ||
|
|
e8498b85e3 | ||
|
|
09a49e4580 | ||
|
|
e482d21949 | ||
|
|
63e560e3b4 | ||
|
|
39a7d3decc | ||
|
|
37036b5e76 | ||
|
|
783a63a8a8 | ||
|
|
fc7f19f900 | ||
|
|
7543f10593 | ||
|
|
20f0b3329a | ||
|
|
746e9948b0 | ||
|
|
58617c5c59 | ||
|
|
f4dc5b963b | ||
|
|
ed8e0fb593 | ||
|
|
7180a1ed52 | ||
|
|
6bab41ce8b | ||
|
|
f94f82a0dc | ||
|
|
38a9c71380 | ||
|
|
c0e1df47a6 | ||
|
|
3b34bfd1c6 | ||
|
|
42b2c3ed52 | ||
|
|
54e6f51512 | ||
|
|
25b15d7470 | ||
|
|
5ec8511d50 | ||
|
|
14e9bda5de | ||
|
|
45a1fc6a96 | ||
|
|
e30fa89405 | ||
|
|
8b931626ce | ||
|
|
7b92012edf | ||
|
|
a9ed3317bf | ||
|
|
40ec23cf13 | ||
|
|
2abf4c068f | ||
|
|
b2d6982318 | ||
|
|
3995ff322d | ||
|
|
7b6773c96a | ||
|
|
1d9f8c2d37 | ||
|
|
e3bf308952 | ||
|
|
834e35f192 | ||
|
|
ae410aabd6 | ||
|
|
e4d891cab5 | ||
|
|
9cfbb90591 | ||
|
|
198bdcab26 | ||
|
|
effa52f9e1 | ||
|
|
7c20c4a664 | ||
|
|
a3f806bb1d | ||
|
|
d426f1efaf | ||
|
|
514c9efcdd | ||
|
|
4f63584179 | ||
|
|
27032af2eb | ||
|
|
d52d328587 | ||
|
|
bf5259096e | ||
|
|
f04ac87091 | ||
|
|
315127d888 | ||
|
|
135a6713e8 | ||
|
|
d95b295e52 | ||
|
|
7e9cf03f4d | ||
|
|
5b2d5ee010 | ||
|
|
ccc879dc5c | ||
|
|
e1bfc6cd38 | ||
|
|
ab1947a028 | ||
|
|
c2764069b5 | ||
|
|
a97d3452a7 | ||
|
|
d74e84abd8 | ||
|
|
c0b5a9ad0c | ||
|
|
332ee40984 | ||
|
|
0675066ab9 | ||
|
|
443b59e676 | ||
|
|
80bc5d921b | ||
|
|
d52ff3e4f6 | ||
|
|
96c6e4d8d8 | ||
|
|
561b9d09b3 | ||
|
|
e4a75b42e9 | ||
|
|
8542c7172e | ||
|
|
f95c799d6e | ||
|
|
e847043307 | ||
|
|
6324c4f22a | ||
|
|
0bdf67f8aa | ||
|
|
4116c1ec66 | ||
|
|
f009a6121e | ||
|
|
d823fd15af | ||
|
|
255424cdc2 | ||
|
|
b049136008 | ||
|
|
d9a52201ad | ||
|
|
42ddeadaca | ||
|
|
5ad950e51e | ||
|
|
b9d918896b | ||
|
|
a39cb74b89 | ||
|
|
58a34fc249 | ||
|
|
bd5452f2cf | ||
|
|
2dcb708022 | ||
|
|
d9be660633 | ||
|
|
d079cb5149 | ||
|
|
25d4ab78fe | ||
|
|
a2f7ecec66 | ||
|
|
4746670ac6 | ||
|
|
dbb8aaeb0b | ||
|
|
ade75793dd | ||
|
|
9ee81cb115 | ||
|
|
ec19bed1fa | ||
|
|
92d555166a | ||
|
|
a39086ab27 | ||
|
|
957c406969 | ||
|
|
6bd2c2e476 | ||
|
|
ee9841e7ec | ||
|
|
8fe229fb08 | ||
|
|
7275707115 | ||
|
|
462e31c2b4 | ||
|
|
fa9b3dfff4 | ||
|
|
107569ef41 | ||
|
|
301b5e6556 | ||
|
|
0b41124b0f | ||
|
|
9f15b14df9 | ||
|
|
a00fdc9b25 | ||
|
|
7a5f9f6a69 | ||
|
|
0fa66acdb8 | ||
|
|
317a073b6e | ||
|
|
3398ddf783 | ||
|
|
c3e00181cb | ||
|
|
1ecee2da0d | ||
|
|
05779ef7ee | ||
|
|
efeff6fcf8 | ||
|
|
dab6a11978 | ||
|
|
5898b48391 | ||
|
|
1db5cb15f0 | ||
|
|
0fc30997eb | ||
|
|
5e0601fe1f | ||
|
|
7019878775 | ||
|
|
2e2a5d62c2 | ||
|
|
144dcf1b5e | ||
|
|
5e4e853ffb | ||
|
|
4c4fc05553 | ||
|
|
9612426680 | ||
|
|
3a68eceaaa | ||
|
|
d1602d538e | ||
|
|
edb0f77177 | ||
|
|
8975c3a7ce | ||
|
|
2f3869f41b | ||
|
|
78843882f9 | ||
|
|
02cb383d3b | ||
|
|
acac519fef | ||
|
|
0ee7ccf6b9 | ||
|
|
97b8e35426 | ||
|
|
f5e4b87d1e | ||
|
|
1e3c4d0eb1 | ||
|
|
980b2c1f4c | ||
|
|
fbbec5d2b9 | ||
|
|
50978364a6 | ||
|
|
3922c73be7 | ||
|
|
a76be91481 | ||
|
|
ff1326cc7b | ||
|
|
710cca5395 | ||
|
|
a9383da2c3 | ||
|
|
bc4c178648 | ||
|
|
7b7e87f177 | ||
|
|
aa1c8c041e | ||
|
|
2e57a7d3e9 | ||
|
|
aa360c0378 | ||
|
|
53c360479a | ||
|
|
46bae88181 | ||
|
|
88b7ad001f | ||
|
|
ae62fbc2c7 | ||
|
|
cb8e2d451d | ||
|
|
b11e15154f | ||
|
|
a373a523f6 | ||
|
|
b37da7cc22 | ||
|
|
40acb95105 | ||
|
|
3640bbd466 | ||
|
|
1bf259beef | ||
|
|
755fec466f | ||
|
|
e1e4016a5c | ||
|
|
29c6d22163 | ||
|
|
25adcfc39d | ||
|
|
e092b31791 | ||
|
|
d02fba8c37 | ||
|
|
cf791e8164 | ||
|
|
e3534d1635 | ||
|
|
af0dff8c6f | ||
|
|
f9a207dd9f | ||
|
|
7e1534a6cd | ||
|
|
5cdbde2686 | ||
|
|
40126563ef | ||
|
|
c08230ce1e | ||
|
|
2e8e04f73e | ||
|
|
24140195d6 | ||
|
|
8d6b8359eb | ||
|
|
2d8d967060 | ||
|
|
fa3ac30894 | ||
|
|
6d108c0fa7 | ||
|
|
915a19fb9d | ||
|
|
516122aa74 | ||
|
|
86b933a0e0 | ||
|
|
8445ec6c17 | ||
|
|
14dd708abc | ||
|
|
87ea442a78 | ||
|
|
de6ed1dcb9 | ||
|
|
a823baabfb | ||
|
|
16ca2314e4 | ||
|
|
45c9428668 | ||
|
|
d1f30d9164 | ||
|
|
662e17ff85 | ||
|
|
9268050eb8 | ||
|
|
a9c292e265 | ||
|
|
b039267b76 | ||
|
|
f75b969ffc | ||
|
|
e37ba75599 | ||
|
|
0d8f8d2cc5 | ||
|
|
a457f5cc4a | ||
|
|
a760ed8c55 | ||
|
|
27048191c8 | ||
|
|
1dcfc3840d | ||
|
|
f357b73f94 | ||
|
|
9ff304ca6b | ||
|
|
dfc0e9b906 | ||
|
|
748749c32a | ||
|
|
5aa9c2bd19 | ||
|
|
cb6ee547ca | ||
|
|
c6d6d07720 | ||
|
|
ffe5d30c2b | ||
|
|
92d61354d4 | ||
|
|
a2d1e88bb3 | ||
|
|
a8b84e430f | ||
|
|
c9786df760 | ||
|
|
195ed0173c | ||
|
|
978200e2ad | ||
|
|
58d5c2c32d | ||
|
|
0274162c4d | ||
|
|
1d3ad0cb52 | ||
|
|
2d4f624935 | ||
|
|
5d6a93332f | ||
|
|
d7b0f628a1 | ||
|
|
ae805eb939 | ||
|
|
edeb08480e | ||
|
|
fe3824c202 | ||
|
|
c7b2b719cf | ||
|
|
75ebb348a0 | ||
|
|
a03cb11257 | ||
|
|
82a000bcca | ||
|
|
6508a223c3 | ||
|
|
b5268def16 | ||
|
|
1c1ca70027 | ||
|
|
2f3a76c43b | ||
|
|
3b11958e33 | ||
|
|
3005439a6a | ||
|
|
5afb7e05ee | ||
|
|
24b0469d74 | ||
|
|
e5b13d9db4 | ||
|
|
f561c458a9 | ||
|
|
4d1b49a7dd | ||
|
|
6ef8fb667f | ||
|
|
3c1e445a59 | ||
|
|
2341c653f7 | ||
|
|
0edae89425 | ||
|
|
97ab842010 | ||
|
|
4977169cf5 | ||
|
|
288ee92d52 | ||
|
|
fa2e7fd498 | ||
|
|
3fb810b540 | ||
|
|
773cf0dcdd | ||
|
|
0c6e161277 | ||
|
|
18cfe72e99 | ||
|
|
01cc2f2c77 | ||
|
|
87e4dec86a | ||
|
|
25f4b76788 | ||
|
|
ad665b765f | ||
|
|
e1adf5e8b0 | ||
|
|
9439ed49c1 | ||
|
|
55da16c4a9 | ||
|
|
674886a17d | ||
|
|
667dab28d4 | ||
|
|
ad35c01462 | ||
|
|
ee9613fa79 | ||
|
|
0ab4e3e041 | ||
|
|
b865e88f59 | ||
|
|
fe975f25f9 | ||
|
|
e726ff425c | ||
|
|
5c3d0c806d | ||
|
|
81efd726cb | ||
|
|
e4422fc939 | ||
|
|
d3fca0a107 | ||
|
|
c993f9a3a3 | ||
|
|
ea6d3bde9c | ||
|
|
2c4ba561bf | ||
|
|
a2660e5996 | ||
|
|
fc5158c41c | ||
|
|
fbca06f4e1 | ||
|
|
16a3dfa30a | ||
|
|
0f6c56ad74 | ||
|
|
49b1bfc41b | ||
|
|
76e936c64d | ||
|
|
ed250d5017 | ||
|
|
410f21cd55 | ||
|
|
91c0066b8b | ||
|
|
dfdf0344de | ||
|
|
fa51af5be1 | ||
|
|
518bfa4d41 | ||
|
|
e8afafca7a | ||
|
|
c281820f0f | ||
|
|
07769c7322 | ||
|
|
c95a8e6776 | ||
|
|
11793800ad | ||
|
|
70b8cdee9b | ||
|
|
28951e98c4 | ||
|
|
b30484dd69 | ||
|
|
b1d0b9afbb | ||
|
|
189b2215c5 | ||
|
|
e8f81c4f30 | ||
|
|
074d73e325 | ||
|
|
9163893879 | ||
|
|
fe6efde449 | ||
|
|
8b25806a2c | ||
|
|
a16de26799 | ||
|
|
fd5ac13828 | ||
|
|
88784fbd31 | ||
|
|
b6257edc9e | ||
|
|
d5b304ce75 | ||
|
|
19b74e6e01 | ||
|
|
5480a31b68 | ||
|
|
0d405c293a | ||
|
|
7a4ce83169 | ||
|
|
bd4a414abd | ||
|
|
e0b1a86038 | ||
|
|
193458eb3d | ||
|
|
e0c51b510f | ||
|
|
8ba820cae1 | ||
|
|
09b0d824b4 | ||
|
|
3c8ac5c789 | ||
|
|
86cf143029 | ||
|
|
b05a9043b5 | ||
|
|
09bcf878f7 | ||
|
|
f2448cc921 | ||
|
|
80b4d63d4b | ||
|
|
06fdd64dab | ||
|
|
3dfc236bbe | ||
|
|
caf1dbdc46 | ||
|
|
ba05bf3ae0 | ||
|
|
d14b993aba | ||
|
|
2a9f7a966c | ||
|
|
d4e0c7efae | ||
|
|
0defad77dd | ||
|
|
80a7b52f38 | ||
|
|
0698bdd907 | ||
|
|
6d409a0050 | ||
|
|
ccf68ffd16 | ||
|
|
fcc4758eb8 | ||
|
|
d05a733109 | ||
|
|
b05199dccf | ||
|
|
0ca4bf4267 | ||
|
|
4709442ef3 | ||
|
|
1d70bfd011 | ||
|
|
7e1eee5fe2 | ||
|
|
3d0d280972 | ||
|
|
25ef3edb20 | ||
|
|
318ce47982 | ||
|
|
7207a17f6f | ||
|
|
aeb13146d2 | ||
|
|
f9f143d62c | ||
|
|
ed228cbcef | ||
|
|
95aeb7b53f | ||
|
|
29ae737475 | ||
|
|
e63f81171c | ||
|
|
b3ee70f4f7 | ||
|
|
6cf15f49bb | ||
|
|
b7353f0bb0 | ||
|
|
e2c0bf3cc0 | ||
|
|
921c41d710 | ||
|
|
bff59a1aaa | ||
|
|
790fb7829a | ||
|
|
4a4f4b01a1 | ||
|
|
84554af7f5 | ||
|
|
2bccb67be4 | ||
|
|
cc9a938054 | ||
|
|
4a9023b989 | ||
|
|
7142ddcb25 | ||
|
|
b36e0d0be7 | ||
|
|
296297915c | ||
|
|
2b1b94835e | ||
|
|
aaaf90902f | ||
|
|
24e406d21a | ||
|
|
6841f5f7c4 | ||
|
|
673e64909a | ||
|
|
863497c695 | ||
|
|
99c1b2039c | ||
|
|
4804a0a9f8 | ||
|
|
024a586a7d | ||
|
|
66c9cfad85 | ||
|
|
83539928e6 | ||
|
|
63686b5c4e | ||
|
|
23d994a4b4 | ||
|
|
cf4f55d9ab | ||
|
|
6e5af1a9f8 | ||
|
|
d496503d5d | ||
|
|
492add1f7a | ||
|
|
012058a866 | ||
|
|
eed357dc93 | ||
|
|
a37b98ca27 | ||
|
|
ca86925a45 | ||
|
|
45f3365d06 | ||
|
|
32f1da7455 | ||
|
|
c6b47647e1 | ||
|
|
e3cf5c235e | ||
|
|
df9d54c994 | ||
|
|
990bdc20b0 | ||
|
|
3f3640fcbd | ||
|
|
470a2ca336 | ||
|
|
61dcf3a275 | ||
|
|
f5564b1c3b | ||
|
|
5278cc9e9e | ||
|
|
e916e04fe1 | ||
|
|
d30d1a2ab2 | ||
|
|
c12f8035c4 | ||
|
|
56e611faaa | ||
|
|
d67de88d34 | ||
|
|
a55246c9f4 | ||
|
|
0d7f6ced8f | ||
|
|
d7b9251b0d | ||
|
|
00983c8967 | ||
|
|
20ccb52912 | ||
|
|
8d292070a4 | ||
|
|
3565ba51b3 | ||
|
|
d17246ce2b | ||
|
|
c86fc223b9 | ||
|
|
bd842403c8 | ||
|
|
a35f6d030c | ||
|
|
879dbba8f0 | ||
|
|
e9e9634306 | ||
|
|
d2ed216670 | ||
|
|
0b446258f5 | ||
|
|
c8315577fe | ||
|
|
5a8ffa5a85 | ||
|
|
7d52b53c24 | ||
|
|
0695b2a1fb | ||
|
|
d685aff5e2 | ||
|
|
b399246d7f | ||
|
|
31690dee58 | ||
|
|
96eaf2119f | ||
|
|
6c14288fa7 | ||
|
|
ad4b9372bd | ||
|
|
8a4cc3b5c2 | ||
|
|
200d94777a | ||
|
|
cadb1d6554 | ||
|
|
633fc92efc | ||
|
|
15049ca853 | ||
|
|
f9365dc9ac | ||
|
|
3e0245a7fc | ||
|
|
da0a7f343a | ||
|
|
40b0f68d2a | ||
|
|
71cd329ded | ||
|
|
563404120f | ||
|
|
43b9436bb8 | ||
|
|
0029d3b743 | ||
|
|
224e537459 | ||
|
|
b0ba0585a7 | ||
|
|
f749c31136 | ||
|
|
1580d23b2b | ||
|
|
90acd8c695 | ||
|
|
45f52289ea | ||
|
|
fe07630e40 | ||
|
|
342c7abd74 | ||
|
|
9f8a028dfc | ||
|
|
3dc0c2081e | ||
|
|
3dd34c9ba9 | ||
|
|
f9973d10ae | ||
|
|
c1fd48468a | ||
|
|
cb4ed90c5c | ||
|
|
dcf8c881ff | ||
|
|
fafc36a9cb | ||
|
|
f02a19669f | ||
|
|
f91c71c8f7 | ||
|
|
7ca57fd7a5 | ||
|
|
f3885a8a05 | ||
|
|
d5d0439471 | ||
|
|
b9c0193022 | ||
|
|
ed5d31a385 | ||
|
|
a5a4329669 | ||
|
|
bd2b3e72f8 | ||
|
|
cfd8a87496 | ||
|
|
c3175ae7b1 | ||
|
|
828e1f81ae | ||
|
|
15e26e1a91 | ||
|
|
2697677239 | ||
|
|
10ab17a7e0 | ||
|
|
dd75ea31df | ||
|
|
3400c121d6 | ||
|
|
73ad417757 | ||
|
|
8e2af077a7 | ||
|
|
7cc7ec962e | ||
|
|
b9450c901a | ||
|
|
721ba5e2c5 | ||
|
|
078fbccc9a | ||
|
|
4196dc2291 | ||
|
|
312ead44c5 | ||
|
|
c243f2f042 | ||
|
|
6b66323ac3 | ||
|
|
dbd8432884 | ||
|
|
9982112b61 | ||
|
|
648910e974 | ||
|
|
81ff76814f | ||
|
|
173c4b7f2f | ||
|
|
95a1edcabc | ||
|
|
0eb2c06e20 | ||
|
|
4d33407f6c | ||
|
|
714e1dc686 | ||
|
|
919ee38049 | ||
|
|
6c884f86d2 | ||
|
|
6e0322dc60 | ||
|
|
88e5348da9 | ||
|
|
5d27cd934d | ||
|
|
d916118ea4 | ||
|
|
47f4faa4e2 | ||
|
|
ae56285331 | ||
|
|
b20ce8bfca | ||
|
|
beb15e27eb | ||
|
|
fd9604c5ef | ||
|
|
31721b5fe3 | ||
|
|
05594f2936 | ||
|
|
0bd60c1989 | ||
|
|
12079cd1e4 | ||
|
|
7afa755597 | ||
|
|
24199a5499 | ||
|
|
b978359803 | ||
|
|
fa2f345611 | ||
|
|
55985c969b | ||
|
|
ecccb8a409 | ||
|
|
36049f05f8 | ||
|
|
1f02594ccc | ||
|
|
5b5baced9a | ||
|
|
97032f8627 | ||
|
|
a79c30a818 | ||
|
|
0e7e3e6178 | ||
|
|
1fdbbb682d | ||
|
|
a5cf024c9f | ||
|
|
af262a035d | ||
|
|
d63fcaf7f1 | ||
|
|
9d7bb57d8a | ||
|
|
41a0c0b55e | ||
|
|
4384f78595 | ||
|
|
79839d2304 | ||
|
|
6460ce3f83 | ||
|
|
b0fa8dfeae | ||
|
|
2957131853 | ||
|
|
9ea8f8201c | ||
|
|
394c82d564 | ||
|
|
faf69d65da | ||
|
|
3b82abd7c7 | ||
|
|
7ae640ce16 | ||
|
|
f2e667173c | ||
|
|
17109a36ce | ||
|
|
6205ec233c | ||
|
|
2b1c6faefd | ||
|
|
4f383be13b | ||
|
|
71f095d6d4 | ||
|
|
dbed4a1a8b | ||
|
|
2b382d588a | ||
|
|
5151a528ac | ||
|
|
5d2f3421d8 | ||
|
|
cdccc1a064 | ||
|
|
92128babef | ||
|
|
38748f9e23 | ||
|
|
14ec148272 | ||
|
|
0874712c97 | ||
|
|
aab9deceef | ||
|
|
c32514bf66 | ||
|
|
e6b1fe9b5f | ||
|
|
54caf501e7 | ||
|
|
fadbb32bd6 | ||
|
|
443780f27e | ||
|
|
010488c899 | ||
|
|
646ea55944 | ||
|
|
8b68912c40 | ||
|
|
9533c92fcc | ||
|
|
1670fa0d0e | ||
|
|
9a9bda17ed | ||
|
|
af7a188bbd | ||
|
|
214aa072b9 | ||
|
|
cc48172fd8 | ||
|
|
ede1a40a02 | ||
|
|
a387496832 | ||
|
|
ae051af9d8 | ||
|
|
42a84a18b0 | ||
|
|
602f63ad45 | ||
|
|
b43533ce8d | ||
|
|
7f7320ae4c | ||
|
|
311149ab4f | ||
|
|
a067adbaf3 | ||
|
|
53dc2ce9b6 | ||
|
|
e21cbe82a9 | ||
|
|
290b1c624e | ||
|
|
2e02625f22 | ||
|
|
fa189ded9d | ||
|
|
41b7db144d | ||
|
|
f93937f40a | ||
|
|
3fe249f25c | ||
|
|
de6b604930 | ||
|
|
86bc7d3e1a | ||
|
|
d35ea7fb15 | ||
|
|
472ff97561 | ||
|
|
4610b1b392 | ||
|
|
c195c64982 | ||
|
|
27987717dc | ||
|
|
2e252ba3e4 | ||
|
|
ae2a5da63f | ||
|
|
aba22689fa | ||
|
|
86cec40286 | ||
|
|
780a6a96f8 | ||
|
|
41743b6afa | ||
|
|
24b51e8851 | ||
|
|
76f080978a | ||
|
|
192988077e | ||
|
|
34b6ed0a05 | ||
|
|
bf3e5fceea | ||
|
|
10657160bc | ||
|
|
89d0724fb4 | ||
|
|
ea17de6225 | ||
|
|
be26a48a16 | ||
|
|
ccd706ea10 | ||
|
|
674b9ad4fe | ||
|
|
69348b1914 | ||
|
|
8443b8e421 | ||
|
|
fd9d738d53 | ||
|
|
caa6f00292 | ||
|
|
8c19f7810d | ||
|
|
a6e5ec2e09 | ||
|
|
0cad5ce5ca | ||
|
|
6abbb5040c | ||
|
|
b28544da9c | ||
|
|
e13c779f0f | ||
|
|
a09f8c4b4a | ||
|
|
4026d54095 | ||
|
|
ee651da23f | ||
|
|
459c0afc55 | ||
|
|
a3b8d4ab2d | ||
|
|
7b5961769a | ||
|
|
cf58a90d74 | ||
|
|
e5d624d1e8 | ||
|
|
e3fe635004 | ||
|
|
5bba7f6df7 | ||
|
|
da6e9492a0 | ||
|
|
561679611e | ||
|
|
4184ebd091 | ||
|
|
fd18fd8403 | ||
|
|
0b2daf7679 | ||
|
|
43a07bb13a | ||
|
|
299f371715 | ||
|
|
40c592ab85 | ||
|
|
4f23c3546f | ||
|
|
d084261a79 | ||
|
|
bfc8ead667 | ||
|
|
dfa223ac6a | ||
|
|
a6583345ba | ||
|
|
37f0d5a28a | ||
|
|
2a8f720bc6 | ||
|
|
1eabfbd0e4 | ||
|
|
bfbaa85272 | ||
|
|
8d3170bcb4 | ||
|
|
32d0790500 | ||
|
|
0e9a54e9a9 | ||
|
|
46ad611d57 | ||
|
|
2429c6c450 | ||
|
|
d5ff477644 | ||
|
|
6e4c627209 | ||
|
|
bd40965afe | ||
|
|
1bf9f7d135 | ||
|
|
11cd0dbbc0 | ||
|
|
4ab61bb088 | ||
|
|
6aeec5872d | ||
|
|
8e83de1c05 | ||
|
|
0f7f465675 | ||
|
|
dae6771a19 | ||
|
|
c45be91d6f | ||
|
|
0004efc2ac | ||
|
|
f32c77c266 | ||
|
|
cfa72af12c | ||
|
|
042c0b005e | ||
|
|
7543df60da | ||
|
|
af0f361ac8 | ||
|
|
e3002aa1bf | ||
|
|
0ea2f457a1 | ||
|
|
232d9b006a | ||
|
|
6a45f6e7e0 | ||
|
|
77ae91c47d | ||
|
|
683233333c | ||
|
|
631ee28cae | ||
|
|
50edf44e84 | ||
|
|
59f48ecea3 | ||
|
|
8919e5546b | ||
|
|
44bc6d7fdb | ||
|
|
8d701e604a | ||
|
|
71e5cb45d3 | ||
|
|
03348b18b5 | ||
|
|
a47147bc5e | ||
|
|
28ebbee61d | ||
|
|
73c8338e52 | ||
|
|
ee6d28b562 | ||
|
|
8166e269ec | ||
|
|
7df813354a | ||
|
|
7d2d27394b | ||
|
|
99401f6e84 | ||
|
|
435502e070 | ||
|
|
1f5a466e46 | ||
|
|
5d2a553059 | ||
|
|
fd14eb4c8c | ||
|
|
a404ca66d1 | ||
|
|
96e913031d | ||
|
|
89a59d5f1a | ||
|
|
1e08c11d40 | ||
|
|
27c554c164 | ||
|
|
5d5b84974b | ||
|
|
d216dcdee0 | ||
|
|
518de822e1 | ||
|
|
5c256dadc8 | ||
|
|
f7d63f8666 | ||
|
|
33f7d52a46 | ||
|
|
ddc544aa07 |
2
.github/workflows/check-change-note.yml
vendored
2
.github/workflows/check-change-note.yml
vendored
@@ -1,3 +1,5 @@
|
||||
name: Check change note
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [labeled, unlabeled, opened, synchronize, reopened, ready_for_review]
|
||||
|
||||
29
.github/workflows/docs-review.yml
vendored
Normal file
29
.github/workflows/docs-review.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
# When a PR is labelled with 'ready-for-docs-review',
|
||||
# this workflow comments on the PR to notify the GitHub CodeQL docs team.
|
||||
name: Request docs review
|
||||
on:
|
||||
# Runs in the context of the base repo.
|
||||
# This gives the workflow write access to comment on PRs.
|
||||
# The workflow should not check out or build the given ref,
|
||||
# or use untrusted data from the event payload in a command line.
|
||||
pull_request_target:
|
||||
types: [labeled]
|
||||
|
||||
jobs:
|
||||
request-docs-review:
|
||||
name: Request docs review
|
||||
# Run only on labelled PRs to the main repository.
|
||||
# Do not run on PRs to forks.
|
||||
if:
|
||||
github.event.label.name == 'ready-for-docs-review'
|
||||
&& github.event.pull_request.draft == false
|
||||
&& github.event.pull_request.base.repo.full_name == 'github/codeql'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Comment to request docs review
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
run: |
|
||||
gh pr comment "$PR_NUMBER" --repo "github/codeql" \
|
||||
--body "Hello @github/docs-content-codeql - this PR is ready for docs review."
|
||||
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"omnisharp.autoStart": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,3 +10,10 @@
|
||||
/java/**/experimental/**/* @github/codeql-java @xcorail
|
||||
/javascript/**/experimental/**/* @github/codeql-javascript @xcorail
|
||||
/python/**/experimental/**/* @github/codeql-python @xcorail
|
||||
|
||||
# Notify members of codeql-go about PRs to the shared data-flow library files
|
||||
/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @github/codeql-java @github/codeql-go
|
||||
/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @github/codeql-java @github/codeql-go
|
||||
/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @github/codeql-java @github/codeql-go
|
||||
/java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @github/codeql-java @github/codeql-go
|
||||
/java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @github/codeql-java @github/codeql-go
|
||||
|
||||
@@ -38,7 +38,7 @@ If you have an idea for a query that you would like to share with other CodeQL u
|
||||
|
||||
- The queries and libraries must be autoformatted, for example using the "Format Document" command in [CodeQL for Visual Studio Code](https://help.semmle.com/codeql/codeql-for-vscode/procedures/about-codeql-for-vscode.html).
|
||||
|
||||
If you prefer, you can use this [pre-commit hook](misc/scripts/pre-commit) that automatically checks whether your files are correctly formatted. See the [pre-commit hook installation guide](docs/install-pre-commit-hook.md) for instructions on how to install the hook.
|
||||
If you prefer, you can use this [pre-commit hook](misc/scripts/pre-commit) that automatically checks whether your files are correctly formatted. See the [pre-commit hook installation guide](docs/pre-commit-hook-setup.md) for instructions on how to install the hook.
|
||||
|
||||
4. **Compilation**
|
||||
|
||||
|
||||
@@ -374,50 +374,50 @@
|
||||
"javascript/ql/src/semmle/javascript/XML.qll",
|
||||
"python/ql/src/semmle/python/xml/XML.qll"
|
||||
],
|
||||
"DuplicationProblems.qhelp": [
|
||||
"cpp/ql/src/Metrics/Files/DuplicationProblems.qhelp",
|
||||
"csharp/ql/src/Metrics/Files/DuplicationProblems.qhelp",
|
||||
"javascript/ql/src/Metrics/DuplicationProblems.qhelp",
|
||||
"python/ql/src/Metrics/DuplicationProblems.qhelp"
|
||||
"DuplicationProblems.inc.qhelp": [
|
||||
"cpp/ql/src/Metrics/Files/DuplicationProblems.inc.qhelp",
|
||||
"csharp/ql/src/Metrics/Files/DuplicationProblems.inc.qhelp",
|
||||
"javascript/ql/src/Metrics/DuplicationProblems.inc.qhelp",
|
||||
"python/ql/src/Metrics/DuplicationProblems.inc.qhelp"
|
||||
],
|
||||
"CommentedOutCodeQuery.qhelp": [
|
||||
"cpp/ql/src/Documentation/CommentedOutCodeQuery.qhelp",
|
||||
"python/ql/src/Lexical/CommentedOutCodeQuery.qhelp",
|
||||
"csharp/ql/src/Bad Practices/Comments/CommentedOutCodeQuery.qhelp",
|
||||
"java/ql/src/Violations of Best Practice/Comments/CommentedOutCodeQuery.qhelp",
|
||||
"javascript/ql/src/Comments/CommentedOutCodeQuery.qhelp"
|
||||
"CommentedOutCodeQuery.inc.qhelp": [
|
||||
"cpp/ql/src/Documentation/CommentedOutCodeQuery.inc.qhelp",
|
||||
"python/ql/src/Lexical/CommentedOutCodeQuery.inc.qhelp",
|
||||
"csharp/ql/src/Bad Practices/Comments/CommentedOutCodeQuery.inc.qhelp",
|
||||
"java/ql/src/Violations of Best Practice/Comments/CommentedOutCodeQuery.inc.qhelp",
|
||||
"javascript/ql/src/Comments/CommentedOutCodeQuery.inc.qhelp"
|
||||
],
|
||||
"FLinesOfCodeReferences.qhelp": [
|
||||
"java/ql/src/Metrics/Files/FLinesOfCodeReferences.qhelp",
|
||||
"javascript/ql/src/Metrics/FLinesOfCodeReferences.qhelp"
|
||||
"FLinesOfCodeReferences.inc.qhelp": [
|
||||
"java/ql/src/Metrics/Files/FLinesOfCodeReferences.inc.qhelp",
|
||||
"javascript/ql/src/Metrics/FLinesOfCodeReferences.inc.qhelp"
|
||||
],
|
||||
"FCommentRatioCommon.qhelp": [
|
||||
"java/ql/src/Metrics/Files/FCommentRatioCommon.qhelp",
|
||||
"javascript/ql/src/Metrics/FCommentRatioCommon.qhelp"
|
||||
"FCommentRatioCommon.inc.qhelp": [
|
||||
"java/ql/src/Metrics/Files/FCommentRatioCommon.inc.qhelp",
|
||||
"javascript/ql/src/Metrics/FCommentRatioCommon.inc.qhelp"
|
||||
],
|
||||
"FLinesOfCodeOverview.qhelp": [
|
||||
"java/ql/src/Metrics/Files/FLinesOfCodeOverview.qhelp",
|
||||
"javascript/ql/src/Metrics/FLinesOfCodeOverview.qhelp"
|
||||
"FLinesOfCodeOverview.inc.qhelp": [
|
||||
"java/ql/src/Metrics/Files/FLinesOfCodeOverview.inc.qhelp",
|
||||
"javascript/ql/src/Metrics/FLinesOfCodeOverview.inc.qhelp"
|
||||
],
|
||||
"CommentedOutCodeMetricOverview.qhelp": [
|
||||
"cpp/ql/src/Metrics/Files/CommentedOutCodeMetricOverview.qhelp",
|
||||
"csharp/ql/src/Metrics/Files/CommentedOutCodeMetricOverview.qhelp",
|
||||
"java/ql/src/Metrics/Files/CommentedOutCodeMetricOverview.qhelp",
|
||||
"javascript/ql/src/Comments/CommentedOutCodeMetricOverview.qhelp",
|
||||
"python/ql/src/Lexical/CommentedOutCodeMetricOverview.qhelp"
|
||||
"CommentedOutCodeMetricOverview.inc.qhelp": [
|
||||
"cpp/ql/src/Metrics/Files/CommentedOutCodeMetricOverview.inc.qhelp",
|
||||
"csharp/ql/src/Metrics/Files/CommentedOutCodeMetricOverview.inc.qhelp",
|
||||
"java/ql/src/Metrics/Files/CommentedOutCodeMetricOverview.inc.qhelp",
|
||||
"javascript/ql/src/Comments/CommentedOutCodeMetricOverview.inc.qhelp",
|
||||
"python/ql/src/Lexical/CommentedOutCodeMetricOverview.inc.qhelp"
|
||||
],
|
||||
"FLinesOfDuplicatedCodeCommon.qhelp": [
|
||||
"cpp/ql/src/Metrics/Files/FLinesOfDuplicatedCodeCommon.qhelp",
|
||||
"java/ql/src/Metrics/Files/FLinesOfDuplicatedCodeCommon.qhelp",
|
||||
"javascript/ql/src/Metrics/FLinesOfDuplicatedCodeCommon.qhelp",
|
||||
"python/ql/src/Metrics/FLinesOfDuplicatedCodeCommon.qhelp"
|
||||
"FLinesOfDuplicatedCodeCommon.inc.qhelp": [
|
||||
"cpp/ql/src/Metrics/Files/FLinesOfDuplicatedCodeCommon.inc.qhelp",
|
||||
"java/ql/src/Metrics/Files/FLinesOfDuplicatedCodeCommon.inc.qhelp",
|
||||
"javascript/ql/src/Metrics/FLinesOfDuplicatedCodeCommon.inc.qhelp",
|
||||
"python/ql/src/Metrics/FLinesOfDuplicatedCodeCommon.inc.qhelp"
|
||||
],
|
||||
"CommentedOutCodeReferences.qhelp": [
|
||||
"cpp/ql/src/Metrics/Files/CommentedOutCodeReferences.qhelp",
|
||||
"csharp/ql/src/Metrics/Files/CommentedOutCodeReferences.qhelp",
|
||||
"java/ql/src/Metrics/Files/CommentedOutCodeReferences.qhelp",
|
||||
"javascript/ql/src/Comments/CommentedOutCodeReferences.qhelp",
|
||||
"python/ql/src/Lexical/CommentedOutCodeReferences.qhelp"
|
||||
"CommentedOutCodeReferences.inc.qhelp": [
|
||||
"cpp/ql/src/Metrics/Files/CommentedOutCodeReferences.inc.qhelp",
|
||||
"csharp/ql/src/Metrics/Files/CommentedOutCodeReferences.inc.qhelp",
|
||||
"java/ql/src/Metrics/Files/CommentedOutCodeReferences.inc.qhelp",
|
||||
"javascript/ql/src/Comments/CommentedOutCodeReferences.inc.qhelp",
|
||||
"python/ql/src/Lexical/CommentedOutCodeReferences.inc.qhelp"
|
||||
],
|
||||
"IDE Contextual Queries": [
|
||||
"cpp/ql/src/IDEContextual.qll",
|
||||
@@ -430,5 +430,9 @@
|
||||
"csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll"
|
||||
],
|
||||
"CryptoAlgorithms Python/JS": [
|
||||
"javascript/ql/src/semmle/javascript/security/CryptoAlgorithms.qll",
|
||||
"python/ql/src/semmle/crypto/Crypto.qll"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<AssemblyName>Semmle.Autobuild.Cpp</AssemblyName>
|
||||
<RootNamespace>Semmle.Autobuild.Cpp</RootNamespace>
|
||||
<ApplicationIcon />
|
||||
@@ -17,7 +17,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Build" Version="16.0.461" />
|
||||
<PackageReference Include="Microsoft.Build" Version="16.9.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* The data-flow library now recognises more side-effects of method chaining (e.g. `someObject.setX(clean).setY(tainted).setZ...` having a side-effect on `someObject`), as well as other related circumstances where a function input is directly passed to its output. All queries that use data-flow analysis, including most security queries, may return more results accordingly.
|
||||
2
cpp/change-notes/2021-03-11-failed-extractions.md
Normal file
2
cpp/change-notes/2021-03-11-failed-extractions.md
Normal file
@@ -0,0 +1,2 @@
|
||||
codescanning
|
||||
* Added cpp/diagnostics/failed-extractions. This query gives information about which extractions did not run to completion.
|
||||
2
cpp/change-notes/2021-03-17-av-rule-79.md
Normal file
2
cpp/change-notes/2021-03-17-av-rule-79.md
Normal file
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* The 'Resource not released in destructor' (cpp/resource-not-released-in-destructor) query has been improved to recognize more releases of resources.
|
||||
@@ -9,7 +9,7 @@
|
||||
It is likely that these conditions indicate an error in the branching condition.
|
||||
Alternatively, the conditions may have been left behind after debugging.</p>
|
||||
|
||||
<include src="aliasAnalysisWarning.qhelp" />
|
||||
<include src="aliasAnalysisWarning.inc.qhelp" />
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
|
||||
@@ -13,7 +13,7 @@ If left in the code base they increase object code size, decrease code comprehen
|
||||
This type of function may be part of the program's API and could be used by external programs.
|
||||
</p>
|
||||
|
||||
<include src="callGraphWarning.qhelp" />
|
||||
<include src="callGraphWarning.inc.qhelp" />
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
|
||||
@@ -10,7 +10,7 @@ This query looks at functions that return file or socket descriptors, but may re
|
||||
This can occur when an operation performed on the open descriptor fails, and the function returns with an error before it closes the open resource. An improperly handled error could cause the function to leak resource descriptors. Failing to close resources in the function that opened them also makes it more difficult to detect leaks.
|
||||
</p>
|
||||
|
||||
<include src="dataFlowWarning.qhelp" />
|
||||
<include src="dataFlowWarning.inc.qhelp" />
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
|
||||
@@ -10,7 +10,7 @@ This rule finds calls to <code>socket</code> where there is no corresponding <co
|
||||
Leaving descriptors open will cause a resource leak that will persist even after the program terminates.
|
||||
</p>
|
||||
|
||||
<include src="aliasAnalysisWarning.qhelp" />
|
||||
<include src="aliasAnalysisWarning.inc.qhelp" />
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
|
||||
@@ -10,7 +10,7 @@ This rule looks at functions that return a <code>FILE*</code>, but may return an
|
||||
This can occur when an operation performed on the open descriptor fails, and the function returns with an error before closing the open resource. An improperly handled error may cause the function to leak file descriptors.
|
||||
</p>
|
||||
|
||||
<include src="dataFlowWarning.qhelp" />
|
||||
<include src="dataFlowWarning.inc.qhelp" />
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
@@ -10,7 +10,7 @@ This rule finds calls to <code>fopen</code> with no corresponding <code>fclose</
|
||||
Leaving files open will cause a resource leak that will persist even after the program terminates.
|
||||
</p>
|
||||
|
||||
<include src="aliasAnalysisWarning.qhelp" />
|
||||
<include src="aliasAnalysisWarning.inc.qhelp" />
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
@@ -10,7 +10,7 @@ Not all compilers generate code that zero-out memory, especially when optimizati
|
||||
is not compliant with the latest language standards. Accessing uninitialized memory will lead to undefined results.
|
||||
</p>
|
||||
|
||||
<include src="dataFlowWarning.qhelp" />
|
||||
<include src="dataFlowWarning.inc.qhelp" />
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
|
||||
@@ -12,7 +12,7 @@ Dereferencing a null pointer and attempting to modify its contents can lead to a
|
||||
important system data (including the interrupt table in some architectures).
|
||||
</p>
|
||||
|
||||
<include src="pointsToWarning.qhelp" />
|
||||
<include src="pointsToWarning.inc.qhelp" />
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
|
||||
@@ -11,7 +11,7 @@ Uninitialized variables may contain any value, as not all compilers generate cod
|
||||
optimizations are enabled or the compiler is not compliant with the latest language standards.
|
||||
</p>
|
||||
|
||||
<include src="callGraphWarning.qhelp" />
|
||||
<include src="callGraphWarning.inc.qhelp" />
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
|
||||
@@ -13,7 +13,7 @@ after. Otherwise, if the value is negative then the program will have failed
|
||||
before performing the test.
|
||||
</p>
|
||||
|
||||
<include src="dataFlowWarning.qhelp" />
|
||||
<include src="dataFlowWarning.inc.qhelp" />
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
This rule looks for functions that allocate memory, but may return without freeing it. This can occur when an operation performed on the memory block fails, and the function returns with an error before freeing the allocated block. This causes the function to leak memory and may eventually lead to software failure.
|
||||
</p>
|
||||
|
||||
<include src="dataFlowWarning.qhelp" />
|
||||
<include src="dataFlowWarning.inc.qhelp" />
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
@@ -10,7 +10,7 @@ This rule finds calls to the <code>alloc</code> family of functions without a co
|
||||
This leads to memory leaks.
|
||||
</p>
|
||||
|
||||
<include src="aliasAnalysisWarning.qhelp" />
|
||||
<include src="aliasAnalysisWarning.inc.qhelp" />
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
@@ -16,7 +16,7 @@ buffer overruns.
|
||||
The query looks only at the return values of functions that may return a negative value (not all functions).
|
||||
</p>
|
||||
|
||||
<include src="dataFlowWarning.qhelp" />
|
||||
<include src="dataFlowWarning.inc.qhelp" />
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
|
||||
@@ -63,7 +63,7 @@ destructors likely not be called (as previously noted), but the pointer will als
|
||||
potentially less of a serious issue than that posed by the first approach, but it should still be avoided.</li>
|
||||
</ul>
|
||||
|
||||
<include src="pointsToWarning.qhelp" />
|
||||
<include src="pointsToWarning.inc.qhelp" />
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
@@ -18,7 +18,7 @@ an array (which could have header data specifying the length of the array) and w
|
||||
element of the 'array', which would likely lead to a segfault due to the invalid header data.
|
||||
</p>
|
||||
|
||||
<include src="pointsToWarning.qhelp" />
|
||||
<include src="pointsToWarning.inc.qhelp" />
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
@@ -19,7 +19,7 @@ the data being copied. Buffer overflows can result to anything from a segmentati
|
||||
if the array is on stack-allocated memory).
|
||||
</p>
|
||||
|
||||
<include src="aliasAnalysisWarning.qhelp" />
|
||||
<include src="aliasAnalysisWarning.inc.qhelp" />
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
|
||||
@@ -14,7 +14,7 @@ Buffer overflows can lead to anything from a segmentation fault to a security vu
|
||||
Ensure that the size parameter is derived from the size of the destination buffer, and
|
||||
not the source buffer.</p>
|
||||
|
||||
<include src="aliasAnalysisWarning.qhelp" />
|
||||
<include src="aliasAnalysisWarning.inc.qhelp" />
|
||||
</recommendation>
|
||||
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ the contents of that memory become undefined after that. Clearly, using a pointe
|
||||
memory after the function has already returned will have undefined results.
|
||||
</p>
|
||||
|
||||
<include src="pointsToWarning.qhelp" />
|
||||
<include src="pointsToWarning.inc.qhelp" />
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
|
||||
@@ -12,7 +12,7 @@ from a segfault to memory corruption that would cause subsequent calls to the dy
|
||||
erratically, to a possible security vulnerability.
|
||||
</p>
|
||||
|
||||
<include src="pointsToWarning.qhelp" />
|
||||
<include src="pointsToWarning.inc.qhelp" />
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
16
cpp/ql/src/Diagnostics/ExtractionErrors.ql
Normal file
16
cpp/ql/src/Diagnostics/ExtractionErrors.ql
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @name Extraction errors
|
||||
* @description List all extraction errors for files in the source code directory.
|
||||
* @kind diagnostic
|
||||
* @id cpp/diagnostics/extraction-errors
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import ExtractionErrors
|
||||
|
||||
from ExtractionError error
|
||||
where
|
||||
error instanceof ExtractionUnknownError or
|
||||
exists(error.getFile().getRelativePath())
|
||||
select error, "Extraction failed in " + error.getFile() + " with error " + error.getErrorMessage(),
|
||||
error.getSeverity()
|
||||
137
cpp/ql/src/Diagnostics/ExtractionErrors.qll
Normal file
137
cpp/ql/src/Diagnostics/ExtractionErrors.qll
Normal file
@@ -0,0 +1,137 @@
|
||||
/**
|
||||
* Provides a common hierarchy of all types of errors that can occur during extraction.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/*
|
||||
* A note about how the C/C++ extractor emits diagnostics:
|
||||
* When the extractor frontend encounters an error, it emits a diagnostic message,
|
||||
* that includes a message, location and severity.
|
||||
* However, that process is best-effort and may fail (e.g. due to lack of memory).
|
||||
* Thus, if the extractor emitted at least one diagnostic of severity discretionary
|
||||
* error (or higher), it *also* emits a simple "There was an error during this compilation"
|
||||
* error diagnostic, without location information.
|
||||
* In the common case, this means that a compilation during which one or more errors happened also gets
|
||||
* the catch-all diagnostic.
|
||||
* This diagnostic has the empty string as file path.
|
||||
* We filter out these useless diagnostics if there is at least one error-level diagnostic
|
||||
* for the affected compilation in the database.
|
||||
* Otherwise, we show it to indicate that something went wrong and that we
|
||||
* don't know what exactly happened.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An error that, if present, leads to a file being marked as non-successfully extracted.
|
||||
*/
|
||||
class ReportableError extends Diagnostic {
|
||||
ReportableError() {
|
||||
(
|
||||
this instanceof CompilerDiscretionaryError or
|
||||
this instanceof CompilerError or
|
||||
this instanceof CompilerCatastrophe
|
||||
) and
|
||||
// Filter for the catch-all diagnostic, see note above.
|
||||
not this.getFile().getAbsolutePath() = ""
|
||||
}
|
||||
}
|
||||
|
||||
private newtype TExtractionError =
|
||||
TReportableError(ReportableError err) or
|
||||
TCompilationFailed(Compilation c, File f) {
|
||||
f = c.getAFileCompiled() and not c.normalTermination()
|
||||
} or
|
||||
// Show the catch-all diagnostic (see note above) only if we haven't seen any other error-level diagnostic
|
||||
// for that compilation
|
||||
TUnknownError(CompilerError err) {
|
||||
not exists(ReportableError e | e.getCompilation() = err.getCompilation())
|
||||
}
|
||||
|
||||
/**
|
||||
* Superclass for the extraction error hierarchy.
|
||||
*/
|
||||
class ExtractionError extends TExtractionError {
|
||||
/** Gets the string representation of the error. */
|
||||
string toString() { none() }
|
||||
|
||||
/** Gets the error message for this error. */
|
||||
string getErrorMessage() { none() }
|
||||
|
||||
/** Gets the file this error occured in. */
|
||||
File getFile() { none() }
|
||||
|
||||
/** Gets the location this error occured in. */
|
||||
Location getLocation() { none() }
|
||||
|
||||
/** Gets the SARIF severity of this error. */
|
||||
int getSeverity() {
|
||||
// Unfortunately, we can't distinguish between errors and fatal errors in SARIF,
|
||||
// so all errors have severity 2.
|
||||
result = 2
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An unrecoverable extraction error, where extraction was unable to finish.
|
||||
* This can be caused by a multitude of reasons, for example:
|
||||
* - hitting a frontend assertion
|
||||
* - crashing due to dereferencing an invalid pointer
|
||||
* - stack overflow
|
||||
* - out of memory
|
||||
*/
|
||||
class ExtractionUnrecoverableError extends ExtractionError, TCompilationFailed {
|
||||
Compilation c;
|
||||
File f;
|
||||
|
||||
ExtractionUnrecoverableError() { this = TCompilationFailed(c, f) }
|
||||
|
||||
override string toString() {
|
||||
result = "Unrecoverable extraction error while compiling " + f.toString()
|
||||
}
|
||||
|
||||
override string getErrorMessage() { result = "unrecoverable compilation failure." }
|
||||
|
||||
override File getFile() { result = f }
|
||||
|
||||
override Location getLocation() { result = f.getLocation() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A recoverable extraction error.
|
||||
* These are compiler errors from the frontend.
|
||||
* Upon encountering one of these, we still continue extraction, but the
|
||||
* database will be incomplete for that file.
|
||||
*/
|
||||
class ExtractionRecoverableError extends ExtractionError, TReportableError {
|
||||
ReportableError err;
|
||||
|
||||
ExtractionRecoverableError() { this = TReportableError(err) }
|
||||
|
||||
override string toString() { result = "Recoverable extraction error: " + err }
|
||||
|
||||
override string getErrorMessage() { result = err.getFullMessage() }
|
||||
|
||||
override File getFile() { result = err.getFile() }
|
||||
|
||||
override Location getLocation() { result = err.getLocation() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An unknown error happened during extraction.
|
||||
* These are only displayed if we know that we encountered an error during extraction,
|
||||
* but, for some reason, failed to emit a proper diagnostic with location information
|
||||
* and error message.
|
||||
*/
|
||||
class ExtractionUnknownError extends ExtractionError, TUnknownError {
|
||||
CompilerError err;
|
||||
|
||||
ExtractionUnknownError() { this = TUnknownError(err) }
|
||||
|
||||
override string toString() { result = "Unknown extraction error: " + err }
|
||||
|
||||
override string getErrorMessage() { result = err.getFullMessage() }
|
||||
|
||||
override File getFile() { result = err.getFile() }
|
||||
|
||||
override Location getLocation() { result = err.getLocation() }
|
||||
}
|
||||
22
cpp/ql/src/Diagnostics/FailedExtractorInvocations.ql
Normal file
22
cpp/ql/src/Diagnostics/FailedExtractorInvocations.ql
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* @name Failed extractor invocations
|
||||
* @description Gives the command line of compilations for which extraction did not run to completion.
|
||||
* @kind diagnostic
|
||||
* @id cpp/diagnostics/failed-extractor-invocations
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
class AnonymousCompilation extends Compilation {
|
||||
override string toString() { result = "<compilation>" }
|
||||
}
|
||||
|
||||
string describe(Compilation c) {
|
||||
if c.getArgument(1) = "--mimic"
|
||||
then result = "compiler invocation " + concat(int i | i > 1 | c.getArgument(i), " " order by i)
|
||||
else result = "extractor invocation " + concat(int i | | c.getArgument(i), " " order by i)
|
||||
}
|
||||
|
||||
from Compilation c
|
||||
where not c.normalTermination()
|
||||
select c, "Extraction aborted for " + describe(c), 2
|
||||
15
cpp/ql/src/Diagnostics/SuccessfullyExtractedFiles.ql
Normal file
15
cpp/ql/src/Diagnostics/SuccessfullyExtractedFiles.ql
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* @name Successfully extracted files
|
||||
* @description Lists all files in the source code directory that were extracted without encountering an error in the file.
|
||||
* @kind diagnostic
|
||||
* @id cpp/diagnostics/successfully-extracted-files
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import ExtractionErrors
|
||||
|
||||
from File f
|
||||
where
|
||||
not exists(ExtractionError e | e.getFile() = f) and
|
||||
exists(f.getRelativePath())
|
||||
select f, ""
|
||||
@@ -2,6 +2,6 @@
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<include src="CommentedOutCodeQuery.qhelp" />
|
||||
<include src="../Metrics/Files/CommentedOutCodeReferences.qhelp" />
|
||||
<include src="CommentedOutCodeQuery.inc.qhelp" />
|
||||
<include src="../Metrics/Files/CommentedOutCodeReferences.inc.qhelp" />
|
||||
</qhelp>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<include src="LeapYear.qhelp" />
|
||||
<include src="LeapYear.inc.qhelp" />
|
||||
|
||||
<p>When performing arithmetic operations on a variable that represents a date, leap years must be taken into account.
|
||||
It is not safe to assume that a year is 365 days long.</p>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<include src="LeapYear.qhelp" />
|
||||
<include src="LeapYear.inc.qhelp" />
|
||||
|
||||
<p>When performing arithmetic operations on a variable that represents a year, it is important to consider that the resulting value may not be a valid date.</p>
|
||||
<p>The typical example is doing simple year arithmetic (i.e. <code>date.year++</code>) without considering if the resulting value will be a valid date or not.</p>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<include src="LeapYear.qhelp" />
|
||||
<include src="LeapYear.inc.qhelp" />
|
||||
|
||||
<p>When using a function that transforms a date structure, and the year on the input argument for the API has been manipulated, it is important to check for the return value of the function to make sure it succeeded.</p>
|
||||
<p>Otherwise, the function may have failed, and the output parameter may contain invalid data that can cause any number of problems on the affected system.</p>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<include src="LeapYear.qhelp" />
|
||||
<include src="LeapYear.inc.qhelp" />
|
||||
|
||||
<p>This query helps to detect when a developer allocates an array or other fixed-length data structure such as <code>std::vector</code> with 365 elements – one for each day of the year.</p>
|
||||
<p>Since leap years have 366 days, there will be no allocated element on December 31st at the end of a leap year; which will lead to a buffer overflow on a leap year.</p>
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<include src="CommentedOutCodeMetricOverview.qhelp" />
|
||||
<include src="CommentedOutCodeReferences.qhelp" />
|
||||
<include src="CommentedOutCodeMetricOverview.inc.qhelp" />
|
||||
<include src="CommentedOutCodeReferences.inc.qhelp" />
|
||||
</qhelp>
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<include src="FLinesOfDuplicatedCodeCommon.qhelp" />
|
||||
<include src="FLinesOfDuplicatedCodeCommon.inc.qhelp" />
|
||||
</qhelp>
|
||||
@@ -14,7 +14,7 @@ for a number of reasons.
|
||||
</p>
|
||||
|
||||
</overview>
|
||||
<include src="DuplicationProblems.qhelp" />
|
||||
<include src="DuplicationProblems.inc.qhelp" />
|
||||
|
||||
<recommendation>
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<include src="CleartextStorage.qhelp" /></qhelp>
|
||||
<include src="CleartextStorage.inc.qhelp" /></qhelp>
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<include src="CleartextStorage.qhelp" /></qhelp>
|
||||
<include src="CleartextStorage.inc.qhelp" /></qhelp>
|
||||
|
||||
11
cpp/ql/src/Summary/LinesOfCode.ql
Normal file
11
cpp/ql/src/Summary/LinesOfCode.ql
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @id cpp/summary/lines-of-code
|
||||
* @name Total lines of C/C++ code in the database
|
||||
* @description The total number of lines of C/C++ code across all files, including system headers, libraries, and auto-generated files. This is a useful metric of the size of a database. For all files that were seen during the build, this query counts the lines of code, excluding whitespace or comments.
|
||||
* @kind metric
|
||||
* @tags summary
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
select sum(File f | f.fromSource() | f.getMetrics().getNumberOfLinesOfCode())
|
||||
@@ -0,0 +1,7 @@
|
||||
if(len<0) return 1;
|
||||
memset(dest, source, len); // GOOD: variable `len` checked before call
|
||||
|
||||
...
|
||||
|
||||
memset(dest, source, len); // BAD: variable `len` checked after call
|
||||
if(len<0) return 1;
|
||||
@@ -0,0 +1,28 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>Checking the function argument after calling the function itself. This situation looks suspicious and requires the attention of the developer. It may be necessary to add validation before calling the function</p>
|
||||
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>We recommend checking before calling the function.</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
<p>The following example demonstrates an erroneous and fixed use of function argument validation.</p>
|
||||
<sample src="LateCheckOfFunctionArgument.c" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>
|
||||
CWE Common Weakness Enumeration:
|
||||
<a href="https://cwe.mitre.org/data/definitions/20.html"> CWE-20: Improper Input Validation</a>.
|
||||
</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* @name Late Check Of Function Argument
|
||||
* @description --Checking the function argument after calling the function itself.
|
||||
* --This situation looks suspicious and requires the attention of the developer.
|
||||
* --It may be necessary to add validation before calling the function.
|
||||
* @kind problem
|
||||
* @id cpp/late-check-of-function-argument
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @tags correctness
|
||||
* security
|
||||
* external/cwe/cwe-20
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
|
||||
/** Holds for a function `f` that has an argument at index `apos` used for positioning in a buffer. */
|
||||
predicate numberArgument(Function f, int apos) {
|
||||
f.hasGlobalOrStdName("write") and apos = 2
|
||||
or
|
||||
f.hasGlobalOrStdName("read") and apos = 2
|
||||
or
|
||||
f.hasGlobalOrStdName("lseek") and apos = 1
|
||||
or
|
||||
f.hasGlobalOrStdName("memmove") and apos = 2
|
||||
or
|
||||
f.hasGlobalOrStdName("memset") and apos = 2
|
||||
or
|
||||
f.hasGlobalOrStdName("memcpy") and apos = 2
|
||||
or
|
||||
f.hasGlobalOrStdName("memcmp") and apos = 2
|
||||
or
|
||||
f.hasGlobalOrStdName("strncat") and apos = 2
|
||||
or
|
||||
f.hasGlobalOrStdName("strncpy") and apos = 2
|
||||
or
|
||||
f.hasGlobalOrStdName("strncmp") and apos = 2
|
||||
or
|
||||
f.hasGlobalOrStdName("snprintf") and apos = 1
|
||||
or
|
||||
f.hasGlobalOrStdName("strndup") and apos = 2
|
||||
}
|
||||
|
||||
class IfCompareWithZero extends IfStmt {
|
||||
IfCompareWithZero() { this.getCondition().(RelationalOperation).getAChild().getValue() = "0" }
|
||||
|
||||
Expr noZerroOperand() {
|
||||
if this.getCondition().(RelationalOperation).getGreaterOperand().getValue() = "0"
|
||||
then result = this.getCondition().(RelationalOperation).getLesserOperand()
|
||||
else result = this.getCondition().(RelationalOperation).getGreaterOperand()
|
||||
}
|
||||
}
|
||||
|
||||
from FunctionCall fc, IfCompareWithZero ifc, int na
|
||||
where
|
||||
numberArgument(fc.getTarget(), na) and
|
||||
globalValueNumber(fc.getArgument(na)) = globalValueNumber(ifc.noZerroOperand()) and
|
||||
dominates(fc, ifc) and
|
||||
not exists(IfStmt ifc1 |
|
||||
dominates(ifc1, fc) and
|
||||
globalValueNumber(fc.getArgument(na)) = globalValueNumber(ifc1.getCondition().getAChild*())
|
||||
)
|
||||
select fc,
|
||||
"The value of argument '$@' appears to be checked after the call, rather than before it.",
|
||||
fc.getArgument(na), fc.getArgument(na).toString()
|
||||
@@ -7,7 +7,7 @@
|
||||
<overview>
|
||||
|
||||
<!-- Mention that this rule may not be applicable in projects that don't follow the JSF standard. -->
|
||||
<include src="../jsfNote.qhelp" />
|
||||
<include src="../jsfNote.inc.qhelp" />
|
||||
|
||||
<p>
|
||||
This query highlights calls to the standard library functions <code>abort, exit, getenv</code> and <code>system</code>.
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
import cpp
|
||||
import Critical.NewDelete
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
|
||||
/**
|
||||
* An expression that acquires a resource, and the kind of resource that is acquired. The
|
||||
@@ -98,7 +99,8 @@ private predicate exprReleases(Expr e, Expr released, string kind) {
|
||||
e.(FunctionCall).getTarget().(MemberFunction).getAnOverridingFunction+() = f
|
||||
) and
|
||||
e.(FunctionCall).getArgument(arg) = released and
|
||||
exprReleases(_, exprOrDereference(f.getParameter(arg).getAnAccess()), kind)
|
||||
exprReleases(_,
|
||||
exprOrDereference(globalValueNumber(f.getParameter(arg).getAnAccess()).getAnExpr()), kind)
|
||||
)
|
||||
or
|
||||
exists(Function f, ThisExpr innerThis |
|
||||
@@ -110,7 +112,7 @@ private predicate exprReleases(Expr e, Expr released, string kind) {
|
||||
) and
|
||||
e.(FunctionCall).getQualifier() = exprOrDereference(released) and
|
||||
innerThis.getEnclosingFunction() = f and
|
||||
exprReleases(_, innerThis, kind)
|
||||
exprReleases(_, globalValueNumber(innerThis).getAnExpr(), kind)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<overview>
|
||||
|
||||
<!-- Mention that this rule may not be applicable in projects that don't follow the JSF standard. -->
|
||||
<include src="../jsfNote.qhelp" />
|
||||
<include src="../jsfNote.inc.qhelp" />
|
||||
|
||||
<p>
|
||||
This query ensures that all operators with opposites (e.g. == and !=) are both defined, and
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<overview>
|
||||
|
||||
<!-- Mention that this rule may not be applicable in projects that don't follow the JSF standard. -->
|
||||
<include src="../jsfNote.qhelp" />
|
||||
<include src="../jsfNote.inc.qhelp" />
|
||||
|
||||
<p>
|
||||
This query highlights return statements that return pointers to an object allocated on the stack. The lifetime
|
||||
@@ -18,7 +18,7 @@ memory after the function has already returned will have undefined results.
|
||||
|
||||
|
||||
<!-- Mention how the results could be probabilistic (uses pointsto) -->
|
||||
<include src="../../Critical/pointsToWarning.qhelp" />
|
||||
<include src="../../Critical/pointsToWarning.inc.qhelp" />
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
@@ -12,7 +12,7 @@ calling convention for x86, it would be whatever value was in the AX/EAX registe
|
||||
assuming the function had a non-float return type that can fit in a machine word.
|
||||
</p>
|
||||
|
||||
<include src="../../Critical/dataFlowWarning.qhelp" />
|
||||
<include src="../../Critical/dataFlowWarning.inc.qhelp" />
|
||||
|
||||
<!--/*FALSEPOSITIVE_WARNING*/-->
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<overview>
|
||||
|
||||
<!-- Mention that this rule may not be applicable in projects that don't follow the JSF standard. -->
|
||||
<include src="../jsfNote.qhelp" />
|
||||
<include src="../jsfNote.inc.qhelp" />
|
||||
|
||||
<p>
|
||||
This query highlights identifiers in an inner scope that hide (have the same name as) an identifier in an outer scope.
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<overview>
|
||||
|
||||
<!-- Mention that this rule may not be applicable in projects that don't follow the JSF standard. -->
|
||||
<include src="../jsfNote.qhelp" />
|
||||
<include src="../jsfNote.inc.qhelp" />
|
||||
|
||||
<p>
|
||||
This query highlights variables with the <code>register</code> storage class specifier. Modern compilers are now capable of
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<overview>
|
||||
|
||||
<!-- Mention that this rule may not be applicable in projects that don't follow the JSF standard. -->
|
||||
<include src="../jsfNote.qhelp" />
|
||||
<include src="../jsfNote.inc.qhelp" />
|
||||
|
||||
<p>
|
||||
This query highlights portions of code that can expose the floating point implementation of the underlying
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<overview>
|
||||
|
||||
<!-- Mention that this rule may not be applicable in projects that don't follow the JSF standard. -->
|
||||
<include src="../jsfNote.qhelp" />
|
||||
<include src="../jsfNote.inc.qhelp" />
|
||||
|
||||
<p>
|
||||
This query highlights string literals that are assigned to a non-<code>const</code> variable. String literals
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<overview>
|
||||
|
||||
<!-- Mention that this rule may not be applicable in projects that don't follow the JSF standard. -->
|
||||
<include src="../jsfNote.qhelp" />
|
||||
<include src="../jsfNote.inc.qhelp" />
|
||||
|
||||
<p>
|
||||
This query finds bit fields with members that are not explicitly declared to be unsigned.
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<overview>
|
||||
|
||||
<!-- Mention that this rule may not be applicable in projects that don't follow the JSF standard. -->
|
||||
<include src="../jsfNote.qhelp" />
|
||||
<include src="../jsfNote.inc.qhelp" />
|
||||
|
||||
<p>
|
||||
This query finds unsigned values that are being negated. Behavior is undefined in such cases.
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<overview>
|
||||
|
||||
<!-- Mention that this rule may not be applicable in projects that don't follow the JSF standard. -->
|
||||
<include src="../jsfNote.qhelp" />
|
||||
<include src="../jsfNote.inc.qhelp" />
|
||||
|
||||
<p>Use of goto statements makes code more difficult to understand and maintain. Consequently, the use
|
||||
of goto statements is deprecated except as a mechanism for breaking out of multiple nested loops.
|
||||
|
||||
@@ -6,6 +6,9 @@ import semmle.code.cpp.Location
|
||||
|
||||
/** A compiler-generated error, warning or remark. */
|
||||
class Diagnostic extends Locatable, @diagnostic {
|
||||
/** Gets the compilation that generated this diagnostic. */
|
||||
Compilation getCompilation() { diagnostic_for(underlyingElement(this), result, _, _) }
|
||||
|
||||
/**
|
||||
* Gets the severity of the message, on a range from 1 to 5: 1=remark,
|
||||
* 2=warning, 3=discretionary error, 4=error, 5=catastrophic error.
|
||||
|
||||
@@ -80,11 +80,9 @@ class Element extends ElementBase {
|
||||
File getFile() { result = this.getLocation().getFile() }
|
||||
|
||||
/**
|
||||
* Holds if this element may be from source.
|
||||
*
|
||||
* Note: this predicate is provided for consistency with the libraries
|
||||
* for other languages, such as Java and Python. In C++, all files are
|
||||
* classified as source files, so this predicate is always true.
|
||||
* Holds if this element may be from source. This predicate holds for all
|
||||
* elements, except for those in the dummy file, whose name is the empty string.
|
||||
* The dummy file contains declarations that are built directly into the compiler.
|
||||
*/
|
||||
predicate fromSource() { this.getFile().fromSource() }
|
||||
|
||||
|
||||
@@ -276,7 +276,10 @@ class File extends Container, @file {
|
||||
c.getAFileCompiled() = this and
|
||||
(
|
||||
c.getAnArgument() = "--microsoft" or
|
||||
c.getAnArgument().toLowerCase().replaceAll("\\", "/").matches("%/cl.exe")
|
||||
c.getAnArgument()
|
||||
.toLowerCase()
|
||||
.replaceAll("\\", "/")
|
||||
.matches(["%/cl.exe", "%/clang-cl.exe"])
|
||||
)
|
||||
)
|
||||
or
|
||||
|
||||
@@ -207,23 +207,14 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) }
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate isAdditionalFlowStep(
|
||||
AdditionalFlowStepSource node1, Node node2, DataFlowCallable callable1, Configuration config
|
||||
) {
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
callable1 = node1.getEnclosingCallable()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow in one local step from `node1` to `node2`.
|
||||
*/
|
||||
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
|
||||
simpleLocalFlowStep(node1, node2) and
|
||||
(
|
||||
simpleLocalFlowStep(node1, node2) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -234,7 +225,8 @@ private predicate localFlowStep(Node node1, Node node2, Configuration config) {
|
||||
* Holds if the additional step from `node1` to `node2` does not jump between callables.
|
||||
*/
|
||||
private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
|
||||
isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -256,14 +248,12 @@ private predicate jumpStep(Node node1, Node node2, Configuration config) {
|
||||
* Holds if the additional step from `node1` to `node2` jumps between callables.
|
||||
*/
|
||||
private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
|
||||
exists(DataFlowCallable callable1 |
|
||||
isAdditionalFlowStep(node1, node2, callable1, config) and
|
||||
node2.getEnclosingCallable() != callable1 and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
)
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -454,8 +444,8 @@ private module Stage1 {
|
||||
// read
|
||||
exists(Node mid, Content c |
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -481,18 +471,18 @@ private module Stage1 {
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
fwdFlow(node, unbind(config)) and
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, _, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
revFlow(mid, toReturn, config) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
store(node, tc, mid, _) and
|
||||
c = tc.getContent()
|
||||
)
|
||||
@@ -562,8 +552,8 @@ private module Stage1 {
|
||||
Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
exists(Content c |
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(node2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(node2, pragma[only_bind_into](config)) and
|
||||
store(node1, tc, node2, contentType) and
|
||||
c = tc.getContent() and
|
||||
exists(ap1)
|
||||
@@ -572,8 +562,8 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(n2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2)
|
||||
}
|
||||
|
||||
@@ -598,7 +588,7 @@ private module Stage1 {
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
throughFlowNodeCand(ret, config) and
|
||||
callable = ret.getEnclosingCallable() and
|
||||
callable = getNodeEnclosingCallable(ret) and
|
||||
kind = ret.getKind()
|
||||
)
|
||||
}
|
||||
@@ -611,7 +601,7 @@ private module Stage1 {
|
||||
exists(ReturnKindExt kind |
|
||||
throughFlowNodeCand(p, config) and
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
p.getEnclosingCallable() = c and
|
||||
getNodeEnclosingCallable(p) = c and
|
||||
exists(ap) and
|
||||
// we don't expect a parameter to return stored in itself
|
||||
not exists(int pos |
|
||||
@@ -636,9 +626,6 @@ private module Stage1 {
|
||||
/* End: Stage 1 logic. */
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
pragma[noinline]
|
||||
private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
|
||||
Stage1::revFlow(node2, config) and
|
||||
@@ -775,7 +762,7 @@ private module Stage2 {
|
||||
bindingset[result, ap]
|
||||
private ApApprox getApprox(Ap ap) { any() }
|
||||
|
||||
private ApNil getApNil(Node node) { any() }
|
||||
private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||
@@ -874,16 +861,16 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -963,7 +950,7 @@ private module Stage2 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -982,7 +969,7 @@ private module Stage2 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -1055,9 +1042,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1069,9 +1056,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1124,9 +1111,10 @@ private module Stage2 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1192,9 +1180,10 @@ private module Stage2 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ unbindBool(ap2), _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1213,13 +1202,13 @@ private module Stage2 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -1250,8 +1239,8 @@ private predicate flowOutOfCallNodeCand2(
|
||||
DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1260,8 +1249,8 @@ private predicate flowIntoCallNodeCand2(
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
private module LocalFlowBigStep {
|
||||
@@ -1316,8 +1305,8 @@ private module LocalFlowBigStep {
|
||||
pragma[noinline]
|
||||
private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
|
||||
additionalLocalFlowStepNodeCand1(node1, node2, config) and
|
||||
Stage2::revFlow(node1, _, _, false, config) and
|
||||
Stage2::revFlow(node2, _, _, false, unbind(config))
|
||||
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1334,7 +1323,7 @@ private module LocalFlowBigStep {
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
@@ -1345,24 +1334,24 @@ private module LocalFlowBigStep {
|
||||
t = getNodeType(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1394,7 +1383,9 @@ private module Stage3 {
|
||||
|
||||
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||
|
||||
private ApNil getApNil(Node node) { result = TFrontNil(getNodeType(node)) }
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||
@@ -1467,6 +1458,13 @@ private module Stage3 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -1478,7 +1476,7 @@ private module Stage3 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, unbindBool(getApprox(ap)), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -1502,16 +1500,16 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -1556,7 +1554,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, unbindBool(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -1591,7 +1589,7 @@ private module Stage3 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1610,7 +1608,7 @@ private module Stage3 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -1635,7 +1633,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindBool(getApprox(ap)), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1683,9 +1681,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1697,9 +1695,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1752,9 +1750,10 @@ private module Stage3 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1820,9 +1819,10 @@ private module Stage3 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1841,13 +1841,13 @@ private module Stage3 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -2087,7 +2087,9 @@ private module Stage4 {
|
||||
|
||||
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
|
||||
|
||||
private ApNil getApNil(Node node) { result = TNil(getNodeType(node)) }
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||
@@ -2131,8 +2133,11 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc, node.getEnclosingCallable())
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2147,8 +2152,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -2157,8 +2162,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
bindingset[node, ap]
|
||||
@@ -2173,6 +2178,13 @@ private module Stage4 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -2184,7 +2196,7 @@ private module Stage4 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, getApprox(ap), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -2208,16 +2220,16 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -2262,7 +2274,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -2297,7 +2309,7 @@ private module Stage4 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -2316,7 +2328,7 @@ private module Stage4 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -2341,7 +2353,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2389,9 +2401,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -2403,9 +2415,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -2458,9 +2470,10 @@ private module Stage4 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2526,9 +2539,10 @@ private module Stage4 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2547,13 +2561,13 @@ private module Stage4 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -2580,14 +2594,16 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
bindingset[conf, result]
|
||||
private Configuration unbind(Configuration conf) { result >= conf and result <= conf }
|
||||
private Configuration unbindConf(Configuration conf) {
|
||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||
}
|
||||
|
||||
private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
|
||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
||||
Stage4::revFlow(n, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
getNodeEnclosingCallable(n) = c
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2750,13 +2766,13 @@ private newtype TPathNode =
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, cc, sc, ap) and
|
||||
config = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), unbind(config))
|
||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
|
||||
)
|
||||
} or
|
||||
TPathNodeSink(Node node, Configuration config) {
|
||||
config.isSink(node) and
|
||||
Stage4::revFlow(node, unbind(config)) and
|
||||
pragma[only_bind_into](config).isSink(node) and
|
||||
Stage4::revFlow(node, pragma[only_bind_into](config)) and
|
||||
(
|
||||
// A sink that is also a source ...
|
||||
config.isSource(node)
|
||||
@@ -2764,7 +2780,7 @@ private newtype TPathNode =
|
||||
// ... or a sink that can be reached from a source
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, _, _, TAccessPathNil(_)) and
|
||||
config = unbind(mid.getConfiguration())
|
||||
pragma[only_bind_into](config) = mid.getConfiguration()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -3061,7 +3077,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
|
||||
private PathNodeMid getSuccMid() {
|
||||
pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
|
||||
result.getConfiguration() = unbind(this.getConfiguration())
|
||||
result.getConfiguration() = unbindConf(this.getConfiguration())
|
||||
}
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
@@ -3073,7 +3089,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
mid = getSuccMid() and
|
||||
mid.getNode() = sink.getNode() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
sink.getConfiguration() = unbind(mid.getConfiguration()) and
|
||||
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
|
||||
result = sink
|
||||
)
|
||||
}
|
||||
@@ -3116,7 +3132,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
localCC = getLocalCallContext(cc, getNodeEnclosingCallable(midnode)) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
@@ -3304,7 +3320,7 @@ private predicate pathThroughCallable0(
|
||||
) {
|
||||
exists(CallContext innercc, SummaryCtx sc |
|
||||
pathIntoCallable(mid, _, cc, innercc, sc, call) and
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration()))
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3316,7 +3332,7 @@ pragma[noinline]
|
||||
private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
|
||||
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration()))
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3402,14 +3418,14 @@ private module FlowExploration {
|
||||
// flow out of a callable
|
||||
viableReturnPosOut(_, getReturnPosition(node1), node2)
|
||||
|
|
||||
c1 = node1.getEnclosingCallable() and
|
||||
c2 = node2.getEnclosingCallable() and
|
||||
c1 = getNodeEnclosingCallable(node1) and
|
||||
c2 = getNodeEnclosingCallable(node2) and
|
||||
c1 != c2
|
||||
)
|
||||
}
|
||||
|
||||
private predicate interestingCallableSrc(DataFlowCallable c, Configuration config) {
|
||||
exists(Node n | config.isSource(n) and c = n.getEnclosingCallable())
|
||||
exists(Node n | config.isSource(n) and c = getNodeEnclosingCallable(n))
|
||||
or
|
||||
exists(DataFlowCallable mid |
|
||||
interestingCallableSrc(mid, config) and callableStep(mid, c, config)
|
||||
@@ -3417,7 +3433,7 @@ private module FlowExploration {
|
||||
}
|
||||
|
||||
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
|
||||
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
|
||||
exists(Node n | config.isSink(n) and c = getNodeEnclosingCallable(n))
|
||||
or
|
||||
exists(DataFlowCallable mid |
|
||||
interestingCallableSink(mid, config) and callableStep(c, mid, config)
|
||||
@@ -3439,20 +3455,20 @@ private module FlowExploration {
|
||||
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
|
||||
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
|
||||
callableStep(c1, c2, config) and
|
||||
ce1 = TCallable(c1, config) and
|
||||
ce2 = TCallable(c2, unbind(config))
|
||||
ce1 = TCallable(c1, pragma[only_bind_into](config)) and
|
||||
ce2 = TCallable(c2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node n, Configuration config |
|
||||
ce1 = TCallableSrc() and
|
||||
config.isSource(n) and
|
||||
ce2 = TCallable(n.getEnclosingCallable(), config)
|
||||
ce2 = TCallable(getNodeEnclosingCallable(n), config)
|
||||
)
|
||||
or
|
||||
exists(Node n, Configuration config |
|
||||
ce2 = TCallableSink() and
|
||||
config.isSink(n) and
|
||||
ce1 = TCallable(n.getEnclosingCallable(), config)
|
||||
ce1 = TCallable(getNodeEnclosingCallable(n), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3583,7 +3599,7 @@ private module FlowExploration {
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
|
||||
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
} or
|
||||
TPartialPathNodeRev(
|
||||
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
|
||||
@@ -3600,7 +3616,7 @@ private module FlowExploration {
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3659,7 +3675,7 @@ private module FlowExploration {
|
||||
* of interprocedural steps.
|
||||
*/
|
||||
int getSourceDistance() {
|
||||
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
|
||||
result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3667,7 +3683,7 @@ private module FlowExploration {
|
||||
* of interprocedural steps.
|
||||
*/
|
||||
int getSinkDistance() {
|
||||
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
|
||||
result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
|
||||
@@ -207,23 +207,14 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) }
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate isAdditionalFlowStep(
|
||||
AdditionalFlowStepSource node1, Node node2, DataFlowCallable callable1, Configuration config
|
||||
) {
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
callable1 = node1.getEnclosingCallable()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow in one local step from `node1` to `node2`.
|
||||
*/
|
||||
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
|
||||
simpleLocalFlowStep(node1, node2) and
|
||||
(
|
||||
simpleLocalFlowStep(node1, node2) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -234,7 +225,8 @@ private predicate localFlowStep(Node node1, Node node2, Configuration config) {
|
||||
* Holds if the additional step from `node1` to `node2` does not jump between callables.
|
||||
*/
|
||||
private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
|
||||
isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -256,14 +248,12 @@ private predicate jumpStep(Node node1, Node node2, Configuration config) {
|
||||
* Holds if the additional step from `node1` to `node2` jumps between callables.
|
||||
*/
|
||||
private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
|
||||
exists(DataFlowCallable callable1 |
|
||||
isAdditionalFlowStep(node1, node2, callable1, config) and
|
||||
node2.getEnclosingCallable() != callable1 and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
)
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -454,8 +444,8 @@ private module Stage1 {
|
||||
// read
|
||||
exists(Node mid, Content c |
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -481,18 +471,18 @@ private module Stage1 {
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
fwdFlow(node, unbind(config)) and
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, _, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
revFlow(mid, toReturn, config) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
store(node, tc, mid, _) and
|
||||
c = tc.getContent()
|
||||
)
|
||||
@@ -562,8 +552,8 @@ private module Stage1 {
|
||||
Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
exists(Content c |
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(node2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(node2, pragma[only_bind_into](config)) and
|
||||
store(node1, tc, node2, contentType) and
|
||||
c = tc.getContent() and
|
||||
exists(ap1)
|
||||
@@ -572,8 +562,8 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(n2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2)
|
||||
}
|
||||
|
||||
@@ -598,7 +588,7 @@ private module Stage1 {
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
throughFlowNodeCand(ret, config) and
|
||||
callable = ret.getEnclosingCallable() and
|
||||
callable = getNodeEnclosingCallable(ret) and
|
||||
kind = ret.getKind()
|
||||
)
|
||||
}
|
||||
@@ -611,7 +601,7 @@ private module Stage1 {
|
||||
exists(ReturnKindExt kind |
|
||||
throughFlowNodeCand(p, config) and
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
p.getEnclosingCallable() = c and
|
||||
getNodeEnclosingCallable(p) = c and
|
||||
exists(ap) and
|
||||
// we don't expect a parameter to return stored in itself
|
||||
not exists(int pos |
|
||||
@@ -636,9 +626,6 @@ private module Stage1 {
|
||||
/* End: Stage 1 logic. */
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
pragma[noinline]
|
||||
private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
|
||||
Stage1::revFlow(node2, config) and
|
||||
@@ -775,7 +762,7 @@ private module Stage2 {
|
||||
bindingset[result, ap]
|
||||
private ApApprox getApprox(Ap ap) { any() }
|
||||
|
||||
private ApNil getApNil(Node node) { any() }
|
||||
private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||
@@ -874,16 +861,16 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -963,7 +950,7 @@ private module Stage2 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -982,7 +969,7 @@ private module Stage2 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -1055,9 +1042,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1069,9 +1056,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1124,9 +1111,10 @@ private module Stage2 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1192,9 +1180,10 @@ private module Stage2 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ unbindBool(ap2), _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1213,13 +1202,13 @@ private module Stage2 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -1250,8 +1239,8 @@ private predicate flowOutOfCallNodeCand2(
|
||||
DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1260,8 +1249,8 @@ private predicate flowIntoCallNodeCand2(
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
private module LocalFlowBigStep {
|
||||
@@ -1316,8 +1305,8 @@ private module LocalFlowBigStep {
|
||||
pragma[noinline]
|
||||
private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
|
||||
additionalLocalFlowStepNodeCand1(node1, node2, config) and
|
||||
Stage2::revFlow(node1, _, _, false, config) and
|
||||
Stage2::revFlow(node2, _, _, false, unbind(config))
|
||||
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1334,7 +1323,7 @@ private module LocalFlowBigStep {
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
@@ -1345,24 +1334,24 @@ private module LocalFlowBigStep {
|
||||
t = getNodeType(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1394,7 +1383,9 @@ private module Stage3 {
|
||||
|
||||
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||
|
||||
private ApNil getApNil(Node node) { result = TFrontNil(getNodeType(node)) }
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||
@@ -1467,6 +1458,13 @@ private module Stage3 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -1478,7 +1476,7 @@ private module Stage3 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, unbindBool(getApprox(ap)), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -1502,16 +1500,16 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -1556,7 +1554,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, unbindBool(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -1591,7 +1589,7 @@ private module Stage3 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1610,7 +1608,7 @@ private module Stage3 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -1635,7 +1633,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindBool(getApprox(ap)), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1683,9 +1681,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1697,9 +1695,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1752,9 +1750,10 @@ private module Stage3 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1820,9 +1819,10 @@ private module Stage3 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1841,13 +1841,13 @@ private module Stage3 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -2087,7 +2087,9 @@ private module Stage4 {
|
||||
|
||||
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
|
||||
|
||||
private ApNil getApNil(Node node) { result = TNil(getNodeType(node)) }
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||
@@ -2131,8 +2133,11 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc, node.getEnclosingCallable())
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2147,8 +2152,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -2157,8 +2162,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
bindingset[node, ap]
|
||||
@@ -2173,6 +2178,13 @@ private module Stage4 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -2184,7 +2196,7 @@ private module Stage4 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, getApprox(ap), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -2208,16 +2220,16 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -2262,7 +2274,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -2297,7 +2309,7 @@ private module Stage4 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -2316,7 +2328,7 @@ private module Stage4 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -2341,7 +2353,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2389,9 +2401,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -2403,9 +2415,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -2458,9 +2470,10 @@ private module Stage4 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2526,9 +2539,10 @@ private module Stage4 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2547,13 +2561,13 @@ private module Stage4 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -2580,14 +2594,16 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
bindingset[conf, result]
|
||||
private Configuration unbind(Configuration conf) { result >= conf and result <= conf }
|
||||
private Configuration unbindConf(Configuration conf) {
|
||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||
}
|
||||
|
||||
private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
|
||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
||||
Stage4::revFlow(n, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
getNodeEnclosingCallable(n) = c
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2750,13 +2766,13 @@ private newtype TPathNode =
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, cc, sc, ap) and
|
||||
config = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), unbind(config))
|
||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
|
||||
)
|
||||
} or
|
||||
TPathNodeSink(Node node, Configuration config) {
|
||||
config.isSink(node) and
|
||||
Stage4::revFlow(node, unbind(config)) and
|
||||
pragma[only_bind_into](config).isSink(node) and
|
||||
Stage4::revFlow(node, pragma[only_bind_into](config)) and
|
||||
(
|
||||
// A sink that is also a source ...
|
||||
config.isSource(node)
|
||||
@@ -2764,7 +2780,7 @@ private newtype TPathNode =
|
||||
// ... or a sink that can be reached from a source
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, _, _, TAccessPathNil(_)) and
|
||||
config = unbind(mid.getConfiguration())
|
||||
pragma[only_bind_into](config) = mid.getConfiguration()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -3061,7 +3077,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
|
||||
private PathNodeMid getSuccMid() {
|
||||
pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
|
||||
result.getConfiguration() = unbind(this.getConfiguration())
|
||||
result.getConfiguration() = unbindConf(this.getConfiguration())
|
||||
}
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
@@ -3073,7 +3089,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
mid = getSuccMid() and
|
||||
mid.getNode() = sink.getNode() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
sink.getConfiguration() = unbind(mid.getConfiguration()) and
|
||||
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
|
||||
result = sink
|
||||
)
|
||||
}
|
||||
@@ -3116,7 +3132,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
localCC = getLocalCallContext(cc, getNodeEnclosingCallable(midnode)) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
@@ -3304,7 +3320,7 @@ private predicate pathThroughCallable0(
|
||||
) {
|
||||
exists(CallContext innercc, SummaryCtx sc |
|
||||
pathIntoCallable(mid, _, cc, innercc, sc, call) and
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration()))
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3316,7 +3332,7 @@ pragma[noinline]
|
||||
private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
|
||||
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration()))
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3402,14 +3418,14 @@ private module FlowExploration {
|
||||
// flow out of a callable
|
||||
viableReturnPosOut(_, getReturnPosition(node1), node2)
|
||||
|
|
||||
c1 = node1.getEnclosingCallable() and
|
||||
c2 = node2.getEnclosingCallable() and
|
||||
c1 = getNodeEnclosingCallable(node1) and
|
||||
c2 = getNodeEnclosingCallable(node2) and
|
||||
c1 != c2
|
||||
)
|
||||
}
|
||||
|
||||
private predicate interestingCallableSrc(DataFlowCallable c, Configuration config) {
|
||||
exists(Node n | config.isSource(n) and c = n.getEnclosingCallable())
|
||||
exists(Node n | config.isSource(n) and c = getNodeEnclosingCallable(n))
|
||||
or
|
||||
exists(DataFlowCallable mid |
|
||||
interestingCallableSrc(mid, config) and callableStep(mid, c, config)
|
||||
@@ -3417,7 +3433,7 @@ private module FlowExploration {
|
||||
}
|
||||
|
||||
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
|
||||
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
|
||||
exists(Node n | config.isSink(n) and c = getNodeEnclosingCallable(n))
|
||||
or
|
||||
exists(DataFlowCallable mid |
|
||||
interestingCallableSink(mid, config) and callableStep(c, mid, config)
|
||||
@@ -3439,20 +3455,20 @@ private module FlowExploration {
|
||||
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
|
||||
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
|
||||
callableStep(c1, c2, config) and
|
||||
ce1 = TCallable(c1, config) and
|
||||
ce2 = TCallable(c2, unbind(config))
|
||||
ce1 = TCallable(c1, pragma[only_bind_into](config)) and
|
||||
ce2 = TCallable(c2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node n, Configuration config |
|
||||
ce1 = TCallableSrc() and
|
||||
config.isSource(n) and
|
||||
ce2 = TCallable(n.getEnclosingCallable(), config)
|
||||
ce2 = TCallable(getNodeEnclosingCallable(n), config)
|
||||
)
|
||||
or
|
||||
exists(Node n, Configuration config |
|
||||
ce2 = TCallableSink() and
|
||||
config.isSink(n) and
|
||||
ce1 = TCallable(n.getEnclosingCallable(), config)
|
||||
ce1 = TCallable(getNodeEnclosingCallable(n), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3583,7 +3599,7 @@ private module FlowExploration {
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
|
||||
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
} or
|
||||
TPartialPathNodeRev(
|
||||
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
|
||||
@@ -3600,7 +3616,7 @@ private module FlowExploration {
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3659,7 +3675,7 @@ private module FlowExploration {
|
||||
* of interprocedural steps.
|
||||
*/
|
||||
int getSourceDistance() {
|
||||
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
|
||||
result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3667,7 +3683,7 @@ private module FlowExploration {
|
||||
* of interprocedural steps.
|
||||
*/
|
||||
int getSinkDistance() {
|
||||
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
|
||||
result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
|
||||
@@ -207,23 +207,14 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) }
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate isAdditionalFlowStep(
|
||||
AdditionalFlowStepSource node1, Node node2, DataFlowCallable callable1, Configuration config
|
||||
) {
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
callable1 = node1.getEnclosingCallable()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow in one local step from `node1` to `node2`.
|
||||
*/
|
||||
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
|
||||
simpleLocalFlowStep(node1, node2) and
|
||||
(
|
||||
simpleLocalFlowStep(node1, node2) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -234,7 +225,8 @@ private predicate localFlowStep(Node node1, Node node2, Configuration config) {
|
||||
* Holds if the additional step from `node1` to `node2` does not jump between callables.
|
||||
*/
|
||||
private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
|
||||
isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -256,14 +248,12 @@ private predicate jumpStep(Node node1, Node node2, Configuration config) {
|
||||
* Holds if the additional step from `node1` to `node2` jumps between callables.
|
||||
*/
|
||||
private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
|
||||
exists(DataFlowCallable callable1 |
|
||||
isAdditionalFlowStep(node1, node2, callable1, config) and
|
||||
node2.getEnclosingCallable() != callable1 and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
)
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -454,8 +444,8 @@ private module Stage1 {
|
||||
// read
|
||||
exists(Node mid, Content c |
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -481,18 +471,18 @@ private module Stage1 {
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
fwdFlow(node, unbind(config)) and
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, _, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
revFlow(mid, toReturn, config) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
store(node, tc, mid, _) and
|
||||
c = tc.getContent()
|
||||
)
|
||||
@@ -562,8 +552,8 @@ private module Stage1 {
|
||||
Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
exists(Content c |
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(node2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(node2, pragma[only_bind_into](config)) and
|
||||
store(node1, tc, node2, contentType) and
|
||||
c = tc.getContent() and
|
||||
exists(ap1)
|
||||
@@ -572,8 +562,8 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(n2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2)
|
||||
}
|
||||
|
||||
@@ -598,7 +588,7 @@ private module Stage1 {
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
throughFlowNodeCand(ret, config) and
|
||||
callable = ret.getEnclosingCallable() and
|
||||
callable = getNodeEnclosingCallable(ret) and
|
||||
kind = ret.getKind()
|
||||
)
|
||||
}
|
||||
@@ -611,7 +601,7 @@ private module Stage1 {
|
||||
exists(ReturnKindExt kind |
|
||||
throughFlowNodeCand(p, config) and
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
p.getEnclosingCallable() = c and
|
||||
getNodeEnclosingCallable(p) = c and
|
||||
exists(ap) and
|
||||
// we don't expect a parameter to return stored in itself
|
||||
not exists(int pos |
|
||||
@@ -636,9 +626,6 @@ private module Stage1 {
|
||||
/* End: Stage 1 logic. */
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
pragma[noinline]
|
||||
private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
|
||||
Stage1::revFlow(node2, config) and
|
||||
@@ -775,7 +762,7 @@ private module Stage2 {
|
||||
bindingset[result, ap]
|
||||
private ApApprox getApprox(Ap ap) { any() }
|
||||
|
||||
private ApNil getApNil(Node node) { any() }
|
||||
private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||
@@ -874,16 +861,16 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -963,7 +950,7 @@ private module Stage2 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -982,7 +969,7 @@ private module Stage2 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -1055,9 +1042,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1069,9 +1056,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1124,9 +1111,10 @@ private module Stage2 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1192,9 +1180,10 @@ private module Stage2 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ unbindBool(ap2), _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1213,13 +1202,13 @@ private module Stage2 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -1250,8 +1239,8 @@ private predicate flowOutOfCallNodeCand2(
|
||||
DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1260,8 +1249,8 @@ private predicate flowIntoCallNodeCand2(
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
private module LocalFlowBigStep {
|
||||
@@ -1316,8 +1305,8 @@ private module LocalFlowBigStep {
|
||||
pragma[noinline]
|
||||
private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
|
||||
additionalLocalFlowStepNodeCand1(node1, node2, config) and
|
||||
Stage2::revFlow(node1, _, _, false, config) and
|
||||
Stage2::revFlow(node2, _, _, false, unbind(config))
|
||||
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1334,7 +1323,7 @@ private module LocalFlowBigStep {
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
@@ -1345,24 +1334,24 @@ private module LocalFlowBigStep {
|
||||
t = getNodeType(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1394,7 +1383,9 @@ private module Stage3 {
|
||||
|
||||
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||
|
||||
private ApNil getApNil(Node node) { result = TFrontNil(getNodeType(node)) }
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||
@@ -1467,6 +1458,13 @@ private module Stage3 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -1478,7 +1476,7 @@ private module Stage3 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, unbindBool(getApprox(ap)), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -1502,16 +1500,16 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -1556,7 +1554,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, unbindBool(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -1591,7 +1589,7 @@ private module Stage3 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1610,7 +1608,7 @@ private module Stage3 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -1635,7 +1633,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindBool(getApprox(ap)), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1683,9 +1681,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1697,9 +1695,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1752,9 +1750,10 @@ private module Stage3 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1820,9 +1819,10 @@ private module Stage3 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1841,13 +1841,13 @@ private module Stage3 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -2087,7 +2087,9 @@ private module Stage4 {
|
||||
|
||||
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
|
||||
|
||||
private ApNil getApNil(Node node) { result = TNil(getNodeType(node)) }
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||
@@ -2131,8 +2133,11 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc, node.getEnclosingCallable())
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2147,8 +2152,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -2157,8 +2162,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
bindingset[node, ap]
|
||||
@@ -2173,6 +2178,13 @@ private module Stage4 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -2184,7 +2196,7 @@ private module Stage4 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, getApprox(ap), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -2208,16 +2220,16 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -2262,7 +2274,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -2297,7 +2309,7 @@ private module Stage4 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -2316,7 +2328,7 @@ private module Stage4 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -2341,7 +2353,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2389,9 +2401,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -2403,9 +2415,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -2458,9 +2470,10 @@ private module Stage4 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2526,9 +2539,10 @@ private module Stage4 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2547,13 +2561,13 @@ private module Stage4 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -2580,14 +2594,16 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
bindingset[conf, result]
|
||||
private Configuration unbind(Configuration conf) { result >= conf and result <= conf }
|
||||
private Configuration unbindConf(Configuration conf) {
|
||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||
}
|
||||
|
||||
private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
|
||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
||||
Stage4::revFlow(n, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
getNodeEnclosingCallable(n) = c
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2750,13 +2766,13 @@ private newtype TPathNode =
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, cc, sc, ap) and
|
||||
config = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), unbind(config))
|
||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
|
||||
)
|
||||
} or
|
||||
TPathNodeSink(Node node, Configuration config) {
|
||||
config.isSink(node) and
|
||||
Stage4::revFlow(node, unbind(config)) and
|
||||
pragma[only_bind_into](config).isSink(node) and
|
||||
Stage4::revFlow(node, pragma[only_bind_into](config)) and
|
||||
(
|
||||
// A sink that is also a source ...
|
||||
config.isSource(node)
|
||||
@@ -2764,7 +2780,7 @@ private newtype TPathNode =
|
||||
// ... or a sink that can be reached from a source
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, _, _, TAccessPathNil(_)) and
|
||||
config = unbind(mid.getConfiguration())
|
||||
pragma[only_bind_into](config) = mid.getConfiguration()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -3061,7 +3077,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
|
||||
private PathNodeMid getSuccMid() {
|
||||
pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
|
||||
result.getConfiguration() = unbind(this.getConfiguration())
|
||||
result.getConfiguration() = unbindConf(this.getConfiguration())
|
||||
}
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
@@ -3073,7 +3089,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
mid = getSuccMid() and
|
||||
mid.getNode() = sink.getNode() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
sink.getConfiguration() = unbind(mid.getConfiguration()) and
|
||||
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
|
||||
result = sink
|
||||
)
|
||||
}
|
||||
@@ -3116,7 +3132,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
localCC = getLocalCallContext(cc, getNodeEnclosingCallable(midnode)) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
@@ -3304,7 +3320,7 @@ private predicate pathThroughCallable0(
|
||||
) {
|
||||
exists(CallContext innercc, SummaryCtx sc |
|
||||
pathIntoCallable(mid, _, cc, innercc, sc, call) and
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration()))
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3316,7 +3332,7 @@ pragma[noinline]
|
||||
private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
|
||||
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration()))
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3402,14 +3418,14 @@ private module FlowExploration {
|
||||
// flow out of a callable
|
||||
viableReturnPosOut(_, getReturnPosition(node1), node2)
|
||||
|
|
||||
c1 = node1.getEnclosingCallable() and
|
||||
c2 = node2.getEnclosingCallable() and
|
||||
c1 = getNodeEnclosingCallable(node1) and
|
||||
c2 = getNodeEnclosingCallable(node2) and
|
||||
c1 != c2
|
||||
)
|
||||
}
|
||||
|
||||
private predicate interestingCallableSrc(DataFlowCallable c, Configuration config) {
|
||||
exists(Node n | config.isSource(n) and c = n.getEnclosingCallable())
|
||||
exists(Node n | config.isSource(n) and c = getNodeEnclosingCallable(n))
|
||||
or
|
||||
exists(DataFlowCallable mid |
|
||||
interestingCallableSrc(mid, config) and callableStep(mid, c, config)
|
||||
@@ -3417,7 +3433,7 @@ private module FlowExploration {
|
||||
}
|
||||
|
||||
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
|
||||
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
|
||||
exists(Node n | config.isSink(n) and c = getNodeEnclosingCallable(n))
|
||||
or
|
||||
exists(DataFlowCallable mid |
|
||||
interestingCallableSink(mid, config) and callableStep(c, mid, config)
|
||||
@@ -3439,20 +3455,20 @@ private module FlowExploration {
|
||||
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
|
||||
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
|
||||
callableStep(c1, c2, config) and
|
||||
ce1 = TCallable(c1, config) and
|
||||
ce2 = TCallable(c2, unbind(config))
|
||||
ce1 = TCallable(c1, pragma[only_bind_into](config)) and
|
||||
ce2 = TCallable(c2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node n, Configuration config |
|
||||
ce1 = TCallableSrc() and
|
||||
config.isSource(n) and
|
||||
ce2 = TCallable(n.getEnclosingCallable(), config)
|
||||
ce2 = TCallable(getNodeEnclosingCallable(n), config)
|
||||
)
|
||||
or
|
||||
exists(Node n, Configuration config |
|
||||
ce2 = TCallableSink() and
|
||||
config.isSink(n) and
|
||||
ce1 = TCallable(n.getEnclosingCallable(), config)
|
||||
ce1 = TCallable(getNodeEnclosingCallable(n), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3583,7 +3599,7 @@ private module FlowExploration {
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
|
||||
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
} or
|
||||
TPartialPathNodeRev(
|
||||
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
|
||||
@@ -3600,7 +3616,7 @@ private module FlowExploration {
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3659,7 +3675,7 @@ private module FlowExploration {
|
||||
* of interprocedural steps.
|
||||
*/
|
||||
int getSourceDistance() {
|
||||
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
|
||||
result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3667,7 +3683,7 @@ private module FlowExploration {
|
||||
* of interprocedural steps.
|
||||
*/
|
||||
int getSinkDistance() {
|
||||
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
|
||||
result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
|
||||
@@ -207,23 +207,14 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) }
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate isAdditionalFlowStep(
|
||||
AdditionalFlowStepSource node1, Node node2, DataFlowCallable callable1, Configuration config
|
||||
) {
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
callable1 = node1.getEnclosingCallable()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow in one local step from `node1` to `node2`.
|
||||
*/
|
||||
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
|
||||
simpleLocalFlowStep(node1, node2) and
|
||||
(
|
||||
simpleLocalFlowStep(node1, node2) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -234,7 +225,8 @@ private predicate localFlowStep(Node node1, Node node2, Configuration config) {
|
||||
* Holds if the additional step from `node1` to `node2` does not jump between callables.
|
||||
*/
|
||||
private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
|
||||
isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -256,14 +248,12 @@ private predicate jumpStep(Node node1, Node node2, Configuration config) {
|
||||
* Holds if the additional step from `node1` to `node2` jumps between callables.
|
||||
*/
|
||||
private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
|
||||
exists(DataFlowCallable callable1 |
|
||||
isAdditionalFlowStep(node1, node2, callable1, config) and
|
||||
node2.getEnclosingCallable() != callable1 and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
)
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -454,8 +444,8 @@ private module Stage1 {
|
||||
// read
|
||||
exists(Node mid, Content c |
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -481,18 +471,18 @@ private module Stage1 {
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
fwdFlow(node, unbind(config)) and
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, _, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
revFlow(mid, toReturn, config) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
store(node, tc, mid, _) and
|
||||
c = tc.getContent()
|
||||
)
|
||||
@@ -562,8 +552,8 @@ private module Stage1 {
|
||||
Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
exists(Content c |
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(node2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(node2, pragma[only_bind_into](config)) and
|
||||
store(node1, tc, node2, contentType) and
|
||||
c = tc.getContent() and
|
||||
exists(ap1)
|
||||
@@ -572,8 +562,8 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(n2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2)
|
||||
}
|
||||
|
||||
@@ -598,7 +588,7 @@ private module Stage1 {
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
throughFlowNodeCand(ret, config) and
|
||||
callable = ret.getEnclosingCallable() and
|
||||
callable = getNodeEnclosingCallable(ret) and
|
||||
kind = ret.getKind()
|
||||
)
|
||||
}
|
||||
@@ -611,7 +601,7 @@ private module Stage1 {
|
||||
exists(ReturnKindExt kind |
|
||||
throughFlowNodeCand(p, config) and
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
p.getEnclosingCallable() = c and
|
||||
getNodeEnclosingCallable(p) = c and
|
||||
exists(ap) and
|
||||
// we don't expect a parameter to return stored in itself
|
||||
not exists(int pos |
|
||||
@@ -636,9 +626,6 @@ private module Stage1 {
|
||||
/* End: Stage 1 logic. */
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
pragma[noinline]
|
||||
private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
|
||||
Stage1::revFlow(node2, config) and
|
||||
@@ -775,7 +762,7 @@ private module Stage2 {
|
||||
bindingset[result, ap]
|
||||
private ApApprox getApprox(Ap ap) { any() }
|
||||
|
||||
private ApNil getApNil(Node node) { any() }
|
||||
private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||
@@ -874,16 +861,16 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -963,7 +950,7 @@ private module Stage2 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -982,7 +969,7 @@ private module Stage2 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -1055,9 +1042,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1069,9 +1056,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1124,9 +1111,10 @@ private module Stage2 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1192,9 +1180,10 @@ private module Stage2 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ unbindBool(ap2), _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1213,13 +1202,13 @@ private module Stage2 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -1250,8 +1239,8 @@ private predicate flowOutOfCallNodeCand2(
|
||||
DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1260,8 +1249,8 @@ private predicate flowIntoCallNodeCand2(
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
private module LocalFlowBigStep {
|
||||
@@ -1316,8 +1305,8 @@ private module LocalFlowBigStep {
|
||||
pragma[noinline]
|
||||
private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
|
||||
additionalLocalFlowStepNodeCand1(node1, node2, config) and
|
||||
Stage2::revFlow(node1, _, _, false, config) and
|
||||
Stage2::revFlow(node2, _, _, false, unbind(config))
|
||||
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1334,7 +1323,7 @@ private module LocalFlowBigStep {
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
@@ -1345,24 +1334,24 @@ private module LocalFlowBigStep {
|
||||
t = getNodeType(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1394,7 +1383,9 @@ private module Stage3 {
|
||||
|
||||
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||
|
||||
private ApNil getApNil(Node node) { result = TFrontNil(getNodeType(node)) }
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||
@@ -1467,6 +1458,13 @@ private module Stage3 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -1478,7 +1476,7 @@ private module Stage3 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, unbindBool(getApprox(ap)), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -1502,16 +1500,16 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -1556,7 +1554,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, unbindBool(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -1591,7 +1589,7 @@ private module Stage3 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1610,7 +1608,7 @@ private module Stage3 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -1635,7 +1633,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindBool(getApprox(ap)), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1683,9 +1681,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1697,9 +1695,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1752,9 +1750,10 @@ private module Stage3 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1820,9 +1819,10 @@ private module Stage3 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1841,13 +1841,13 @@ private module Stage3 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -2087,7 +2087,9 @@ private module Stage4 {
|
||||
|
||||
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
|
||||
|
||||
private ApNil getApNil(Node node) { result = TNil(getNodeType(node)) }
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||
@@ -2131,8 +2133,11 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc, node.getEnclosingCallable())
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2147,8 +2152,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -2157,8 +2162,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
bindingset[node, ap]
|
||||
@@ -2173,6 +2178,13 @@ private module Stage4 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -2184,7 +2196,7 @@ private module Stage4 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, getApprox(ap), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -2208,16 +2220,16 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -2262,7 +2274,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -2297,7 +2309,7 @@ private module Stage4 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -2316,7 +2328,7 @@ private module Stage4 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -2341,7 +2353,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2389,9 +2401,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -2403,9 +2415,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -2458,9 +2470,10 @@ private module Stage4 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2526,9 +2539,10 @@ private module Stage4 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2547,13 +2561,13 @@ private module Stage4 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -2580,14 +2594,16 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
bindingset[conf, result]
|
||||
private Configuration unbind(Configuration conf) { result >= conf and result <= conf }
|
||||
private Configuration unbindConf(Configuration conf) {
|
||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||
}
|
||||
|
||||
private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
|
||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
||||
Stage4::revFlow(n, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
getNodeEnclosingCallable(n) = c
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2750,13 +2766,13 @@ private newtype TPathNode =
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, cc, sc, ap) and
|
||||
config = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), unbind(config))
|
||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
|
||||
)
|
||||
} or
|
||||
TPathNodeSink(Node node, Configuration config) {
|
||||
config.isSink(node) and
|
||||
Stage4::revFlow(node, unbind(config)) and
|
||||
pragma[only_bind_into](config).isSink(node) and
|
||||
Stage4::revFlow(node, pragma[only_bind_into](config)) and
|
||||
(
|
||||
// A sink that is also a source ...
|
||||
config.isSource(node)
|
||||
@@ -2764,7 +2780,7 @@ private newtype TPathNode =
|
||||
// ... or a sink that can be reached from a source
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, _, _, TAccessPathNil(_)) and
|
||||
config = unbind(mid.getConfiguration())
|
||||
pragma[only_bind_into](config) = mid.getConfiguration()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -3061,7 +3077,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
|
||||
private PathNodeMid getSuccMid() {
|
||||
pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
|
||||
result.getConfiguration() = unbind(this.getConfiguration())
|
||||
result.getConfiguration() = unbindConf(this.getConfiguration())
|
||||
}
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
@@ -3073,7 +3089,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
mid = getSuccMid() and
|
||||
mid.getNode() = sink.getNode() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
sink.getConfiguration() = unbind(mid.getConfiguration()) and
|
||||
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
|
||||
result = sink
|
||||
)
|
||||
}
|
||||
@@ -3116,7 +3132,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
localCC = getLocalCallContext(cc, getNodeEnclosingCallable(midnode)) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
@@ -3304,7 +3320,7 @@ private predicate pathThroughCallable0(
|
||||
) {
|
||||
exists(CallContext innercc, SummaryCtx sc |
|
||||
pathIntoCallable(mid, _, cc, innercc, sc, call) and
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration()))
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3316,7 +3332,7 @@ pragma[noinline]
|
||||
private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
|
||||
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration()))
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3402,14 +3418,14 @@ private module FlowExploration {
|
||||
// flow out of a callable
|
||||
viableReturnPosOut(_, getReturnPosition(node1), node2)
|
||||
|
|
||||
c1 = node1.getEnclosingCallable() and
|
||||
c2 = node2.getEnclosingCallable() and
|
||||
c1 = getNodeEnclosingCallable(node1) and
|
||||
c2 = getNodeEnclosingCallable(node2) and
|
||||
c1 != c2
|
||||
)
|
||||
}
|
||||
|
||||
private predicate interestingCallableSrc(DataFlowCallable c, Configuration config) {
|
||||
exists(Node n | config.isSource(n) and c = n.getEnclosingCallable())
|
||||
exists(Node n | config.isSource(n) and c = getNodeEnclosingCallable(n))
|
||||
or
|
||||
exists(DataFlowCallable mid |
|
||||
interestingCallableSrc(mid, config) and callableStep(mid, c, config)
|
||||
@@ -3417,7 +3433,7 @@ private module FlowExploration {
|
||||
}
|
||||
|
||||
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
|
||||
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
|
||||
exists(Node n | config.isSink(n) and c = getNodeEnclosingCallable(n))
|
||||
or
|
||||
exists(DataFlowCallable mid |
|
||||
interestingCallableSink(mid, config) and callableStep(c, mid, config)
|
||||
@@ -3439,20 +3455,20 @@ private module FlowExploration {
|
||||
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
|
||||
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
|
||||
callableStep(c1, c2, config) and
|
||||
ce1 = TCallable(c1, config) and
|
||||
ce2 = TCallable(c2, unbind(config))
|
||||
ce1 = TCallable(c1, pragma[only_bind_into](config)) and
|
||||
ce2 = TCallable(c2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node n, Configuration config |
|
||||
ce1 = TCallableSrc() and
|
||||
config.isSource(n) and
|
||||
ce2 = TCallable(n.getEnclosingCallable(), config)
|
||||
ce2 = TCallable(getNodeEnclosingCallable(n), config)
|
||||
)
|
||||
or
|
||||
exists(Node n, Configuration config |
|
||||
ce2 = TCallableSink() and
|
||||
config.isSink(n) and
|
||||
ce1 = TCallable(n.getEnclosingCallable(), config)
|
||||
ce1 = TCallable(getNodeEnclosingCallable(n), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3583,7 +3599,7 @@ private module FlowExploration {
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
|
||||
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
} or
|
||||
TPartialPathNodeRev(
|
||||
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
|
||||
@@ -3600,7 +3616,7 @@ private module FlowExploration {
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3659,7 +3675,7 @@ private module FlowExploration {
|
||||
* of interprocedural steps.
|
||||
*/
|
||||
int getSourceDistance() {
|
||||
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
|
||||
result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3667,7 +3683,7 @@ private module FlowExploration {
|
||||
* of interprocedural steps.
|
||||
*/
|
||||
int getSinkDistance() {
|
||||
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
|
||||
result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
|
||||
@@ -26,15 +26,243 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
|
||||
tupleLimit = 1000
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a simple data-flow analysis for resolving lambda calls. The analysis
|
||||
* currently excludes read-steps, store-steps, and flow-through.
|
||||
*
|
||||
* The analysis uses non-linear recursion: When computing a flow path in or out
|
||||
* of a call, we use the results of the analysis recursively to resolve lamba
|
||||
* calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly.
|
||||
*/
|
||||
private module LambdaFlow {
|
||||
private predicate viableParamNonLambda(DataFlowCall call, int i, ParameterNode p) {
|
||||
p.isParameterOf(viableCallable(call), i)
|
||||
}
|
||||
|
||||
private predicate viableParamLambda(DataFlowCall call, int i, ParameterNode p) {
|
||||
p.isParameterOf(viableCallableLambda(call, _), i)
|
||||
}
|
||||
|
||||
private predicate viableParamArgNonLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
|
||||
exists(int i |
|
||||
viableParamNonLambda(call, i, p) and
|
||||
arg.argumentOf(call, i)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate viableParamArgLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
|
||||
exists(int i |
|
||||
viableParamLambda(call, i, p) and
|
||||
arg.argumentOf(call, i)
|
||||
)
|
||||
}
|
||||
|
||||
private newtype TReturnPositionSimple =
|
||||
TReturnPositionSimple0(DataFlowCallable c, ReturnKind kind) {
|
||||
exists(ReturnNode ret |
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
kind = ret.getKind()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private TReturnPositionSimple getReturnPositionSimple(ReturnNode ret, ReturnKind kind) {
|
||||
result = TReturnPositionSimple0(getNodeEnclosingCallable(ret), kind)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private TReturnPositionSimple viableReturnPosNonLambda(DataFlowCall call, ReturnKind kind) {
|
||||
result = TReturnPositionSimple0(viableCallable(call), kind)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private TReturnPositionSimple viableReturnPosLambda(
|
||||
DataFlowCall call, DataFlowCallOption lastCall, ReturnKind kind
|
||||
) {
|
||||
result = TReturnPositionSimple0(viableCallableLambda(call, lastCall), kind)
|
||||
}
|
||||
|
||||
private predicate viableReturnPosOutNonLambda(
|
||||
DataFlowCall call, TReturnPositionSimple pos, OutNode out
|
||||
) {
|
||||
exists(ReturnKind kind |
|
||||
pos = viableReturnPosNonLambda(call, kind) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate viableReturnPosOutLambda(
|
||||
DataFlowCall call, DataFlowCallOption lastCall, TReturnPositionSimple pos, OutNode out
|
||||
) {
|
||||
exists(ReturnKind kind |
|
||||
pos = viableReturnPosLambda(call, lastCall, kind) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow (inter-procedurally) from `node` (of type `t`) to
|
||||
* the lambda call `lambdaCall`.
|
||||
*
|
||||
* The parameter `toReturn` indicates whether the path from `node` to
|
||||
* `lambdaCall` goes through a return, and `toJump` whether the path goes
|
||||
* through a jump step.
|
||||
*
|
||||
* The call context `lastCall` records the last call on the path from `node`
|
||||
* to `lambdaCall`, if any. That is, `lastCall` is able to target the enclosing
|
||||
* callable of `lambdaCall`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlow(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn,
|
||||
boolean toJump, DataFlowCallOption lastCall
|
||||
) {
|
||||
revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and
|
||||
if node instanceof CastNode or node instanceof ArgumentNode or node instanceof ReturnNode
|
||||
then compatibleTypes(t, getNodeType(node))
|
||||
else any()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlow0(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn,
|
||||
boolean toJump, DataFlowCallOption lastCall
|
||||
) {
|
||||
lambdaCall(lambdaCall, kind, node) and
|
||||
t = getNodeType(node) and
|
||||
toReturn = false and
|
||||
toJump = false and
|
||||
lastCall = TDataFlowCallNone()
|
||||
or
|
||||
// local flow
|
||||
exists(Node mid, DataFlowType t0 |
|
||||
revLambdaFlow(lambdaCall, kind, mid, t0, toReturn, toJump, lastCall)
|
||||
|
|
||||
simpleLocalFlowStep(node, mid) and
|
||||
t = t0
|
||||
or
|
||||
exists(boolean preservesValue |
|
||||
additionalLambdaFlowStep(node, mid, preservesValue) and
|
||||
getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid)
|
||||
|
|
||||
preservesValue = false and
|
||||
t = getNodeType(node)
|
||||
or
|
||||
preservesValue = true and
|
||||
t = t0
|
||||
)
|
||||
)
|
||||
or
|
||||
// jump step
|
||||
exists(Node mid, DataFlowType t0 |
|
||||
revLambdaFlow(lambdaCall, kind, mid, t0, _, _, _) and
|
||||
toReturn = false and
|
||||
toJump = true and
|
||||
lastCall = TDataFlowCallNone()
|
||||
|
|
||||
jumpStep(node, mid) and
|
||||
t = t0
|
||||
or
|
||||
exists(boolean preservesValue |
|
||||
additionalLambdaFlowStep(node, mid, preservesValue) and
|
||||
getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid)
|
||||
|
|
||||
preservesValue = false and
|
||||
t = getNodeType(node)
|
||||
or
|
||||
preservesValue = true and
|
||||
t = t0
|
||||
)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(ParameterNode p, DataFlowCallOption lastCall0, DataFlowCall call |
|
||||
revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and
|
||||
(
|
||||
if lastCall0 = TDataFlowCallNone() and toJump = false
|
||||
then lastCall = TDataFlowCallSome(call)
|
||||
else lastCall = lastCall0
|
||||
) and
|
||||
toReturn = false
|
||||
|
|
||||
viableParamArgNonLambda(call, p, node)
|
||||
or
|
||||
viableParamArgLambda(call, p, node) // non-linear recursion
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(TReturnPositionSimple pos |
|
||||
revLambdaFlowOut(lambdaCall, kind, pos, t, toJump, lastCall) and
|
||||
getReturnPositionSimple(node, node.(ReturnNode).getKind()) = pos and
|
||||
toReturn = true
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlowOutLambdaCall(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, OutNode out, DataFlowType t, boolean toJump,
|
||||
DataFlowCall call, DataFlowCallOption lastCall
|
||||
) {
|
||||
revLambdaFlow(lambdaCall, kind, out, t, _, toJump, lastCall) and
|
||||
exists(ReturnKindExt rk |
|
||||
out = rk.getAnOutNode(call) and
|
||||
lambdaCall(call, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlowOut(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, TReturnPositionSimple pos, DataFlowType t,
|
||||
boolean toJump, DataFlowCallOption lastCall
|
||||
) {
|
||||
exists(DataFlowCall call, OutNode out |
|
||||
revLambdaFlow(lambdaCall, kind, out, t, _, toJump, lastCall) and
|
||||
viableReturnPosOutNonLambda(call, pos, out)
|
||||
or
|
||||
// non-linear recursion
|
||||
revLambdaFlowOutLambdaCall(lambdaCall, kind, out, t, toJump, call, lastCall) and
|
||||
viableReturnPosOutLambda(call, _, pos, out)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlowIn(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, ParameterNode p, DataFlowType t, boolean toJump,
|
||||
DataFlowCallOption lastCall
|
||||
) {
|
||||
revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall)
|
||||
}
|
||||
}
|
||||
|
||||
private DataFlowCallable viableCallableExt(DataFlowCall call) {
|
||||
result = viableCallable(call)
|
||||
or
|
||||
result = viableCallableLambda(call, _)
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
/**
|
||||
* Gets a viable target for the lambda call `call`.
|
||||
*
|
||||
* `lastCall` records the call required to reach `call` in order for the result
|
||||
* to be a viable target, if any.
|
||||
*/
|
||||
cached
|
||||
DataFlowCallable viableCallableLambda(DataFlowCall call, DataFlowCallOption lastCall) {
|
||||
exists(Node creation, LambdaCallKind kind |
|
||||
LambdaFlow::revLambdaFlow(call, kind, creation, _, _, _, lastCall) and
|
||||
lambdaCreation(creation, kind, result)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `p` is the `i`th parameter of a viable dispatch target of `call`.
|
||||
* The instance parameter is considered to have index `-1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate viableParam(DataFlowCall call, int i, ParameterNode p) {
|
||||
p.isParameterOf(viableCallable(call), i)
|
||||
p.isParameterOf(viableCallableExt(call), i)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,7 +280,7 @@ private module Cached {
|
||||
|
||||
pragma[nomagic]
|
||||
private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) {
|
||||
viableCallable(call) = result.getCallable() and
|
||||
viableCallableExt(call) = result.getCallable() and
|
||||
kind = result.getKind()
|
||||
}
|
||||
|
||||
@@ -317,6 +545,35 @@ private module Cached {
|
||||
|
||||
cached
|
||||
private module DispatchWithCallContext {
|
||||
/**
|
||||
* Holds if the set of viable implementations that can be called by `call`
|
||||
* might be improved by knowing the call context.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) {
|
||||
mayBenefitFromCallContext(call, callable)
|
||||
or
|
||||
callable = call.getEnclosingCallable() and
|
||||
exists(viableCallableLambda(call, TDataFlowCallSome(_)))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) {
|
||||
result = viableImplInCallContext(call, ctx)
|
||||
or
|
||||
result = viableCallableLambda(call, TDataFlowCallSome(ctx))
|
||||
or
|
||||
exists(DataFlowCallable enclosing |
|
||||
mayBenefitFromCallContextExt(call, enclosing) and
|
||||
enclosing = viableCallableExt(ctx) and
|
||||
result = viableCallableLambda(call, TDataFlowCallNone())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the call context `ctx` reduces the set of viable run-time
|
||||
* dispatch targets of call `call` in `c`.
|
||||
@@ -324,10 +581,10 @@ private module Cached {
|
||||
cached
|
||||
predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) {
|
||||
exists(int tgts, int ctxtgts |
|
||||
mayBenefitFromCallContext(call, c) and
|
||||
c = viableCallable(ctx) and
|
||||
ctxtgts = count(viableImplInCallContext(call, ctx)) and
|
||||
tgts = strictcount(viableCallable(call)) and
|
||||
mayBenefitFromCallContextExt(call, c) and
|
||||
c = viableCallableExt(ctx) and
|
||||
ctxtgts = count(viableImplInCallContextExt(call, ctx)) and
|
||||
tgts = strictcount(viableCallableExt(call)) and
|
||||
ctxtgts < tgts
|
||||
)
|
||||
}
|
||||
@@ -339,7 +596,7 @@ private module Cached {
|
||||
*/
|
||||
cached
|
||||
DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
|
||||
result = viableImplInCallContext(call, ctx) and
|
||||
result = viableImplInCallContextExt(call, ctx) and
|
||||
reducedViableImplInCallContext(call, _, ctx)
|
||||
}
|
||||
|
||||
@@ -351,10 +608,10 @@ private module Cached {
|
||||
cached
|
||||
predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) {
|
||||
exists(int tgts, int ctxtgts |
|
||||
mayBenefitFromCallContext(call, _) and
|
||||
c = viableCallable(call) and
|
||||
ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and
|
||||
tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and
|
||||
mayBenefitFromCallContextExt(call, _) and
|
||||
c = viableCallableExt(call) and
|
||||
ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContextExt(call, ctx)) and
|
||||
tgts = strictcount(DataFlowCall ctx | viableCallableExt(ctx) = call.getEnclosingCallable()) and
|
||||
ctxtgts < tgts
|
||||
)
|
||||
}
|
||||
@@ -367,7 +624,7 @@ private module Cached {
|
||||
*/
|
||||
cached
|
||||
DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) {
|
||||
result = viableImplInCallContext(call, ctx) and
|
||||
result = viableImplInCallContextExt(call, ctx) and
|
||||
reducedViableImplInReturn(result, call)
|
||||
}
|
||||
}
|
||||
@@ -415,6 +672,30 @@ private module Cached {
|
||||
store(node1, tc.getContent(), node2, contentType, tc.getContainerType())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `fromNode` to `toNode` because they are the post-update
|
||||
* nodes of some function output and input respectively, where the output and input
|
||||
* are aliases. A typical example is a function returning `this`, implementing a fluent
|
||||
* interface.
|
||||
*/
|
||||
cached
|
||||
predicate reverseStepThroughInputOutputAlias(PostUpdateNode fromNode, PostUpdateNode toNode) {
|
||||
exists(Node fromPre, Node toPre |
|
||||
fromPre = fromNode.getPreUpdateNode() and
|
||||
toPre = toNode.getPreUpdateNode()
|
||||
|
|
||||
exists(DataFlowCall c |
|
||||
// Does the language-specific simpleLocalFlowStep already model flow
|
||||
// from function input to output?
|
||||
fromPre = getAnOutNode(c, _) and
|
||||
toPre.(ArgumentNode).argumentOf(c, _) and
|
||||
simpleLocalFlowStep(toPre.(ArgumentNode), fromPre)
|
||||
)
|
||||
or
|
||||
argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the call context `call` either improves virtual dispatch in
|
||||
* `callable` or if it allows us to prune unreachable nodes in `callable`.
|
||||
@@ -423,7 +704,7 @@ private module Cached {
|
||||
predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
|
||||
reducedViableImplInCallContext(_, callable, call)
|
||||
or
|
||||
exists(Node n | n.getEnclosingCallable() = callable | isUnreachableInCall(n, call))
|
||||
exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCall(n, call))
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -457,6 +738,11 @@ private module Cached {
|
||||
TBooleanNone() or
|
||||
TBooleanSome(boolean b) { b = true or b = false }
|
||||
|
||||
cached
|
||||
newtype TDataFlowCallOption =
|
||||
TDataFlowCallNone() or
|
||||
TDataFlowCallSome(DataFlowCall call)
|
||||
|
||||
cached
|
||||
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
|
||||
|
||||
@@ -568,7 +854,7 @@ class CallContextSomeCall extends CallContextCall, TSomeCall {
|
||||
override string toString() { result = "CcSomeCall" }
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) {
|
||||
exists(ParameterNode p | p.getEnclosingCallable() = callable)
|
||||
exists(ParameterNode p | getNodeEnclosingCallable(p) = callable)
|
||||
}
|
||||
|
||||
override predicate matchesCall(DataFlowCall call) { any() }
|
||||
@@ -613,7 +899,7 @@ class LocalCallContextSpecificCall extends LocalCallContext, TSpecificLocalCall
|
||||
}
|
||||
|
||||
private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) {
|
||||
exists(Node n | n.getEnclosingCallable() = callable and isUnreachableInCall(n, call))
|
||||
exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCall(n, call))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -722,9 +1008,22 @@ class ReturnPosition extends TReturnPosition0 {
|
||||
string toString() { result = "[" + kind + "] " + c }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the enclosing callable of `n`. Unlike `n.getEnclosingCallable()`, this
|
||||
* predicate ensures that joins go from `n` to the result instead of the other
|
||||
* way around.
|
||||
*/
|
||||
pragma[inline]
|
||||
DataFlowCallable getNodeEnclosingCallable(Node n) {
|
||||
exists(Node n0 |
|
||||
pragma[only_bind_into](n0) = n and
|
||||
pragma[only_bind_into](result) = n0.getEnclosingCallable()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private DataFlowCallable returnNodeGetEnclosingCallable(ReturnNodeExt ret) {
|
||||
result = ret.getEnclosingCallable()
|
||||
result = getNodeEnclosingCallable(ret)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -740,7 +1039,7 @@ ReturnPosition getReturnPosition(ReturnNodeExt ret) {
|
||||
|
||||
bindingset[cc, callable]
|
||||
predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall call) {
|
||||
cc instanceof CallContextAny and callable = viableCallable(call)
|
||||
cc instanceof CallContextAny and callable = viableCallableExt(call)
|
||||
or
|
||||
exists(DataFlowCallable c0, DataFlowCall call0 |
|
||||
call0.getEnclosingCallable() = callable and
|
||||
@@ -754,14 +1053,14 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
|
||||
exists(DataFlowCall ctx | cc = TSpecificCall(ctx) |
|
||||
if reducedViableImplInCallContext(call, _, ctx)
|
||||
then result = prunedViableImplInCallContext(call, ctx)
|
||||
else result = viableCallable(call)
|
||||
else result = viableCallableExt(call)
|
||||
)
|
||||
or
|
||||
result = viableCallable(call) and cc instanceof CallContextSomeCall
|
||||
result = viableCallableExt(call) and cc instanceof CallContextSomeCall
|
||||
or
|
||||
result = viableCallable(call) and cc instanceof CallContextAny
|
||||
result = viableCallableExt(call) and cc instanceof CallContextAny
|
||||
or
|
||||
result = viableCallable(call) and cc instanceof CallContextReturn
|
||||
result = viableCallableExt(call) and cc instanceof CallContextReturn
|
||||
}
|
||||
|
||||
predicate read = readStep/3;
|
||||
@@ -775,6 +1074,19 @@ class BooleanOption extends TBooleanOption {
|
||||
}
|
||||
}
|
||||
|
||||
/** An optional `DataFlowCall`. */
|
||||
class DataFlowCallOption extends TDataFlowCallOption {
|
||||
string toString() {
|
||||
this = TDataFlowCallNone() and
|
||||
result = "(none)"
|
||||
or
|
||||
exists(DataFlowCall call |
|
||||
this = TDataFlowCallSome(call) and
|
||||
result = call.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Content tagged with the type of a containing object. */
|
||||
class TypedContent extends MkTypedContent {
|
||||
private Content c;
|
||||
|
||||
@@ -207,23 +207,14 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) }
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate isAdditionalFlowStep(
|
||||
AdditionalFlowStepSource node1, Node node2, DataFlowCallable callable1, Configuration config
|
||||
) {
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
callable1 = node1.getEnclosingCallable()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow in one local step from `node1` to `node2`.
|
||||
*/
|
||||
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
|
||||
simpleLocalFlowStep(node1, node2) and
|
||||
(
|
||||
simpleLocalFlowStep(node1, node2) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -234,7 +225,8 @@ private predicate localFlowStep(Node node1, Node node2, Configuration config) {
|
||||
* Holds if the additional step from `node1` to `node2` does not jump between callables.
|
||||
*/
|
||||
private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
|
||||
isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -256,14 +248,12 @@ private predicate jumpStep(Node node1, Node node2, Configuration config) {
|
||||
* Holds if the additional step from `node1` to `node2` jumps between callables.
|
||||
*/
|
||||
private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
|
||||
exists(DataFlowCallable callable1 |
|
||||
isAdditionalFlowStep(node1, node2, callable1, config) and
|
||||
node2.getEnclosingCallable() != callable1 and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
)
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -454,8 +444,8 @@ private module Stage1 {
|
||||
// read
|
||||
exists(Node mid, Content c |
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -481,18 +471,18 @@ private module Stage1 {
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
fwdFlow(node, unbind(config)) and
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, _, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
revFlow(mid, toReturn, config) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
store(node, tc, mid, _) and
|
||||
c = tc.getContent()
|
||||
)
|
||||
@@ -562,8 +552,8 @@ private module Stage1 {
|
||||
Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
exists(Content c |
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(node2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(node2, pragma[only_bind_into](config)) and
|
||||
store(node1, tc, node2, contentType) and
|
||||
c = tc.getContent() and
|
||||
exists(ap1)
|
||||
@@ -572,8 +562,8 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(n2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2)
|
||||
}
|
||||
|
||||
@@ -598,7 +588,7 @@ private module Stage1 {
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
throughFlowNodeCand(ret, config) and
|
||||
callable = ret.getEnclosingCallable() and
|
||||
callable = getNodeEnclosingCallable(ret) and
|
||||
kind = ret.getKind()
|
||||
)
|
||||
}
|
||||
@@ -611,7 +601,7 @@ private module Stage1 {
|
||||
exists(ReturnKindExt kind |
|
||||
throughFlowNodeCand(p, config) and
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
p.getEnclosingCallable() = c and
|
||||
getNodeEnclosingCallable(p) = c and
|
||||
exists(ap) and
|
||||
// we don't expect a parameter to return stored in itself
|
||||
not exists(int pos |
|
||||
@@ -636,9 +626,6 @@ private module Stage1 {
|
||||
/* End: Stage 1 logic. */
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
pragma[noinline]
|
||||
private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
|
||||
Stage1::revFlow(node2, config) and
|
||||
@@ -775,7 +762,7 @@ private module Stage2 {
|
||||
bindingset[result, ap]
|
||||
private ApApprox getApprox(Ap ap) { any() }
|
||||
|
||||
private ApNil getApNil(Node node) { any() }
|
||||
private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||
@@ -874,16 +861,16 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -963,7 +950,7 @@ private module Stage2 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -982,7 +969,7 @@ private module Stage2 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -1055,9 +1042,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1069,9 +1056,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1124,9 +1111,10 @@ private module Stage2 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1192,9 +1180,10 @@ private module Stage2 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ unbindBool(ap2), _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1213,13 +1202,13 @@ private module Stage2 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -1250,8 +1239,8 @@ private predicate flowOutOfCallNodeCand2(
|
||||
DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1260,8 +1249,8 @@ private predicate flowIntoCallNodeCand2(
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
private module LocalFlowBigStep {
|
||||
@@ -1316,8 +1305,8 @@ private module LocalFlowBigStep {
|
||||
pragma[noinline]
|
||||
private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
|
||||
additionalLocalFlowStepNodeCand1(node1, node2, config) and
|
||||
Stage2::revFlow(node1, _, _, false, config) and
|
||||
Stage2::revFlow(node2, _, _, false, unbind(config))
|
||||
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1334,7 +1323,7 @@ private module LocalFlowBigStep {
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
@@ -1345,24 +1334,24 @@ private module LocalFlowBigStep {
|
||||
t = getNodeType(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1394,7 +1383,9 @@ private module Stage3 {
|
||||
|
||||
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||
|
||||
private ApNil getApNil(Node node) { result = TFrontNil(getNodeType(node)) }
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||
@@ -1467,6 +1458,13 @@ private module Stage3 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -1478,7 +1476,7 @@ private module Stage3 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, unbindBool(getApprox(ap)), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -1502,16 +1500,16 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -1556,7 +1554,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, unbindBool(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -1591,7 +1589,7 @@ private module Stage3 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1610,7 +1608,7 @@ private module Stage3 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -1635,7 +1633,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindBool(getApprox(ap)), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1683,9 +1681,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1697,9 +1695,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1752,9 +1750,10 @@ private module Stage3 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1820,9 +1819,10 @@ private module Stage3 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1841,13 +1841,13 @@ private module Stage3 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -2087,7 +2087,9 @@ private module Stage4 {
|
||||
|
||||
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
|
||||
|
||||
private ApNil getApNil(Node node) { result = TNil(getNodeType(node)) }
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||
@@ -2131,8 +2133,11 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc, node.getEnclosingCallable())
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2147,8 +2152,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -2157,8 +2162,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
bindingset[node, ap]
|
||||
@@ -2173,6 +2178,13 @@ private module Stage4 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -2184,7 +2196,7 @@ private module Stage4 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, getApprox(ap), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -2208,16 +2220,16 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -2262,7 +2274,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -2297,7 +2309,7 @@ private module Stage4 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -2316,7 +2328,7 @@ private module Stage4 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -2341,7 +2353,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2389,9 +2401,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -2403,9 +2415,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -2458,9 +2470,10 @@ private module Stage4 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2526,9 +2539,10 @@ private module Stage4 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2547,13 +2561,13 @@ private module Stage4 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -2580,14 +2594,16 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
bindingset[conf, result]
|
||||
private Configuration unbind(Configuration conf) { result >= conf and result <= conf }
|
||||
private Configuration unbindConf(Configuration conf) {
|
||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||
}
|
||||
|
||||
private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
|
||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
||||
Stage4::revFlow(n, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
getNodeEnclosingCallable(n) = c
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2750,13 +2766,13 @@ private newtype TPathNode =
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, cc, sc, ap) and
|
||||
config = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), unbind(config))
|
||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
|
||||
)
|
||||
} or
|
||||
TPathNodeSink(Node node, Configuration config) {
|
||||
config.isSink(node) and
|
||||
Stage4::revFlow(node, unbind(config)) and
|
||||
pragma[only_bind_into](config).isSink(node) and
|
||||
Stage4::revFlow(node, pragma[only_bind_into](config)) and
|
||||
(
|
||||
// A sink that is also a source ...
|
||||
config.isSource(node)
|
||||
@@ -2764,7 +2780,7 @@ private newtype TPathNode =
|
||||
// ... or a sink that can be reached from a source
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, _, _, TAccessPathNil(_)) and
|
||||
config = unbind(mid.getConfiguration())
|
||||
pragma[only_bind_into](config) = mid.getConfiguration()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -3061,7 +3077,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
|
||||
private PathNodeMid getSuccMid() {
|
||||
pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
|
||||
result.getConfiguration() = unbind(this.getConfiguration())
|
||||
result.getConfiguration() = unbindConf(this.getConfiguration())
|
||||
}
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
@@ -3073,7 +3089,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
mid = getSuccMid() and
|
||||
mid.getNode() = sink.getNode() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
sink.getConfiguration() = unbind(mid.getConfiguration()) and
|
||||
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
|
||||
result = sink
|
||||
)
|
||||
}
|
||||
@@ -3116,7 +3132,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
localCC = getLocalCallContext(cc, getNodeEnclosingCallable(midnode)) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
@@ -3304,7 +3320,7 @@ private predicate pathThroughCallable0(
|
||||
) {
|
||||
exists(CallContext innercc, SummaryCtx sc |
|
||||
pathIntoCallable(mid, _, cc, innercc, sc, call) and
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration()))
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3316,7 +3332,7 @@ pragma[noinline]
|
||||
private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
|
||||
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration()))
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3402,14 +3418,14 @@ private module FlowExploration {
|
||||
// flow out of a callable
|
||||
viableReturnPosOut(_, getReturnPosition(node1), node2)
|
||||
|
|
||||
c1 = node1.getEnclosingCallable() and
|
||||
c2 = node2.getEnclosingCallable() and
|
||||
c1 = getNodeEnclosingCallable(node1) and
|
||||
c2 = getNodeEnclosingCallable(node2) and
|
||||
c1 != c2
|
||||
)
|
||||
}
|
||||
|
||||
private predicate interestingCallableSrc(DataFlowCallable c, Configuration config) {
|
||||
exists(Node n | config.isSource(n) and c = n.getEnclosingCallable())
|
||||
exists(Node n | config.isSource(n) and c = getNodeEnclosingCallable(n))
|
||||
or
|
||||
exists(DataFlowCallable mid |
|
||||
interestingCallableSrc(mid, config) and callableStep(mid, c, config)
|
||||
@@ -3417,7 +3433,7 @@ private module FlowExploration {
|
||||
}
|
||||
|
||||
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
|
||||
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
|
||||
exists(Node n | config.isSink(n) and c = getNodeEnclosingCallable(n))
|
||||
or
|
||||
exists(DataFlowCallable mid |
|
||||
interestingCallableSink(mid, config) and callableStep(c, mid, config)
|
||||
@@ -3439,20 +3455,20 @@ private module FlowExploration {
|
||||
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
|
||||
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
|
||||
callableStep(c1, c2, config) and
|
||||
ce1 = TCallable(c1, config) and
|
||||
ce2 = TCallable(c2, unbind(config))
|
||||
ce1 = TCallable(c1, pragma[only_bind_into](config)) and
|
||||
ce2 = TCallable(c2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node n, Configuration config |
|
||||
ce1 = TCallableSrc() and
|
||||
config.isSource(n) and
|
||||
ce2 = TCallable(n.getEnclosingCallable(), config)
|
||||
ce2 = TCallable(getNodeEnclosingCallable(n), config)
|
||||
)
|
||||
or
|
||||
exists(Node n, Configuration config |
|
||||
ce2 = TCallableSink() and
|
||||
config.isSink(n) and
|
||||
ce1 = TCallable(n.getEnclosingCallable(), config)
|
||||
ce1 = TCallable(getNodeEnclosingCallable(n), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3583,7 +3599,7 @@ private module FlowExploration {
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
|
||||
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
} or
|
||||
TPartialPathNodeRev(
|
||||
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
|
||||
@@ -3600,7 +3616,7 @@ private module FlowExploration {
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3659,7 +3675,7 @@ private module FlowExploration {
|
||||
* of interprocedural steps.
|
||||
*/
|
||||
int getSourceDistance() {
|
||||
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
|
||||
result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3667,7 +3683,7 @@ private module FlowExploration {
|
||||
* of interprocedural steps.
|
||||
*/
|
||||
int getSinkDistance() {
|
||||
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
|
||||
result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
|
||||
@@ -312,3 +312,14 @@ predicate isImmutableOrUnobservable(Node n) {
|
||||
|
||||
/** Holds if `n` should be hidden from path explanations. */
|
||||
predicate nodeIsHidden(Node n) { none() }
|
||||
|
||||
class LambdaCallKind = Unit;
|
||||
|
||||
/** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */
|
||||
predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) { none() }
|
||||
|
||||
/** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */
|
||||
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { none() }
|
||||
|
||||
/** Extra data-flow steps needed for lamba flow analysis. */
|
||||
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }
|
||||
|
||||
@@ -207,23 +207,14 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) }
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate isAdditionalFlowStep(
|
||||
AdditionalFlowStepSource node1, Node node2, DataFlowCallable callable1, Configuration config
|
||||
) {
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
callable1 = node1.getEnclosingCallable()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow in one local step from `node1` to `node2`.
|
||||
*/
|
||||
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
|
||||
simpleLocalFlowStep(node1, node2) and
|
||||
(
|
||||
simpleLocalFlowStep(node1, node2) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -234,7 +225,8 @@ private predicate localFlowStep(Node node1, Node node2, Configuration config) {
|
||||
* Holds if the additional step from `node1` to `node2` does not jump between callables.
|
||||
*/
|
||||
private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
|
||||
isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -256,14 +248,12 @@ private predicate jumpStep(Node node1, Node node2, Configuration config) {
|
||||
* Holds if the additional step from `node1` to `node2` jumps between callables.
|
||||
*/
|
||||
private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
|
||||
exists(DataFlowCallable callable1 |
|
||||
isAdditionalFlowStep(node1, node2, callable1, config) and
|
||||
node2.getEnclosingCallable() != callable1 and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
)
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -454,8 +444,8 @@ private module Stage1 {
|
||||
// read
|
||||
exists(Node mid, Content c |
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -481,18 +471,18 @@ private module Stage1 {
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
fwdFlow(node, unbind(config)) and
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, _, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
revFlow(mid, toReturn, config) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
store(node, tc, mid, _) and
|
||||
c = tc.getContent()
|
||||
)
|
||||
@@ -562,8 +552,8 @@ private module Stage1 {
|
||||
Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
exists(Content c |
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(node2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(node2, pragma[only_bind_into](config)) and
|
||||
store(node1, tc, node2, contentType) and
|
||||
c = tc.getContent() and
|
||||
exists(ap1)
|
||||
@@ -572,8 +562,8 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(n2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2)
|
||||
}
|
||||
|
||||
@@ -598,7 +588,7 @@ private module Stage1 {
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
throughFlowNodeCand(ret, config) and
|
||||
callable = ret.getEnclosingCallable() and
|
||||
callable = getNodeEnclosingCallable(ret) and
|
||||
kind = ret.getKind()
|
||||
)
|
||||
}
|
||||
@@ -611,7 +601,7 @@ private module Stage1 {
|
||||
exists(ReturnKindExt kind |
|
||||
throughFlowNodeCand(p, config) and
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
p.getEnclosingCallable() = c and
|
||||
getNodeEnclosingCallable(p) = c and
|
||||
exists(ap) and
|
||||
// we don't expect a parameter to return stored in itself
|
||||
not exists(int pos |
|
||||
@@ -636,9 +626,6 @@ private module Stage1 {
|
||||
/* End: Stage 1 logic. */
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
pragma[noinline]
|
||||
private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
|
||||
Stage1::revFlow(node2, config) and
|
||||
@@ -775,7 +762,7 @@ private module Stage2 {
|
||||
bindingset[result, ap]
|
||||
private ApApprox getApprox(Ap ap) { any() }
|
||||
|
||||
private ApNil getApNil(Node node) { any() }
|
||||
private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||
@@ -874,16 +861,16 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -963,7 +950,7 @@ private module Stage2 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -982,7 +969,7 @@ private module Stage2 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -1055,9 +1042,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1069,9 +1056,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1124,9 +1111,10 @@ private module Stage2 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1192,9 +1180,10 @@ private module Stage2 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ unbindBool(ap2), _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1213,13 +1202,13 @@ private module Stage2 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -1250,8 +1239,8 @@ private predicate flowOutOfCallNodeCand2(
|
||||
DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1260,8 +1249,8 @@ private predicate flowIntoCallNodeCand2(
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
private module LocalFlowBigStep {
|
||||
@@ -1316,8 +1305,8 @@ private module LocalFlowBigStep {
|
||||
pragma[noinline]
|
||||
private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
|
||||
additionalLocalFlowStepNodeCand1(node1, node2, config) and
|
||||
Stage2::revFlow(node1, _, _, false, config) and
|
||||
Stage2::revFlow(node2, _, _, false, unbind(config))
|
||||
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1334,7 +1323,7 @@ private module LocalFlowBigStep {
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
@@ -1345,24 +1334,24 @@ private module LocalFlowBigStep {
|
||||
t = getNodeType(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1394,7 +1383,9 @@ private module Stage3 {
|
||||
|
||||
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||
|
||||
private ApNil getApNil(Node node) { result = TFrontNil(getNodeType(node)) }
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||
@@ -1467,6 +1458,13 @@ private module Stage3 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -1478,7 +1476,7 @@ private module Stage3 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, unbindBool(getApprox(ap)), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -1502,16 +1500,16 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -1556,7 +1554,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, unbindBool(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -1591,7 +1589,7 @@ private module Stage3 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1610,7 +1608,7 @@ private module Stage3 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -1635,7 +1633,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindBool(getApprox(ap)), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1683,9 +1681,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1697,9 +1695,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1752,9 +1750,10 @@ private module Stage3 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1820,9 +1819,10 @@ private module Stage3 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1841,13 +1841,13 @@ private module Stage3 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -2087,7 +2087,9 @@ private module Stage4 {
|
||||
|
||||
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
|
||||
|
||||
private ApNil getApNil(Node node) { result = TNil(getNodeType(node)) }
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||
@@ -2131,8 +2133,11 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc, node.getEnclosingCallable())
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2147,8 +2152,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -2157,8 +2162,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
bindingset[node, ap]
|
||||
@@ -2173,6 +2178,13 @@ private module Stage4 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -2184,7 +2196,7 @@ private module Stage4 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, getApprox(ap), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -2208,16 +2220,16 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -2262,7 +2274,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -2297,7 +2309,7 @@ private module Stage4 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -2316,7 +2328,7 @@ private module Stage4 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -2341,7 +2353,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2389,9 +2401,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -2403,9 +2415,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -2458,9 +2470,10 @@ private module Stage4 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2526,9 +2539,10 @@ private module Stage4 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2547,13 +2561,13 @@ private module Stage4 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -2580,14 +2594,16 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
bindingset[conf, result]
|
||||
private Configuration unbind(Configuration conf) { result >= conf and result <= conf }
|
||||
private Configuration unbindConf(Configuration conf) {
|
||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||
}
|
||||
|
||||
private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
|
||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
||||
Stage4::revFlow(n, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
getNodeEnclosingCallable(n) = c
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2750,13 +2766,13 @@ private newtype TPathNode =
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, cc, sc, ap) and
|
||||
config = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), unbind(config))
|
||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
|
||||
)
|
||||
} or
|
||||
TPathNodeSink(Node node, Configuration config) {
|
||||
config.isSink(node) and
|
||||
Stage4::revFlow(node, unbind(config)) and
|
||||
pragma[only_bind_into](config).isSink(node) and
|
||||
Stage4::revFlow(node, pragma[only_bind_into](config)) and
|
||||
(
|
||||
// A sink that is also a source ...
|
||||
config.isSource(node)
|
||||
@@ -2764,7 +2780,7 @@ private newtype TPathNode =
|
||||
// ... or a sink that can be reached from a source
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, _, _, TAccessPathNil(_)) and
|
||||
config = unbind(mid.getConfiguration())
|
||||
pragma[only_bind_into](config) = mid.getConfiguration()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -3061,7 +3077,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
|
||||
private PathNodeMid getSuccMid() {
|
||||
pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
|
||||
result.getConfiguration() = unbind(this.getConfiguration())
|
||||
result.getConfiguration() = unbindConf(this.getConfiguration())
|
||||
}
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
@@ -3073,7 +3089,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
mid = getSuccMid() and
|
||||
mid.getNode() = sink.getNode() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
sink.getConfiguration() = unbind(mid.getConfiguration()) and
|
||||
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
|
||||
result = sink
|
||||
)
|
||||
}
|
||||
@@ -3116,7 +3132,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
localCC = getLocalCallContext(cc, getNodeEnclosingCallable(midnode)) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
@@ -3304,7 +3320,7 @@ private predicate pathThroughCallable0(
|
||||
) {
|
||||
exists(CallContext innercc, SummaryCtx sc |
|
||||
pathIntoCallable(mid, _, cc, innercc, sc, call) and
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration()))
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3316,7 +3332,7 @@ pragma[noinline]
|
||||
private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
|
||||
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration()))
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3402,14 +3418,14 @@ private module FlowExploration {
|
||||
// flow out of a callable
|
||||
viableReturnPosOut(_, getReturnPosition(node1), node2)
|
||||
|
|
||||
c1 = node1.getEnclosingCallable() and
|
||||
c2 = node2.getEnclosingCallable() and
|
||||
c1 = getNodeEnclosingCallable(node1) and
|
||||
c2 = getNodeEnclosingCallable(node2) and
|
||||
c1 != c2
|
||||
)
|
||||
}
|
||||
|
||||
private predicate interestingCallableSrc(DataFlowCallable c, Configuration config) {
|
||||
exists(Node n | config.isSource(n) and c = n.getEnclosingCallable())
|
||||
exists(Node n | config.isSource(n) and c = getNodeEnclosingCallable(n))
|
||||
or
|
||||
exists(DataFlowCallable mid |
|
||||
interestingCallableSrc(mid, config) and callableStep(mid, c, config)
|
||||
@@ -3417,7 +3433,7 @@ private module FlowExploration {
|
||||
}
|
||||
|
||||
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
|
||||
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
|
||||
exists(Node n | config.isSink(n) and c = getNodeEnclosingCallable(n))
|
||||
or
|
||||
exists(DataFlowCallable mid |
|
||||
interestingCallableSink(mid, config) and callableStep(c, mid, config)
|
||||
@@ -3439,20 +3455,20 @@ private module FlowExploration {
|
||||
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
|
||||
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
|
||||
callableStep(c1, c2, config) and
|
||||
ce1 = TCallable(c1, config) and
|
||||
ce2 = TCallable(c2, unbind(config))
|
||||
ce1 = TCallable(c1, pragma[only_bind_into](config)) and
|
||||
ce2 = TCallable(c2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node n, Configuration config |
|
||||
ce1 = TCallableSrc() and
|
||||
config.isSource(n) and
|
||||
ce2 = TCallable(n.getEnclosingCallable(), config)
|
||||
ce2 = TCallable(getNodeEnclosingCallable(n), config)
|
||||
)
|
||||
or
|
||||
exists(Node n, Configuration config |
|
||||
ce2 = TCallableSink() and
|
||||
config.isSink(n) and
|
||||
ce1 = TCallable(n.getEnclosingCallable(), config)
|
||||
ce1 = TCallable(getNodeEnclosingCallable(n), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3583,7 +3599,7 @@ private module FlowExploration {
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
|
||||
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
} or
|
||||
TPartialPathNodeRev(
|
||||
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
|
||||
@@ -3600,7 +3616,7 @@ private module FlowExploration {
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3659,7 +3675,7 @@ private module FlowExploration {
|
||||
* of interprocedural steps.
|
||||
*/
|
||||
int getSourceDistance() {
|
||||
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
|
||||
result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3667,7 +3683,7 @@ private module FlowExploration {
|
||||
* of interprocedural steps.
|
||||
*/
|
||||
int getSinkDistance() {
|
||||
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
|
||||
result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
|
||||
@@ -207,23 +207,14 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) }
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate isAdditionalFlowStep(
|
||||
AdditionalFlowStepSource node1, Node node2, DataFlowCallable callable1, Configuration config
|
||||
) {
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
callable1 = node1.getEnclosingCallable()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow in one local step from `node1` to `node2`.
|
||||
*/
|
||||
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
|
||||
simpleLocalFlowStep(node1, node2) and
|
||||
(
|
||||
simpleLocalFlowStep(node1, node2) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -234,7 +225,8 @@ private predicate localFlowStep(Node node1, Node node2, Configuration config) {
|
||||
* Holds if the additional step from `node1` to `node2` does not jump between callables.
|
||||
*/
|
||||
private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
|
||||
isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -256,14 +248,12 @@ private predicate jumpStep(Node node1, Node node2, Configuration config) {
|
||||
* Holds if the additional step from `node1` to `node2` jumps between callables.
|
||||
*/
|
||||
private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
|
||||
exists(DataFlowCallable callable1 |
|
||||
isAdditionalFlowStep(node1, node2, callable1, config) and
|
||||
node2.getEnclosingCallable() != callable1 and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
)
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -454,8 +444,8 @@ private module Stage1 {
|
||||
// read
|
||||
exists(Node mid, Content c |
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -481,18 +471,18 @@ private module Stage1 {
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
fwdFlow(node, unbind(config)) and
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, _, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
revFlow(mid, toReturn, config) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
store(node, tc, mid, _) and
|
||||
c = tc.getContent()
|
||||
)
|
||||
@@ -562,8 +552,8 @@ private module Stage1 {
|
||||
Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
exists(Content c |
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(node2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(node2, pragma[only_bind_into](config)) and
|
||||
store(node1, tc, node2, contentType) and
|
||||
c = tc.getContent() and
|
||||
exists(ap1)
|
||||
@@ -572,8 +562,8 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(n2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2)
|
||||
}
|
||||
|
||||
@@ -598,7 +588,7 @@ private module Stage1 {
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
throughFlowNodeCand(ret, config) and
|
||||
callable = ret.getEnclosingCallable() and
|
||||
callable = getNodeEnclosingCallable(ret) and
|
||||
kind = ret.getKind()
|
||||
)
|
||||
}
|
||||
@@ -611,7 +601,7 @@ private module Stage1 {
|
||||
exists(ReturnKindExt kind |
|
||||
throughFlowNodeCand(p, config) and
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
p.getEnclosingCallable() = c and
|
||||
getNodeEnclosingCallable(p) = c and
|
||||
exists(ap) and
|
||||
// we don't expect a parameter to return stored in itself
|
||||
not exists(int pos |
|
||||
@@ -636,9 +626,6 @@ private module Stage1 {
|
||||
/* End: Stage 1 logic. */
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
pragma[noinline]
|
||||
private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
|
||||
Stage1::revFlow(node2, config) and
|
||||
@@ -775,7 +762,7 @@ private module Stage2 {
|
||||
bindingset[result, ap]
|
||||
private ApApprox getApprox(Ap ap) { any() }
|
||||
|
||||
private ApNil getApNil(Node node) { any() }
|
||||
private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||
@@ -874,16 +861,16 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -963,7 +950,7 @@ private module Stage2 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -982,7 +969,7 @@ private module Stage2 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -1055,9 +1042,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1069,9 +1056,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1124,9 +1111,10 @@ private module Stage2 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1192,9 +1180,10 @@ private module Stage2 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ unbindBool(ap2), _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1213,13 +1202,13 @@ private module Stage2 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -1250,8 +1239,8 @@ private predicate flowOutOfCallNodeCand2(
|
||||
DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1260,8 +1249,8 @@ private predicate flowIntoCallNodeCand2(
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
private module LocalFlowBigStep {
|
||||
@@ -1316,8 +1305,8 @@ private module LocalFlowBigStep {
|
||||
pragma[noinline]
|
||||
private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
|
||||
additionalLocalFlowStepNodeCand1(node1, node2, config) and
|
||||
Stage2::revFlow(node1, _, _, false, config) and
|
||||
Stage2::revFlow(node2, _, _, false, unbind(config))
|
||||
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1334,7 +1323,7 @@ private module LocalFlowBigStep {
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
@@ -1345,24 +1334,24 @@ private module LocalFlowBigStep {
|
||||
t = getNodeType(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1394,7 +1383,9 @@ private module Stage3 {
|
||||
|
||||
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||
|
||||
private ApNil getApNil(Node node) { result = TFrontNil(getNodeType(node)) }
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||
@@ -1467,6 +1458,13 @@ private module Stage3 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -1478,7 +1476,7 @@ private module Stage3 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, unbindBool(getApprox(ap)), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -1502,16 +1500,16 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -1556,7 +1554,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, unbindBool(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -1591,7 +1589,7 @@ private module Stage3 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1610,7 +1608,7 @@ private module Stage3 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -1635,7 +1633,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindBool(getApprox(ap)), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1683,9 +1681,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1697,9 +1695,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1752,9 +1750,10 @@ private module Stage3 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1820,9 +1819,10 @@ private module Stage3 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1841,13 +1841,13 @@ private module Stage3 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -2087,7 +2087,9 @@ private module Stage4 {
|
||||
|
||||
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
|
||||
|
||||
private ApNil getApNil(Node node) { result = TNil(getNodeType(node)) }
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||
@@ -2131,8 +2133,11 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc, node.getEnclosingCallable())
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2147,8 +2152,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -2157,8 +2162,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
bindingset[node, ap]
|
||||
@@ -2173,6 +2178,13 @@ private module Stage4 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -2184,7 +2196,7 @@ private module Stage4 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, getApprox(ap), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -2208,16 +2220,16 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -2262,7 +2274,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -2297,7 +2309,7 @@ private module Stage4 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -2316,7 +2328,7 @@ private module Stage4 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -2341,7 +2353,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2389,9 +2401,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -2403,9 +2415,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -2458,9 +2470,10 @@ private module Stage4 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2526,9 +2539,10 @@ private module Stage4 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2547,13 +2561,13 @@ private module Stage4 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -2580,14 +2594,16 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
bindingset[conf, result]
|
||||
private Configuration unbind(Configuration conf) { result >= conf and result <= conf }
|
||||
private Configuration unbindConf(Configuration conf) {
|
||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||
}
|
||||
|
||||
private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
|
||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
||||
Stage4::revFlow(n, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
getNodeEnclosingCallable(n) = c
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2750,13 +2766,13 @@ private newtype TPathNode =
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, cc, sc, ap) and
|
||||
config = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), unbind(config))
|
||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
|
||||
)
|
||||
} or
|
||||
TPathNodeSink(Node node, Configuration config) {
|
||||
config.isSink(node) and
|
||||
Stage4::revFlow(node, unbind(config)) and
|
||||
pragma[only_bind_into](config).isSink(node) and
|
||||
Stage4::revFlow(node, pragma[only_bind_into](config)) and
|
||||
(
|
||||
// A sink that is also a source ...
|
||||
config.isSource(node)
|
||||
@@ -2764,7 +2780,7 @@ private newtype TPathNode =
|
||||
// ... or a sink that can be reached from a source
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, _, _, TAccessPathNil(_)) and
|
||||
config = unbind(mid.getConfiguration())
|
||||
pragma[only_bind_into](config) = mid.getConfiguration()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -3061,7 +3077,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
|
||||
private PathNodeMid getSuccMid() {
|
||||
pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
|
||||
result.getConfiguration() = unbind(this.getConfiguration())
|
||||
result.getConfiguration() = unbindConf(this.getConfiguration())
|
||||
}
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
@@ -3073,7 +3089,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
mid = getSuccMid() and
|
||||
mid.getNode() = sink.getNode() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
sink.getConfiguration() = unbind(mid.getConfiguration()) and
|
||||
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
|
||||
result = sink
|
||||
)
|
||||
}
|
||||
@@ -3116,7 +3132,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
localCC = getLocalCallContext(cc, getNodeEnclosingCallable(midnode)) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
@@ -3304,7 +3320,7 @@ private predicate pathThroughCallable0(
|
||||
) {
|
||||
exists(CallContext innercc, SummaryCtx sc |
|
||||
pathIntoCallable(mid, _, cc, innercc, sc, call) and
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration()))
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3316,7 +3332,7 @@ pragma[noinline]
|
||||
private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
|
||||
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration()))
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3402,14 +3418,14 @@ private module FlowExploration {
|
||||
// flow out of a callable
|
||||
viableReturnPosOut(_, getReturnPosition(node1), node2)
|
||||
|
|
||||
c1 = node1.getEnclosingCallable() and
|
||||
c2 = node2.getEnclosingCallable() and
|
||||
c1 = getNodeEnclosingCallable(node1) and
|
||||
c2 = getNodeEnclosingCallable(node2) and
|
||||
c1 != c2
|
||||
)
|
||||
}
|
||||
|
||||
private predicate interestingCallableSrc(DataFlowCallable c, Configuration config) {
|
||||
exists(Node n | config.isSource(n) and c = n.getEnclosingCallable())
|
||||
exists(Node n | config.isSource(n) and c = getNodeEnclosingCallable(n))
|
||||
or
|
||||
exists(DataFlowCallable mid |
|
||||
interestingCallableSrc(mid, config) and callableStep(mid, c, config)
|
||||
@@ -3417,7 +3433,7 @@ private module FlowExploration {
|
||||
}
|
||||
|
||||
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
|
||||
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
|
||||
exists(Node n | config.isSink(n) and c = getNodeEnclosingCallable(n))
|
||||
or
|
||||
exists(DataFlowCallable mid |
|
||||
interestingCallableSink(mid, config) and callableStep(c, mid, config)
|
||||
@@ -3439,20 +3455,20 @@ private module FlowExploration {
|
||||
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
|
||||
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
|
||||
callableStep(c1, c2, config) and
|
||||
ce1 = TCallable(c1, config) and
|
||||
ce2 = TCallable(c2, unbind(config))
|
||||
ce1 = TCallable(c1, pragma[only_bind_into](config)) and
|
||||
ce2 = TCallable(c2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node n, Configuration config |
|
||||
ce1 = TCallableSrc() and
|
||||
config.isSource(n) and
|
||||
ce2 = TCallable(n.getEnclosingCallable(), config)
|
||||
ce2 = TCallable(getNodeEnclosingCallable(n), config)
|
||||
)
|
||||
or
|
||||
exists(Node n, Configuration config |
|
||||
ce2 = TCallableSink() and
|
||||
config.isSink(n) and
|
||||
ce1 = TCallable(n.getEnclosingCallable(), config)
|
||||
ce1 = TCallable(getNodeEnclosingCallable(n), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3583,7 +3599,7 @@ private module FlowExploration {
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
|
||||
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
} or
|
||||
TPartialPathNodeRev(
|
||||
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
|
||||
@@ -3600,7 +3616,7 @@ private module FlowExploration {
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3659,7 +3675,7 @@ private module FlowExploration {
|
||||
* of interprocedural steps.
|
||||
*/
|
||||
int getSourceDistance() {
|
||||
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
|
||||
result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3667,7 +3683,7 @@ private module FlowExploration {
|
||||
* of interprocedural steps.
|
||||
*/
|
||||
int getSinkDistance() {
|
||||
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
|
||||
result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
|
||||
@@ -207,23 +207,14 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) }
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate isAdditionalFlowStep(
|
||||
AdditionalFlowStepSource node1, Node node2, DataFlowCallable callable1, Configuration config
|
||||
) {
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
callable1 = node1.getEnclosingCallable()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow in one local step from `node1` to `node2`.
|
||||
*/
|
||||
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
|
||||
simpleLocalFlowStep(node1, node2) and
|
||||
(
|
||||
simpleLocalFlowStep(node1, node2) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -234,7 +225,8 @@ private predicate localFlowStep(Node node1, Node node2, Configuration config) {
|
||||
* Holds if the additional step from `node1` to `node2` does not jump between callables.
|
||||
*/
|
||||
private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
|
||||
isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -256,14 +248,12 @@ private predicate jumpStep(Node node1, Node node2, Configuration config) {
|
||||
* Holds if the additional step from `node1` to `node2` jumps between callables.
|
||||
*/
|
||||
private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
|
||||
exists(DataFlowCallable callable1 |
|
||||
isAdditionalFlowStep(node1, node2, callable1, config) and
|
||||
node2.getEnclosingCallable() != callable1 and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
)
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -454,8 +444,8 @@ private module Stage1 {
|
||||
// read
|
||||
exists(Node mid, Content c |
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -481,18 +471,18 @@ private module Stage1 {
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
fwdFlow(node, unbind(config)) and
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, _, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
revFlow(mid, toReturn, config) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
store(node, tc, mid, _) and
|
||||
c = tc.getContent()
|
||||
)
|
||||
@@ -562,8 +552,8 @@ private module Stage1 {
|
||||
Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
exists(Content c |
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(node2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(node2, pragma[only_bind_into](config)) and
|
||||
store(node1, tc, node2, contentType) and
|
||||
c = tc.getContent() and
|
||||
exists(ap1)
|
||||
@@ -572,8 +562,8 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(n2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2)
|
||||
}
|
||||
|
||||
@@ -598,7 +588,7 @@ private module Stage1 {
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
throughFlowNodeCand(ret, config) and
|
||||
callable = ret.getEnclosingCallable() and
|
||||
callable = getNodeEnclosingCallable(ret) and
|
||||
kind = ret.getKind()
|
||||
)
|
||||
}
|
||||
@@ -611,7 +601,7 @@ private module Stage1 {
|
||||
exists(ReturnKindExt kind |
|
||||
throughFlowNodeCand(p, config) and
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
p.getEnclosingCallable() = c and
|
||||
getNodeEnclosingCallable(p) = c and
|
||||
exists(ap) and
|
||||
// we don't expect a parameter to return stored in itself
|
||||
not exists(int pos |
|
||||
@@ -636,9 +626,6 @@ private module Stage1 {
|
||||
/* End: Stage 1 logic. */
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
pragma[noinline]
|
||||
private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
|
||||
Stage1::revFlow(node2, config) and
|
||||
@@ -775,7 +762,7 @@ private module Stage2 {
|
||||
bindingset[result, ap]
|
||||
private ApApprox getApprox(Ap ap) { any() }
|
||||
|
||||
private ApNil getApNil(Node node) { any() }
|
||||
private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||
@@ -874,16 +861,16 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -963,7 +950,7 @@ private module Stage2 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -982,7 +969,7 @@ private module Stage2 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -1055,9 +1042,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1069,9 +1056,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1124,9 +1111,10 @@ private module Stage2 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1192,9 +1180,10 @@ private module Stage2 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ unbindBool(ap2), _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1213,13 +1202,13 @@ private module Stage2 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -1250,8 +1239,8 @@ private predicate flowOutOfCallNodeCand2(
|
||||
DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1260,8 +1249,8 @@ private predicate flowIntoCallNodeCand2(
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
private module LocalFlowBigStep {
|
||||
@@ -1316,8 +1305,8 @@ private module LocalFlowBigStep {
|
||||
pragma[noinline]
|
||||
private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
|
||||
additionalLocalFlowStepNodeCand1(node1, node2, config) and
|
||||
Stage2::revFlow(node1, _, _, false, config) and
|
||||
Stage2::revFlow(node2, _, _, false, unbind(config))
|
||||
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1334,7 +1323,7 @@ private module LocalFlowBigStep {
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
@@ -1345,24 +1334,24 @@ private module LocalFlowBigStep {
|
||||
t = getNodeType(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1394,7 +1383,9 @@ private module Stage3 {
|
||||
|
||||
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||
|
||||
private ApNil getApNil(Node node) { result = TFrontNil(getNodeType(node)) }
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||
@@ -1467,6 +1458,13 @@ private module Stage3 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -1478,7 +1476,7 @@ private module Stage3 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, unbindBool(getApprox(ap)), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -1502,16 +1500,16 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -1556,7 +1554,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, unbindBool(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -1591,7 +1589,7 @@ private module Stage3 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1610,7 +1608,7 @@ private module Stage3 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -1635,7 +1633,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindBool(getApprox(ap)), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1683,9 +1681,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1697,9 +1695,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1752,9 +1750,10 @@ private module Stage3 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1820,9 +1819,10 @@ private module Stage3 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1841,13 +1841,13 @@ private module Stage3 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -2087,7 +2087,9 @@ private module Stage4 {
|
||||
|
||||
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
|
||||
|
||||
private ApNil getApNil(Node node) { result = TNil(getNodeType(node)) }
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||
@@ -2131,8 +2133,11 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc, node.getEnclosingCallable())
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2147,8 +2152,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -2157,8 +2162,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
bindingset[node, ap]
|
||||
@@ -2173,6 +2178,13 @@ private module Stage4 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -2184,7 +2196,7 @@ private module Stage4 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, getApprox(ap), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -2208,16 +2220,16 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -2262,7 +2274,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -2297,7 +2309,7 @@ private module Stage4 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -2316,7 +2328,7 @@ private module Stage4 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -2341,7 +2353,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2389,9 +2401,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -2403,9 +2415,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -2458,9 +2470,10 @@ private module Stage4 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2526,9 +2539,10 @@ private module Stage4 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2547,13 +2561,13 @@ private module Stage4 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -2580,14 +2594,16 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
bindingset[conf, result]
|
||||
private Configuration unbind(Configuration conf) { result >= conf and result <= conf }
|
||||
private Configuration unbindConf(Configuration conf) {
|
||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||
}
|
||||
|
||||
private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
|
||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
||||
Stage4::revFlow(n, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
getNodeEnclosingCallable(n) = c
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2750,13 +2766,13 @@ private newtype TPathNode =
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, cc, sc, ap) and
|
||||
config = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), unbind(config))
|
||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
|
||||
)
|
||||
} or
|
||||
TPathNodeSink(Node node, Configuration config) {
|
||||
config.isSink(node) and
|
||||
Stage4::revFlow(node, unbind(config)) and
|
||||
pragma[only_bind_into](config).isSink(node) and
|
||||
Stage4::revFlow(node, pragma[only_bind_into](config)) and
|
||||
(
|
||||
// A sink that is also a source ...
|
||||
config.isSource(node)
|
||||
@@ -2764,7 +2780,7 @@ private newtype TPathNode =
|
||||
// ... or a sink that can be reached from a source
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, _, _, TAccessPathNil(_)) and
|
||||
config = unbind(mid.getConfiguration())
|
||||
pragma[only_bind_into](config) = mid.getConfiguration()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -3061,7 +3077,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
|
||||
private PathNodeMid getSuccMid() {
|
||||
pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
|
||||
result.getConfiguration() = unbind(this.getConfiguration())
|
||||
result.getConfiguration() = unbindConf(this.getConfiguration())
|
||||
}
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
@@ -3073,7 +3089,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
mid = getSuccMid() and
|
||||
mid.getNode() = sink.getNode() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
sink.getConfiguration() = unbind(mid.getConfiguration()) and
|
||||
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
|
||||
result = sink
|
||||
)
|
||||
}
|
||||
@@ -3116,7 +3132,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
localCC = getLocalCallContext(cc, getNodeEnclosingCallable(midnode)) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
@@ -3304,7 +3320,7 @@ private predicate pathThroughCallable0(
|
||||
) {
|
||||
exists(CallContext innercc, SummaryCtx sc |
|
||||
pathIntoCallable(mid, _, cc, innercc, sc, call) and
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration()))
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3316,7 +3332,7 @@ pragma[noinline]
|
||||
private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
|
||||
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration()))
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3402,14 +3418,14 @@ private module FlowExploration {
|
||||
// flow out of a callable
|
||||
viableReturnPosOut(_, getReturnPosition(node1), node2)
|
||||
|
|
||||
c1 = node1.getEnclosingCallable() and
|
||||
c2 = node2.getEnclosingCallable() and
|
||||
c1 = getNodeEnclosingCallable(node1) and
|
||||
c2 = getNodeEnclosingCallable(node2) and
|
||||
c1 != c2
|
||||
)
|
||||
}
|
||||
|
||||
private predicate interestingCallableSrc(DataFlowCallable c, Configuration config) {
|
||||
exists(Node n | config.isSource(n) and c = n.getEnclosingCallable())
|
||||
exists(Node n | config.isSource(n) and c = getNodeEnclosingCallable(n))
|
||||
or
|
||||
exists(DataFlowCallable mid |
|
||||
interestingCallableSrc(mid, config) and callableStep(mid, c, config)
|
||||
@@ -3417,7 +3433,7 @@ private module FlowExploration {
|
||||
}
|
||||
|
||||
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
|
||||
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
|
||||
exists(Node n | config.isSink(n) and c = getNodeEnclosingCallable(n))
|
||||
or
|
||||
exists(DataFlowCallable mid |
|
||||
interestingCallableSink(mid, config) and callableStep(c, mid, config)
|
||||
@@ -3439,20 +3455,20 @@ private module FlowExploration {
|
||||
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
|
||||
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
|
||||
callableStep(c1, c2, config) and
|
||||
ce1 = TCallable(c1, config) and
|
||||
ce2 = TCallable(c2, unbind(config))
|
||||
ce1 = TCallable(c1, pragma[only_bind_into](config)) and
|
||||
ce2 = TCallable(c2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node n, Configuration config |
|
||||
ce1 = TCallableSrc() and
|
||||
config.isSource(n) and
|
||||
ce2 = TCallable(n.getEnclosingCallable(), config)
|
||||
ce2 = TCallable(getNodeEnclosingCallable(n), config)
|
||||
)
|
||||
or
|
||||
exists(Node n, Configuration config |
|
||||
ce2 = TCallableSink() and
|
||||
config.isSink(n) and
|
||||
ce1 = TCallable(n.getEnclosingCallable(), config)
|
||||
ce1 = TCallable(getNodeEnclosingCallable(n), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3583,7 +3599,7 @@ private module FlowExploration {
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
|
||||
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
} or
|
||||
TPartialPathNodeRev(
|
||||
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
|
||||
@@ -3600,7 +3616,7 @@ private module FlowExploration {
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3659,7 +3675,7 @@ private module FlowExploration {
|
||||
* of interprocedural steps.
|
||||
*/
|
||||
int getSourceDistance() {
|
||||
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
|
||||
result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3667,7 +3683,7 @@ private module FlowExploration {
|
||||
* of interprocedural steps.
|
||||
*/
|
||||
int getSinkDistance() {
|
||||
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
|
||||
result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
|
||||
@@ -207,23 +207,14 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
)
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepSource extends Node {
|
||||
AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) }
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate isAdditionalFlowStep(
|
||||
AdditionalFlowStepSource node1, Node node2, DataFlowCallable callable1, Configuration config
|
||||
) {
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
callable1 = node1.getEnclosingCallable()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow in one local step from `node1` to `node2`.
|
||||
*/
|
||||
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
|
||||
simpleLocalFlowStep(node1, node2) and
|
||||
(
|
||||
simpleLocalFlowStep(node1, node2) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -234,7 +225,8 @@ private predicate localFlowStep(Node node1, Node node2, Configuration config) {
|
||||
* Holds if the additional step from `node1` to `node2` does not jump between callables.
|
||||
*/
|
||||
private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
|
||||
isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -256,14 +248,12 @@ private predicate jumpStep(Node node1, Node node2, Configuration config) {
|
||||
* Holds if the additional step from `node1` to `node2` jumps between callables.
|
||||
*/
|
||||
private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
|
||||
exists(DataFlowCallable callable1 |
|
||||
isAdditionalFlowStep(node1, node2, callable1, config) and
|
||||
node2.getEnclosingCallable() != callable1 and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
)
|
||||
config.isAdditionalFlowStep(node1, node2) and
|
||||
getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
not fullBarrier(node2, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -454,8 +444,8 @@ private module Stage1 {
|
||||
// read
|
||||
exists(Node mid, Content c |
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
@@ -481,18 +471,18 @@ private module Stage1 {
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Content c, Configuration config) {
|
||||
exists(Node mid, Node node |
|
||||
fwdFlow(node, unbind(config)) and
|
||||
fwdFlow(node, pragma[only_bind_into](config)) and
|
||||
read(node, c, mid) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, _, config)
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
revFlow(pragma[only_bind_into](mid), _, pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowStore(Content c, Node node, boolean toReturn, Configuration config) {
|
||||
exists(Node mid, TypedContent tc |
|
||||
revFlow(mid, toReturn, config) and
|
||||
fwdFlowConsCand(c, unbind(config)) and
|
||||
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
|
||||
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
|
||||
store(node, tc, mid, _) and
|
||||
c = tc.getContent()
|
||||
)
|
||||
@@ -562,8 +552,8 @@ private module Stage1 {
|
||||
Node node1, Ap ap1, TypedContent tc, Node node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
exists(Content c |
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(node2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(node2, pragma[only_bind_into](config)) and
|
||||
store(node1, tc, node2, contentType) and
|
||||
c = tc.getContent() and
|
||||
exists(ap1)
|
||||
@@ -572,8 +562,8 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate readStepCand(Node n1, Content c, Node n2, Configuration config) {
|
||||
revFlowIsReadAndStored(c, config) and
|
||||
revFlow(n2, unbind(config)) and
|
||||
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
|
||||
revFlow(n2, pragma[only_bind_into](config)) and
|
||||
read(n1, c, n2)
|
||||
}
|
||||
|
||||
@@ -598,7 +588,7 @@ private module Stage1 {
|
||||
) {
|
||||
exists(ReturnNodeExt ret |
|
||||
throughFlowNodeCand(ret, config) and
|
||||
callable = ret.getEnclosingCallable() and
|
||||
callable = getNodeEnclosingCallable(ret) and
|
||||
kind = ret.getKind()
|
||||
)
|
||||
}
|
||||
@@ -611,7 +601,7 @@ private module Stage1 {
|
||||
exists(ReturnKindExt kind |
|
||||
throughFlowNodeCand(p, config) and
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
p.getEnclosingCallable() = c and
|
||||
getNodeEnclosingCallable(p) = c and
|
||||
exists(ap) and
|
||||
// we don't expect a parameter to return stored in itself
|
||||
not exists(int pos |
|
||||
@@ -636,9 +626,6 @@ private module Stage1 {
|
||||
/* End: Stage 1 logic. */
|
||||
}
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
pragma[noinline]
|
||||
private predicate localFlowStepNodeCand1(Node node1, Node node2, Configuration config) {
|
||||
Stage1::revFlow(node2, config) and
|
||||
@@ -775,7 +762,7 @@ private module Stage2 {
|
||||
bindingset[result, ap]
|
||||
private ApApprox getApprox(Ap ap) { any() }
|
||||
|
||||
private ApNil getApNil(Node node) { any() }
|
||||
private ApNil getApNil(Node node) { PrevStage::revFlow(node, _) and exists(result) }
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||
@@ -874,16 +861,16 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -963,7 +950,7 @@ private module Stage2 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -982,7 +969,7 @@ private module Stage2 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -1055,9 +1042,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1069,9 +1056,9 @@ private module Stage2 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1124,9 +1111,10 @@ private module Stage2 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1192,9 +1180,10 @@ private module Stage2 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ unbindBool(ap2), _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1213,13 +1202,13 @@ private module Stage2 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -1250,8 +1239,8 @@ private predicate flowOutOfCallNodeCand2(
|
||||
DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1260,8 +1249,8 @@ private predicate flowIntoCallNodeCand2(
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, config) and
|
||||
Stage2::revFlow(node1, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node1, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
private module LocalFlowBigStep {
|
||||
@@ -1316,8 +1305,8 @@ private module LocalFlowBigStep {
|
||||
pragma[noinline]
|
||||
private predicate additionalLocalFlowStepNodeCand2(Node node1, Node node2, Configuration config) {
|
||||
additionalLocalFlowStepNodeCand1(node1, node2, config) and
|
||||
Stage2::revFlow(node1, _, _, false, config) and
|
||||
Stage2::revFlow(node2, _, _, false, unbind(config))
|
||||
Stage2::revFlow(node1, _, _, false, pragma[only_bind_into](config)) and
|
||||
Stage2::revFlow(node2, _, _, false, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1334,7 +1323,7 @@ private module LocalFlowBigStep {
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, config) and
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
@@ -1345,24 +1334,24 @@ private module LocalFlowBigStep {
|
||||
t = getNodeType(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, config, cc) and
|
||||
localFlowStepPlus(node1, mid, preservesValue, t, pragma[only_bind_into](config), cc) and
|
||||
localFlowStepNodeCand1(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
localFlowStepPlus(node1, mid, _, _, config, cc) and
|
||||
localFlowStepPlus(node1, mid, _, _, pragma[only_bind_into](config), cc) and
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
Stage2::revFlow(node2, unbind(config))
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1394,7 +1383,9 @@ private module Stage3 {
|
||||
|
||||
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||
|
||||
private ApNil getApNil(Node node) { result = TFrontNil(getNodeType(node)) }
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||
@@ -1467,6 +1458,13 @@ private module Stage3 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -1478,7 +1476,7 @@ private module Stage3 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, unbindBool(getApprox(ap)), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -1502,16 +1500,16 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -1556,7 +1554,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, unbindBool(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -1591,7 +1589,7 @@ private module Stage3 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -1610,7 +1608,7 @@ private module Stage3 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -1635,7 +1633,7 @@ private module Stage3 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindBool(getApprox(ap)), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1683,9 +1681,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -1697,9 +1695,9 @@ private module Stage3 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -1752,9 +1750,10 @@ private module Stage3 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1820,9 +1819,10 @@ private module Stage3 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1841,13 +1841,13 @@ private module Stage3 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -2087,7 +2087,9 @@ private module Stage4 {
|
||||
|
||||
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
|
||||
|
||||
private ApNil getApNil(Node node) { result = TNil(getNodeType(node)) }
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
private Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||
@@ -2131,8 +2133,11 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc, node.getEnclosingCallable())
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2147,8 +2152,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowOutOfCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -2157,8 +2162,8 @@ private module Stage4 {
|
||||
Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, config) and
|
||||
PrevStage::revFlow(node1, _, _, _, unbind(config))
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
PrevStage::revFlow(node1, _, _, _, pragma[only_bind_into](config))
|
||||
}
|
||||
|
||||
bindingset[node, ap]
|
||||
@@ -2173,6 +2178,13 @@ private module Stage4 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` is reachable with access path `ap` from a source in the
|
||||
* configuration `config`.
|
||||
@@ -2184,7 +2196,7 @@ private module Stage4 {
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(Node node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, getApprox(ap), config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
@@ -2208,16 +2220,16 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid |
|
||||
fwdFlow(mid, _, _, ap, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, ap, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
jumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone()
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(mid, _, _, nil, config) and
|
||||
flowCand(node, _, unbind(config)) and
|
||||
fwdFlow(mid, _, _, nil, pragma[only_bind_into](config)) and
|
||||
flowCand(node, _, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(mid, node, config) and
|
||||
cc = ccNone() and
|
||||
argAp = apNone() and
|
||||
@@ -2262,7 +2274,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -2297,7 +2309,7 @@ private module Stage4 {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
|
|
||||
ap instanceof ApNil or allowsFieldFlow = true
|
||||
)
|
||||
@@ -2316,7 +2328,7 @@ private module Stage4 {
|
||||
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
|
||||
fwdFlow(ret, innercc, argAp, ap, config) and
|
||||
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
|
||||
inner = ret.getEnclosingCallable() and
|
||||
inner = getNodeEnclosingCallable(ret) and
|
||||
checkCallContextReturn(innercc, inner, call) and
|
||||
ccOut = getCallContextReturn(inner, call)
|
||||
|
|
||||
@@ -2341,7 +2353,7 @@ private module Stage4 {
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2389,9 +2401,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
localStep(node, mid, false, _, config, _) and
|
||||
revFlow(mid, toReturn, returnAp, nil, config) and
|
||||
revFlow(mid, toReturn, returnAp, nil, pragma[only_bind_into](config)) and
|
||||
ap instanceof ApNil
|
||||
)
|
||||
or
|
||||
@@ -2403,9 +2415,9 @@ private module Stage4 {
|
||||
)
|
||||
or
|
||||
exists(Node mid, ApNil nil |
|
||||
fwdFlow(node, _, _, ap, config) and
|
||||
fwdFlow(node, _, _, ap, pragma[only_bind_into](config)) and
|
||||
additionalJumpStep(node, mid, config) and
|
||||
revFlow(mid, _, _, nil, config) and
|
||||
revFlow(pragma[only_bind_into](mid), _, _, nil, pragma[only_bind_into](config)) and
|
||||
toReturn = false and
|
||||
returnAp = apNone() and
|
||||
ap instanceof ApNil
|
||||
@@ -2458,9 +2470,10 @@ private module Stage4 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate revFlowConsCand(Ap cons, Content c, Ap tail, Configuration config) {
|
||||
exists(Node mid |
|
||||
exists(Node mid, Ap tail0 |
|
||||
revFlow(mid, _, _, tail, config) and
|
||||
readStepFwd(_, cons, c, mid, tail, config)
|
||||
tail = pragma[only_bind_into](tail0) and
|
||||
readStepFwd(_, cons, c, mid, tail0, config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2526,9 +2539,10 @@ private module Stage4 {
|
||||
|
||||
predicate readStepCand(Node node1, Content c, Node node2, Configuration config) {
|
||||
exists(Ap ap1, Ap ap2 |
|
||||
revFlow(node2, _, _, ap2, config) and
|
||||
revFlow(node2, _, _, pragma[only_bind_into](ap2), pragma[only_bind_into](config)) and
|
||||
readStepFwd(node1, ap1, c, node2, ap2, config) and
|
||||
revFlowStore(ap1, c, /*unbind*/ ap2, _, _, _, _, _, unbind(config))
|
||||
revFlowStore(ap1, c, pragma[only_bind_into](ap2), _, _, _, _, _,
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2547,13 +2561,13 @@ private module Stage4 {
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = p.getEnclosingCallable()
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
revFlow(ret, true, apSome(_), ap0, config) and
|
||||
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
|
||||
kind = ret.getKind() and
|
||||
@@ -2580,14 +2594,16 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
bindingset[conf, result]
|
||||
private Configuration unbind(Configuration conf) { result >= conf and result <= conf }
|
||||
private Configuration unbindConf(Configuration conf) {
|
||||
exists(Configuration c | result = pragma[only_bind_into](c) and conf = pragma[only_bind_into](c))
|
||||
}
|
||||
|
||||
private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration config) {
|
||||
exists(DataFlowCallable c, AccessPathApprox apa0 |
|
||||
Stage4::parameterMayFlowThrough(_, c, apa, _) and
|
||||
Stage4::revFlow(n, true, _, apa0, config) and
|
||||
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
|
||||
n.getEnclosingCallable() = c
|
||||
getNodeEnclosingCallable(n) = c
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2750,13 +2766,13 @@ private newtype TPathNode =
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, cc, sc, ap) and
|
||||
config = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), unbind(config))
|
||||
pragma[only_bind_into](config) = mid.getConfiguration() and
|
||||
Stage4::revFlow(node, _, _, ap.getApprox(), pragma[only_bind_into](config))
|
||||
)
|
||||
} or
|
||||
TPathNodeSink(Node node, Configuration config) {
|
||||
config.isSink(node) and
|
||||
Stage4::revFlow(node, unbind(config)) and
|
||||
pragma[only_bind_into](config).isSink(node) and
|
||||
Stage4::revFlow(node, pragma[only_bind_into](config)) and
|
||||
(
|
||||
// A sink that is also a source ...
|
||||
config.isSource(node)
|
||||
@@ -2764,7 +2780,7 @@ private newtype TPathNode =
|
||||
// ... or a sink that can be reached from a source
|
||||
exists(PathNodeMid mid |
|
||||
pathStep(mid, node, _, _, TAccessPathNil(_)) and
|
||||
config = unbind(mid.getConfiguration())
|
||||
pragma[only_bind_into](config) = mid.getConfiguration()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -3061,7 +3077,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
|
||||
private PathNodeMid getSuccMid() {
|
||||
pathStep(this, result.getNode(), result.getCallContext(), result.getSummaryCtx(), result.getAp()) and
|
||||
result.getConfiguration() = unbind(this.getConfiguration())
|
||||
result.getConfiguration() = unbindConf(this.getConfiguration())
|
||||
}
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
@@ -3073,7 +3089,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
mid = getSuccMid() and
|
||||
mid.getNode() = sink.getNode() and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
sink.getConfiguration() = unbind(mid.getConfiguration()) and
|
||||
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
|
||||
result = sink
|
||||
)
|
||||
}
|
||||
@@ -3116,7 +3132,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
conf = mid.getConfiguration() and
|
||||
cc = mid.getCallContext() and
|
||||
sc = mid.getSummaryCtx() and
|
||||
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
|
||||
localCC = getLocalCallContext(cc, getNodeEnclosingCallable(midnode)) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
@@ -3304,7 +3320,7 @@ private predicate pathThroughCallable0(
|
||||
) {
|
||||
exists(CallContext innercc, SummaryCtx sc |
|
||||
pathIntoCallable(mid, _, cc, innercc, sc, call) and
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbind(mid.getConfiguration()))
|
||||
paramFlowsThrough(kind, innercc, sc, ap, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3316,7 +3332,7 @@ pragma[noinline]
|
||||
private predicate pathThroughCallable(PathNodeMid mid, Node out, CallContext cc, AccessPath ap) {
|
||||
exists(DataFlowCall call, ReturnKindExt kind, AccessPathApprox apa |
|
||||
pathThroughCallable0(call, mid, kind, cc, ap, apa) and
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbind(mid.getConfiguration()))
|
||||
out = getAnOutNodeFlow(kind, call, apa, unbindConf(mid.getConfiguration()))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3402,14 +3418,14 @@ private module FlowExploration {
|
||||
// flow out of a callable
|
||||
viableReturnPosOut(_, getReturnPosition(node1), node2)
|
||||
|
|
||||
c1 = node1.getEnclosingCallable() and
|
||||
c2 = node2.getEnclosingCallable() and
|
||||
c1 = getNodeEnclosingCallable(node1) and
|
||||
c2 = getNodeEnclosingCallable(node2) and
|
||||
c1 != c2
|
||||
)
|
||||
}
|
||||
|
||||
private predicate interestingCallableSrc(DataFlowCallable c, Configuration config) {
|
||||
exists(Node n | config.isSource(n) and c = n.getEnclosingCallable())
|
||||
exists(Node n | config.isSource(n) and c = getNodeEnclosingCallable(n))
|
||||
or
|
||||
exists(DataFlowCallable mid |
|
||||
interestingCallableSrc(mid, config) and callableStep(mid, c, config)
|
||||
@@ -3417,7 +3433,7 @@ private module FlowExploration {
|
||||
}
|
||||
|
||||
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
|
||||
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
|
||||
exists(Node n | config.isSink(n) and c = getNodeEnclosingCallable(n))
|
||||
or
|
||||
exists(DataFlowCallable mid |
|
||||
interestingCallableSink(mid, config) and callableStep(c, mid, config)
|
||||
@@ -3439,20 +3455,20 @@ private module FlowExploration {
|
||||
private predicate callableExtStepFwd(TCallableExt ce1, TCallableExt ce2) {
|
||||
exists(DataFlowCallable c1, DataFlowCallable c2, Configuration config |
|
||||
callableStep(c1, c2, config) and
|
||||
ce1 = TCallable(c1, config) and
|
||||
ce2 = TCallable(c2, unbind(config))
|
||||
ce1 = TCallable(c1, pragma[only_bind_into](config)) and
|
||||
ce2 = TCallable(c2, pragma[only_bind_into](config))
|
||||
)
|
||||
or
|
||||
exists(Node n, Configuration config |
|
||||
ce1 = TCallableSrc() and
|
||||
config.isSource(n) and
|
||||
ce2 = TCallable(n.getEnclosingCallable(), config)
|
||||
ce2 = TCallable(getNodeEnclosingCallable(n), config)
|
||||
)
|
||||
or
|
||||
exists(Node n, Configuration config |
|
||||
ce2 = TCallableSink() and
|
||||
config.isSink(n) and
|
||||
ce1 = TCallable(n.getEnclosingCallable(), config)
|
||||
ce1 = TCallable(getNodeEnclosingCallable(n), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3583,7 +3599,7 @@ private module FlowExploration {
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
|
||||
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
} or
|
||||
TPartialPathNodeRev(
|
||||
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
|
||||
@@ -3600,7 +3616,7 @@ private module FlowExploration {
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
|
||||
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3659,7 +3675,7 @@ private module FlowExploration {
|
||||
* of interprocedural steps.
|
||||
*/
|
||||
int getSourceDistance() {
|
||||
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
|
||||
result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3667,7 +3683,7 @@ private module FlowExploration {
|
||||
* of interprocedural steps.
|
||||
*/
|
||||
int getSinkDistance() {
|
||||
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
|
||||
result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
|
||||
@@ -26,15 +26,243 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
|
||||
tupleLimit = 1000
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a simple data-flow analysis for resolving lambda calls. The analysis
|
||||
* currently excludes read-steps, store-steps, and flow-through.
|
||||
*
|
||||
* The analysis uses non-linear recursion: When computing a flow path in or out
|
||||
* of a call, we use the results of the analysis recursively to resolve lamba
|
||||
* calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly.
|
||||
*/
|
||||
private module LambdaFlow {
|
||||
private predicate viableParamNonLambda(DataFlowCall call, int i, ParameterNode p) {
|
||||
p.isParameterOf(viableCallable(call), i)
|
||||
}
|
||||
|
||||
private predicate viableParamLambda(DataFlowCall call, int i, ParameterNode p) {
|
||||
p.isParameterOf(viableCallableLambda(call, _), i)
|
||||
}
|
||||
|
||||
private predicate viableParamArgNonLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
|
||||
exists(int i |
|
||||
viableParamNonLambda(call, i, p) and
|
||||
arg.argumentOf(call, i)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate viableParamArgLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
|
||||
exists(int i |
|
||||
viableParamLambda(call, i, p) and
|
||||
arg.argumentOf(call, i)
|
||||
)
|
||||
}
|
||||
|
||||
private newtype TReturnPositionSimple =
|
||||
TReturnPositionSimple0(DataFlowCallable c, ReturnKind kind) {
|
||||
exists(ReturnNode ret |
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
kind = ret.getKind()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private TReturnPositionSimple getReturnPositionSimple(ReturnNode ret, ReturnKind kind) {
|
||||
result = TReturnPositionSimple0(getNodeEnclosingCallable(ret), kind)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private TReturnPositionSimple viableReturnPosNonLambda(DataFlowCall call, ReturnKind kind) {
|
||||
result = TReturnPositionSimple0(viableCallable(call), kind)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private TReturnPositionSimple viableReturnPosLambda(
|
||||
DataFlowCall call, DataFlowCallOption lastCall, ReturnKind kind
|
||||
) {
|
||||
result = TReturnPositionSimple0(viableCallableLambda(call, lastCall), kind)
|
||||
}
|
||||
|
||||
private predicate viableReturnPosOutNonLambda(
|
||||
DataFlowCall call, TReturnPositionSimple pos, OutNode out
|
||||
) {
|
||||
exists(ReturnKind kind |
|
||||
pos = viableReturnPosNonLambda(call, kind) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate viableReturnPosOutLambda(
|
||||
DataFlowCall call, DataFlowCallOption lastCall, TReturnPositionSimple pos, OutNode out
|
||||
) {
|
||||
exists(ReturnKind kind |
|
||||
pos = viableReturnPosLambda(call, lastCall, kind) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow (inter-procedurally) from `node` (of type `t`) to
|
||||
* the lambda call `lambdaCall`.
|
||||
*
|
||||
* The parameter `toReturn` indicates whether the path from `node` to
|
||||
* `lambdaCall` goes through a return, and `toJump` whether the path goes
|
||||
* through a jump step.
|
||||
*
|
||||
* The call context `lastCall` records the last call on the path from `node`
|
||||
* to `lambdaCall`, if any. That is, `lastCall` is able to target the enclosing
|
||||
* callable of `lambdaCall`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlow(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn,
|
||||
boolean toJump, DataFlowCallOption lastCall
|
||||
) {
|
||||
revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and
|
||||
if node instanceof CastNode or node instanceof ArgumentNode or node instanceof ReturnNode
|
||||
then compatibleTypes(t, getNodeType(node))
|
||||
else any()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlow0(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn,
|
||||
boolean toJump, DataFlowCallOption lastCall
|
||||
) {
|
||||
lambdaCall(lambdaCall, kind, node) and
|
||||
t = getNodeType(node) and
|
||||
toReturn = false and
|
||||
toJump = false and
|
||||
lastCall = TDataFlowCallNone()
|
||||
or
|
||||
// local flow
|
||||
exists(Node mid, DataFlowType t0 |
|
||||
revLambdaFlow(lambdaCall, kind, mid, t0, toReturn, toJump, lastCall)
|
||||
|
|
||||
simpleLocalFlowStep(node, mid) and
|
||||
t = t0
|
||||
or
|
||||
exists(boolean preservesValue |
|
||||
additionalLambdaFlowStep(node, mid, preservesValue) and
|
||||
getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid)
|
||||
|
|
||||
preservesValue = false and
|
||||
t = getNodeType(node)
|
||||
or
|
||||
preservesValue = true and
|
||||
t = t0
|
||||
)
|
||||
)
|
||||
or
|
||||
// jump step
|
||||
exists(Node mid, DataFlowType t0 |
|
||||
revLambdaFlow(lambdaCall, kind, mid, t0, _, _, _) and
|
||||
toReturn = false and
|
||||
toJump = true and
|
||||
lastCall = TDataFlowCallNone()
|
||||
|
|
||||
jumpStep(node, mid) and
|
||||
t = t0
|
||||
or
|
||||
exists(boolean preservesValue |
|
||||
additionalLambdaFlowStep(node, mid, preservesValue) and
|
||||
getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid)
|
||||
|
|
||||
preservesValue = false and
|
||||
t = getNodeType(node)
|
||||
or
|
||||
preservesValue = true and
|
||||
t = t0
|
||||
)
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(ParameterNode p, DataFlowCallOption lastCall0, DataFlowCall call |
|
||||
revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and
|
||||
(
|
||||
if lastCall0 = TDataFlowCallNone() and toJump = false
|
||||
then lastCall = TDataFlowCallSome(call)
|
||||
else lastCall = lastCall0
|
||||
) and
|
||||
toReturn = false
|
||||
|
|
||||
viableParamArgNonLambda(call, p, node)
|
||||
or
|
||||
viableParamArgLambda(call, p, node) // non-linear recursion
|
||||
)
|
||||
or
|
||||
// flow out of a callable
|
||||
exists(TReturnPositionSimple pos |
|
||||
revLambdaFlowOut(lambdaCall, kind, pos, t, toJump, lastCall) and
|
||||
getReturnPositionSimple(node, node.(ReturnNode).getKind()) = pos and
|
||||
toReturn = true
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlowOutLambdaCall(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, OutNode out, DataFlowType t, boolean toJump,
|
||||
DataFlowCall call, DataFlowCallOption lastCall
|
||||
) {
|
||||
revLambdaFlow(lambdaCall, kind, out, t, _, toJump, lastCall) and
|
||||
exists(ReturnKindExt rk |
|
||||
out = rk.getAnOutNode(call) and
|
||||
lambdaCall(call, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlowOut(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, TReturnPositionSimple pos, DataFlowType t,
|
||||
boolean toJump, DataFlowCallOption lastCall
|
||||
) {
|
||||
exists(DataFlowCall call, OutNode out |
|
||||
revLambdaFlow(lambdaCall, kind, out, t, _, toJump, lastCall) and
|
||||
viableReturnPosOutNonLambda(call, pos, out)
|
||||
or
|
||||
// non-linear recursion
|
||||
revLambdaFlowOutLambdaCall(lambdaCall, kind, out, t, toJump, call, lastCall) and
|
||||
viableReturnPosOutLambda(call, _, pos, out)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlowIn(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, ParameterNode p, DataFlowType t, boolean toJump,
|
||||
DataFlowCallOption lastCall
|
||||
) {
|
||||
revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall)
|
||||
}
|
||||
}
|
||||
|
||||
private DataFlowCallable viableCallableExt(DataFlowCall call) {
|
||||
result = viableCallable(call)
|
||||
or
|
||||
result = viableCallableLambda(call, _)
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
/**
|
||||
* Gets a viable target for the lambda call `call`.
|
||||
*
|
||||
* `lastCall` records the call required to reach `call` in order for the result
|
||||
* to be a viable target, if any.
|
||||
*/
|
||||
cached
|
||||
DataFlowCallable viableCallableLambda(DataFlowCall call, DataFlowCallOption lastCall) {
|
||||
exists(Node creation, LambdaCallKind kind |
|
||||
LambdaFlow::revLambdaFlow(call, kind, creation, _, _, _, lastCall) and
|
||||
lambdaCreation(creation, kind, result)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `p` is the `i`th parameter of a viable dispatch target of `call`.
|
||||
* The instance parameter is considered to have index `-1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate viableParam(DataFlowCall call, int i, ParameterNode p) {
|
||||
p.isParameterOf(viableCallable(call), i)
|
||||
p.isParameterOf(viableCallableExt(call), i)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,7 +280,7 @@ private module Cached {
|
||||
|
||||
pragma[nomagic]
|
||||
private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKindExt kind) {
|
||||
viableCallable(call) = result.getCallable() and
|
||||
viableCallableExt(call) = result.getCallable() and
|
||||
kind = result.getKind()
|
||||
}
|
||||
|
||||
@@ -317,6 +545,35 @@ private module Cached {
|
||||
|
||||
cached
|
||||
private module DispatchWithCallContext {
|
||||
/**
|
||||
* Holds if the set of viable implementations that can be called by `call`
|
||||
* might be improved by knowing the call context.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) {
|
||||
mayBenefitFromCallContext(call, callable)
|
||||
or
|
||||
callable = call.getEnclosingCallable() and
|
||||
exists(viableCallableLambda(call, TDataFlowCallSome(_)))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||
* restricted to those `call`s for which a context might make a difference.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) {
|
||||
result = viableImplInCallContext(call, ctx)
|
||||
or
|
||||
result = viableCallableLambda(call, TDataFlowCallSome(ctx))
|
||||
or
|
||||
exists(DataFlowCallable enclosing |
|
||||
mayBenefitFromCallContextExt(call, enclosing) and
|
||||
enclosing = viableCallableExt(ctx) and
|
||||
result = viableCallableLambda(call, TDataFlowCallNone())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the call context `ctx` reduces the set of viable run-time
|
||||
* dispatch targets of call `call` in `c`.
|
||||
@@ -324,10 +581,10 @@ private module Cached {
|
||||
cached
|
||||
predicate reducedViableImplInCallContext(DataFlowCall call, DataFlowCallable c, DataFlowCall ctx) {
|
||||
exists(int tgts, int ctxtgts |
|
||||
mayBenefitFromCallContext(call, c) and
|
||||
c = viableCallable(ctx) and
|
||||
ctxtgts = count(viableImplInCallContext(call, ctx)) and
|
||||
tgts = strictcount(viableCallable(call)) and
|
||||
mayBenefitFromCallContextExt(call, c) and
|
||||
c = viableCallableExt(ctx) and
|
||||
ctxtgts = count(viableImplInCallContextExt(call, ctx)) and
|
||||
tgts = strictcount(viableCallableExt(call)) and
|
||||
ctxtgts < tgts
|
||||
)
|
||||
}
|
||||
@@ -339,7 +596,7 @@ private module Cached {
|
||||
*/
|
||||
cached
|
||||
DataFlowCallable prunedViableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
|
||||
result = viableImplInCallContext(call, ctx) and
|
||||
result = viableImplInCallContextExt(call, ctx) and
|
||||
reducedViableImplInCallContext(call, _, ctx)
|
||||
}
|
||||
|
||||
@@ -351,10 +608,10 @@ private module Cached {
|
||||
cached
|
||||
predicate reducedViableImplInReturn(DataFlowCallable c, DataFlowCall call) {
|
||||
exists(int tgts, int ctxtgts |
|
||||
mayBenefitFromCallContext(call, _) and
|
||||
c = viableCallable(call) and
|
||||
ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContext(call, ctx)) and
|
||||
tgts = strictcount(DataFlowCall ctx | viableCallable(ctx) = call.getEnclosingCallable()) and
|
||||
mayBenefitFromCallContextExt(call, _) and
|
||||
c = viableCallableExt(call) and
|
||||
ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContextExt(call, ctx)) and
|
||||
tgts = strictcount(DataFlowCall ctx | viableCallableExt(ctx) = call.getEnclosingCallable()) and
|
||||
ctxtgts < tgts
|
||||
)
|
||||
}
|
||||
@@ -367,7 +624,7 @@ private module Cached {
|
||||
*/
|
||||
cached
|
||||
DataFlowCallable prunedViableImplInCallContextReverse(DataFlowCall call, DataFlowCall ctx) {
|
||||
result = viableImplInCallContext(call, ctx) and
|
||||
result = viableImplInCallContextExt(call, ctx) and
|
||||
reducedViableImplInReturn(result, call)
|
||||
}
|
||||
}
|
||||
@@ -415,6 +672,30 @@ private module Cached {
|
||||
store(node1, tc.getContent(), node2, contentType, tc.getContainerType())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `fromNode` to `toNode` because they are the post-update
|
||||
* nodes of some function output and input respectively, where the output and input
|
||||
* are aliases. A typical example is a function returning `this`, implementing a fluent
|
||||
* interface.
|
||||
*/
|
||||
cached
|
||||
predicate reverseStepThroughInputOutputAlias(PostUpdateNode fromNode, PostUpdateNode toNode) {
|
||||
exists(Node fromPre, Node toPre |
|
||||
fromPre = fromNode.getPreUpdateNode() and
|
||||
toPre = toNode.getPreUpdateNode()
|
||||
|
|
||||
exists(DataFlowCall c |
|
||||
// Does the language-specific simpleLocalFlowStep already model flow
|
||||
// from function input to output?
|
||||
fromPre = getAnOutNode(c, _) and
|
||||
toPre.(ArgumentNode).argumentOf(c, _) and
|
||||
simpleLocalFlowStep(toPre.(ArgumentNode), fromPre)
|
||||
)
|
||||
or
|
||||
argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the call context `call` either improves virtual dispatch in
|
||||
* `callable` or if it allows us to prune unreachable nodes in `callable`.
|
||||
@@ -423,7 +704,7 @@ private module Cached {
|
||||
predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
|
||||
reducedViableImplInCallContext(_, callable, call)
|
||||
or
|
||||
exists(Node n | n.getEnclosingCallable() = callable | isUnreachableInCall(n, call))
|
||||
exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCall(n, call))
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -457,6 +738,11 @@ private module Cached {
|
||||
TBooleanNone() or
|
||||
TBooleanSome(boolean b) { b = true or b = false }
|
||||
|
||||
cached
|
||||
newtype TDataFlowCallOption =
|
||||
TDataFlowCallNone() or
|
||||
TDataFlowCallSome(DataFlowCall call)
|
||||
|
||||
cached
|
||||
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
|
||||
|
||||
@@ -568,7 +854,7 @@ class CallContextSomeCall extends CallContextCall, TSomeCall {
|
||||
override string toString() { result = "CcSomeCall" }
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) {
|
||||
exists(ParameterNode p | p.getEnclosingCallable() = callable)
|
||||
exists(ParameterNode p | getNodeEnclosingCallable(p) = callable)
|
||||
}
|
||||
|
||||
override predicate matchesCall(DataFlowCall call) { any() }
|
||||
@@ -613,7 +899,7 @@ class LocalCallContextSpecificCall extends LocalCallContext, TSpecificLocalCall
|
||||
}
|
||||
|
||||
private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) {
|
||||
exists(Node n | n.getEnclosingCallable() = callable and isUnreachableInCall(n, call))
|
||||
exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCall(n, call))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -722,9 +1008,22 @@ class ReturnPosition extends TReturnPosition0 {
|
||||
string toString() { result = "[" + kind + "] " + c }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the enclosing callable of `n`. Unlike `n.getEnclosingCallable()`, this
|
||||
* predicate ensures that joins go from `n` to the result instead of the other
|
||||
* way around.
|
||||
*/
|
||||
pragma[inline]
|
||||
DataFlowCallable getNodeEnclosingCallable(Node n) {
|
||||
exists(Node n0 |
|
||||
pragma[only_bind_into](n0) = n and
|
||||
pragma[only_bind_into](result) = n0.getEnclosingCallable()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private DataFlowCallable returnNodeGetEnclosingCallable(ReturnNodeExt ret) {
|
||||
result = ret.getEnclosingCallable()
|
||||
result = getNodeEnclosingCallable(ret)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -740,7 +1039,7 @@ ReturnPosition getReturnPosition(ReturnNodeExt ret) {
|
||||
|
||||
bindingset[cc, callable]
|
||||
predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall call) {
|
||||
cc instanceof CallContextAny and callable = viableCallable(call)
|
||||
cc instanceof CallContextAny and callable = viableCallableExt(call)
|
||||
or
|
||||
exists(DataFlowCallable c0, DataFlowCall call0 |
|
||||
call0.getEnclosingCallable() = callable and
|
||||
@@ -754,14 +1053,14 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
|
||||
exists(DataFlowCall ctx | cc = TSpecificCall(ctx) |
|
||||
if reducedViableImplInCallContext(call, _, ctx)
|
||||
then result = prunedViableImplInCallContext(call, ctx)
|
||||
else result = viableCallable(call)
|
||||
else result = viableCallableExt(call)
|
||||
)
|
||||
or
|
||||
result = viableCallable(call) and cc instanceof CallContextSomeCall
|
||||
result = viableCallableExt(call) and cc instanceof CallContextSomeCall
|
||||
or
|
||||
result = viableCallable(call) and cc instanceof CallContextAny
|
||||
result = viableCallableExt(call) and cc instanceof CallContextAny
|
||||
or
|
||||
result = viableCallable(call) and cc instanceof CallContextReturn
|
||||
result = viableCallableExt(call) and cc instanceof CallContextReturn
|
||||
}
|
||||
|
||||
predicate read = readStep/3;
|
||||
@@ -775,6 +1074,19 @@ class BooleanOption extends TBooleanOption {
|
||||
}
|
||||
}
|
||||
|
||||
/** An optional `DataFlowCall`. */
|
||||
class DataFlowCallOption extends TDataFlowCallOption {
|
||||
string toString() {
|
||||
this = TDataFlowCallNone() and
|
||||
result = "(none)"
|
||||
or
|
||||
exists(DataFlowCall call |
|
||||
this = TDataFlowCallSome(call) and
|
||||
result = call.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Content tagged with the type of a containing object. */
|
||||
class TypedContent extends MkTypedContent {
|
||||
private Content c;
|
||||
|
||||
@@ -31,9 +31,19 @@ private class PrimaryArgumentNode extends ArgumentNode {
|
||||
override predicate argumentOf(DataFlowCall call, int pos) { op = call.getArgumentOperand(pos) }
|
||||
|
||||
override string toString() {
|
||||
result = "Argument " + op.(PositionalArgumentOperand).getIndex()
|
||||
exists(Expr unconverted |
|
||||
unconverted = op.getDef().getUnconvertedResultExpression() and
|
||||
result = unconverted.toString()
|
||||
)
|
||||
or
|
||||
op instanceof ThisArgumentOperand and result = "This argument"
|
||||
// Certain instructions don't map to an unconverted result expression. For these cases
|
||||
// we fall back to a simpler naming scheme. This can happen in IR-generated constructors.
|
||||
not exists(op.getDef().getUnconvertedResultExpression()) and
|
||||
(
|
||||
result = "Argument " + op.(PositionalArgumentOperand).getIndex()
|
||||
or
|
||||
op instanceof ThisArgumentOperand and result = "Argument this"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +62,18 @@ private class SideEffectArgumentNode extends ArgumentNode {
|
||||
pos = getArgumentPosOfSideEffect(read.getIndex())
|
||||
}
|
||||
|
||||
override string toString() { result = "Argument " + read.getIndex() + " indirection" }
|
||||
override string toString() {
|
||||
result = read.getArgumentDef().getUnconvertedResultExpression().toString() + " indirection"
|
||||
or
|
||||
// Some instructions don't map to an unconverted result expression. For these cases
|
||||
// we fall back to a simpler naming scheme. This can happen in IR-generated constructors.
|
||||
not exists(read.getArgumentDef().getUnconvertedResultExpression()) and
|
||||
(
|
||||
if read.getIndex() = -1
|
||||
then result = "Argument this indirection"
|
||||
else result = "Argument " + read.getIndex() + " indirection"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private newtype TReturnKind =
|
||||
@@ -526,4 +547,15 @@ predicate isImmutableOrUnobservable(Node n) {
|
||||
}
|
||||
|
||||
/** Holds if `n` should be hidden from path explanations. */
|
||||
predicate nodeIsHidden(Node n) { n instanceof OperandNode }
|
||||
predicate nodeIsHidden(Node n) { n instanceof OperandNode and not n instanceof ArgumentNode }
|
||||
|
||||
class LambdaCallKind = Unit;
|
||||
|
||||
/** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */
|
||||
predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) { none() }
|
||||
|
||||
/** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */
|
||||
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { none() }
|
||||
|
||||
/** Extra data-flow steps needed for lamba flow analysis. */
|
||||
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }
|
||||
|
||||
@@ -693,7 +693,11 @@ private predicate simpleInstructionLocalFlowStep(Operand opFrom, Instruction iTo
|
||||
exists(ChiInstruction chi | chi = iTo |
|
||||
opFrom.getAnyDef() instanceof WriteSideEffectInstruction and
|
||||
chi.getPartialOperand() = opFrom and
|
||||
not chi.isResultConflated()
|
||||
not chi.isResultConflated() and
|
||||
// In a call such as `set_value(&x->val);` we don't want the memory representing `x` to receive
|
||||
// dataflow by a simple step. Instead, this is handled by field flow. If we add a simple step here
|
||||
// we can get field-to-object flow.
|
||||
not chi.isPartialUpdate()
|
||||
)
|
||||
or
|
||||
// Flow through modeled functions
|
||||
|
||||
@@ -2055,6 +2055,13 @@ class ChiInstruction extends Instruction {
|
||||
final predicate getUpdatedInterval(int startBit, int endBit) {
|
||||
Construction::getIntervalUpdatedByChi(this, startBit, endBit)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `ChiPartialOperand` totally, but not exactly, overlaps with the `ChiTotalOperand`.
|
||||
* This means that the `ChiPartialOperand` will not override the entire memory associated with the
|
||||
* `ChiTotalOperand`.
|
||||
*/
|
||||
final predicate isPartialUpdate() { Construction::chiOnlyPartiallyUpdatesLocation(this) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,79 +10,32 @@ private import Imports::MemoryAccessKind
|
||||
private import Imports::IRType
|
||||
private import Imports::Overlap
|
||||
private import Imports::OperandTag
|
||||
|
||||
cached
|
||||
private newtype TOperand =
|
||||
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
|
||||
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
|
||||
not Construction::isInCycle(useInstr) and
|
||||
strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1
|
||||
} or
|
||||
TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) {
|
||||
useInstr.getOpcode().hasOperand(tag)
|
||||
} or
|
||||
TPhiOperand(
|
||||
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
|
||||
) {
|
||||
defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
|
||||
}
|
||||
private import Imports::TOperand
|
||||
private import internal.OperandInternal
|
||||
|
||||
/**
|
||||
* Base class for all register operands. This is a placeholder for the IPA union type that we will
|
||||
* eventually use for this purpose.
|
||||
* An operand of an `Instruction` in this stage of the IR. Implemented as a union of the branches
|
||||
* of `TOperand` that are used in this stage.
|
||||
*/
|
||||
private class RegisterOperandBase extends TRegisterOperand {
|
||||
/** Gets a textual representation of this element. */
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the register operand with the specified parameters.
|
||||
*/
|
||||
private RegisterOperandBase registerOperand(
|
||||
Instruction useInstr, RegisterOperandTag tag, Instruction defInstr
|
||||
) {
|
||||
result = TRegisterOperand(useInstr, tag, defInstr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for all non-Phi memory operands. This is a placeholder for the IPA union type that we
|
||||
* will eventually use for this purpose.
|
||||
*/
|
||||
private class NonPhiMemoryOperandBase extends TNonPhiMemoryOperand {
|
||||
/** Gets a textual representation of this element. */
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the non-Phi memory operand with the specified parameters.
|
||||
*/
|
||||
private NonPhiMemoryOperandBase nonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) {
|
||||
result = TNonPhiMemoryOperand(useInstr, tag)
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for all Phi operands. This is a placeholder for the IPA union type that we will
|
||||
* eventually use for this purpose.
|
||||
*/
|
||||
private class PhiOperandBase extends TPhiOperand {
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Phi operand with the specified parameters.
|
||||
*/
|
||||
private PhiOperandBase phiOperand(
|
||||
Instruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
|
||||
) {
|
||||
result = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap)
|
||||
}
|
||||
private class TStageOperand =
|
||||
TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand;
|
||||
|
||||
/**
|
||||
* An operand of an `Instruction`. The operand represents a use of the result of one instruction
|
||||
* (the defining instruction) in another instruction (the use instruction)
|
||||
*/
|
||||
class Operand extends TOperand {
|
||||
class Operand extends TStageOperand {
|
||||
cached
|
||||
Operand() {
|
||||
// Ensure that the operand does not refer to instructions from earlier stages that are unreachable here
|
||||
exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) or
|
||||
exists(Instruction use | this = nonSSAMemoryOperand(use, _)) or
|
||||
exists(Instruction use, Instruction def, IRBlock predecessorBlock |
|
||||
this = phiOperand(use, def, predecessorBlock, _)
|
||||
) or
|
||||
exists(Instruction use | this = chiOperand(use, _))
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = "Operand" }
|
||||
|
||||
@@ -238,9 +191,11 @@ class Operand extends TOperand {
|
||||
* An operand that consumes a memory result (e.g. the `LoadOperand` on a `Load` instruction).
|
||||
*/
|
||||
class MemoryOperand extends Operand {
|
||||
cached
|
||||
MemoryOperand() {
|
||||
this instanceof NonPhiMemoryOperandBase or
|
||||
this instanceof PhiOperandBase
|
||||
this instanceof TNonSSAMemoryOperand or
|
||||
this instanceof TPhiOperand or
|
||||
this instanceof TChiOperand
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -278,7 +233,8 @@ class NonPhiOperand extends Operand {
|
||||
|
||||
NonPhiOperand() {
|
||||
this = registerOperand(useInstr, tag, _) or
|
||||
this = nonPhiMemoryOperand(useInstr, tag)
|
||||
this = nonSSAMemoryOperand(useInstr, tag) or
|
||||
this = chiOperand(useInstr, tag)
|
||||
}
|
||||
|
||||
final override Instruction getUse() { result = useInstr }
|
||||
@@ -298,10 +254,11 @@ class NonPhiOperand extends Operand {
|
||||
/**
|
||||
* An operand that consumes a register (non-memory) result.
|
||||
*/
|
||||
class RegisterOperand extends NonPhiOperand, RegisterOperandBase {
|
||||
class RegisterOperand extends NonPhiOperand, TRegisterOperand {
|
||||
override RegisterOperandTag tag;
|
||||
Instruction defInstr;
|
||||
|
||||
cached
|
||||
RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) }
|
||||
|
||||
final override string toString() { result = tag.toString() }
|
||||
@@ -317,10 +274,15 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase {
|
||||
/**
|
||||
* A memory operand other than the operand of a `Phi` instruction.
|
||||
*/
|
||||
class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase {
|
||||
class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand {
|
||||
override MemoryOperandTag tag;
|
||||
|
||||
NonPhiMemoryOperand() { this = nonPhiMemoryOperand(useInstr, tag) }
|
||||
cached
|
||||
NonPhiMemoryOperand() {
|
||||
this = nonSSAMemoryOperand(useInstr, tag)
|
||||
or
|
||||
this = chiOperand(useInstr, tag)
|
||||
}
|
||||
|
||||
final override string toString() { result = tag.toString() }
|
||||
|
||||
@@ -462,12 +424,13 @@ class SideEffectOperand extends TypedOperand {
|
||||
/**
|
||||
* An operand of a `PhiInstruction`.
|
||||
*/
|
||||
class PhiInputOperand extends MemoryOperand, PhiOperandBase {
|
||||
class PhiInputOperand extends MemoryOperand, TPhiOperand {
|
||||
PhiInstruction useInstr;
|
||||
Instruction defInstr;
|
||||
IRBlock predecessorBlock;
|
||||
Overlap overlap;
|
||||
|
||||
cached
|
||||
PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) }
|
||||
|
||||
override string toString() { result = "Phi" }
|
||||
|
||||
@@ -629,7 +629,11 @@ MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
|
||||
}
|
||||
|
||||
/** Gets the start bit offset of a `MemoryLocation`, if any. */
|
||||
int getStartBitOffset(VariableMemoryLocation location) { result = location.getStartBitOffset() }
|
||||
int getStartBitOffset(VariableMemoryLocation location) {
|
||||
result = location.getStartBitOffset() and Ints::hasValue(result)
|
||||
}
|
||||
|
||||
/** Gets the end bit offset of a `MemoryLocation`, if any. */
|
||||
int getEndBitOffset(VariableMemoryLocation location) { result = location.getEndBitOffset() }
|
||||
int getEndBitOffset(VariableMemoryLocation location) {
|
||||
result = location.getEndBitOffset() and Ints::hasValue(result)
|
||||
}
|
||||
|
||||
@@ -2,3 +2,4 @@ import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind
|
||||
import semmle.code.cpp.ir.implementation.IRType as IRType
|
||||
import semmle.code.cpp.ir.internal.Overlap as Overlap
|
||||
import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag
|
||||
import semmle.code.cpp.ir.implementation.internal.TOperand as TOperand
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
private import semmle.code.cpp.ir.implementation.internal.TOperand
|
||||
import AliasedSSAOperands
|
||||
@@ -6,6 +6,7 @@ private import Imports::Overlap
|
||||
private import Imports::TInstruction
|
||||
private import Imports::RawIR as RawIR
|
||||
private import SSAInstructions
|
||||
private import SSAOperands
|
||||
private import NewIR
|
||||
|
||||
private class OldBlock = Reachability::ReachableBlock;
|
||||
@@ -177,6 +178,22 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `ChiPartialOperand` only partially overlaps with the `ChiTotalOperand`.
|
||||
* This means that the `ChiPartialOperand` will not override the entire memory associated
|
||||
* with the `ChiTotalOperand`.
|
||||
*/
|
||||
cached
|
||||
predicate chiOnlyPartiallyUpdatesLocation(ChiInstruction chi) {
|
||||
exists(Alias::MemoryLocation location, OldInstruction oldInstruction |
|
||||
oldInstruction = getOldInstruction(chi.getPartial()) and
|
||||
location = Alias::getResultMemoryLocation(oldInstruction)
|
||||
|
|
||||
Alias::getStartBitOffset(location) != 0 or
|
||||
Alias::getEndBitOffset(location) != 8 * location.getType().getByteSize()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
|
||||
* through a phi instruction and therefore should be impossible.
|
||||
|
||||
@@ -3,3 +3,4 @@ import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag
|
||||
import semmle.code.cpp.ir.internal.Overlap as Overlap
|
||||
import semmle.code.cpp.ir.implementation.internal.TInstruction as TInstruction
|
||||
import semmle.code.cpp.ir.implementation.raw.IR as RawIR
|
||||
import semmle.code.cpp.ir.implementation.internal.TOperand as TOperand
|
||||
|
||||
@@ -5,3 +5,4 @@ import semmle.code.cpp.ir.implementation.aliased_ssa.IR as NewIR
|
||||
import semmle.code.cpp.ir.implementation.internal.TInstruction::AliasedSSAInstructions as SSAInstructions
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
import AliasedSSA as Alias
|
||||
import semmle.code.cpp.ir.implementation.internal.TOperand::AliasedSSAOperands as SSAOperands
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
private import TInstruction
|
||||
private import OperandTag
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as RawConstruction
|
||||
private import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedConstruction
|
||||
private import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSAConstruction as AliasedConstruction
|
||||
private import semmle.code.cpp.ir.implementation.raw.IR as Raw
|
||||
private import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as Unaliased
|
||||
private import semmle.code.cpp.ir.implementation.aliased_ssa.IR as Aliased
|
||||
private import semmle.code.cpp.ir.internal.Overlap
|
||||
|
||||
/**
|
||||
* Provides the newtype used to represent operands across all phases of the IR.
|
||||
*/
|
||||
private module Internal {
|
||||
/**
|
||||
* An IR operand. `TOperand` is shared across all phases of the IR. There are branches of this
|
||||
* type for operands created directly from the AST (`TRegisterOperand` and `TNonSSAMemoryOperand`),
|
||||
* for operands computed by each stage of SSA construction (`T*PhiOperand` and
|
||||
* `TAliasedChiOperand`), and a placehold branch for operands that do not exist in a given
|
||||
* stage of IR construction (`TNoOperand`).
|
||||
*/
|
||||
cached
|
||||
newtype TOperand =
|
||||
// RAW
|
||||
TRegisterOperand(TRawInstruction useInstr, RegisterOperandTag tag, TRawInstruction defInstr) {
|
||||
defInstr = RawConstruction::getRegisterOperandDefinition(useInstr, tag) and
|
||||
not RawConstruction::isInCycle(useInstr) and
|
||||
strictcount(RawConstruction::getRegisterOperandDefinition(useInstr, tag)) = 1
|
||||
} or
|
||||
// Placeholder for Phi and Chi operands in stages that don't have the corresponding instructions
|
||||
TNoOperand() { none() } or
|
||||
// Can be "removed" later when there's unreachable code
|
||||
// These operands can be reused across all three stages. They just get different defs.
|
||||
TNonSSAMemoryOperand(Raw::Instruction useInstr, MemoryOperandTag tag) {
|
||||
// Has no definition in raw but will get definitions later
|
||||
useInstr.getOpcode().hasOperand(tag)
|
||||
} or
|
||||
TUnaliasedPhiOperand(
|
||||
Unaliased::PhiInstruction useInstr, Unaliased::Instruction defInstr,
|
||||
Unaliased::IRBlock predecessorBlock, Overlap overlap
|
||||
) {
|
||||
defInstr = UnaliasedConstruction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
|
||||
} or
|
||||
//// ALIASED
|
||||
////
|
||||
// Until we share SSA, these will be all the phis there are. With SSA
|
||||
// sharing, these will add to the ones that are already there.
|
||||
// If we share SSA, be careful with the case where we remove all possible
|
||||
// indirect writes to a variable because they're dead code. In that case it's
|
||||
// important that we use the same definition of "is variable aliased" across
|
||||
// the phases.
|
||||
TAliasedPhiOperand(
|
||||
TAliasedSSAPhiInstruction useInstr, Aliased::Instruction defInstr,
|
||||
Aliased::IRBlock predecessorBlock, Overlap overlap
|
||||
) {
|
||||
defInstr = AliasedConstruction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
|
||||
} or
|
||||
TAliasedChiOperand(TAliasedSSAChiInstruction useInstr, ChiOperandTag tag) { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Reexports some branches from `TOperand` so they can be used in stage modules without importing
|
||||
* `TOperand` itself.
|
||||
*/
|
||||
private module Shared {
|
||||
class TRegisterOperand = Internal::TRegisterOperand;
|
||||
|
||||
/**
|
||||
* Returns the register operand with the specified parameters.
|
||||
*/
|
||||
TRegisterOperand registerOperand(
|
||||
TRawInstruction useInstr, RegisterOperandTag tag, TRawInstruction defInstr
|
||||
) {
|
||||
result = Internal::TRegisterOperand(useInstr, tag, defInstr)
|
||||
}
|
||||
|
||||
class TNonSSAMemoryOperand = Internal::TNonSSAMemoryOperand;
|
||||
|
||||
/**
|
||||
* Returns the non-Phi memory operand with the specified parameters.
|
||||
*/
|
||||
TNonSSAMemoryOperand nonSSAMemoryOperand(TRawInstruction useInstr, MemoryOperandTag tag) {
|
||||
result = Internal::TNonSSAMemoryOperand(useInstr, tag)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides wrappers for the constructors of each branch of `TOperand` that is used by the
|
||||
* raw IR stage.
|
||||
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
|
||||
* a class alias.
|
||||
*/
|
||||
module RawOperands {
|
||||
import Shared
|
||||
|
||||
class TPhiOperand = Internal::TNoOperand;
|
||||
|
||||
class TChiOperand = Internal::TNoOperand;
|
||||
|
||||
class TNonPhiMemoryOperand = TNonSSAMemoryOperand or TChiOperand;
|
||||
|
||||
/**
|
||||
* Returns the Phi operand with the specified parameters.
|
||||
*/
|
||||
TPhiOperand phiOperand(
|
||||
Raw::PhiInstruction useInstr, Raw::Instruction defInstr, Raw::IRBlock predecessorBlock,
|
||||
Overlap overlap
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Chi operand with the specified parameters.
|
||||
*/
|
||||
TChiOperand chiOperand(Raw::Instruction useInstr, ChiOperandTag tag) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides wrappers for the constructors of each branch of `TOperand` that is used by the
|
||||
* unaliased SSA stage.
|
||||
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
|
||||
* a class alias.
|
||||
*/
|
||||
module UnaliasedSSAOperands {
|
||||
import Shared
|
||||
|
||||
class TPhiOperand = Internal::TUnaliasedPhiOperand;
|
||||
|
||||
class TChiOperand = Internal::TNoOperand;
|
||||
|
||||
class TNonPhiMemoryOperand = TNonSSAMemoryOperand or TChiOperand;
|
||||
|
||||
/**
|
||||
* Returns the Phi operand with the specified parameters.
|
||||
*/
|
||||
TPhiOperand phiOperand(
|
||||
Unaliased::PhiInstruction useInstr, Unaliased::Instruction defInstr,
|
||||
Unaliased::IRBlock predecessorBlock, Overlap overlap
|
||||
) {
|
||||
result = Internal::TUnaliasedPhiOperand(useInstr, defInstr, predecessorBlock, overlap)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Chi operand with the specified parameters.
|
||||
*/
|
||||
TChiOperand chiOperand(Unaliased::Instruction useInstr, ChiOperandTag tag) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides wrappers for the constructors of each branch of `TOperand` that is used by the
|
||||
* asliased SSA stage.
|
||||
* These wrappers are not parameterized because it is not possible to invoke an IPA constructor via
|
||||
* a class alias.
|
||||
*/
|
||||
module AliasedSSAOperands {
|
||||
import Shared
|
||||
|
||||
class TPhiOperand = Internal::TAliasedPhiOperand;
|
||||
|
||||
class TChiOperand = Internal::TAliasedChiOperand;
|
||||
|
||||
class TNonPhiMemoryOperand = TNonSSAMemoryOperand or TChiOperand;
|
||||
|
||||
/**
|
||||
* Returns the Phi operand with the specified parameters.
|
||||
*/
|
||||
TPhiOperand phiOperand(
|
||||
TAliasedSSAPhiInstruction useInstr, Aliased::Instruction defInstr,
|
||||
Aliased::IRBlock predecessorBlock, Overlap overlap
|
||||
) {
|
||||
result = Internal::TAliasedPhiOperand(useInstr, defInstr, predecessorBlock, overlap)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Chi operand with the specified parameters.
|
||||
*/
|
||||
TChiOperand chiOperand(TAliasedSSAChiInstruction useInstr, ChiOperandTag tag) {
|
||||
result = Internal::TAliasedChiOperand(useInstr, tag)
|
||||
}
|
||||
}
|
||||
@@ -2055,6 +2055,13 @@ class ChiInstruction extends Instruction {
|
||||
final predicate getUpdatedInterval(int startBit, int endBit) {
|
||||
Construction::getIntervalUpdatedByChi(this, startBit, endBit)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `ChiPartialOperand` totally, but not exactly, overlaps with the `ChiTotalOperand`.
|
||||
* This means that the `ChiPartialOperand` will not override the entire memory associated with the
|
||||
* `ChiTotalOperand`.
|
||||
*/
|
||||
final predicate isPartialUpdate() { Construction::chiOnlyPartiallyUpdatesLocation(this) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,79 +10,32 @@ private import Imports::MemoryAccessKind
|
||||
private import Imports::IRType
|
||||
private import Imports::Overlap
|
||||
private import Imports::OperandTag
|
||||
|
||||
cached
|
||||
private newtype TOperand =
|
||||
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
|
||||
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
|
||||
not Construction::isInCycle(useInstr) and
|
||||
strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1
|
||||
} or
|
||||
TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) {
|
||||
useInstr.getOpcode().hasOperand(tag)
|
||||
} or
|
||||
TPhiOperand(
|
||||
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
|
||||
) {
|
||||
defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
|
||||
}
|
||||
private import Imports::TOperand
|
||||
private import internal.OperandInternal
|
||||
|
||||
/**
|
||||
* Base class for all register operands. This is a placeholder for the IPA union type that we will
|
||||
* eventually use for this purpose.
|
||||
* An operand of an `Instruction` in this stage of the IR. Implemented as a union of the branches
|
||||
* of `TOperand` that are used in this stage.
|
||||
*/
|
||||
private class RegisterOperandBase extends TRegisterOperand {
|
||||
/** Gets a textual representation of this element. */
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the register operand with the specified parameters.
|
||||
*/
|
||||
private RegisterOperandBase registerOperand(
|
||||
Instruction useInstr, RegisterOperandTag tag, Instruction defInstr
|
||||
) {
|
||||
result = TRegisterOperand(useInstr, tag, defInstr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for all non-Phi memory operands. This is a placeholder for the IPA union type that we
|
||||
* will eventually use for this purpose.
|
||||
*/
|
||||
private class NonPhiMemoryOperandBase extends TNonPhiMemoryOperand {
|
||||
/** Gets a textual representation of this element. */
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the non-Phi memory operand with the specified parameters.
|
||||
*/
|
||||
private NonPhiMemoryOperandBase nonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) {
|
||||
result = TNonPhiMemoryOperand(useInstr, tag)
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for all Phi operands. This is a placeholder for the IPA union type that we will
|
||||
* eventually use for this purpose.
|
||||
*/
|
||||
private class PhiOperandBase extends TPhiOperand {
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Phi operand with the specified parameters.
|
||||
*/
|
||||
private PhiOperandBase phiOperand(
|
||||
Instruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
|
||||
) {
|
||||
result = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap)
|
||||
}
|
||||
private class TStageOperand =
|
||||
TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand;
|
||||
|
||||
/**
|
||||
* An operand of an `Instruction`. The operand represents a use of the result of one instruction
|
||||
* (the defining instruction) in another instruction (the use instruction)
|
||||
*/
|
||||
class Operand extends TOperand {
|
||||
class Operand extends TStageOperand {
|
||||
cached
|
||||
Operand() {
|
||||
// Ensure that the operand does not refer to instructions from earlier stages that are unreachable here
|
||||
exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) or
|
||||
exists(Instruction use | this = nonSSAMemoryOperand(use, _)) or
|
||||
exists(Instruction use, Instruction def, IRBlock predecessorBlock |
|
||||
this = phiOperand(use, def, predecessorBlock, _)
|
||||
) or
|
||||
exists(Instruction use | this = chiOperand(use, _))
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = "Operand" }
|
||||
|
||||
@@ -238,9 +191,11 @@ class Operand extends TOperand {
|
||||
* An operand that consumes a memory result (e.g. the `LoadOperand` on a `Load` instruction).
|
||||
*/
|
||||
class MemoryOperand extends Operand {
|
||||
cached
|
||||
MemoryOperand() {
|
||||
this instanceof NonPhiMemoryOperandBase or
|
||||
this instanceof PhiOperandBase
|
||||
this instanceof TNonSSAMemoryOperand or
|
||||
this instanceof TPhiOperand or
|
||||
this instanceof TChiOperand
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -278,7 +233,8 @@ class NonPhiOperand extends Operand {
|
||||
|
||||
NonPhiOperand() {
|
||||
this = registerOperand(useInstr, tag, _) or
|
||||
this = nonPhiMemoryOperand(useInstr, tag)
|
||||
this = nonSSAMemoryOperand(useInstr, tag) or
|
||||
this = chiOperand(useInstr, tag)
|
||||
}
|
||||
|
||||
final override Instruction getUse() { result = useInstr }
|
||||
@@ -298,10 +254,11 @@ class NonPhiOperand extends Operand {
|
||||
/**
|
||||
* An operand that consumes a register (non-memory) result.
|
||||
*/
|
||||
class RegisterOperand extends NonPhiOperand, RegisterOperandBase {
|
||||
class RegisterOperand extends NonPhiOperand, TRegisterOperand {
|
||||
override RegisterOperandTag tag;
|
||||
Instruction defInstr;
|
||||
|
||||
cached
|
||||
RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) }
|
||||
|
||||
final override string toString() { result = tag.toString() }
|
||||
@@ -317,10 +274,15 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase {
|
||||
/**
|
||||
* A memory operand other than the operand of a `Phi` instruction.
|
||||
*/
|
||||
class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase {
|
||||
class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand {
|
||||
override MemoryOperandTag tag;
|
||||
|
||||
NonPhiMemoryOperand() { this = nonPhiMemoryOperand(useInstr, tag) }
|
||||
cached
|
||||
NonPhiMemoryOperand() {
|
||||
this = nonSSAMemoryOperand(useInstr, tag)
|
||||
or
|
||||
this = chiOperand(useInstr, tag)
|
||||
}
|
||||
|
||||
final override string toString() { result = tag.toString() }
|
||||
|
||||
@@ -462,12 +424,13 @@ class SideEffectOperand extends TypedOperand {
|
||||
/**
|
||||
* An operand of a `PhiInstruction`.
|
||||
*/
|
||||
class PhiInputOperand extends MemoryOperand, PhiOperandBase {
|
||||
class PhiInputOperand extends MemoryOperand, TPhiOperand {
|
||||
PhiInstruction useInstr;
|
||||
Instruction defInstr;
|
||||
IRBlock predecessorBlock;
|
||||
Overlap overlap;
|
||||
|
||||
cached
|
||||
PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) }
|
||||
|
||||
override string toString() { result = "Phi" }
|
||||
|
||||
@@ -194,6 +194,8 @@ predicate getIntervalUpdatedByChi(ChiInstruction chi, int startBit, int endBit)
|
||||
*/
|
||||
predicate getUsedInterval(Operand operand, int startBit, int endBit) { none() }
|
||||
|
||||
predicate chiOnlyPartiallyUpdatesLocation(ChiInstruction chi) { none() }
|
||||
|
||||
/** Gets a non-phi instruction that defines an operand of `instr`. */
|
||||
private Instruction getNonPhiOperandDef(Instruction instr) {
|
||||
result = getRegisterOperandDefinition(instr, _)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user