mirror of
https://github.com/github/codeql.git
synced 2026-05-17 20:57:07 +02:00
Compare commits
1516 Commits
codeql-cli
...
ginsbach/w
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8cdd8b6ae0 | ||
|
|
0194af9432 | ||
|
|
7974e3ad38 | ||
|
|
b05512a958 | ||
|
|
bf4d88175c | ||
|
|
8f152b7380 | ||
|
|
fc121e1cbd | ||
|
|
a247ae4357 | ||
|
|
74ae2e0857 | ||
|
|
8e371fd05a | ||
|
|
948f1d8e34 | ||
|
|
d7e560c611 | ||
|
|
3e21f479a9 | ||
|
|
d66506b0a3 | ||
|
|
48e783184c | ||
|
|
0d9a85ca6b | ||
|
|
24d8abd2c2 | ||
|
|
922b276fac | ||
|
|
717070c7e4 | ||
|
|
a7f97895ac | ||
|
|
0e5a2c4573 | ||
|
|
549c9eee1a | ||
|
|
a87731115a | ||
|
|
beb66fc4db | ||
|
|
744c495ac2 | ||
|
|
2905bb8b9a | ||
|
|
7d6a497136 | ||
|
|
f85aff869c | ||
|
|
5016c6436a | ||
|
|
d27316eb3e | ||
|
|
0afe22d60c | ||
|
|
dd86da3f24 | ||
|
|
31ac6442e8 | ||
|
|
d55db836cb | ||
|
|
498f9b2547 | ||
|
|
51d04cb5b3 | ||
|
|
c0b65314be | ||
|
|
c7cd75437f | ||
|
|
a3d17a1437 | ||
|
|
78370cf63f | ||
|
|
504c34ed2c | ||
|
|
d6f9e37e39 | ||
|
|
9e5a38debd | ||
|
|
d3c6093f37 | ||
|
|
c8f2937df9 | ||
|
|
7f1f2b4dd3 | ||
|
|
dcdd54593e | ||
|
|
8f91e9eba0 | ||
|
|
f4e636dcd6 | ||
|
|
097b6e5e33 | ||
|
|
d913668943 | ||
|
|
b4e35f54d9 | ||
|
|
646bf99489 | ||
|
|
df5eab33f9 | ||
|
|
b1f28afcbd | ||
|
|
474b337eeb | ||
|
|
c91ed80e6c | ||
|
|
7ac7830973 | ||
|
|
3fe5dd0f35 | ||
|
|
8b465e86e0 | ||
|
|
d9f243d18a | ||
|
|
fd88b72101 | ||
|
|
65ac5b862d | ||
|
|
2241d7b359 | ||
|
|
75edcf0b4f | ||
|
|
69468514f0 | ||
|
|
91be483c57 | ||
|
|
fc96c1c400 | ||
|
|
5db6abe2f4 | ||
|
|
894f5d523c | ||
|
|
10e76ff28f | ||
|
|
fc7d9c2c09 | ||
|
|
90e8368258 | ||
|
|
7adb7b67f2 | ||
|
|
8783746516 | ||
|
|
88e6cbaacd | ||
|
|
80d41d9fe5 | ||
|
|
ca89560849 | ||
|
|
08fa611700 | ||
|
|
2a501956b3 | ||
|
|
b69be30b88 | ||
|
|
b53759c5a0 | ||
|
|
7a7586488a | ||
|
|
be69c3a458 | ||
|
|
2d1ba59e6d | ||
|
|
68e53054c6 | ||
|
|
fab8400ecd | ||
|
|
856d512aa6 | ||
|
|
7c1720a1d1 | ||
|
|
5437bd7a41 | ||
|
|
cf80773453 | ||
|
|
d1eb774737 | ||
|
|
e0606d61b6 | ||
|
|
c12837cff0 | ||
|
|
7b8a51f995 | ||
|
|
47a419a5f1 | ||
|
|
4463293dc4 | ||
|
|
f16605b3c1 | ||
|
|
167dc86f7a | ||
|
|
95e65dec8f | ||
|
|
42b8f923be | ||
|
|
6cdef782c8 | ||
|
|
420215931c | ||
|
|
d3576b9c92 | ||
|
|
56d7342398 | ||
|
|
58f3048808 | ||
|
|
f1fab854c4 | ||
|
|
3815797dda | ||
|
|
8ba5bddae8 | ||
|
|
5c37e6a435 | ||
|
|
7ef641e7b2 | ||
|
|
ee0140e704 | ||
|
|
23908f9ec2 | ||
|
|
6e754c70aa | ||
|
|
e86a3b5e57 | ||
|
|
a400a1e9d4 | ||
|
|
76468559ba | ||
|
|
926fedb7fb | ||
|
|
00a7576679 | ||
|
|
8af7f4a484 | ||
|
|
ccb3ea4453 | ||
|
|
509fc8a640 | ||
|
|
26c3ff2cee | ||
|
|
215118c7ea | ||
|
|
720b5d6da3 | ||
|
|
ab62bb66f4 | ||
|
|
d72dd9b861 | ||
|
|
2bb2baf6f7 | ||
|
|
3705970bfd | ||
|
|
d739a8cac2 | ||
|
|
ee269fbc69 | ||
|
|
fb3e56eac8 | ||
|
|
a62997463f | ||
|
|
ed5619498c | ||
|
|
67e9f06304 | ||
|
|
976ccda135 | ||
|
|
b277082462 | ||
|
|
a3c57c43c8 | ||
|
|
74c9994305 | ||
|
|
059a5f35fa | ||
|
|
4ac21e9f3f | ||
|
|
69cd9dfb7d | ||
|
|
8b2009cfb1 | ||
|
|
ab53f3b380 | ||
|
|
e333267e69 | ||
|
|
fc3f5adbbb | ||
|
|
28eef264e5 | ||
|
|
390ee3a6b8 | ||
|
|
3ca670146e | ||
|
|
dc4a0c1d38 | ||
|
|
066cdb55d7 | ||
|
|
f03c99ab03 | ||
|
|
4964ce347b | ||
|
|
95f26aadd3 | ||
|
|
5ee74d269a | ||
|
|
d5793418f9 | ||
|
|
b160badbf6 | ||
|
|
616a57d6d4 | ||
|
|
05c045070e | ||
|
|
568724bffd | ||
|
|
ab90fe18fd | ||
|
|
ded377bcd2 | ||
|
|
c547907784 | ||
|
|
5bcf810a7c | ||
|
|
9ee9186a1a | ||
|
|
aaf754ebf5 | ||
|
|
6931d9a6f7 | ||
|
|
edf1a90161 | ||
|
|
6fa2f1e653 | ||
|
|
dfad1fc740 | ||
|
|
483199878d | ||
|
|
2912c2e7f5 | ||
|
|
27c680e28b | ||
|
|
38bce39baa | ||
|
|
cef845ac47 | ||
|
|
ea38f0d3bd | ||
|
|
000826af11 | ||
|
|
182b2d0457 | ||
|
|
633f228dc2 | ||
|
|
bb1cb73675 | ||
|
|
b77b3da8d6 | ||
|
|
c05ef1225c | ||
|
|
65183cde80 | ||
|
|
bd99114cd6 | ||
|
|
a24c1c8114 | ||
|
|
fa94fedfc3 | ||
|
|
97bc7e38d2 | ||
|
|
7ab91bb185 | ||
|
|
bb97507ebc | ||
|
|
21f43252e6 | ||
|
|
0935c5a0f2 | ||
|
|
8c3980d80b | ||
|
|
ae857db657 | ||
|
|
b2c0259197 | ||
|
|
fdcc517b9f | ||
|
|
f41301f8f5 | ||
|
|
0691cac5ab | ||
|
|
8142810455 | ||
|
|
ecd40e5cae | ||
|
|
711a74c9c9 | ||
|
|
08731fc6cf | ||
|
|
bd4b189373 | ||
|
|
ad9ea40954 | ||
|
|
c4069362ce | ||
|
|
e813257431 | ||
|
|
404a6c1506 | ||
|
|
c78285e557 | ||
|
|
c3890a9435 | ||
|
|
ee62522c51 | ||
|
|
c67ab8f1f0 | ||
|
|
2787c2f874 | ||
|
|
e81b40978e | ||
|
|
6693c5bdd0 | ||
|
|
9e39b08325 | ||
|
|
44de127bff | ||
|
|
af0723c185 | ||
|
|
84d43946de | ||
|
|
213d011a8c | ||
|
|
39c7816ede | ||
|
|
0cb826a511 | ||
|
|
3240536d0e | ||
|
|
4d2db08934 | ||
|
|
0376a13dd8 | ||
|
|
a8865e2fa2 | ||
|
|
dfd63e5d5a | ||
|
|
d288b9216e | ||
|
|
9c5ad44e27 | ||
|
|
16bde2729d | ||
|
|
058925cca9 | ||
|
|
73521e22de | ||
|
|
c35a2b959a | ||
|
|
e8347c2c20 | ||
|
|
902a4368a1 | ||
|
|
2f14a6218a | ||
|
|
baa926359e | ||
|
|
8b9c5f8228 | ||
|
|
d5450f1df6 | ||
|
|
d07c71c99d | ||
|
|
160fa148f1 | ||
|
|
e60628d463 | ||
|
|
f2b4e31e7f | ||
|
|
310baab73f | ||
|
|
b0f745365d | ||
|
|
4ae3a23089 | ||
|
|
2b9fb79b1d | ||
|
|
c27363cea5 | ||
|
|
0f141edbc3 | ||
|
|
21e01b809f | ||
|
|
8a800986a2 | ||
|
|
20b532ec5e | ||
|
|
c0c71c509c | ||
|
|
c4322848ec | ||
|
|
12ccd7e3b6 | ||
|
|
05ee853c4e | ||
|
|
3fae3fd93e | ||
|
|
6a20a4dcc3 | ||
|
|
d968eea914 | ||
|
|
81d23c066c | ||
|
|
d401d18e71 | ||
|
|
ec85ee4537 | ||
|
|
03825a6052 | ||
|
|
fc27c6c547 | ||
|
|
3655514924 | ||
|
|
b6721971dd | ||
|
|
d4a89b2fd8 | ||
|
|
d49c23fe67 | ||
|
|
0e169ba10e | ||
|
|
c54f08f33a | ||
|
|
66ee67a781 | ||
|
|
f75110365f | ||
|
|
a5850f4a99 | ||
|
|
e78e2ac266 | ||
|
|
18ce257fc8 | ||
|
|
53d61c4fb6 | ||
|
|
36cc7b5e3f | ||
|
|
35f1c45d32 | ||
|
|
c127b109d0 | ||
|
|
be09ffec3f | ||
|
|
805f86a5cf | ||
|
|
3d990c5950 | ||
|
|
30554a16da | ||
|
|
ee1d2b645b | ||
|
|
ce23db2e9c | ||
|
|
b5ea41fcca | ||
|
|
d61adccd3c | ||
|
|
a1a3c98d92 | ||
|
|
28fdeba4fa | ||
|
|
444a15a461 | ||
|
|
0f20eeb395 | ||
|
|
b27b77c38f | ||
|
|
249e4097e3 | ||
|
|
b207929e0a | ||
|
|
3daec8e6a2 | ||
|
|
caaf5436c6 | ||
|
|
6d5a0f2f84 | ||
|
|
a1b5cc3bc6 | ||
|
|
e4736d064e | ||
|
|
f45307f990 | ||
|
|
5dae920783 | ||
|
|
63f708dd57 | ||
|
|
6cc714464c | ||
|
|
21f8135fa6 | ||
|
|
afc4f51e9c | ||
|
|
bd3d2ec686 | ||
|
|
7adc3c2fba | ||
|
|
bd0a196a39 | ||
|
|
befc80b3cb | ||
|
|
914184f3dd | ||
|
|
0c8886967b | ||
|
|
1112c0f994 | ||
|
|
7d4feaca2f | ||
|
|
ade99c2c2b | ||
|
|
346af4f97a | ||
|
|
9738de2cb9 | ||
|
|
23113c4ff7 | ||
|
|
1bf0e01a83 | ||
|
|
4009c01558 | ||
|
|
96aa182893 | ||
|
|
8bfeae768f | ||
|
|
1a56f0b79c | ||
|
|
044c92016b | ||
|
|
37377644c9 | ||
|
|
c6db90e9b7 | ||
|
|
4cc88662e2 | ||
|
|
9178f4b1c5 | ||
|
|
51e08d4940 | ||
|
|
3aec9c1a41 | ||
|
|
05ce49adaf | ||
|
|
5b79094f34 | ||
|
|
523ed8272d | ||
|
|
0509a12790 | ||
|
|
afa89256c5 | ||
|
|
64a2320be7 | ||
|
|
2e266c7ddd | ||
|
|
fb606112fa | ||
|
|
e08b629cb5 | ||
|
|
017beb6786 | ||
|
|
79ed94b22c | ||
|
|
04a785b9fb | ||
|
|
a41e9055c5 | ||
|
|
05d693e3bb | ||
|
|
37db21d269 | ||
|
|
0b322a3143 | ||
|
|
5be9fbbc5a | ||
|
|
0e53ad33f6 | ||
|
|
0e7eeb3051 | ||
|
|
3670c729c0 | ||
|
|
3889c8afec | ||
|
|
a09c12acfe | ||
|
|
7455b1b4f0 | ||
|
|
3d891f0b39 | ||
|
|
d717fc7b1f | ||
|
|
824c243268 | ||
|
|
772d5eacca | ||
|
|
4e8ae77b6f | ||
|
|
98f7f70814 | ||
|
|
50c63a88c3 | ||
|
|
b1a3633495 | ||
|
|
7cc97836a9 | ||
|
|
78b9682a4e | ||
|
|
a7030c7fed | ||
|
|
c3058f4744 | ||
|
|
455b840712 | ||
|
|
004450b201 | ||
|
|
86822f6c61 | ||
|
|
3cf4f1f956 | ||
|
|
6f2103f312 | ||
|
|
9b5bb95766 | ||
|
|
0da0670a79 | ||
|
|
71e3041370 | ||
|
|
4f53a1ab40 | ||
|
|
d0b8b32345 | ||
|
|
671e968936 | ||
|
|
bc8c55836a | ||
|
|
1b4c3c7415 | ||
|
|
819be43ce7 | ||
|
|
b4bd7af9c8 | ||
|
|
e3f10c0e32 | ||
|
|
deb3db3f95 | ||
|
|
354dee1b09 | ||
|
|
109d1ad27f | ||
|
|
822d4525af | ||
|
|
ad12f383d9 | ||
|
|
43dc9bbc94 | ||
|
|
e6077127be | ||
|
|
956507b5fa | ||
|
|
1954c0ba84 | ||
|
|
4c597dd467 | ||
|
|
6de5b3021e | ||
|
|
6e059ea002 | ||
|
|
96a4d91a6c | ||
|
|
98dcd4e52b | ||
|
|
635fb4c25a | ||
|
|
a385b30c29 | ||
|
|
958e2fab05 | ||
|
|
3b04bedee0 | ||
|
|
5d0a4cae90 | ||
|
|
3e4ff9e472 | ||
|
|
5a4e661e60 | ||
|
|
bdb41423e2 | ||
|
|
ed42c878b0 | ||
|
|
b36d35bf1e | ||
|
|
407dcea751 | ||
|
|
1712d01b74 | ||
|
|
9b4442be8b | ||
|
|
aaef4ef22b | ||
|
|
cb28bc80b7 | ||
|
|
7134eb9079 | ||
|
|
2b8afe55e8 | ||
|
|
1caa5c4780 | ||
|
|
6c78a247f2 | ||
|
|
9b1c54e81b | ||
|
|
180904e9f6 | ||
|
|
fea9f5f431 | ||
|
|
a8a920c8f0 | ||
|
|
8a01799fb8 | ||
|
|
b724e51cab | ||
|
|
4b8d4f5bbd | ||
|
|
e448dcb725 | ||
|
|
9f1704560b | ||
|
|
1dab1590ea | ||
|
|
1a708affbf | ||
|
|
d2646ea4ad | ||
|
|
0dceabe704 | ||
|
|
64354bbfaa | ||
|
|
ff9327a035 | ||
|
|
b05e211e21 | ||
|
|
353d43a039 | ||
|
|
5149ffdd16 | ||
|
|
9c936867fa | ||
|
|
a7cc9f98ef | ||
|
|
454324781d | ||
|
|
cac1bef6ea | ||
|
|
fe8deeaf6b | ||
|
|
383210096c | ||
|
|
e98bfe921e | ||
|
|
bb7934b381 | ||
|
|
c113cfd8b7 | ||
|
|
0bc4b0421d | ||
|
|
5a9e27c6fc | ||
|
|
94f0a1532d | ||
|
|
a0f5e45ae9 | ||
|
|
ba335089c4 | ||
|
|
9c72e73a82 | ||
|
|
30d7f0dc98 | ||
|
|
71780228ae | ||
|
|
2c9a6e7bef | ||
|
|
e25305e3cc | ||
|
|
f9599da32d | ||
|
|
be9cbd79d6 | ||
|
|
59c6f76457 | ||
|
|
2302c8d5fa | ||
|
|
a19373ab54 | ||
|
|
205469316c | ||
|
|
489e1e94e4 | ||
|
|
9e95f6e7c1 | ||
|
|
226792c73a | ||
|
|
5df8583056 | ||
|
|
ff73c0b247 | ||
|
|
f611d06ed0 | ||
|
|
08e86fdfe5 | ||
|
|
e977d6eb75 | ||
|
|
b9a1a1fd5c | ||
|
|
b6f8e5057b | ||
|
|
94fec5f8b7 | ||
|
|
0d08718f08 | ||
|
|
775ed41592 | ||
|
|
16b62486e9 | ||
|
|
2a6f979ce6 | ||
|
|
9362ae0687 | ||
|
|
63a2657aef | ||
|
|
7080b256fb | ||
|
|
def62e8c22 | ||
|
|
1ed11b297b | ||
|
|
84f00c21df | ||
|
|
1d0cb0407d | ||
|
|
b9da6ce04a | ||
|
|
a447b049fc | ||
|
|
63fe4fb317 | ||
|
|
078d2522d2 | ||
|
|
45968efd28 | ||
|
|
231b07795c | ||
|
|
fcaf5e7657 | ||
|
|
3acec94773 | ||
|
|
149c4491ce | ||
|
|
9e4fa90f6e | ||
|
|
26502881d7 | ||
|
|
0c4181178d | ||
|
|
ef0ea247c4 | ||
|
|
02707f0777 | ||
|
|
5085e462b0 | ||
|
|
01a95316c2 | ||
|
|
6408ee2eaf | ||
|
|
3eba5b0aac | ||
|
|
357e1c0802 | ||
|
|
00137f2905 | ||
|
|
98a0959784 | ||
|
|
fc2c62350e | ||
|
|
9f8a9b9cad | ||
|
|
890f96d9b5 | ||
|
|
c0569da65c | ||
|
|
2a07441c19 | ||
|
|
9c893cb0f4 | ||
|
|
7581cbade6 | ||
|
|
583513bafd | ||
|
|
43ca8ea5f7 | ||
|
|
a5cfdd2cfe | ||
|
|
62dfd1fa7d | ||
|
|
38548c9acd | ||
|
|
038bf612be | ||
|
|
f02c86cb22 | ||
|
|
a55b43b67e | ||
|
|
31bd701bd5 | ||
|
|
9bfb0d93ca | ||
|
|
897105de02 | ||
|
|
19c5889775 | ||
|
|
13d915927b | ||
|
|
7046f1a902 | ||
|
|
76700d17d6 | ||
|
|
f8d428cb2d | ||
|
|
93e55e2631 | ||
|
|
1797b6c7f9 | ||
|
|
581f4ed757 | ||
|
|
0ec3ee29e4 | ||
|
|
bb58a50503 | ||
|
|
f2de440886 | ||
|
|
3e376f95c4 | ||
|
|
b1ee864ad9 | ||
|
|
9e87f4ec4e | ||
|
|
408dd31d3c | ||
|
|
9ece4dac0f | ||
|
|
d82878ac3b | ||
|
|
0b1637a409 | ||
|
|
b60bffaf83 | ||
|
|
d4fdd50e2c | ||
|
|
dd1bb18938 | ||
|
|
1f9239089f | ||
|
|
b2a7a3ed30 | ||
|
|
2b7e599dc4 | ||
|
|
61d4d17225 | ||
|
|
408954e4d8 | ||
|
|
0053158884 | ||
|
|
87cd72496c | ||
|
|
cb524b6c19 | ||
|
|
bc6685aa3f | ||
|
|
5458c02cc2 | ||
|
|
33db0c13cd | ||
|
|
9128ec72ad | ||
|
|
80eb0a2df6 | ||
|
|
437bba1e3c | ||
|
|
15e4b7f95d | ||
|
|
0159956fa5 | ||
|
|
d607c13ab6 | ||
|
|
8296abcea8 | ||
|
|
9585390941 | ||
|
|
b2cb284ff2 | ||
|
|
7d84cfacef | ||
|
|
39862740e0 | ||
|
|
579c955892 | ||
|
|
175c71221a | ||
|
|
23b508c5e7 | ||
|
|
60965b0d8c | ||
|
|
a27dac029f | ||
|
|
36abf8733e | ||
|
|
9acc71a7cb | ||
|
|
9e6f28e335 | ||
|
|
29aec0d770 | ||
|
|
c5193cf03f | ||
|
|
06514159be | ||
|
|
daad62c4e0 | ||
|
|
1ab75eb6f4 | ||
|
|
118840dad4 | ||
|
|
c2d97b98e2 | ||
|
|
e36b42a03f | ||
|
|
f3661c34ee | ||
|
|
95742aec69 | ||
|
|
64f8316a6d | ||
|
|
1e327289b2 | ||
|
|
50abb6e3a1 | ||
|
|
5c2bf68a05 | ||
|
|
f8d45f04ed | ||
|
|
40b74167e0 | ||
|
|
3c8ea167c4 | ||
|
|
6ed1016bb8 | ||
|
|
92b4eb7f02 | ||
|
|
e1028a2765 | ||
|
|
5c79ad2412 | ||
|
|
af0c32c01d | ||
|
|
605f28f741 | ||
|
|
946fcf1c82 | ||
|
|
b0975bb3ea | ||
|
|
a8280f9b12 | ||
|
|
0678745677 | ||
|
|
341dbcef2e | ||
|
|
8aa6b1a87c | ||
|
|
451d36dc97 | ||
|
|
c9c8259ed0 | ||
|
|
5d827b6fc8 | ||
|
|
3e7dc12246 | ||
|
|
c37994089c | ||
|
|
254de76078 | ||
|
|
dedf765542 | ||
|
|
42ae5f4f7d | ||
|
|
b359205d17 | ||
|
|
578ce1e512 | ||
|
|
7fbc62358e | ||
|
|
0e183ab4a4 | ||
|
|
fa36ba901a | ||
|
|
d269a7e717 | ||
|
|
216f204438 | ||
|
|
583d0889e2 | ||
|
|
5d05e4d224 | ||
|
|
0f24db8759 | ||
|
|
f8570bb293 | ||
|
|
d361d999b7 | ||
|
|
02e41d8018 | ||
|
|
3eb1813584 | ||
|
|
cb736c8c82 | ||
|
|
972cc47f67 | ||
|
|
b4a2a9db25 | ||
|
|
bd3b3178ba | ||
|
|
c9b2c7885e | ||
|
|
52a9040d73 | ||
|
|
2387dc640c | ||
|
|
8489403051 | ||
|
|
b3bdf89fc2 | ||
|
|
4be183c7f6 | ||
|
|
b30ae3980c | ||
|
|
fe57876fd8 | ||
|
|
897d12420b | ||
|
|
97186b3d30 | ||
|
|
56ba0f080a | ||
|
|
a7fcf52267 | ||
|
|
392adf2a25 | ||
|
|
b29f35f564 | ||
|
|
64fed4cb10 | ||
|
|
ed64ed3d8d | ||
|
|
b4f01c9afa | ||
|
|
53a320a810 | ||
|
|
bb447d7174 | ||
|
|
447f339857 | ||
|
|
92508beb82 | ||
|
|
f43d427875 | ||
|
|
bc7cc2f7ce | ||
|
|
da36508714 | ||
|
|
591ac38c31 | ||
|
|
54c79bff74 | ||
|
|
2e40d01397 | ||
|
|
44d2bf42d7 | ||
|
|
fd23e0bdda | ||
|
|
3b6cd0f681 | ||
|
|
9de8085571 | ||
|
|
2d0c9b6bf2 | ||
|
|
55723618a9 | ||
|
|
2965a1f204 | ||
|
|
5158e7964e | ||
|
|
36fe72246b | ||
|
|
4810308b16 | ||
|
|
77208bcc91 | ||
|
|
e2ed0d02b0 | ||
|
|
37dae67a0d | ||
|
|
419d25cbcf | ||
|
|
981c5deb57 | ||
|
|
d853f0c400 | ||
|
|
a6bb9ebb9f | ||
|
|
079c7e089d | ||
|
|
273e8ce4ef | ||
|
|
00235ed3b3 | ||
|
|
25b012db48 | ||
|
|
5f7d3d0d36 | ||
|
|
7be45e7c5e | ||
|
|
6e73d13670 | ||
|
|
2890fe6d61 | ||
|
|
7ed09904b4 | ||
|
|
aa52585120 | ||
|
|
89a5acf6e8 | ||
|
|
7f131c1f35 | ||
|
|
1008411594 | ||
|
|
d1457995dd | ||
|
|
8daca01c87 | ||
|
|
4879104568 | ||
|
|
b0ad927fdd | ||
|
|
a404faa302 | ||
|
|
7825a2cdfc | ||
|
|
1a4845f417 | ||
|
|
f93b68d4dc | ||
|
|
98d936d8b3 | ||
|
|
f341d5010d | ||
|
|
9b0ef2fe21 | ||
|
|
58d198261e | ||
|
|
646639bc73 | ||
|
|
f22b11881e | ||
|
|
45e1a61d7b | ||
|
|
30fbb8f1e7 | ||
|
|
e77117f902 | ||
|
|
929d9da4b4 | ||
|
|
7c13163413 | ||
|
|
178cb6c90f | ||
|
|
7c0b0642c8 | ||
|
|
15c103e42d | ||
|
|
dee974ff2d | ||
|
|
c37dbb2e68 | ||
|
|
3cfd30ef6f | ||
|
|
be39883166 | ||
|
|
afd2f58f9f | ||
|
|
697b2dcde8 | ||
|
|
b6bd782746 | ||
|
|
e4d74cf098 | ||
|
|
0102d68f38 | ||
|
|
e0fcb15739 | ||
|
|
b96b665262 | ||
|
|
037e6369ce | ||
|
|
d7f26dfc18 | ||
|
|
fda750ef26 | ||
|
|
423ff32d04 | ||
|
|
6d4ddc0329 | ||
|
|
bc56d16c18 | ||
|
|
dfc91b8331 | ||
|
|
bb23866cec | ||
|
|
d35a501121 | ||
|
|
a43698802f | ||
|
|
310a2c8bb3 | ||
|
|
2656a52880 | ||
|
|
abeefcaced | ||
|
|
d2fad180f8 | ||
|
|
5aeaab7c6d | ||
|
|
58d5ad48d5 | ||
|
|
d7c14775bf | ||
|
|
11bf982728 | ||
|
|
24de826133 | ||
|
|
32737a17fb | ||
|
|
172d6139e2 | ||
|
|
c281e54d22 | ||
|
|
57016ddbde | ||
|
|
7d2a60e910 | ||
|
|
b4d35b52c3 | ||
|
|
5446532e1d | ||
|
|
acd4cf2878 | ||
|
|
e8d835b422 | ||
|
|
c7686b1838 | ||
|
|
cf5f838b13 | ||
|
|
e003b04061 | ||
|
|
cd57e61f65 | ||
|
|
91d28fb8b0 | ||
|
|
63f087a8e9 | ||
|
|
364d48948f | ||
|
|
3ff8e010b2 | ||
|
|
9f91dde76f | ||
|
|
17c4bbbc4e | ||
|
|
1b948ac2e2 | ||
|
|
036fddfdb5 | ||
|
|
02d6de81a7 | ||
|
|
feb3a8deb1 | ||
|
|
6924c6c51c | ||
|
|
3da88f2103 | ||
|
|
17d1c77a14 | ||
|
|
4f2060f96b | ||
|
|
10be2735ec | ||
|
|
8d11bc97ca | ||
|
|
d90527bead | ||
|
|
9349e6922d | ||
|
|
eeae91e620 | ||
|
|
046aeaa38c | ||
|
|
8b756d7f1b | ||
|
|
650446f761 | ||
|
|
a5ebe8c600 | ||
|
|
8687c5c145 | ||
|
|
8a7d28a2ed | ||
|
|
4c21980d4f | ||
|
|
9635a36044 | ||
|
|
760231c004 | ||
|
|
c77c7b0a98 | ||
|
|
837f20108d | ||
|
|
157e4670fd | ||
|
|
79c1374925 | ||
|
|
1510048f7a | ||
|
|
d8165145c7 | ||
|
|
ebd38eaf3b | ||
|
|
b8c11503f0 | ||
|
|
0a86642056 | ||
|
|
4e3791dc0d | ||
|
|
720fbaf301 | ||
|
|
1510fe370d | ||
|
|
2329b31601 | ||
|
|
a460e3ad3d | ||
|
|
40637c18ce | ||
|
|
0818c1d703 | ||
|
|
cc4827600b | ||
|
|
04b0682bbf | ||
|
|
fd8f745468 | ||
|
|
2d618d6b92 | ||
|
|
f130616369 | ||
|
|
3b437fe6cf | ||
|
|
d2b874f217 | ||
|
|
e1d0bbb021 | ||
|
|
6fd4a8afff | ||
|
|
be2fe6e171 | ||
|
|
8d2768b2ce | ||
|
|
701e815368 | ||
|
|
cd310eb9d5 | ||
|
|
992a4df12f | ||
|
|
996cda9b97 | ||
|
|
6874b8d4b3 | ||
|
|
80d5b17900 | ||
|
|
cae0060a89 | ||
|
|
affdedd840 | ||
|
|
46197e6e69 | ||
|
|
351f35d9bc | ||
|
|
87d42b02c0 | ||
|
|
3e53484bb3 | ||
|
|
e544faed6d | ||
|
|
17fd758df1 | ||
|
|
595bdedb22 | ||
|
|
0b7a6671dd | ||
|
|
f329c3fdab | ||
|
|
0a6aef71a2 | ||
|
|
652e8b4872 | ||
|
|
9e2832a82d | ||
|
|
b9ce1aefc0 | ||
|
|
c9c4c067b6 | ||
|
|
a335bb0115 | ||
|
|
ad267404c9 | ||
|
|
d7f0b9a7fa | ||
|
|
749db379ca | ||
|
|
dbb3d3dc17 | ||
|
|
53daa7c436 | ||
|
|
11304b2ae1 | ||
|
|
7f01586bf1 | ||
|
|
e5bce548de | ||
|
|
956311457d | ||
|
|
9b3ccade43 | ||
|
|
3d117243e4 | ||
|
|
02eb447a35 | ||
|
|
a6b486a448 | ||
|
|
d73ba13b28 | ||
|
|
b39a3ab12c | ||
|
|
8adaee05b6 | ||
|
|
6109ef5e88 | ||
|
|
7d300b53d7 | ||
|
|
d42a01cb3a | ||
|
|
e5160929eb | ||
|
|
30ba69d991 | ||
|
|
036e181bc1 | ||
|
|
716568ebd1 | ||
|
|
9820116734 | ||
|
|
52a2260dc7 | ||
|
|
c738f387b1 | ||
|
|
1da48ed4d1 | ||
|
|
bfbfe7af13 | ||
|
|
21004006d6 | ||
|
|
cf5f760ecd | ||
|
|
83477439a1 | ||
|
|
b7483a5394 | ||
|
|
322bdcb703 | ||
|
|
8ce5c46e05 | ||
|
|
a790eb8110 | ||
|
|
a8cbdc92b9 | ||
|
|
551a7ce9e5 | ||
|
|
c069c3384e | ||
|
|
cb9a9db356 | ||
|
|
2ac1e60406 | ||
|
|
86ef2588f1 | ||
|
|
51bab81f56 | ||
|
|
3f0a3266aa | ||
|
|
99dd5330c2 | ||
|
|
517fd23ca5 | ||
|
|
a9527fd913 | ||
|
|
2faf52b6bd | ||
|
|
675de07c3e | ||
|
|
ed34c96357 | ||
|
|
eb9b41acab | ||
|
|
a764a79090 | ||
|
|
c13ee0859a | ||
|
|
4cf0b8e725 | ||
|
|
3d8e173c57 | ||
|
|
80ac2aff26 | ||
|
|
f372274857 | ||
|
|
2373bf2dfb | ||
|
|
1cf30d2a9e | ||
|
|
ab58cb3d44 | ||
|
|
f0491af64c | ||
|
|
0c724a8427 | ||
|
|
38daeb4df2 | ||
|
|
03b12dbc6d | ||
|
|
365b4d722d | ||
|
|
903f364dab | ||
|
|
073a43ce74 | ||
|
|
461d4e45af | ||
|
|
c9f54ea1ad | ||
|
|
ee13ff71d6 | ||
|
|
26cddc7d04 | ||
|
|
6c69c1aeeb | ||
|
|
69973d0fa2 | ||
|
|
cbf158ea6b | ||
|
|
36de496d47 | ||
|
|
ed2a8db8c9 | ||
|
|
9c3b7e81c7 | ||
|
|
a66083d685 | ||
|
|
fd4e8f8282 | ||
|
|
61880ba90a | ||
|
|
a006a92f8d | ||
|
|
f22db2a30b | ||
|
|
a0e3e3afaf | ||
|
|
fb95c488e8 | ||
|
|
e22ec50dee | ||
|
|
a8193dac08 | ||
|
|
60e4faba4c | ||
|
|
48ff8e237c | ||
|
|
3ecd13531f | ||
|
|
59ff3f315b | ||
|
|
094d2f3b7d | ||
|
|
a44490b470 | ||
|
|
0626684442 | ||
|
|
acf8fd0f03 | ||
|
|
a93132daae | ||
|
|
43ae7462b4 | ||
|
|
b44db460f6 | ||
|
|
2d615ef503 | ||
|
|
cc63563a88 | ||
|
|
8e11abca40 | ||
|
|
ffcb345916 | ||
|
|
9a41c80626 | ||
|
|
695b02a94c | ||
|
|
2c1cc9ead6 | ||
|
|
f45916efda | ||
|
|
8382e85901 | ||
|
|
f07d844362 | ||
|
|
98001c494f | ||
|
|
41b89669a9 | ||
|
|
bc49bc7095 | ||
|
|
e0e58b24ea | ||
|
|
224d3790b5 | ||
|
|
b11703cc74 | ||
|
|
5eb1f8abbd | ||
|
|
0ebb24ebeb | ||
|
|
667b26b5d9 | ||
|
|
a5f4d43d61 | ||
|
|
7045597139 | ||
|
|
c194598d37 | ||
|
|
e852540254 | ||
|
|
c777f1d8d7 | ||
|
|
32a8b9a857 | ||
|
|
a23d8deb10 | ||
|
|
885044e331 | ||
|
|
b7e49c78fe | ||
|
|
d1462eda1c | ||
|
|
32500c834d | ||
|
|
acc28df785 | ||
|
|
564a6873f8 | ||
|
|
c4ab6fb7b4 | ||
|
|
f07030ba97 | ||
|
|
a9566728b5 | ||
|
|
7119eda009 | ||
|
|
86bc0eb853 | ||
|
|
b43989e6a1 | ||
|
|
2850b8e952 | ||
|
|
cbfa5ad303 | ||
|
|
cee1a12489 | ||
|
|
c926a47d50 | ||
|
|
cca38a64be | ||
|
|
53def60e4f | ||
|
|
1ce7c3448f | ||
|
|
fd7cbd0c96 | ||
|
|
8fa3fb0561 | ||
|
|
314839fc09 | ||
|
|
c1651ad30c | ||
|
|
125d1465c8 | ||
|
|
a3421e7ab2 | ||
|
|
20416ae034 | ||
|
|
c96ee8671e | ||
|
|
480ce39618 | ||
|
|
a1fab8ac52 | ||
|
|
36bdee0e8b | ||
|
|
ecbce88ec7 | ||
|
|
95ac2c8edd | ||
|
|
f08a0e5653 | ||
|
|
ab3edf37d7 | ||
|
|
43306f4700 | ||
|
|
8c8e4e6a70 | ||
|
|
068a9d88e7 | ||
|
|
c541390c1b | ||
|
|
9ff894bf83 | ||
|
|
e9e93c0eea | ||
|
|
85ecfe2723 | ||
|
|
8159098dc0 | ||
|
|
49d1937dc4 | ||
|
|
d4877a9038 | ||
|
|
57784dc746 | ||
|
|
4f9b6d1192 | ||
|
|
bc5b477f79 | ||
|
|
0cc8eaf3b4 | ||
|
|
51c27de049 | ||
|
|
b9788eb53c | ||
|
|
649286995a | ||
|
|
fb004bacc3 | ||
|
|
67835ee273 | ||
|
|
23df459c16 | ||
|
|
fe76b0849b | ||
|
|
92839123ae | ||
|
|
a8284d5b97 | ||
|
|
e0a73ce797 | ||
|
|
244966e216 | ||
|
|
62de15cd22 | ||
|
|
f8bbda0cdc | ||
|
|
9db235ac36 | ||
|
|
35f294f096 | ||
|
|
4b51e22bb4 | ||
|
|
ec952248a9 | ||
|
|
f27203cc43 | ||
|
|
1349bf7b0b | ||
|
|
93500bd95a | ||
|
|
95937c9ac7 | ||
|
|
0b21b273ed | ||
|
|
937a620f4d | ||
|
|
e8d7925084 | ||
|
|
25e26b9ac0 | ||
|
|
6cceb73807 | ||
|
|
d2b991bcb5 | ||
|
|
09ba25fe9b | ||
|
|
8c95a9ae39 | ||
|
|
2dadc752d6 | ||
|
|
d57ec5d1ac | ||
|
|
e3b052199a | ||
|
|
eb01ffbdae | ||
|
|
2f98212eca | ||
|
|
8f1c7c57a8 | ||
|
|
909dc84bb6 | ||
|
|
a18cd74756 | ||
|
|
21576387f3 | ||
|
|
50523e0ac0 | ||
|
|
d126c0a1d3 | ||
|
|
3db5dd4661 | ||
|
|
108bcef104 | ||
|
|
0f710b1981 | ||
|
|
c26d05b1d5 | ||
|
|
5a4efab742 | ||
|
|
96a66fa4ee | ||
|
|
67ad6d9a0f | ||
|
|
faf07dac91 | ||
|
|
3e26236648 | ||
|
|
2770a53d38 | ||
|
|
c103939c2d | ||
|
|
49ca88957c | ||
|
|
603843e698 | ||
|
|
3613ceb07f | ||
|
|
f1d0b50670 | ||
|
|
f453fe26c6 | ||
|
|
b381f4826c | ||
|
|
149af57eac | ||
|
|
88fee2748e | ||
|
|
0775d35591 | ||
|
|
3f215d0954 | ||
|
|
093c63ea3b | ||
|
|
5ce3f9d6ff | ||
|
|
92e0e195a4 | ||
|
|
6d72b4fd39 | ||
|
|
16902c2f56 | ||
|
|
7a511c5682 | ||
|
|
a53cbc1631 | ||
|
|
bd86388447 | ||
|
|
bf81122fc6 | ||
|
|
e0352fe763 | ||
|
|
c6e7b8d4fd | ||
|
|
4100d68a71 | ||
|
|
725122decc | ||
|
|
a72b1340eb | ||
|
|
44d62df3f7 | ||
|
|
470b4d8658 | ||
|
|
98dfe1a00a | ||
|
|
f17bbd9982 | ||
|
|
c83daa66e7 | ||
|
|
b466f0515d | ||
|
|
8155334fa7 | ||
|
|
7d7cbc49db | ||
|
|
0ce08617ba | ||
|
|
e345064a53 | ||
|
|
2e948da3b4 | ||
|
|
1be2be843d | ||
|
|
7f16c52217 | ||
|
|
b21672c81c | ||
|
|
1dbfe2369d | ||
|
|
f584ff9acf | ||
|
|
8dc7b6403a | ||
|
|
d20a0c9e82 | ||
|
|
cc2a531684 | ||
|
|
9d1ef21d85 | ||
|
|
c7c65736a9 | ||
|
|
86755c6a98 | ||
|
|
506c95d098 | ||
|
|
d4ce42ac4f | ||
|
|
e93b72d563 | ||
|
|
983b64a05f | ||
|
|
57fd2e3578 | ||
|
|
e936540863 | ||
|
|
f1619f1ee8 | ||
|
|
f14fb3bf9e | ||
|
|
936757b4bf | ||
|
|
d33b04cd96 | ||
|
|
9488b8bb18 | ||
|
|
554404575d | ||
|
|
c93e0c08fd | ||
|
|
54dad57cf4 | ||
|
|
2b257318f1 | ||
|
|
62a0775cf6 | ||
|
|
2ca95166d9 | ||
|
|
208d5157fa | ||
|
|
2576c86ebf | ||
|
|
c2f112cb92 | ||
|
|
5e59f6d558 | ||
|
|
8734df334b | ||
|
|
229250dc54 | ||
|
|
716e0f1404 | ||
|
|
f100c8a9c0 | ||
|
|
ed78acb1d4 | ||
|
|
dbef36cbbb | ||
|
|
eaa2d4d831 | ||
|
|
2f34588770 | ||
|
|
a456458a38 | ||
|
|
446ad5ec9e | ||
|
|
c812bd948a | ||
|
|
7aae51c876 | ||
|
|
28fb0edfbe | ||
|
|
6cab85712f | ||
|
|
1c27ca610a | ||
|
|
a5220bf616 | ||
|
|
25a0e09130 | ||
|
|
1beac06236 | ||
|
|
7fb5bd0cab | ||
|
|
9abe02f419 | ||
|
|
bc9682c22d | ||
|
|
ed2cb739c5 | ||
|
|
344c2d3c3d | ||
|
|
90868a4788 | ||
|
|
203b0e3d88 | ||
|
|
cdd613358b | ||
|
|
7e20829f36 | ||
|
|
6a3859fc83 | ||
|
|
bd4934380a | ||
|
|
33c990f6b0 | ||
|
|
3d49b8cb91 | ||
|
|
0fe4baec34 | ||
|
|
09fbf480db | ||
|
|
e3b2e0a1de | ||
|
|
3b82452d76 | ||
|
|
75afa011ff | ||
|
|
e90035a5a5 | ||
|
|
24360d3a4c | ||
|
|
77ba7b473d | ||
|
|
0511e72520 | ||
|
|
57bd3f3c14 | ||
|
|
6bfc49c069 | ||
|
|
32b264bdee | ||
|
|
d53c334488 | ||
|
|
28ff3f412d | ||
|
|
867471b122 | ||
|
|
9d52db3ca7 | ||
|
|
5b905cfe18 | ||
|
|
1564aee57a | ||
|
|
c82b5eb040 | ||
|
|
dbc6cf63c2 | ||
|
|
bd3f6d1234 | ||
|
|
51f489211b | ||
|
|
5d9778c64d | ||
|
|
3e67ebacb0 | ||
|
|
3b6b40489f | ||
|
|
4b7440d4d5 | ||
|
|
419fbe77ab | ||
|
|
b83da2255c | ||
|
|
b94c189946 | ||
|
|
7e33b571c9 | ||
|
|
eeb8c74666 | ||
|
|
70824b3f0b | ||
|
|
801eb538db | ||
|
|
fe0e7f5eac | ||
|
|
08c3bf26d5 | ||
|
|
0ae8b69102 | ||
|
|
28d6cad3d0 | ||
|
|
72ae902e0d | ||
|
|
c146b27c1a | ||
|
|
8ff9c98d26 | ||
|
|
32dc894d54 | ||
|
|
a0465d20cb | ||
|
|
ed8ffab356 | ||
|
|
47530d7526 | ||
|
|
b25dc03dac | ||
|
|
e13a9c9716 | ||
|
|
d3485cac34 | ||
|
|
8d15680af4 | ||
|
|
4955f95f64 | ||
|
|
63831cc62b | ||
|
|
b023d73016 | ||
|
|
1473778bb8 | ||
|
|
70974ea197 | ||
|
|
47686a6e4c | ||
|
|
8d30ee5c3c | ||
|
|
a1ccbcdaf1 | ||
|
|
de879c0707 | ||
|
|
2f2d72f282 | ||
|
|
88932a495c | ||
|
|
59200386a7 | ||
|
|
f2fb26df37 | ||
|
|
e3ab94fc6b | ||
|
|
41168e2b36 | ||
|
|
234f62fd05 | ||
|
|
6d86239929 | ||
|
|
9610ed163a | ||
|
|
12a6410a0a | ||
|
|
c5c80204d5 | ||
|
|
c96b8301ed | ||
|
|
3df23eecb6 | ||
|
|
02a5c0875e | ||
|
|
a9af135d7e | ||
|
|
ac0430883a | ||
|
|
61cff8faed | ||
|
|
b8bfdcc719 | ||
|
|
93bcc3724a | ||
|
|
17d1768259 | ||
|
|
4289e358bf | ||
|
|
6d6150d051 | ||
|
|
deefbefffc | ||
|
|
1f5e52e822 | ||
|
|
98cee7d339 | ||
|
|
c067d519d9 | ||
|
|
61e89d4841 | ||
|
|
0056c39bdd | ||
|
|
9e6aac8ef4 | ||
|
|
f8f3770a58 | ||
|
|
52c2e37aca | ||
|
|
2759d53f42 | ||
|
|
c5ddd40dc3 | ||
|
|
9abaad65c6 | ||
|
|
530be38b84 | ||
|
|
4a45731c85 | ||
|
|
c9c99464cf | ||
|
|
1a5eede39f | ||
|
|
5c9a239776 | ||
|
|
98398a9efd | ||
|
|
67ec5d325c | ||
|
|
adaf3234ec | ||
|
|
7021be05c5 | ||
|
|
52279d4bea | ||
|
|
fae907df65 | ||
|
|
bda074835e | ||
|
|
2012e97842 | ||
|
|
64c7d4e597 | ||
|
|
0035defd72 | ||
|
|
5051f10586 | ||
|
|
3e54136086 | ||
|
|
5fe3c1a0a9 | ||
|
|
3a2f87f0a7 | ||
|
|
b8049f19e2 | ||
|
|
8f750d4ad3 | ||
|
|
f84a05526d | ||
|
|
633152940c | ||
|
|
17d1e6d614 | ||
|
|
5d6c6b4b9b | ||
|
|
5bfd2ad07f | ||
|
|
36a8134490 | ||
|
|
b7ae62c3a3 | ||
|
|
1c815f12da | ||
|
|
151420fd0f | ||
|
|
e42f8439de | ||
|
|
24539dc0ee | ||
|
|
a43bb1fb6d | ||
|
|
23d2f11840 | ||
|
|
fa90655dd0 | ||
|
|
3d94ccf5dd | ||
|
|
ce638096de | ||
|
|
f2bc413318 | ||
|
|
3c26779f40 | ||
|
|
a4924856a2 | ||
|
|
8d0f6086af | ||
|
|
27408fefe2 | ||
|
|
9a56601dd3 | ||
|
|
b5be9d07aa | ||
|
|
b38a9d51e6 | ||
|
|
13eb9e0833 | ||
|
|
30e1b88b7f | ||
|
|
6c8b4a82c1 | ||
|
|
da08c6e63e | ||
|
|
98143b071d | ||
|
|
1e6b5391d6 | ||
|
|
b46a3616d8 | ||
|
|
585606a933 | ||
|
|
0b4650a4c9 | ||
|
|
20aa05b090 | ||
|
|
7d0cfc69f1 | ||
|
|
0ff7cc845c | ||
|
|
921b560e89 | ||
|
|
198a4ca79b | ||
|
|
7cdf439b83 | ||
|
|
0e81fd2624 | ||
|
|
993999f64f | ||
|
|
6b19e69d30 | ||
|
|
1890e63d4c | ||
|
|
4a6589d0ae | ||
|
|
42e6c7eb2e | ||
|
|
c03e9d6c75 | ||
|
|
5bfdca895b | ||
|
|
230b9cf5d3 | ||
|
|
c1e3ccfb6c | ||
|
|
c8a6e837b5 | ||
|
|
7a0bfd1a69 | ||
|
|
54a91c73b0 | ||
|
|
d09458a486 | ||
|
|
7ec86b5e7f | ||
|
|
fe046ec71e | ||
|
|
3a83ecf067 | ||
|
|
f800bf243f | ||
|
|
701b935564 | ||
|
|
1534b387bb | ||
|
|
6c24699403 | ||
|
|
adb1ed380a | ||
|
|
73e940de74 | ||
|
|
0200aedc2e | ||
|
|
26bac9f425 | ||
|
|
a54e810804 | ||
|
|
f4a476ea4e | ||
|
|
1385b22642 | ||
|
|
164b383fda | ||
|
|
405c1f3fc7 | ||
|
|
fa2ae1420a | ||
|
|
347cbe422d | ||
|
|
0c0556bb38 | ||
|
|
6ca425f033 | ||
|
|
ea8c8df653 | ||
|
|
6c1ec6d96b | ||
|
|
8949b9eb0a | ||
|
|
01fd00de56 | ||
|
|
2f3d516413 | ||
|
|
4f46908224 | ||
|
|
79d6731ed8 | ||
|
|
36b0ab1de5 | ||
|
|
a28a36ab29 | ||
|
|
e90fb1a225 | ||
|
|
e0e6d5724e | ||
|
|
d489d63b8e | ||
|
|
28ad667578 | ||
|
|
af5a61782c | ||
|
|
0e98ea0c10 | ||
|
|
67a5831ac0 | ||
|
|
c0bb169342 | ||
|
|
add0c88530 | ||
|
|
d998d06b94 | ||
|
|
a88c3682ff | ||
|
|
84c9137152 | ||
|
|
f27d2bdf6d | ||
|
|
d0c82d3756 | ||
|
|
17d7ba8049 | ||
|
|
b3ff3f7ee7 | ||
|
|
8f467003d2 | ||
|
|
63b732ce1f | ||
|
|
4d856d4461 | ||
|
|
3914a93504 | ||
|
|
c516d69b98 | ||
|
|
0b1705f302 | ||
|
|
15206fd2ce | ||
|
|
98204a15a6 | ||
|
|
43fbcc1c8a | ||
|
|
dd6b27df24 | ||
|
|
cd820917bc | ||
|
|
2541e9cb6a | ||
|
|
048c72a0f2 | ||
|
|
aa2abf76ba | ||
|
|
732ef92830 | ||
|
|
c684b74b3d | ||
|
|
6fff746b16 | ||
|
|
9a96230523 | ||
|
|
514a69c47a | ||
|
|
87f3ba2684 | ||
|
|
731f4559b4 | ||
|
|
4094b18407 | ||
|
|
0ffb80e3b1 | ||
|
|
41c9394b4b | ||
|
|
f05313435d | ||
|
|
9b8056371f | ||
|
|
1a2e341b7c | ||
|
|
c8b1bc3a89 | ||
|
|
5667901a2a | ||
|
|
0a35feef76 | ||
|
|
57953c523c | ||
|
|
a2d75c4fed | ||
|
|
eeac7e322a | ||
|
|
4b7c57c077 | ||
|
|
0a5d58ed8a | ||
|
|
a0a1ddee86 | ||
|
|
bc36e0db43 | ||
|
|
cc592b124b | ||
|
|
0b6589c8be | ||
|
|
f0ddfc9283 | ||
|
|
72f28513eb | ||
|
|
4941d9b7bf | ||
|
|
df60268023 | ||
|
|
48975fa7d2 | ||
|
|
19d08d7b40 | ||
|
|
a78f2115f2 | ||
|
|
bb53780ba9 | ||
|
|
0ef3eee4ed | ||
|
|
891b975899 | ||
|
|
bda223771b | ||
|
|
82cb4a8d68 | ||
|
|
dcabce679a | ||
|
|
31eaa80f5b | ||
|
|
7d556b354d | ||
|
|
ecdadd1826 | ||
|
|
a93aabab40 | ||
|
|
919c6b4b0a | ||
|
|
abdebc29f9 | ||
|
|
23876cb581 | ||
|
|
10cc574289 | ||
|
|
01c13c4703 | ||
|
|
c5577cb09a | ||
|
|
d02c529872 | ||
|
|
de9469bbfc | ||
|
|
ee03837357 | ||
|
|
cbbc7b2bcd | ||
|
|
1784c202a7 | ||
|
|
97d26687fe | ||
|
|
7a1d953fca | ||
|
|
60525ec301 | ||
|
|
9e696ff0fb | ||
|
|
d5171fc043 | ||
|
|
3b856010f2 | ||
|
|
ea8c6f04e2 | ||
|
|
87e1a062ea | ||
|
|
186db7f43e | ||
|
|
7ed018aff6 | ||
|
|
72b37a5b1b | ||
|
|
86dde6eab1 | ||
|
|
502cf38fcc | ||
|
|
1b1c3f953b | ||
|
|
b366ffa69e | ||
|
|
617ba65ef5 | ||
|
|
eb4f1e1ba0 | ||
|
|
23d3109071 | ||
|
|
6ba35f4aac | ||
|
|
9f02c144a8 | ||
|
|
ffc6af73b7 | ||
|
|
748f5344ff | ||
|
|
95d1994196 | ||
|
|
15a43ffe36 | ||
|
|
f795d5e0d3 | ||
|
|
0521ef87da | ||
|
|
e02b51f42b | ||
|
|
aac0c27dcd | ||
|
|
95284ad71d | ||
|
|
476309af6d | ||
|
|
6fe8bafc7d | ||
|
|
872a000a33 | ||
|
|
45bdb22db8 | ||
|
|
8119fd2ad1 | ||
|
|
2baf2aa5c1 | ||
|
|
40f4e71b86 | ||
|
|
58971f9f4e | ||
|
|
520ba47293 | ||
|
|
e698ee77f7 | ||
|
|
2c96e6cf96 | ||
|
|
5ce3af0591 | ||
|
|
92c00cb741 | ||
|
|
f1e44bce4a | ||
|
|
a03e6faf37 | ||
|
|
409d95c522 | ||
|
|
23f620d255 | ||
|
|
6a6727fc80 | ||
|
|
6901cd4899 | ||
|
|
22e741c7a3 | ||
|
|
dbb3d458f5 | ||
|
|
a6a0fa28c4 | ||
|
|
97690b4eb7 | ||
|
|
ff1ed3a012 | ||
|
|
81c56b9bed | ||
|
|
31deca016f | ||
|
|
ca2e6587fe | ||
|
|
b5ae417851 | ||
|
|
b76854a384 | ||
|
|
19872e9aed | ||
|
|
985d3d469a | ||
|
|
42f55e1ebe | ||
|
|
d34233b44f | ||
|
|
16308fe557 | ||
|
|
14a23eed4f | ||
|
|
75b79039a1 | ||
|
|
81e372d078 | ||
|
|
a64fc2b24e | ||
|
|
0b326aae20 | ||
|
|
44d99f8cd4 | ||
|
|
ec4c155043 | ||
|
|
a56dd60baa | ||
|
|
b9809b071e | ||
|
|
048167d39a | ||
|
|
3af8773dd6 | ||
|
|
86c04e6971 | ||
|
|
39103af718 | ||
|
|
b56fe2b25f | ||
|
|
19ff00bad4 | ||
|
|
ce2db21f15 | ||
|
|
77729918c1 | ||
|
|
5aed82a210 | ||
|
|
04641a3f2d | ||
|
|
c2e44fa180 | ||
|
|
db8766ca69 | ||
|
|
525aeb6551 | ||
|
|
29eacbd28b | ||
|
|
bd00988c37 | ||
|
|
68040b717e | ||
|
|
275d75295c | ||
|
|
049bff09e6 | ||
|
|
2a6ba40a93 | ||
|
|
04ad94d1cc | ||
|
|
afbeca0d54 | ||
|
|
95ed5465de | ||
|
|
fbe857d1fa | ||
|
|
7d79be71d1 | ||
|
|
26b030f8cc | ||
|
|
dc73fcc4e8 | ||
|
|
dc58f6fa87 |
30
.github/workflows/close-stale.yml
vendored
Normal file
30
.github/workflows/close-stale.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: Mark stale issues
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "30 1 * * *"
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
if: github.repository == 'github/codeql'
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@v3
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
stale-issue-message: 'This issue is stale because it has been open 14 days with no activity. Comment or remove the `Stale` label in order to avoid having this issue closed in 7 days.'
|
||||
close-issue-message: 'This issue was closed because it has been inactive for 7 days.'
|
||||
days-before-stale: 14
|
||||
days-before-close: 7
|
||||
only-labels: awaiting-response
|
||||
|
||||
# do not mark PRs as stale
|
||||
days-before-pr-stale: -1
|
||||
days-before-pr-close: -1
|
||||
|
||||
# Uncomment for dry-run
|
||||
# debug-only: true
|
||||
# operations-per-run: 1000
|
||||
11
.github/workflows/codeql-analysis.yml
vendored
11
.github/workflows/codeql-analysis.yml
vendored
@@ -19,13 +19,18 @@ jobs:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
security-events: write
|
||||
pull-requests: read
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
uses: github/codeql-action/init@main
|
||||
# Override language selection by uncommenting this and choosing your languages
|
||||
with:
|
||||
languages: csharp
|
||||
@@ -34,7 +39,7 @@ jobs:
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
uses: github/codeql-action/autobuild@main
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
@@ -48,4 +53,4 @@ jobs:
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
uses: github/codeql-action/analyze@main
|
||||
|
||||
29
.github/workflows/docs-review.yml
vendored
29
.github/workflows/docs-review.yml
vendored
@@ -1,29 +0,0 @@
|
||||
# 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."
|
||||
@@ -5,6 +5,7 @@
|
||||
"java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll",
|
||||
"java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll",
|
||||
"java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll",
|
||||
"java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl6.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll",
|
||||
@@ -36,6 +37,7 @@
|
||||
"cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
|
||||
"cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll",
|
||||
@@ -55,6 +57,10 @@
|
||||
"csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll",
|
||||
"python/ql/src/semmle/python/dataflow/new/internal/DataFlowImplConsistency.qll"
|
||||
],
|
||||
"DataFlow Java/C# Flow Summaries": [
|
||||
"java/ql/src/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll"
|
||||
],
|
||||
"SsaReadPosition Java/C#": [
|
||||
"java/ql/src/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll",
|
||||
"csharp/ql/src/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll"
|
||||
@@ -376,7 +382,6 @@
|
||||
],
|
||||
"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"
|
||||
],
|
||||
@@ -429,10 +434,15 @@
|
||||
"SSA C#": [
|
||||
"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"
|
||||
"csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll",
|
||||
"csharp/ql/src/semmle/code/cil/internal/SsaImplCommon.qll"
|
||||
],
|
||||
"CryptoAlgorithms Python/JS": [
|
||||
"javascript/ql/src/semmle/javascript/security/CryptoAlgorithms.qll",
|
||||
"python/ql/src/semmle/crypto/Crypto.qll"
|
||||
],
|
||||
"SensitiveDataHeuristics Python/JS": [
|
||||
"javascript/ql/src/semmle/javascript/security/internal/SensitiveDataHeuristics.qll",
|
||||
"python/ql/src/semmle/python/security/internal/SensitiveDataHeuristics.qll"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using System;
|
||||
using System.Linq;
|
||||
using Microsoft.Build.Construction;
|
||||
using System.Xml;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Autobuild.Cpp.Tests
|
||||
{
|
||||
@@ -43,6 +44,8 @@ namespace Semmle.Autobuild.Cpp.Tests
|
||||
public IDictionary<string, int> RunProcess = new Dictionary<string, int>();
|
||||
public IDictionary<string, string> RunProcessOut = new Dictionary<string, string>();
|
||||
public IDictionary<string, string> RunProcessWorkingDirectory = new Dictionary<string, string>();
|
||||
public HashSet<string> CreateDirectories { get; } = new HashSet<string>();
|
||||
public HashSet<(string, string)> DownloadFiles { get; } = new HashSet<(string, string)>();
|
||||
|
||||
int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary<string, string>? env, out IList<string> stdOut)
|
||||
{
|
||||
@@ -135,6 +138,14 @@ namespace Semmle.Autobuild.Cpp.Tests
|
||||
|
||||
string IBuildActions.GetFullPath(string path) => path;
|
||||
|
||||
string? IBuildActions.GetFileName(string? path) => Path.GetFileName(path?.Replace('\\', '/'));
|
||||
|
||||
public string? GetDirectoryName(string? path)
|
||||
{
|
||||
var dir = Path.GetDirectoryName(path?.Replace('\\', '/'));
|
||||
return dir is null ? path : path?.Substring(0, dir.Length);
|
||||
}
|
||||
|
||||
void IBuildActions.WriteAllText(string filename, string contents)
|
||||
{
|
||||
}
|
||||
@@ -153,6 +164,18 @@ namespace Semmle.Autobuild.Cpp.Tests
|
||||
s = s.Replace($"%{kvp.Key}%", kvp.Value);
|
||||
return s;
|
||||
}
|
||||
|
||||
public void CreateDirectory(string path)
|
||||
{
|
||||
if (!CreateDirectories.Contains(path))
|
||||
throw new ArgumentException($"Missing CreateDirectory, {path}");
|
||||
}
|
||||
|
||||
public void DownloadFile(string address, string fileName)
|
||||
{
|
||||
if (!DownloadFiles.Contains((address, fileName)))
|
||||
throw new ArgumentException($"Missing DownloadFile, {address}, {fileName}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -213,6 +236,7 @@ namespace Semmle.Autobuild.Cpp.Tests
|
||||
Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_SOURCE_ARCHIVE_DIR"] = "";
|
||||
Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_ROOT"] = $@"C:\codeql\{codeqlUpperLanguage.ToLowerInvariant()}";
|
||||
Actions.GetEnvironmentVariable["CODEQL_JAVA_HOME"] = @"C:\codeql\tools\java";
|
||||
Actions.GetEnvironmentVariable["CODEQL_PLATFORM"] = "win64";
|
||||
Actions.GetEnvironmentVariable["SEMMLE_DIST"] = @"C:\odasa";
|
||||
Actions.GetEnvironmentVariable["SEMMLE_JAVA_HOME"] = @"C:\odasa\tools\java";
|
||||
Actions.GetEnvironmentVariable["SEMMLE_PLATFORM_TOOLS"] = @"C:\odasa\tools";
|
||||
@@ -273,7 +297,8 @@ namespace Semmle.Autobuild.Cpp.Tests
|
||||
[Fact]
|
||||
public void TestCppAutobuilderSuccess()
|
||||
{
|
||||
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\csharp\nuget\nuget.exe restore C:\Project\test.sln"] = 1;
|
||||
Actions.RunProcess[@"cmd.exe /C nuget restore C:\Project\test.sln -DisableParallelProcessing"] = 1;
|
||||
Actions.RunProcess[@"cmd.exe /C C:\Project\.nuget\nuget.exe restore C:\Project\test.sln -DisableParallelProcessing"] = 0;
|
||||
Actions.RunProcess[@"cmd.exe /C CALL ^""C:\Program Files ^(x86^)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat^"" && set Platform=&& type NUL && C:\odasa\tools\odasa index --auto msbuild C:\Project\test.sln /p:UseSharedCompilation=false /t:rebuild /p:Platform=""x86"" /p:Configuration=""Release"" /p:MvcBuildViews=true"] = 0;
|
||||
Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = "";
|
||||
Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = 1;
|
||||
@@ -286,11 +311,13 @@ namespace Semmle.Autobuild.Cpp.Tests
|
||||
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = true;
|
||||
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.slx";
|
||||
Actions.EnumerateDirectories[@"C:\Project"] = "";
|
||||
Actions.CreateDirectories.Add(@"C:\Project\.nuget");
|
||||
Actions.DownloadFiles.Add(("https://dist.nuget.org/win-x86-commandline/latest/nuget.exe", @"C:\Project\.nuget\nuget.exe"));
|
||||
|
||||
var autobuilder = CreateAutoBuilder(true);
|
||||
var solution = new TestSolution(@"C:\Project\test.sln");
|
||||
autobuilder.ProjectsOrSolutionsToBuild.Add(solution);
|
||||
TestAutobuilderScript(autobuilder, 0, 2);
|
||||
TestAutobuilderScript(autobuilder, 0, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
2
cpp/change-notes/2021-03-11-overflow-abs.md
Normal file
2
cpp/change-notes/2021-03-11-overflow-abs.md
Normal file
@@ -0,0 +1,2 @@
|
||||
lgtm
|
||||
* The `cpp/tainted-arithmetic`, `cpp/arithmetic-with-extreme-values`, and `cpp/uncontrolled-arithmetic` queries now recognize more functions as returning the absolute value of their input. As a result, they produce fewer false positives.
|
||||
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* The 'Assignment where comparison was intended' (cpp/assign-where-compare-meant) query has been improved to flag fewer benign assignments in conditionals.
|
||||
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* The 'Unsigned difference expression compared to zero' (cpp/unsigned-difference-expression-compared-zero) query has been improved to produce fewer false positive results.
|
||||
2
cpp/change-notes/2021-04-13-arithmetic-queries.md
Normal file
2
cpp/change-notes/2021-04-13-arithmetic-queries.md
Normal file
@@ -0,0 +1,2 @@
|
||||
lgtm
|
||||
* The queries cpp/tainted-arithmetic, cpp/uncontrolled-arithmetic, and cpp/arithmetic-with-extreme-values have been improved to produce fewer false positives.
|
||||
@@ -0,0 +1,2 @@
|
||||
codescanning
|
||||
* The 'Pointer to stack object used as return value' (cpp/return-stack-allocated-object) query has been deprecated, and any uses should be replaced with `Returning stack-allocated memory` (cpp/return-stack-allocated-memory).
|
||||
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* The 'Comparison with wider type' (cpp/comparison-with-wider-type) query has been improved to produce fewer false positives.
|
||||
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* The `exprMightOverflowPositively` and `exprMightOverflowNegatively` predicates from the `SimpleRangeAnalysis` library now recognize more expressions that might overflow.
|
||||
@@ -39,7 +39,7 @@ then replace all the relevant occurrences in the code.</p>
|
||||
</li>
|
||||
<li>
|
||||
Mats Henricson and Erik Nyquist, <i>Industrial Strength C++</i>, published by Prentice Hall PTR (1997).
|
||||
Chapter 5: Object Life Cycle, Rec 5.4 (<a href="http://mongers.org/industrial-c++/">PDF</a>).
|
||||
Chapter 5: Object Life Cycle, Rec 5.4 (<a href="https://web.archive.org/web/20190919025638/https://mongers.org/industrial-c++/">PDF</a>).
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://www.securecoding.cert.org/confluence/display/c/DCL06-C.+Use+meaningful+symbolic+constants+to+represent+literal+values">DCL06-C. Use meaningful symbolic constants to represent literal values</a>
|
||||
|
||||
@@ -38,7 +38,7 @@ constant.</p>
|
||||
</li>
|
||||
<li>
|
||||
Mats Henricson and Erik Nyquist, <i>Industrial Strength C++</i>, published by Prentice Hall PTR (1997).
|
||||
Chapter 5: Object Life Cycle, Rec 5.4 (<a href="http://mongers.org/industrial-c++/">PDF</a>).
|
||||
Chapter 5: Object Life Cycle, Rec 5.4 (<a href="https://web.archive.org/web/20190919025638/https://mongers.org/industrial-c++/">PDF</a>).
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://www.securecoding.cert.org/confluence/display/c/DCL06-C.+Use+meaningful+symbolic+constants+to+represent+literal+values">DCL06-C. Use meaningful symbolic constants to represent literal values</a>
|
||||
|
||||
@@ -21,7 +21,7 @@ Review the purpose of the each global variable flagged by this rule and update e
|
||||
|
||||
<li>
|
||||
Mats Henricson and Erik Nyquist, <i>Industrial Strength C++</i>, published by Prentice Hall PTR (1997).
|
||||
Chapter 1: Naming, Rec 1.1 (<a href="http://mongers.org/industrial-c++/">PDF</a>).
|
||||
Chapter 1: Naming, Rec 1.1 (<a href="https://web.archive.org/web/20190919025638/https://mongers.org/industrial-c++/">PDF</a>).
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://www.learncpp.com/cpp-tutorial/42-global-variables/">Global variables</a>.
|
||||
|
||||
@@ -45,7 +45,7 @@ this rule.
|
||||
</li>
|
||||
<li>
|
||||
Mats Henricson and Erik Nyquist, <i>Industrial Strength C++</i>, Rule 4.6. Prentice Hall PTR, 1997.
|
||||
(<a href="http://mongers.org/industrial-c++/">PDF</a>).
|
||||
(<a href="https://web.archive.org/web/20190919025638/https://mongers.org/industrial-c++/">PDF</a>).
|
||||
</li>
|
||||
<li>
|
||||
cplusplus.com: <a href="http://www.cplusplus.com/doc/tutorial/control/">Control Structures</a>.
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
* @tags reliability
|
||||
* security
|
||||
* external/cwe/cwe-562
|
||||
* @deprecated This query is not suitable for production use and has been deprecated. Use
|
||||
* cpp/return-stack-allocated-memory instead.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.pointsto.PointsTo
|
||||
|
||||
@@ -32,7 +32,7 @@ Check the return value of functions that return status information.
|
||||
<references>
|
||||
|
||||
<li>
|
||||
M. Henricson and E. Nyquist, <i>Industrial Strength C++</i>, Chapter 12: Error handling. Prentice Hall PTR, 1997 (<a href="http://mongers.org/industrial-c++/">available online</a>).
|
||||
M. Henricson and E. Nyquist, <i>Industrial Strength C++</i>, Chapter 12: Error handling. Prentice Hall PTR, 1997 (<a href="https://web.archive.org/web/20190919025638/https://mongers.org/industrial-c++/">available online</a>).
|
||||
</li>
|
||||
<li>
|
||||
The CERT C Secure Coding Standard: <a href="https://www.securecoding.cert.org/confluence/display/perl/EXP32-PL.+Do+not+ignore+function+return+values">EXP32-PL. Do not ignore function return values</a>.
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
* @id cpp/signed-overflow-check
|
||||
* @tags correctness
|
||||
* security
|
||||
* external/cwe/cwe-128
|
||||
* external/cwe/cwe-190
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @precision high
|
||||
* @id cpp/upcast-array-pointer-arithmetic
|
||||
* @tags correctness
|
||||
* reliability
|
||||
* security
|
||||
* external/cwe/cwe-119
|
||||
* external/cwe/cwe-843
|
||||
* @id cpp/upcast-array-pointer-arithmetic
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
* @tags reliability
|
||||
* correctness
|
||||
* security
|
||||
* external/cwe/cwe-190
|
||||
* external/cwe/cwe-253
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
* @tags reliability
|
||||
* correctness
|
||||
* security
|
||||
* external/cwe/cwe-234
|
||||
* external/cwe/cwe-685
|
||||
*/
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ class BooleanControllingAssignmentInExpr extends BooleanControllingAssignment {
|
||||
override predicate isWhitelisted() {
|
||||
this.getConversion().(ParenthesisExpr).isParenthesised()
|
||||
or
|
||||
// whitelist this assignment if all comparison operations in the expression that this
|
||||
// Allow this assignment if all comparison operations in the expression that this
|
||||
// assignment is part of, are not parenthesized. In that case it seems like programmer
|
||||
// is fine with unparenthesized comparison operands to binary logical operators, and
|
||||
// the parenthesis around this assignment was used to call it out as an assignment.
|
||||
@@ -62,6 +62,21 @@ class BooleanControllingAssignmentInExpr extends BooleanControllingAssignment {
|
||||
forex(ComparisonOperation op | op = getComparisonOperand*(this.getParent+()) |
|
||||
not op.isParenthesised()
|
||||
)
|
||||
or
|
||||
// Match a pattern like:
|
||||
// ```
|
||||
// if((a = b) && use_value(a)) { ... }
|
||||
// ```
|
||||
// where the assignment is meant to update the value of `a` before it's used in some other boolean
|
||||
// subexpression that is guarenteed to be evaluate _after_ the assignment.
|
||||
this.isParenthesised() and
|
||||
exists(LogicalAndExpr parent, Variable var, VariableAccess access |
|
||||
var = this.getLValue().(VariableAccess).getTarget() and
|
||||
access = var.getAnAccess() and
|
||||
not access.isUsedAsLValue() and
|
||||
parent.getRightOperand() = access.getParent*() and
|
||||
parent.getLeftOperand() = this.getParent*()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ indication that there may be cases unhandled by the <code>switch</code> statemen
|
||||
MSDN Library: <a href="https://docs.microsoft.com/en-us/cpp/cpp/switch-statement-cpp">switch statement (C++)</a>
|
||||
</li>
|
||||
<li>
|
||||
M. Henricson and E. Nyquist, <i>Industrial Strength C++</i>, Chapter 4: Control Flow, Rec 4.5. Prentice Hall PTR, 1997 (<a href="http://mongers.org/industrial-c++/">available online</a>).
|
||||
M. Henricson and E. Nyquist, <i>Industrial Strength C++</i>, Chapter 4: Control Flow, Rec 4.5. Prentice Hall PTR, 1997 (<a href="https://web.archive.org/web/20190919025638/https://mongers.org/industrial-c++/">available online</a>).
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
* @id cpp/pointer-overflow-check
|
||||
* @tags reliability
|
||||
* security
|
||||
* external/cwe/cwe-758
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.dataflow.EscapesTree
|
||||
import semmle.code.cpp.models.interfaces.PointerWrapper
|
||||
import semmle.code.cpp.dataflow.DataFlow
|
||||
|
||||
/**
|
||||
@@ -39,6 +40,10 @@ predicate hasNontrivialConversion(Expr e) {
|
||||
e instanceof ParenthesisExpr
|
||||
)
|
||||
or
|
||||
// A smart pointer can be stack-allocated while the data it points to is heap-allocated.
|
||||
// So we exclude such "conversions" from this predicate.
|
||||
e = any(PointerWrapper wrapper).getAnUnwrapperFunction().getACallToThisFunction()
|
||||
or
|
||||
hasNontrivialConversion(e.getConversion())
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
* @tags correctness
|
||||
* language-features
|
||||
* security
|
||||
* external/cwe/cwe-670
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
* @tags correctness
|
||||
* maintainability
|
||||
* security
|
||||
* external/cwe/cwe-234
|
||||
* external/cwe/cwe-685
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* @kind treemap
|
||||
* @treemap.warnOn highValues
|
||||
* @metricType externalDependency
|
||||
* @precision medium
|
||||
* @id cpp/external-dependencies
|
||||
* @tags modularity
|
||||
*/
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
* @treemap.warnOn highValues
|
||||
* @metricType file
|
||||
* @metricAggregate avg sum max
|
||||
* @precision very-high
|
||||
* @id cpp/lines-of-code-in-files
|
||||
* @tags maintainability
|
||||
* complexity
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* @treemap.warnOn highValues
|
||||
* @metricType file
|
||||
* @metricAggregate avg sum max
|
||||
* @precision high
|
||||
* @id cpp/lines-of-commented-out-code-in-files
|
||||
* @tags documentation
|
||||
*/
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
* @treemap.warnOn lowValues
|
||||
* @metricType file
|
||||
* @metricAggregate avg sum max
|
||||
* @precision very-high
|
||||
* @id cpp/lines-of-comments-in-files
|
||||
* @tags maintainability
|
||||
* documentation
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
* @treemap.warnOn highValues
|
||||
* @metricType file
|
||||
* @metricAggregate avg sum max
|
||||
* @precision high
|
||||
* @id cpp/duplicated-lines-in-files
|
||||
* @tags testability
|
||||
* modularity
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
* @treemap.warnOn lowValues
|
||||
* @metricType file
|
||||
* @metricAggregate avg sum max
|
||||
* @precision medium
|
||||
* @id cpp/tests-in-files
|
||||
* @tags maintainability
|
||||
*/
|
||||
|
||||
@@ -29,7 +29,7 @@ build time: the more included files, the longer the compilation time.</p>
|
||||
<a href="http://www.drdobbs.com/cpp/decoupling-c-header-files/212701130">Decoupling C Header Files</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://wiki.hsr.ch/Prog3/files/overload72-FINAL_DesigningHeaderFiles.pdf">C++ Best Practice -
|
||||
<a href="https://accu.org/journals/overload/14/72/griffiths_1995/">C++ Best Practice -
|
||||
Designing Header Files</a>
|
||||
</li>
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ they are contributing to unnecessarily long build times and creating artificial
|
||||
<a href="http://www.drdobbs.com/cpp/decoupling-c-header-files/212701130">Decoupling C Header Files</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://wiki.hsr.ch/Prog3/files/overload72-FINAL_DesigningHeaderFiles.pdf">C++ Best Practice -
|
||||
<a href="https://accu.org/journals/overload/14/72/griffiths_1995/">C++ Best Practice -
|
||||
Designing Header Files</a>
|
||||
</li>
|
||||
</references>
|
||||
|
||||
@@ -49,7 +49,9 @@ where
|
||||
small = rel.getLesserOperand() and
|
||||
large = rel.getGreaterOperand() and
|
||||
rel = l.getCondition().getAChild*() and
|
||||
upperBound(large).log2() > getComparisonSize(small) * 8 and
|
||||
forall(Expr conv | conv = large.getConversion*() |
|
||||
upperBound(conv).log2() > getComparisonSize(small) * 8
|
||||
) and
|
||||
// Ignore cases where the smaller type is int or larger
|
||||
// These are still bugs, but you should need a very large string or array to
|
||||
// trigger them. We will want to disable this for some applications, but it's
|
||||
|
||||
@@ -28,6 +28,7 @@ predicate outOfBoundsExpr(Expr expr, string kind) {
|
||||
|
||||
from Expr use, Expr origin, string kind
|
||||
where
|
||||
not use.getUnspecifiedType() instanceof PointerType and
|
||||
outOfBoundsExpr(use, kind) and
|
||||
tainted(origin, use) and
|
||||
origin != use and
|
||||
|
||||
@@ -12,29 +12,60 @@
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.commons.Exclusions
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
|
||||
import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
|
||||
import semmle.code.cpp.controlflow.Guards
|
||||
import semmle.code.cpp.dataflow.DataFlow
|
||||
|
||||
/** Holds if `sub` is guarded by a condition which ensures that `left >= right`. */
|
||||
/**
|
||||
* Holds if `sub` is guarded by a condition which ensures that
|
||||
* `left >= right`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
predicate isGuarded(SubExpr sub, Expr left, Expr right) {
|
||||
exists(GuardCondition guard |
|
||||
guard.controls(sub.getBasicBlock(), true) and
|
||||
guard.ensuresLt(left, right, 0, sub.getBasicBlock(), false)
|
||||
exists(GuardCondition guard, int k |
|
||||
guard.controls(sub.getBasicBlock(), _) and
|
||||
guard.ensuresLt(left, right, k, sub.getBasicBlock(), false) and
|
||||
k >= 0
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `sub` will never be negative. */
|
||||
predicate nonNegative(SubExpr sub) {
|
||||
not exprMightOverflowNegatively(sub.getFullyConverted())
|
||||
/**
|
||||
* Holds if `n` is known or suspected to be less than or equal to
|
||||
* `sub.getLeftOperand()`.
|
||||
*/
|
||||
predicate exprIsSubLeftOrLess(SubExpr sub, DataFlow::Node n) {
|
||||
n.asExpr() = sub.getLeftOperand()
|
||||
or
|
||||
// The subtraction is guarded by a check of the form `left >= right`.
|
||||
exists(GVN left, GVN right |
|
||||
// This is basically a poor man's version of a directional unbind operator.
|
||||
strictcount([left, globalValueNumber(sub.getLeftOperand())]) = 1 and
|
||||
strictcount([right, globalValueNumber(sub.getRightOperand())]) = 1 and
|
||||
isGuarded(sub, left.getAnExpr(), right.getAnExpr())
|
||||
exists(DataFlow::Node other |
|
||||
// dataflow
|
||||
exprIsSubLeftOrLess(sub, other) and
|
||||
(
|
||||
DataFlow::localFlowStep(n, other) or
|
||||
DataFlow::localFlowStep(other, n)
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(DataFlow::Node other |
|
||||
// guard constraining `sub`
|
||||
exprIsSubLeftOrLess(sub, other) and
|
||||
isGuarded(sub, other.asExpr(), n.asExpr()) // other >= n
|
||||
)
|
||||
or
|
||||
exists(DataFlow::Node other, float p, float q |
|
||||
// linear access of `other`
|
||||
exprIsSubLeftOrLess(sub, other) and
|
||||
linearAccess(n.asExpr(), other.asExpr(), p, q) and // n = p * other + q
|
||||
p <= 1 and
|
||||
q <= 0
|
||||
)
|
||||
or
|
||||
exists(DataFlow::Node other, float p, float q |
|
||||
// linear access of `n`
|
||||
exprIsSubLeftOrLess(sub, other) and
|
||||
linearAccess(other.asExpr(), n.asExpr(), p, q) and // other = p * n + q
|
||||
p >= 1 and
|
||||
q >= 0
|
||||
)
|
||||
}
|
||||
|
||||
@@ -45,5 +76,6 @@ where
|
||||
ro.getLesserOperand().getValue().toInt() = 0 and
|
||||
ro.getGreaterOperand() = sub and
|
||||
sub.getFullyConverted().getUnspecifiedType().(IntegralType).isUnsigned() and
|
||||
not nonNegative(sub)
|
||||
exprMightOverflowNegatively(sub.getFullyConverted()) and // generally catches false positives involving constants
|
||||
not exprIsSubLeftOrLess(sub, DataFlow::exprNode(sub.getRightOperand())) // generally catches false positives where there's a relation between the left and right operands
|
||||
select ro, "Unsigned subtraction can never be negative."
|
||||
|
||||
@@ -93,7 +93,7 @@ class QuotedCommandInCreateProcessFunctionConfiguration extends DataFlow2::Confi
|
||||
|
||||
bindingset[s]
|
||||
predicate isQuotedOrNoSpaceApplicationNameOnCmd(string s) {
|
||||
s.regexpMatch("\"([^\"])*\"(\\s|.)*") // The first element (path) is quoted
|
||||
s.regexpMatch("\"([^\"])*\"[\\s\\S]*") // The first element (path) is quoted
|
||||
or
|
||||
s.regexpMatch("[^\\s]+") // There are no spaces in the string
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
while(intIndex > 2)
|
||||
{
|
||||
...
|
||||
intIndex--;
|
||||
...
|
||||
} // GOOD: correct cycle
|
||||
...
|
||||
while(intIndex > 2)
|
||||
{
|
||||
...
|
||||
int intIndex;
|
||||
intIndex--;
|
||||
...
|
||||
} // BAD: the variable used in the condition does not change.
|
||||
@@ -0,0 +1,26 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>Using variables with the same name is dangerous. However, such a situation inside the while loop can create an infinite loop exhausting resources. Requires the attention of developers.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>We recommend not to use local variables inside a loop if their names are the same as the variables in the condition of this loop.</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
<p>The following example demonstrates an erroneous and corrected use of a local variable within a loop.</p>
|
||||
<sample src="DeclarationOfVariableWithUnnecessarilyWideScope.c" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>
|
||||
CERT C Coding Standard:
|
||||
<a href="https://wiki.sei.cmu.edu/confluence/display/c/DCL01-C.+Do+not+reuse+variable+names+in+subscopes">DCL01-C. Do not reuse variable names in subscopes</a>.
|
||||
</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* @name Errors When Using Variable Declaration Inside Loop
|
||||
* @description Using variables with the same name is dangerous.
|
||||
* However, such a situation inside the while loop can create an infinite loop exhausting resources.
|
||||
* Requires the attention of developers.
|
||||
* @kind problem
|
||||
* @id cpp/errors-when-using-variable-declaration-inside-loop
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @tags correctness
|
||||
* security
|
||||
* external/cwe/cwe-1126
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* Errors when using a variable declaration inside a loop.
|
||||
*/
|
||||
class DangerousWhileLoop extends WhileStmt {
|
||||
Expr exp;
|
||||
Declaration dl;
|
||||
|
||||
DangerousWhileLoop() {
|
||||
this = dl.getParentScope().(BlockStmt).getParent*() and
|
||||
exp = this.getCondition().getAChild*() and
|
||||
not exp instanceof PointerFieldAccess and
|
||||
not exp instanceof ValueFieldAccess and
|
||||
exp.(VariableAccess).getTarget().getName() = dl.getName() and
|
||||
not exp.getParent*() instanceof FunctionCall
|
||||
}
|
||||
|
||||
Declaration getDeclaration() { result = dl }
|
||||
|
||||
/** Holds when there are changes to the variables involved in the condition. */
|
||||
predicate isUseThisVariable() {
|
||||
exists(Variable v |
|
||||
this.getCondition().getAChild*().(VariableAccess).getTarget() = v and
|
||||
(
|
||||
exists(Assignment aexp |
|
||||
this = aexp.getEnclosingStmt().getParentStmt*() and
|
||||
(
|
||||
aexp.getLValue().(ArrayExpr).getArrayBase().(VariableAccess).getTarget() = v
|
||||
or
|
||||
aexp.getLValue().(VariableAccess).getTarget() = v
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(CrementOperation crm |
|
||||
this = crm.getEnclosingStmt().getParentStmt*() and
|
||||
crm.getOperand().(VariableAccess).getTarget() = v
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
from DangerousWhileLoop lp
|
||||
where not lp.isUseThisVariable()
|
||||
select lp.getDeclaration(), "A variable with this name is used in the $@ condition.", lp, "loop"
|
||||
@@ -0,0 +1,43 @@
|
||||
// BAD: the allocation will throw an unhandled exception
|
||||
// instead of returning a null pointer.
|
||||
void bad1(std::size_t length) noexcept {
|
||||
int* dest = new int[length];
|
||||
if(!dest) {
|
||||
return;
|
||||
}
|
||||
std::memset(dest, 0, length);
|
||||
// ...
|
||||
}
|
||||
|
||||
// BAD: the allocation won't throw an exception, but
|
||||
// instead return a null pointer.
|
||||
void bad2(std::size_t length) noexcept {
|
||||
try {
|
||||
int* dest = new(std::nothrow) int[length];
|
||||
std::memset(dest, 0, length);
|
||||
// ...
|
||||
} catch(std::bad_alloc&) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
// GOOD: the allocation failure is handled appropiately.
|
||||
void good1(std::size_t length) noexcept {
|
||||
try {
|
||||
int* dest = new int[length];
|
||||
std::memset(dest, 0, length);
|
||||
// ...
|
||||
} catch(std::bad_alloc&) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
// GOOD: the allocation failure is handled appropiately.
|
||||
void good2(std::size_t length) noexcept {
|
||||
int* dest = new int[length];
|
||||
if(!dest) {
|
||||
return;
|
||||
}
|
||||
std::memset(dest, 0, length);
|
||||
// ...
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>Different overloads of the <code>new</code> operator handle allocation failures in different ways.
|
||||
If <code>new T</code> fails for some type <code>T</code>, it throws a <code>std::bad_alloc</code> exception,
|
||||
but <code>new(std::nothrow) T</code> returns a null pointer. If the programmer does not use the corresponding
|
||||
method of error handling, allocation failure may go unhandled and could cause the program to behave in
|
||||
unexpected ways.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>Make sure that exceptions are handled appropriately if <code>new T</code> is used. On the other hand,
|
||||
make sure to handle the possibility of null pointers if <code>new(std::nothrow) T</code> is used.</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
<sample src="IncorrectAllocationErrorHandling.cpp" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>
|
||||
CERT C++ Coding Standard:
|
||||
<a href="https://wiki.sei.cmu.edu/confluence/display/cplusplus/MEM52-CPP.+Detect+and+handle+memory+allocation+errors">MEM52-CPP. Detect and handle memory allocation errors</a>.
|
||||
</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,224 @@
|
||||
/**
|
||||
* @name Incorrect allocation-error handling
|
||||
* @description `operator new` throws an exception on allocation failures, while `operator new(std::nothrow)` returns a null pointer. Mixing up these two failure conditions can result in unexpected behavior.
|
||||
* @kind problem
|
||||
* @id cpp/incorrect-allocation-error-handling
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @tags correctness
|
||||
* security
|
||||
* external/cwe/cwe-570
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
import semmle.code.cpp.controlflow.Guards
|
||||
|
||||
/**
|
||||
* A C++ `delete` or `delete[]` expression.
|
||||
*/
|
||||
class DeleteOrDeleteArrayExpr extends Expr {
|
||||
DeleteOrDeleteArrayExpr() { this instanceof DeleteExpr or this instanceof DeleteArrayExpr }
|
||||
|
||||
DeallocationFunction getDeallocator() {
|
||||
result = [this.(DeleteExpr).getDeallocator(), this.(DeleteArrayExpr).getDeallocator()]
|
||||
}
|
||||
|
||||
Destructor getDestructor() {
|
||||
result = [this.(DeleteExpr).getDestructor(), this.(DeleteArrayExpr).getDestructor()]
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets the `Constructor` invoked when `newExpr` allocates memory. */
|
||||
Constructor getConstructorForAllocation(NewOrNewArrayExpr newExpr) {
|
||||
result.getACallToThisFunction() = newExpr.getInitializer()
|
||||
}
|
||||
|
||||
/** Gets the `Destructor` invoked when `deleteExpr` deallocates memory. */
|
||||
Destructor getDestructorForDeallocation(DeleteOrDeleteArrayExpr deleteExpr) {
|
||||
result = deleteExpr.getDestructor()
|
||||
}
|
||||
|
||||
/** Holds if the evaluation of `newExpr` may throw an exception. */
|
||||
predicate newMayThrow(NewOrNewArrayExpr newExpr) {
|
||||
functionMayThrow(newExpr.getAllocator()) or
|
||||
functionMayThrow(getConstructorForAllocation(newExpr))
|
||||
}
|
||||
|
||||
/** Holds if the evaluation of `deleteExpr` may throw an exception. */
|
||||
predicate deleteMayThrow(DeleteOrDeleteArrayExpr deleteExpr) {
|
||||
functionMayThrow(deleteExpr.getDeallocator()) or
|
||||
functionMayThrow(getDestructorForDeallocation(deleteExpr))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the function may throw an exception when called. That is, if the body of the function looks
|
||||
* like it might throw an exception, and the function does not have a `noexcept` or `throw()` specifier.
|
||||
*/
|
||||
predicate functionMayThrow(Function f) {
|
||||
(not exists(f.getBlock()) or stmtMayThrow(f.getBlock())) and
|
||||
not f.isNoExcept() and
|
||||
not f.isNoThrow()
|
||||
}
|
||||
|
||||
/** Holds if the evaluation of `stmt` may throw an exception. */
|
||||
predicate stmtMayThrow(Stmt stmt) {
|
||||
stmtMayThrow(stmt.(BlockStmt).getAStmt())
|
||||
or
|
||||
convertedExprMayThrow(stmt.(ExprStmt).getExpr())
|
||||
or
|
||||
convertedExprMayThrow(stmt.(DeclStmt).getADeclaration().(Variable).getInitializer().getExpr())
|
||||
or
|
||||
exists(IfStmt ifStmt | ifStmt = stmt |
|
||||
convertedExprMayThrow(ifStmt.getCondition()) or
|
||||
stmtMayThrow([ifStmt.getThen(), ifStmt.getElse()])
|
||||
)
|
||||
or
|
||||
exists(ConstexprIfStmt constIfStmt | constIfStmt = stmt |
|
||||
stmtMayThrow([constIfStmt.getThen(), constIfStmt.getElse()])
|
||||
)
|
||||
or
|
||||
exists(Loop loop | loop = stmt |
|
||||
convertedExprMayThrow(loop.getCondition()) or
|
||||
stmtMayThrow(loop.getStmt())
|
||||
)
|
||||
or
|
||||
// The case for `Loop` already checked the condition and the statement.
|
||||
convertedExprMayThrow(stmt.(RangeBasedForStmt).getUpdate())
|
||||
or
|
||||
// The case for `Loop` already checked the condition and the statement.
|
||||
exists(ForStmt forStmt | forStmt = stmt |
|
||||
stmtMayThrow(forStmt.getInitialization())
|
||||
or
|
||||
convertedExprMayThrow(forStmt.getUpdate())
|
||||
)
|
||||
or
|
||||
exists(SwitchStmt switchStmt | switchStmt = stmt |
|
||||
convertedExprMayThrow(switchStmt.getExpr()) or
|
||||
stmtMayThrow(switchStmt.getStmt())
|
||||
)
|
||||
or
|
||||
// NOTE: We don't include `TryStmt` as those exceptions are not "observable" outside the function.
|
||||
stmtMayThrow(stmt.(Handler).getBlock())
|
||||
or
|
||||
convertedExprMayThrow(stmt.(CoReturnStmt).getExpr())
|
||||
or
|
||||
convertedExprMayThrow(stmt.(ReturnStmt).getExpr())
|
||||
}
|
||||
|
||||
/** Holds if the evaluation of `e` (including conversions) may throw an exception. */
|
||||
predicate convertedExprMayThrow(Expr e) {
|
||||
exprMayThrow(e)
|
||||
or
|
||||
convertedExprMayThrow(e.getConversion())
|
||||
}
|
||||
|
||||
/** Holds if the evaluation of `e` may throw an exception. */
|
||||
predicate exprMayThrow(Expr e) {
|
||||
e instanceof DynamicCast
|
||||
or
|
||||
e instanceof TypeidOperator
|
||||
or
|
||||
e instanceof ThrowExpr
|
||||
or
|
||||
newMayThrow(e)
|
||||
or
|
||||
deleteMayThrow(e)
|
||||
or
|
||||
convertedExprMayThrow(e.(UnaryOperation).getOperand())
|
||||
or
|
||||
exists(BinaryOperation binOp | binOp = e |
|
||||
convertedExprMayThrow([binOp.getLeftOperand(), binOp.getRightOperand()])
|
||||
)
|
||||
or
|
||||
exists(Assignment assign | assign = e |
|
||||
convertedExprMayThrow([assign.getLValue(), assign.getRValue()])
|
||||
)
|
||||
or
|
||||
exists(CommaExpr comma | comma = e |
|
||||
convertedExprMayThrow([comma.getLeftOperand(), comma.getRightOperand()])
|
||||
)
|
||||
or
|
||||
exists(StmtExpr stmtExpr | stmtExpr = e |
|
||||
convertedExprMayThrow(stmtExpr.getResultExpr()) or
|
||||
stmtMayThrow(stmtExpr.getStmt())
|
||||
)
|
||||
or
|
||||
convertedExprMayThrow(e.(Conversion).getExpr())
|
||||
or
|
||||
exists(FunctionCall fc | fc = e |
|
||||
not exists(fc.getTarget()) or
|
||||
functionMayThrow(fc.getTarget()) or
|
||||
convertedExprMayThrow(fc.getAnArgument())
|
||||
)
|
||||
}
|
||||
|
||||
/** An allocator that might throw an exception. */
|
||||
class ThrowingAllocator extends Function {
|
||||
ThrowingAllocator() {
|
||||
exists(NewOrNewArrayExpr newExpr |
|
||||
newExpr.getAllocator() = this and
|
||||
functionMayThrow(this)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** The `std::bad_alloc` exception and its `bsl` variant. */
|
||||
class BadAllocType extends Class {
|
||||
BadAllocType() { this.hasGlobalOrStdOrBslName("bad_alloc") }
|
||||
}
|
||||
|
||||
/**
|
||||
* A catch block that catches a `std::bad_alloc` (or any of its superclasses), or a catch
|
||||
* block that catches every exception (i.e., `catch(...)`).
|
||||
*/
|
||||
class BadAllocCatchBlock extends CatchBlock {
|
||||
BadAllocCatchBlock() {
|
||||
this.getParameter().getUnspecifiedType().stripType() =
|
||||
any(BadAllocType badAlloc).getABaseClass*()
|
||||
or
|
||||
not exists(this.getParameter())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `newExpr` is embedded in a `try` statement with a catch block `catchBlock` that
|
||||
* catches a `std::bad_alloc` exception, but nothing in the `try` block (including the `newExpr`)
|
||||
* will throw that exception.
|
||||
*/
|
||||
predicate noThrowInTryBlock(NewOrNewArrayExpr newExpr, BadAllocCatchBlock catchBlock) {
|
||||
exists(TryStmt try |
|
||||
not stmtMayThrow(try.getStmt()) and
|
||||
try.getACatchClause() = catchBlock and
|
||||
newExpr.getEnclosingBlock().getEnclosingBlock*() = try.getStmt()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `newExpr` is handles allocation failures by throwing an exception, yet
|
||||
* the guard condition `guard` compares the result of `newExpr` to a null value.
|
||||
*/
|
||||
predicate nullCheckInThrowingNew(NewOrNewArrayExpr newExpr, GuardCondition guard) {
|
||||
newExpr.getAllocator() instanceof ThrowingAllocator and
|
||||
(
|
||||
// Handles null comparisons.
|
||||
guard.ensuresEq(globalValueNumber(newExpr).getAnExpr(), any(NullValue null), _, _, _)
|
||||
or
|
||||
// Handles `if(ptr)` and `if(!ptr)` cases.
|
||||
guard = globalValueNumber(newExpr).getAnExpr()
|
||||
)
|
||||
}
|
||||
|
||||
from NewOrNewArrayExpr newExpr, Element element, string msg, string elementString
|
||||
where
|
||||
not newExpr.isFromUninstantiatedTemplate(_) and
|
||||
(
|
||||
noThrowInTryBlock(newExpr, element) and
|
||||
msg = "This allocation cannot throw. $@ is unnecessary." and
|
||||
elementString = "This catch block"
|
||||
or
|
||||
nullCheckInThrowingNew(newExpr, element) and
|
||||
msg = "This allocation cannot return null. $@ is unnecessary." and
|
||||
elementString = "This check"
|
||||
)
|
||||
select newExpr, msg, element, elementString
|
||||
@@ -1,35 +0,0 @@
|
||||
// BAD: on memory allocation error, the program terminates.
|
||||
void badFunction(const int *source, std::size_t length) noexcept {
|
||||
int * dest = new int[length];
|
||||
std::memset(dest, 0, length);
|
||||
// ..
|
||||
}
|
||||
// GOOD: memory allocation error will be handled.
|
||||
void goodFunction(const int *source, std::size_t length) noexcept {
|
||||
try {
|
||||
int * dest = new int[length];
|
||||
} catch(std::bad_alloc) {
|
||||
// ...
|
||||
}
|
||||
std::memset(dest, 0, length);
|
||||
// ..
|
||||
}
|
||||
// BAD: memory allocation error will not be handled.
|
||||
void badFunction(const int *source, std::size_t length) noexcept {
|
||||
try {
|
||||
int * dest = new (std::nothrow) int[length];
|
||||
} catch(std::bad_alloc) {
|
||||
// ...
|
||||
}
|
||||
std::memset(dest, 0, length);
|
||||
// ..
|
||||
}
|
||||
// GOOD: memory allocation error will be handled.
|
||||
void goodFunction(const int *source, std::size_t length) noexcept {
|
||||
int * dest = new (std::nothrow) int[length];
|
||||
if (!dest) {
|
||||
return;
|
||||
}
|
||||
std::memset(dest, 0, length);
|
||||
// ..
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>When using the <code>new</code> operator to allocate memory, you need to pay attention to the different ways of detecting errors. <code>::operator new(std::size_t)</code> throws an exception on error, whereas <code>::operator new(std::size_t, const std::nothrow_t &)</code> returns zero on error. The programmer can get confused and check the error that occurs when allocating memory incorrectly. That can lead to an unhandled program termination or to a violation of the program logic.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>Use the correct error detection method corresponding with the memory allocation.</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
<p>The following example demonstrates various approaches to detecting memory allocation errors using the <code>new</code> operator.</p>
|
||||
<sample src="WrongInDetectingAndHandlingMemoryAllocationErrors.cpp" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>
|
||||
CERT C++ Coding Standard:
|
||||
<a href="https://wiki.sei.cmu.edu/confluence/display/cplusplus/MEM52-CPP.+Detect+and+handle+memory+allocation+errors">MEM52-CPP. Detect and handle memory allocation errors</a>.
|
||||
</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -1,87 +0,0 @@
|
||||
/**
|
||||
* @name Detect And Handle Memory Allocation Errors
|
||||
* @description --::operator new(std::size_t) throws an exception on error, and ::operator new(std::size_t, const std::nothrow_t &) returns zero on error.
|
||||
* --the programmer can get confused when check the error that occurs when allocating memory incorrectly.
|
||||
* @kind problem
|
||||
* @id cpp/detect-and-handle-memory-allocation-errors
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @tags correctness
|
||||
* security
|
||||
* external/cwe/cwe-570
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* Lookup if condition compare with 0
|
||||
*/
|
||||
class IfCompareWithZero extends IfStmt {
|
||||
IfCompareWithZero() {
|
||||
this.getCondition().(EQExpr).getAChild().getValue() = "0"
|
||||
or
|
||||
this.getCondition().(NEExpr).getAChild().getValue() = "0" and
|
||||
this.hasElse()
|
||||
or
|
||||
this.getCondition().(NEExpr).getAChild().getValue() = "0" and
|
||||
this.getThen().getAChild*() instanceof ReturnStmt
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* lookup for calls to `operator new`, with incorrect error handling.
|
||||
*/
|
||||
class WrongCheckErrorOperatorNew extends FunctionCall {
|
||||
Expr exp;
|
||||
|
||||
WrongCheckErrorOperatorNew() {
|
||||
this = exp.(NewOrNewArrayExpr).getAChild().(FunctionCall) and
|
||||
(
|
||||
this.getTarget().hasGlobalOrStdName("operator new")
|
||||
or
|
||||
this.getTarget().hasGlobalOrStdName("operator new[]")
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if handler `try ... catch` exists.
|
||||
*/
|
||||
predicate isExistsTryCatchBlock() {
|
||||
exists(TryStmt ts | this.getEnclosingStmt() = ts.getStmt().getAChild*())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if results call `operator new` check in `operator if`.
|
||||
*/
|
||||
predicate isExistsIfCondition() {
|
||||
exists(IfCompareWithZero ifc, AssignExpr aex, Initializer it |
|
||||
// call `operator new` directly from the condition of `operator if`.
|
||||
this = ifc.getCondition().getAChild*()
|
||||
or
|
||||
// check results call `operator new` with variable appropriation
|
||||
postDominates(ifc, this) and
|
||||
aex.getAChild() = exp and
|
||||
ifc.getCondition().getAChild().(VariableAccess).getTarget() =
|
||||
aex.getLValue().(VariableAccess).getTarget()
|
||||
or
|
||||
// check results call `operator new` with declaration variable
|
||||
postDominates(ifc, this) and
|
||||
exp = it.getExpr() and
|
||||
it.getDeclaration() = ifc.getCondition().getAChild().(VariableAccess).getTarget()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(std::nothrow)` exists in call `operator new`.
|
||||
*/
|
||||
predicate isExistsNothrow() { this.getAChild().toString() = "nothrow" }
|
||||
}
|
||||
|
||||
from WrongCheckErrorOperatorNew op
|
||||
where
|
||||
// use call `operator new` with `(std::nothrow)` and checking error using `try ... catch` block and not `operator if`
|
||||
op.isExistsNothrow() and not op.isExistsIfCondition() and op.isExistsTryCatchBlock()
|
||||
or
|
||||
// use call `operator new` without `(std::nothrow)` and checking error using `operator if` and not `try ... catch` block
|
||||
not op.isExistsNothrow() and not op.isExistsTryCatchBlock() and op.isExistsIfCondition()
|
||||
select op, "memory allocation error check is incorrect or missing"
|
||||
@@ -0,0 +1,17 @@
|
||||
while(flagsLoop)
|
||||
{
|
||||
...
|
||||
if(flagsIf) break;
|
||||
...
|
||||
}while(flagsLoop); // BAD: when exiting through `break`, it is possible to get into an eternal loop.
|
||||
...
|
||||
while(flagsLoop)
|
||||
{
|
||||
...
|
||||
if(flagsIf) break;
|
||||
...
|
||||
} // GOOD: correct cycle
|
||||
...
|
||||
if(intA+intB) return 1; // BAD: possibly no comparison
|
||||
...
|
||||
if(intA+intB>intC) return 1; // GOOD: correct comparison
|
||||
@@ -0,0 +1,28 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>In some situations, after code refactoring, parts of the old constructs may remain. They are correctly accepted by the compiler, but can critically affect program execution. For example, if you switch from `do {...} while ();` to `while () {...}` forgetting to remove the old construct completely, you get `while(){...}while();` which may be vulnerable. These code snippets look suspicious and require the developer's attention.</p>
|
||||
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>We recommend that you use more explicit code transformations.</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
<p>The following example demonstrates the erroneous and corrected sections of the code.</p>
|
||||
<sample src="InsufficientControlFlowManagementAfterRefactoringTheCode.c" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>
|
||||
CWE Common Weakness Enumeration:
|
||||
<a href="https://cwe.mitre.org/data/definitions/691.html"> CWE-691: Insufficient Control Flow Management</a>.
|
||||
</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* @name Errors After Refactoring
|
||||
* @description --In some situations, after code refactoring, parts of the old constructs may remain.
|
||||
* --They are correctly accepted by the compiler, but can critically affect program execution.
|
||||
* --For example, if you switch from `do {...} while ();` to `while () {...}` with errors, you run the risk of running out of resources.
|
||||
* --These code snippets look suspicious and require the developer's attention.
|
||||
* @kind problem
|
||||
* @id cpp/errors-after-refactoring
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @tags correctness
|
||||
* security
|
||||
* external/cwe/cwe-691
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.valuenumbering.HashCons
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
|
||||
/**
|
||||
* Using `while` directly after the body of another` while`.
|
||||
*/
|
||||
class UsingWhileAfterWhile extends WhileStmt {
|
||||
/**
|
||||
* Using a loop call after another loop has finished running can result in an eternal loop.
|
||||
* For example, perhaps as a result of refactoring, the `do ... while ()` loop was incorrectly corrected.
|
||||
* Even in the case of deliberate use of such an expression, it is better to correct it.
|
||||
*/
|
||||
UsingWhileAfterWhile() {
|
||||
exists(WhileStmt wh1 |
|
||||
wh1.getStmt().getAChild*().(BreakStmt).(ControlFlowNode).getASuccessor().getASuccessor() =
|
||||
this and
|
||||
hashCons(wh1.getCondition()) = hashCons(this.getCondition()) and
|
||||
this.getStmt() instanceof EmptyStmt
|
||||
)
|
||||
or
|
||||
exists(ForStmt fr1 |
|
||||
fr1.getStmt().getAChild*().(BreakStmt).(ControlFlowNode).getASuccessor().getASuccessor() =
|
||||
this and
|
||||
hashCons(fr1.getCondition()) = hashCons(this.getCondition()) and
|
||||
this.getStmt() instanceof EmptyStmt
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Using arithmetic in a condition.
|
||||
*/
|
||||
class UsingArithmeticInComparison extends BinaryArithmeticOperation {
|
||||
/**
|
||||
* Using arithmetic operations in a comparison operation can be dangerous.
|
||||
* For example, part of the comparison may have been lost as a result of refactoring.
|
||||
* Even if you deliberately use such an expression, it is better to add an explicit comparison.
|
||||
*/
|
||||
UsingArithmeticInComparison() {
|
||||
this.getParent*() instanceof IfStmt and
|
||||
not this.getAChild*().isConstant() and
|
||||
not this.getParent*() instanceof Call and
|
||||
not this.getParent*() instanceof AssignExpr and
|
||||
not this.getParent*() instanceof ArrayExpr and
|
||||
not this.getParent*() instanceof RemExpr and
|
||||
not this.getParent*() instanceof AssignBitwiseOperation and
|
||||
not this.getParent*() instanceof AssignArithmeticOperation and
|
||||
not this.getParent*() instanceof EqualityOperation and
|
||||
not this.getParent*() instanceof RelationalOperation
|
||||
}
|
||||
|
||||
/** Holds when the expression is inside the loop body. */
|
||||
predicate insideTheLoop() { exists(Loop lp | lp.getStmt().getAChild*() = this.getParent*()) }
|
||||
|
||||
/** Holds when the expression is used in binary operations. */
|
||||
predicate workingWithValue() {
|
||||
this.getParent*() instanceof BinaryBitwiseOperation or
|
||||
this.getParent*() instanceof NotExpr
|
||||
}
|
||||
|
||||
/** Holds when the expression contains a pointer. */
|
||||
predicate workingWithPointer() {
|
||||
this.getAChild*().getFullyConverted().getType() instanceof DerivedType
|
||||
}
|
||||
|
||||
/** Holds when a null comparison expression exists. */
|
||||
predicate compareWithZero() {
|
||||
exists(Expr exp |
|
||||
exp instanceof ComparisonOperation and
|
||||
(
|
||||
globalValueNumber(exp.getAChild*()) = globalValueNumber(this) or
|
||||
hashCons(exp.getAChild*()) = hashCons(this)
|
||||
) and
|
||||
(
|
||||
exp.(ComparisonOperation).getLeftOperand().getValue() = "0" or
|
||||
exp.(ComparisonOperation).getRightOperand().getValue() = "0"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds when a comparison expression exists. */
|
||||
predicate compareWithOutZero() {
|
||||
exists(Expr exp |
|
||||
exp instanceof ComparisonOperation and
|
||||
(
|
||||
globalValueNumber(exp.getAChild*()) = globalValueNumber(this) or
|
||||
hashCons(exp.getAChild*()) = hashCons(this)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
from Expr exp
|
||||
where
|
||||
exp instanceof UsingArithmeticInComparison and
|
||||
not exp.(UsingArithmeticInComparison).workingWithValue() and
|
||||
not exp.(UsingArithmeticInComparison).workingWithPointer() and
|
||||
not exp.(UsingArithmeticInComparison).insideTheLoop() and
|
||||
not exp.(UsingArithmeticInComparison).compareWithZero() and
|
||||
exp.(UsingArithmeticInComparison).compareWithOutZero()
|
||||
or
|
||||
exists(WhileStmt wst | wst instanceof UsingWhileAfterWhile and exp = wst.getCondition())
|
||||
select exp, "this expression needs your attention"
|
||||
@@ -0,0 +1,4 @@
|
||||
if(len>0 & memset(buf,0,len)) return 1; // BAD: `memset` will be called regardless of the value of the `len` variable. moreover, one cannot be sure that it will happen after verification
|
||||
...
|
||||
if(len>0 && memset(buf,0,len)) return 1; // GOOD: `memset` will be called after the `len` variable has been checked.
|
||||
...
|
||||
@@ -0,0 +1,28 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>Using bitwise operations can be a mistake in some situations. For example, if parameters are evaluated in an expression and the function should be called only upon certain test results. These bitwise operations look suspicious and require developer attention.</p>
|
||||
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>We recommend that you evaluate the correctness of using the specified bit operations.</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
<p>The following example demonstrates the erroneous and fixed use of bit and logical operations.</p>
|
||||
<sample src="InsufficientControlFlowManagementWhenUsingBitOperations.c" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>
|
||||
CWE Common Weakness Enumeration:
|
||||
<a href="https://cwe.mitre.org/data/definitions/691.html"> CWE-691: Insufficient Control Flow Management</a>.
|
||||
</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* @name Errors When Using Bit Operations
|
||||
* @description Unlike the binary operations `||` and `&&`, there is no sequence point after evaluating an
|
||||
* operand of a bitwise operation like `|` or `&`. If left-to-right evaluation is expected this may be confusing.
|
||||
* @kind problem
|
||||
* @id cpp/errors-when-using-bit-operations
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @tags correctness
|
||||
* security
|
||||
* external/cwe/cwe-691
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
|
||||
/**
|
||||
* Dangerous uses of bit operations.
|
||||
* For example: `if(intA>0 & intA<10 & charBuf&myFunc(charBuf[intA]))`.
|
||||
* In this case, the function will be called in any case, and even the sequence of the call is not guaranteed.
|
||||
*/
|
||||
class DangerousBitOperations extends BinaryBitwiseOperation {
|
||||
FunctionCall bfc;
|
||||
|
||||
/**
|
||||
* The assignment indicates the conscious use of the bit operator.
|
||||
* Use in comparison, conversion, or return value indicates conscious use of the bit operator.
|
||||
* The use of shifts and bitwise operations on any element of an expression indicates a conscious use of the bitwise operator.
|
||||
*/
|
||||
DangerousBitOperations() {
|
||||
bfc = this.getRightOperand() and
|
||||
not this.getParent*() instanceof Assignment and
|
||||
not this.getParent*() instanceof Initializer and
|
||||
not this.getParent*() instanceof ReturnStmt and
|
||||
not this.getParent*() instanceof EqualityOperation and
|
||||
not this.getParent*() instanceof UnaryLogicalOperation and
|
||||
not this.getParent*() instanceof BinaryLogicalOperation and
|
||||
not this.getAChild*() instanceof BitwiseXorExpr and
|
||||
not this.getAChild*() instanceof LShiftExpr and
|
||||
not this.getAChild*() instanceof RShiftExpr
|
||||
}
|
||||
|
||||
/** Holds when part of a bit expression is used in a logical operation. */
|
||||
predicate useInLogicalOperations() {
|
||||
exists(BinaryLogicalOperation blop, Expr exp |
|
||||
blop.getAChild*() = exp and
|
||||
exp.(FunctionCall).getTarget() = bfc.getTarget() and
|
||||
not exp.getParent() instanceof ComparisonOperation and
|
||||
not exp.getParent() instanceof BinaryBitwiseOperation
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds when part of a bit expression is used as part of another supply. For example, as an argument to another function. */
|
||||
predicate useInOtherCalls() {
|
||||
bfc.hasQualifier() or
|
||||
bfc.getTarget() instanceof Operator or
|
||||
exists(FunctionCall fc | fc.getAnArgument().getAChild*() = this) or
|
||||
bfc.getTarget() instanceof BuiltInFunction
|
||||
}
|
||||
|
||||
/** Holds when the bit expression contains both arguments and a function call. */
|
||||
predicate dangerousArgumentChecking() {
|
||||
not this.getLeftOperand() instanceof Call and
|
||||
globalValueNumber(this.getLeftOperand().getAChild*()) = globalValueNumber(bfc.getAnArgument())
|
||||
}
|
||||
|
||||
/** Holds when function calls are present in the bit expression. */
|
||||
predicate functionCallsInBitsExpression() {
|
||||
this.getLeftOperand().getAChild*() instanceof FunctionCall
|
||||
}
|
||||
}
|
||||
|
||||
from DangerousBitOperations dbo
|
||||
where
|
||||
not dbo.useInOtherCalls() and
|
||||
dbo.useInLogicalOperations() and
|
||||
(not dbo.functionCallsInBitsExpression() or dbo.dangerousArgumentChecking())
|
||||
select dbo, "This bitwise operation appears in a context where a Boolean operation is expected."
|
||||
@@ -0,0 +1,11 @@
|
||||
if(len=funcReadData()==0) return 1; // BAD: variable `len` will not equal the value returned by function `funcReadData()`
|
||||
...
|
||||
if((len=funcReadData())==0) return 1; // GOOD: variable `len` equal the value returned by function `funcReadData()`
|
||||
...
|
||||
bool a=true;
|
||||
a++;// BAD: variable `a` does not change its meaning
|
||||
bool b;
|
||||
b=-a;// BAD: variable `b` equal `true`
|
||||
...
|
||||
a=false;// GOOD: variable `a` equal `false`
|
||||
b=!a;// GOOD: variable `b` equal `false`
|
||||
@@ -0,0 +1,28 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>Finding places of confusing use of boolean type. For example, a unary minus does not work before a boolean type and an increment always gives true.</p>
|
||||
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>we recommend making the code simpler.</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
<p>The following example demonstrates erroneous and fixed methods for using a boolean data type.</p>
|
||||
<sample src="OperatorPrecedenceLogicErrorWhenUseBoolType.c" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>
|
||||
CERT C Coding Standard:
|
||||
<a href="https://wiki.sei.cmu.edu/confluence/display/c/EXP00-C.+Use+parentheses+for+precedence+of+operation">EXP00-C. Use parentheses for precedence of operation</a>.
|
||||
</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* @name Operator Precedence Logic Error When Use Bool Type
|
||||
* @description --Finding places of confusing use of boolean type.
|
||||
* --For example, a unary minus does not work before a boolean type and an increment always gives true.
|
||||
* @kind problem
|
||||
* @id cpp/operator-precedence-logic-error-when-use-bool-type
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @tags correctness
|
||||
* security
|
||||
* external/cwe/cwe-783
|
||||
* external/cwe/cwe-480
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.valuenumbering.HashCons
|
||||
|
||||
/** Holds if `exp` increments a boolean value. */
|
||||
predicate incrementBoolType(IncrementOperation exp) {
|
||||
exp.getOperand().getType() instanceof BoolType
|
||||
}
|
||||
|
||||
/** Holds if `exp` applies the unary minus operator to a boolean type. */
|
||||
predicate revertSignBoolType(UnaryMinusExpr exp) {
|
||||
exp.getAnOperand().getType() instanceof BoolType and
|
||||
exp.getFullyConverted().getType() instanceof BoolType
|
||||
}
|
||||
|
||||
/** Holds, if this is an expression, uses comparison and assignment outside of execution precedence. */
|
||||
predicate assignBoolType(Expr exp) {
|
||||
exists(ComparisonOperation co |
|
||||
exp.(AssignExpr).getRValue() = co and
|
||||
exp.isCondition() and
|
||||
not co.isParenthesised() and
|
||||
not exp.(AssignExpr).getLValue().getType() instanceof BoolType and
|
||||
not exists(Expr exbl |
|
||||
hashCons(exbl.(AssignExpr).getLValue()) = hashCons(exp.(AssignExpr).getLValue()) and
|
||||
not exbl.isCondition() and
|
||||
exbl.(AssignExpr).getRValue().getType() instanceof BoolType and
|
||||
exbl.(AssignExpr).getLValue().getType() = exp.(AssignExpr).getLValue().getType()
|
||||
) and
|
||||
co.getLeftOperand() instanceof FunctionCall and
|
||||
not co.getRightOperand().getType() instanceof BoolType and
|
||||
not co.getRightOperand().getValue() = "0" and
|
||||
not co.getRightOperand().getValue() = "1"
|
||||
)
|
||||
}
|
||||
|
||||
from Expr exp
|
||||
where
|
||||
incrementBoolType(exp) or
|
||||
revertSignBoolType(exp) or
|
||||
assignBoolType(exp)
|
||||
select exp, "this expression needs attention"
|
||||
@@ -3,7 +3,7 @@
|
||||
* @description The expression `buffer [strlen (buffer)] = 0` is potentially dangerous, if the variable `buffer` does not have a terminal zero, then access beyond the bounds of the allocated memory is possible, which will lead to undefined behavior.
|
||||
* If terminal zero is present, then the specified expression is meaningless.
|
||||
* @kind problem
|
||||
* @id cpp/access-memory-location-after-end-buffer
|
||||
* @id cpp/access-memory-location-after-end-buffer-strlen
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @tags correctness
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* @name Access Of Memory Location After The End Of A Buffer Using Strncat
|
||||
* @description Calls of the form `strncat(dest, source, sizeof (dest) - strlen (dest))` set the third argument to one more than possible. So when `dest` is full, the expression `sizeof(dest) - strlen (dest)` will be equal to one, and not zero as the programmer might think. Making a call of this type may result in a zero byte being written just outside the `dest` buffer.
|
||||
* @kind problem
|
||||
* @id cpp/access-memory-location-after-end-buffer
|
||||
* @id cpp/access-memory-location-after-end-buffer-strncat
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @tags correctness
|
||||
@@ -11,54 +11,32 @@
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.models.implementations.Strcat
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
|
||||
/**
|
||||
* A call to `strncat` of the form `strncat(buff, str, someExpr - strlen(buf))`, for some expression `someExpr` equal to `sizeof(buff)`.
|
||||
* Holds if `call` is a call to `strncat` such that `sizeArg` and `destArg` are the size and
|
||||
* destination arguments, respectively.
|
||||
*/
|
||||
class WrongCallStrncat extends FunctionCall {
|
||||
Expr leftsomeExpr;
|
||||
|
||||
WrongCallStrncat() {
|
||||
this.getTarget().hasGlobalOrStdName("strncat") and
|
||||
// the expression of the first argument in `strncat` and `strnlen` is identical
|
||||
globalValueNumber(this.getArgument(0)) =
|
||||
globalValueNumber(this.getArgument(2).(SubExpr).getRightOperand().(StrlenCall).getStringExpr()) and
|
||||
// using a string constant often speaks of manually calculating the length of the required buffer.
|
||||
(
|
||||
not this.getArgument(1) instanceof StringLiteral and
|
||||
not this.getArgument(1) instanceof CharLiteral
|
||||
) and
|
||||
// for use in predicates
|
||||
leftsomeExpr = this.getArgument(2).(SubExpr).getLeftOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the left side of the expression `someExpr` equal to `sizeof(buf)`.
|
||||
*/
|
||||
predicate isExpressionEqualSizeof() {
|
||||
// the left side of the expression `someExpr` is `sizeof(buf)`.
|
||||
globalValueNumber(this.getArgument(0)) =
|
||||
globalValueNumber(leftsomeExpr.(SizeofExprOperator).getExprOperand())
|
||||
or
|
||||
// value of the left side of the expression `someExpr` equal `sizeof(buf)` value, and `buf` is array.
|
||||
leftsomeExpr.getValue().toInt() = this.getArgument(0).getType().getSize()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the left side of the expression `someExpr` equal to variable containing the length of the memory allocated for the buffer.
|
||||
*/
|
||||
predicate isVariableEqualValueSizegBuffer() {
|
||||
// the left side of expression `someExpr` is the variable that was used in the function of allocating memory for the buffer`.
|
||||
exists(AllocationExpr alc |
|
||||
leftsomeExpr.(VariableAccess).getTarget() =
|
||||
alc.(FunctionCall).getArgument(0).(VariableAccess).getTarget()
|
||||
)
|
||||
}
|
||||
predicate interestringCallWithArgs(Call call, Expr sizeArg, Expr destArg) {
|
||||
exists(StrcatFunction strcat |
|
||||
strcat = call.getTarget() and
|
||||
sizeArg = call.getArgument(strcat.getParamSize()) and
|
||||
destArg = call.getArgument(strcat.getParamDest())
|
||||
)
|
||||
}
|
||||
|
||||
from WrongCallStrncat sc
|
||||
from FunctionCall call, Expr sizeArg, Expr destArg, SubExpr sub, int n
|
||||
where
|
||||
sc.isExpressionEqualSizeof() or
|
||||
sc.isVariableEqualValueSizegBuffer()
|
||||
select sc, "if the used buffer is full, writing out of the buffer is possible"
|
||||
interestringCallWithArgs(call, sizeArg, destArg) and
|
||||
// The destination buffer is an array of size n
|
||||
destArg.getUnspecifiedType().(ArrayType).getSize() = n and
|
||||
// The size argument is equivalent to a subtraction
|
||||
globalValueNumber(sizeArg).getAnExpr() = sub and
|
||||
// ... where the left side of the subtraction is the constant n
|
||||
globalValueNumber(sub.getLeftOperand()).getAnExpr().getValue().toInt() = n and
|
||||
// ... and the right side of the subtraction is a call to `strlen` where the argument is the
|
||||
// destination buffer.
|
||||
globalValueNumber(sub.getRightOperand()).getAnExpr().(StrlenCall).getStringExpr() =
|
||||
globalValueNumber(destArg).getAnExpr()
|
||||
select call, "Possible out-of-bounds write due to incorrect size argument."
|
||||
|
||||
12
cpp/ql/src/external/tests/DefectFilter.ql
vendored
12
cpp/ql/src/external/tests/DefectFilter.ql
vendored
@@ -1,12 +0,0 @@
|
||||
/**
|
||||
* @name Defect filter
|
||||
* @description Only include results in large files (200) lines of code, and change the message.
|
||||
* @tags filter
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import external.DefectFilter
|
||||
|
||||
from DefectResult res
|
||||
where res.getFile().getMetrics().getNumberOfLinesOfCode() > 200
|
||||
select res, "Large files: " + res.getMessage()
|
||||
@@ -1,18 +0,0 @@
|
||||
/**
|
||||
* @name Defect from external data
|
||||
* @description Insert description here...
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @tags external-data
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import external.ExternalArtifact
|
||||
|
||||
from ExternalData d, File u
|
||||
where
|
||||
d.getQueryPath() = "external-data.ql" and
|
||||
u.getShortName() = d.getField(0)
|
||||
select u,
|
||||
d.getField(5) + ", " + d.getFieldAsDate(1) + ", " + d.getField(2) + ", " + d.getFieldAsFloat(3) +
|
||||
", " + d.getFieldAsInt(4) + ": " + d.getNumFields()
|
||||
12
cpp/ql/src/external/tests/MetricFilter.ql
vendored
12
cpp/ql/src/external/tests/MetricFilter.ql
vendored
@@ -1,12 +0,0 @@
|
||||
/**
|
||||
* @name Metric filter
|
||||
* @description Only include results in large files (200) lines of code.
|
||||
* @tags filter
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import external.MetricFilter
|
||||
|
||||
from MetricResult res
|
||||
where res.getFile().getMetrics().getNumberOfLinesOfCode() > 200
|
||||
select res, res.getValue()
|
||||
@@ -1,16 +0,0 @@
|
||||
/**
|
||||
* @name Filter: exclude results from files that are autogenerated
|
||||
* @description Use this filter to return results only if they are
|
||||
* located in files that are maintained manually.
|
||||
* @kind problem
|
||||
* @id cpp/autogenerated-filter
|
||||
* @tags filter
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.AutogeneratedFile
|
||||
import external.DefectFilter
|
||||
|
||||
from DefectResult res
|
||||
where not res.getFile() instanceof AutogeneratedFile
|
||||
select res, res.getMessage()
|
||||
@@ -1,16 +0,0 @@
|
||||
/**
|
||||
* @name Metric filter: exclude results from files that are autogenerated
|
||||
* @description Use this filter to return results only if they are
|
||||
* located in files that are maintained manually.
|
||||
* @kind treemap
|
||||
* @id cpp/autogenerated-for-metric-filter
|
||||
* @tags filter
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.AutogeneratedFile
|
||||
import external.MetricFilter
|
||||
|
||||
from MetricResult res
|
||||
where not res.getFile() instanceof AutogeneratedFile
|
||||
select res, res.getValue()
|
||||
@@ -1,16 +0,0 @@
|
||||
/**
|
||||
* @name Filter: exclude results from files for which we do not have
|
||||
* source code
|
||||
* @description Use this filter to return results only if they are
|
||||
* located in files for which we have source code.
|
||||
* @kind problem
|
||||
* @id cpp/from-source-filter
|
||||
* @tags filter
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import external.DefectFilter
|
||||
|
||||
from DefectResult res
|
||||
where res.getFile().fromSource()
|
||||
select res, res.getMessage()
|
||||
@@ -1,36 +0,0 @@
|
||||
/**
|
||||
* @name Filter: exclude results on lines covered by a macro expansion
|
||||
* @description Use this filter to return results only when there is no
|
||||
* macro expansion whose location spans all the lines of
|
||||
* the result's location.
|
||||
* @kind problem
|
||||
* @id cpp/macros-filter
|
||||
* @tags filter
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import external.DefectFilter
|
||||
|
||||
predicate macroLocation(File f, int startLine, int endLine) {
|
||||
exists(MacroInvocation mi, Location l |
|
||||
l = mi.getLocation() and
|
||||
l.getFile() = f and
|
||||
l.getStartLine() = startLine and
|
||||
l.getEndLine() = endLine
|
||||
)
|
||||
}
|
||||
|
||||
predicate macroCovering(DefectResult r) {
|
||||
exists(File f, int macroStart, int macroEnd, int defectStart, int defectEnd |
|
||||
f = r.getFile() and
|
||||
defectStart = r.getStartLine() and
|
||||
defectEnd = r.getEndLine() and
|
||||
macroLocation(f, macroStart, macroEnd) and
|
||||
macroStart <= defectStart and
|
||||
macroEnd >= defectEnd
|
||||
)
|
||||
}
|
||||
|
||||
from DefectResult res
|
||||
where not macroCovering(res)
|
||||
select res, res.getMessage()
|
||||
@@ -91,16 +91,17 @@ private predicate exprReleases(Expr e, Expr released, string kind) {
|
||||
// `e` is a call to a release function and `released` is the released argument
|
||||
releaseExpr(e, released, kind)
|
||||
or
|
||||
exists(Function f, int arg |
|
||||
exists(int arg, VariableAccess access, Function f |
|
||||
// `e` is a call to a function that releases one of it's parameters,
|
||||
// and `released` is the corresponding argument
|
||||
(
|
||||
e.(FunctionCall).getTarget() = f or
|
||||
e.(FunctionCall).getTarget().(MemberFunction).getAnOverridingFunction+() = f
|
||||
) and
|
||||
access = f.getParameter(arg).getAnAccess() and
|
||||
e.(FunctionCall).getArgument(arg) = released and
|
||||
exprReleases(_,
|
||||
exprOrDereference(globalValueNumber(f.getParameter(arg).getAnAccess()).getAnExpr()), kind)
|
||||
pragma[only_bind_into](exprOrDereference(globalValueNumber(access).getAnExpr())), kind)
|
||||
)
|
||||
or
|
||||
exists(Function f, ThisExpr innerThis |
|
||||
@@ -112,7 +113,7 @@ private predicate exprReleases(Expr e, Expr released, string kind) {
|
||||
) and
|
||||
e.(FunctionCall).getQualifier() = exprOrDereference(released) and
|
||||
innerThis.getEnclosingFunction() = f and
|
||||
exprReleases(_, globalValueNumber(innerThis).getAnExpr(), kind)
|
||||
exprReleases(_, pragma[only_bind_into](globalValueNumber(innerThis).getAnExpr()), kind)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ the break statement only exits from one level of the loop.</p>
|
||||
</li>
|
||||
<li>
|
||||
Mats Henricson and Erik Nyquist, <i>Industrial Strength C++</i>, published by Prentice Hall PTR (1997).
|
||||
Chapter 4: Control Flow, Rule 4.6 (<a href="http://mongers.org/industrial-c++/">PDF</a>).
|
||||
Chapter 4: Control Flow, Rule 4.6 (<a href="https://web.archive.org/web/20190919025638/https://mongers.org/industrial-c++/">PDF</a>).
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://www.cplusplus.com/doc/tutorial/control/">www.cplusplus.com Control Structures</a>
|
||||
|
||||
@@ -39,7 +39,7 @@ loop if the loop requires more complicated variable iteration.
|
||||
</li>
|
||||
<li>
|
||||
Mats Henricson and Erik Nyquist, <i>Industrial Strength C++</i>, published by Prentice Hall PTR (1997).
|
||||
Chapter 4: Control Flow, Rule 4.1 (<a href="http://mongers.org/industrial-c++/">PDF</a>).
|
||||
Chapter 4: Control Flow, Rule 4.1 (<a href="https://web.archive.org/web/20190919025638/https://mongers.org/industrial-c++/">PDF</a>).
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@ class Location extends @location {
|
||||
}
|
||||
|
||||
/** Holds if `this` comes on a line strictly before `l`. */
|
||||
pragma[inline]
|
||||
predicate isBefore(Location l) {
|
||||
this.getFile() = l.getFile() and this.getEndLine() < l.getStartLine()
|
||||
}
|
||||
|
||||
@@ -101,6 +101,7 @@ class Type extends Locatable, @type {
|
||||
*
|
||||
* For example, starting with `const i64* const` in the context of `typedef long long i64;`, this predicate will return `long long*`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
Type getUnspecifiedType() { unspecifiedtype(underlyingElement(this), unresolveElement(result)) }
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,6 +14,7 @@ import cpp
|
||||
* In rare cases, the same node is used in multiple control-flow scopes. This
|
||||
* confuses the dominance analysis, so this predicate is used to exclude them.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate hasMultiScopeNode(Function f) {
|
||||
exists(ControlFlowNode node |
|
||||
node.getControlFlowScope() = f and
|
||||
|
||||
@@ -1307,7 +1307,8 @@ private predicate conditionJumps(Expr test, boolean truth, Node n2, Pos p2) {
|
||||
)
|
||||
}
|
||||
|
||||
// Factored out for performance. See QL-796.
|
||||
// Pulled out for performance. See
|
||||
// https://github.com/github/codeql-coreql-team/issues/1044.
|
||||
private predicate normalGroupMemberBaseCase(Node memberNode, Pos memberPos, Node atNode) {
|
||||
memberNode = atNode and
|
||||
memberPos.isAt() and
|
||||
|
||||
@@ -104,9 +104,43 @@ private predicate loopConditionAlwaysUponEntry(ControlFlowNode loop, Expr condit
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* This relation is the same as the `el instanceof Function`, only obfuscated
|
||||
* so the optimizer will not understand that any `FunctionCall.getTarget()`
|
||||
* should be in this relation.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate isFunction(Element el) {
|
||||
el instanceof Function
|
||||
or
|
||||
el.(Expr).getParent() = el
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `fc` is a `FunctionCall` with no return value for `getTarget`. This
|
||||
* can happen in case of rare database inconsistencies.
|
||||
*/
|
||||
pragma[noopt]
|
||||
private predicate callHasNoTarget(@funbindexpr fc) {
|
||||
exists(Function f |
|
||||
funbind(fc, f) and
|
||||
not isFunction(f)
|
||||
)
|
||||
}
|
||||
|
||||
// Pulled out for performance. See
|
||||
// https://github.com/github/codeql-coreql-team/issues/1044.
|
||||
private predicate potentiallyReturningFunctionCall_base(FunctionCall fc) {
|
||||
fc.isVirtual()
|
||||
or
|
||||
callHasNoTarget(fc)
|
||||
}
|
||||
|
||||
/** A function call that *may* return; if in doubt, we assume it may. */
|
||||
private predicate potentiallyReturningFunctionCall(FunctionCall fc) {
|
||||
potentiallyReturningFunction(fc.getTarget()) or fc.isVirtual()
|
||||
potentiallyReturningFunctionCall_base(fc)
|
||||
or
|
||||
potentiallyReturningFunction(fc.getTarget())
|
||||
}
|
||||
|
||||
/** A function that *may* return; if in doubt, we assume it may. */
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
private import cpp
|
||||
private import semmle.code.cpp.models.interfaces.PointerWrapper
|
||||
|
||||
/**
|
||||
* Holds if `f` is an instantiation of the `std::move` or `std::forward`
|
||||
@@ -94,6 +95,12 @@ private predicate pointerToPointerStep(Expr pointerIn, Expr pointerOut) {
|
||||
|
||||
private predicate lvalueToReferenceStep(Expr lvalueIn, Expr referenceOut) {
|
||||
lvalueIn.getConversion() = referenceOut.(ReferenceToExpr)
|
||||
or
|
||||
exists(PointerWrapper wrapper, Call call | call = referenceOut |
|
||||
referenceOut.getUnspecifiedType() instanceof ReferenceType and
|
||||
call = wrapper.getAnUnwrapperFunction().getACallToThisFunction() and
|
||||
lvalueIn = call.getQualifier().getFullyConverted()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate referenceToLvalueStep(Expr referenceIn, Expr lvalueOut) {
|
||||
@@ -106,6 +113,13 @@ private predicate referenceToPointerStep(Expr referenceIn, Expr pointerOut) {
|
||||
stdAddressOf(call.getTarget()) and
|
||||
referenceIn = call.getArgument(0).getFullyConverted()
|
||||
)
|
||||
or
|
||||
exists(CopyConstructor copy, Call call | call = pointerOut |
|
||||
copy.getDeclaringType() instanceof PointerWrapper and
|
||||
call.getTarget() = copy and
|
||||
// The 0'th argument is the value being copied.
|
||||
referenceIn = call.getArgument(0).getFullyConverted()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate referenceToReferenceStep(Expr referenceIn, Expr referenceOut) {
|
||||
@@ -190,6 +204,19 @@ private predicate pointerToUpdate(Expr pointer, Expr outer, ControlFlowNode node
|
||||
// See the `lvalueToUpdate` case for an explanation of this conjunct.
|
||||
call.getType().isDeeplyConstBelow()
|
||||
)
|
||||
or
|
||||
// Pointer wrappers behave as raw pointers for dataflow purposes.
|
||||
outer = call.getAnArgument().getFullyConverted() and
|
||||
exists(PointerWrapper wrapper | wrapper = outer.getType().stripTopLevelSpecifiers() |
|
||||
not wrapper.pointsToConst()
|
||||
)
|
||||
or
|
||||
outer = call.getQualifier().getFullyConverted() and
|
||||
outer.getUnspecifiedType() instanceof PointerWrapper and
|
||||
not (
|
||||
call.getTarget().hasSpecifier("const") and
|
||||
call.getType().isDeeplyConstBelow()
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(PointerFieldAccess fa |
|
||||
@@ -218,7 +245,9 @@ private predicate referenceToUpdate(Expr reference, Expr outer, ControlFlowNode
|
||||
not stdIdentityFunction(call.getTarget()) and
|
||||
not stdAddressOf(call.getTarget()) and
|
||||
exists(ReferenceType rt | rt = outer.getType().stripTopLevelSpecifiers() |
|
||||
not rt.getBaseType().isConst()
|
||||
not rt.getBaseType().isConst() or
|
||||
rt.getBaseType().getUnspecifiedType() =
|
||||
any(PointerWrapper wrapper | not wrapper.pointsToConst())
|
||||
)
|
||||
) and
|
||||
reference = outer
|
||||
|
||||
@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
* 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) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
) and
|
||||
simpleLocalFlowStepExt(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
|
||||
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
|
||||
*/
|
||||
private predicate jumpStep(Node node1, Node node2, Configuration config) {
|
||||
jumpStep(node1, node2) and
|
||||
jumpStepCached(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -388,7 +385,7 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
@@ -515,24 +512,22 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
|
||||
exists(ParamNode p |
|
||||
revFlow(p, toReturn, config) and
|
||||
viableParamArgNodeCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
|
||||
revFlowIn(call, arg, true, config)
|
||||
}
|
||||
|
||||
@@ -597,7 +592,7 @@ private module Stage1 {
|
||||
* Holds if flow may enter through `p` and reach a return node making `p` a
|
||||
* candidate for the origin of a summary.
|
||||
*/
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnKindExt kind |
|
||||
throughFlowNodeCand(p, config) and
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgNodeCand1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
|
||||
Stage1::revFlow(arg, config)
|
||||
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
|
||||
) {
|
||||
viableParamArgNodeCand1(call, p, arg, config) and
|
||||
Stage1::revFlow(p, config) and
|
||||
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, arg, p, config) and
|
||||
exists(int b, int j |
|
||||
@@ -944,10 +938,10 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -992,7 +986,7 @@ private module Stage2 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
)
|
||||
@@ -1133,10 +1127,9 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1146,7 +1139,7 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1199,13 +1192,13 @@ private module Stage2 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand2(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
|
||||
*/
|
||||
private class FlowCheckNode extends Node {
|
||||
FlowCheckNode() {
|
||||
this instanceof CastNode or
|
||||
clearsContent(this, _)
|
||||
castNode(this) or
|
||||
clearsContentCached(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
|
||||
config.isSource(node) or
|
||||
jumpStep(_, node, config) or
|
||||
additionalJumpStep(_, node, config) or
|
||||
node instanceof ParameterNode or
|
||||
node instanceof ParamNode or
|
||||
node instanceof OutNodeExt or
|
||||
store(_, _, node, _) or
|
||||
read(_, _, node) or
|
||||
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getNodeType(node1)
|
||||
t = getNodeDataFlowType(node1)
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2)
|
||||
t = getNodeDataFlowType(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
t = getNodeDataFlowType(node2) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
@@ -1384,7 +1376,7 @@ private module Stage3 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -1443,7 +1435,9 @@ private module Stage3 {
|
||||
bindingset[node, ap]
|
||||
private predicate filter(Node node, Ap ap) {
|
||||
not ap.isClearedAt(node) and
|
||||
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any()
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -1583,10 +1577,10 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -1631,7 +1625,7 @@ private module Stage3 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -1772,10 +1766,9 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1785,7 +1778,7 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1838,13 +1831,13 @@ private module Stage3 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2088,7 +2081,7 @@ private module Stage4 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -2133,11 +2126,8 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(node))
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2158,8 +2148,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCall(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
@@ -2303,10 +2292,10 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -2351,7 +2340,7 @@ private module Stage4 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -2492,10 +2481,9 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -2505,7 +2493,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -2558,13 +2546,13 @@ private module Stage4 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2609,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
|
||||
|
||||
private newtype TSummaryCtx =
|
||||
TSummaryCtxNone() or
|
||||
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||
TSummaryCtxSome(ParamNode p, AccessPath ap) {
|
||||
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
|
||||
}
|
||||
|
||||
@@ -2630,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||
|
||||
/** A summary context from which a flow summary can be generated. */
|
||||
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
private ParameterNode p;
|
||||
private ParamNode p;
|
||||
private AccessPath ap;
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
@@ -2761,7 +2749,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2982,7 +2970,7 @@ class PathNode extends TPathNode {
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
nodeIsHidden(this.getNode()) and
|
||||
hiddenNode(this.getNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
}
|
||||
@@ -3132,7 +3120,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, getNodeEnclosingCallable(midnode)) and
|
||||
localCC = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(midnode)) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
@@ -3151,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -3238,7 +3226,7 @@ pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3251,7 +3239,7 @@ pragma[noinline]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
@@ -3275,7 +3263,7 @@ private predicate pathIntoCallable0(
|
||||
* respectively.
|
||||
*/
|
||||
private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
@@ -3571,7 +3559,7 @@ private module FlowExploration {
|
||||
|
||||
private newtype TSummaryCtx1 =
|
||||
TSummaryCtx1None() or
|
||||
TSummaryCtx1Param(ParameterNode p)
|
||||
TSummaryCtx1Param(ParamNode p)
|
||||
|
||||
private newtype TSummaryCtx2 =
|
||||
TSummaryCtx2None() or
|
||||
@@ -3594,7 +3582,7 @@ private module FlowExploration {
|
||||
cc instanceof CallContextAny and
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
not fullBarrier(node, config) and
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
@@ -3614,7 +3602,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not clearsContentCached(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
)
|
||||
@@ -3628,9 +3616,9 @@ private module FlowExploration {
|
||||
exists(PartialPathNodeFwd mid |
|
||||
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not clearsContent(node, ap.getHead().getContent()) and
|
||||
not clearsContentCached(node, ap.getHead().getContent()) and
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeType(node), ap.getType())
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
)
|
||||
}
|
||||
@@ -3786,7 +3774,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -3800,7 +3788,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
@@ -3816,7 +3804,7 @@ private module FlowExploration {
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
partialPathStoreStep(mid, _, _, node, ap) and
|
||||
@@ -3830,7 +3818,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
apConsFwd(ap, tc, ap0, config) and
|
||||
compatibleTypes(ap.getType(), getNodeType(node))
|
||||
compatibleTypes(ap.getType(), getNodeDataFlowType(node))
|
||||
)
|
||||
or
|
||||
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
|
||||
@@ -3927,7 +3915,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3946,7 +3934,7 @@ private module FlowExploration {
|
||||
}
|
||||
|
||||
private predicate partialPathIntoCallable(
|
||||
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
|
||||
PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
@@ -3983,7 +3971,7 @@ private module FlowExploration {
|
||||
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
|
||||
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
|
||||
)
|
||||
@@ -4040,7 +4028,7 @@ private module FlowExploration {
|
||||
apConsRev(ap, c, ap0, config)
|
||||
)
|
||||
or
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
mid.getNode() = p and
|
||||
viableParamArg(_, p, node) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4118,7 +4106,7 @@ private module FlowExploration {
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParameterNode p |
|
||||
exists(PartialPathNodeRev mid, ParamNode p |
|
||||
mid.getNode() = p and
|
||||
p.isParameterOf(_, pos) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4141,7 +4129,7 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
|
||||
PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
|
||||
@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
* 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) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
) and
|
||||
simpleLocalFlowStepExt(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
|
||||
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
|
||||
*/
|
||||
private predicate jumpStep(Node node1, Node node2, Configuration config) {
|
||||
jumpStep(node1, node2) and
|
||||
jumpStepCached(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -388,7 +385,7 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
@@ -515,24 +512,22 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
|
||||
exists(ParamNode p |
|
||||
revFlow(p, toReturn, config) and
|
||||
viableParamArgNodeCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
|
||||
revFlowIn(call, arg, true, config)
|
||||
}
|
||||
|
||||
@@ -597,7 +592,7 @@ private module Stage1 {
|
||||
* Holds if flow may enter through `p` and reach a return node making `p` a
|
||||
* candidate for the origin of a summary.
|
||||
*/
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnKindExt kind |
|
||||
throughFlowNodeCand(p, config) and
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgNodeCand1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
|
||||
Stage1::revFlow(arg, config)
|
||||
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
|
||||
) {
|
||||
viableParamArgNodeCand1(call, p, arg, config) and
|
||||
Stage1::revFlow(p, config) and
|
||||
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, arg, p, config) and
|
||||
exists(int b, int j |
|
||||
@@ -944,10 +938,10 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -992,7 +986,7 @@ private module Stage2 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
)
|
||||
@@ -1133,10 +1127,9 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1146,7 +1139,7 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1199,13 +1192,13 @@ private module Stage2 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand2(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
|
||||
*/
|
||||
private class FlowCheckNode extends Node {
|
||||
FlowCheckNode() {
|
||||
this instanceof CastNode or
|
||||
clearsContent(this, _)
|
||||
castNode(this) or
|
||||
clearsContentCached(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
|
||||
config.isSource(node) or
|
||||
jumpStep(_, node, config) or
|
||||
additionalJumpStep(_, node, config) or
|
||||
node instanceof ParameterNode or
|
||||
node instanceof ParamNode or
|
||||
node instanceof OutNodeExt or
|
||||
store(_, _, node, _) or
|
||||
read(_, _, node) or
|
||||
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getNodeType(node1)
|
||||
t = getNodeDataFlowType(node1)
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2)
|
||||
t = getNodeDataFlowType(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
t = getNodeDataFlowType(node2) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
@@ -1384,7 +1376,7 @@ private module Stage3 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -1443,7 +1435,9 @@ private module Stage3 {
|
||||
bindingset[node, ap]
|
||||
private predicate filter(Node node, Ap ap) {
|
||||
not ap.isClearedAt(node) and
|
||||
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any()
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -1583,10 +1577,10 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -1631,7 +1625,7 @@ private module Stage3 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -1772,10 +1766,9 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1785,7 +1778,7 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1838,13 +1831,13 @@ private module Stage3 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2088,7 +2081,7 @@ private module Stage4 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -2133,11 +2126,8 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(node))
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2158,8 +2148,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCall(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
@@ -2303,10 +2292,10 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -2351,7 +2340,7 @@ private module Stage4 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -2492,10 +2481,9 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -2505,7 +2493,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -2558,13 +2546,13 @@ private module Stage4 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2609,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
|
||||
|
||||
private newtype TSummaryCtx =
|
||||
TSummaryCtxNone() or
|
||||
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||
TSummaryCtxSome(ParamNode p, AccessPath ap) {
|
||||
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
|
||||
}
|
||||
|
||||
@@ -2630,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||
|
||||
/** A summary context from which a flow summary can be generated. */
|
||||
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
private ParameterNode p;
|
||||
private ParamNode p;
|
||||
private AccessPath ap;
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
@@ -2761,7 +2749,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2982,7 +2970,7 @@ class PathNode extends TPathNode {
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
nodeIsHidden(this.getNode()) and
|
||||
hiddenNode(this.getNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
}
|
||||
@@ -3132,7 +3120,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, getNodeEnclosingCallable(midnode)) and
|
||||
localCC = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(midnode)) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
@@ -3151,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -3238,7 +3226,7 @@ pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3251,7 +3239,7 @@ pragma[noinline]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
@@ -3275,7 +3263,7 @@ private predicate pathIntoCallable0(
|
||||
* respectively.
|
||||
*/
|
||||
private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
@@ -3571,7 +3559,7 @@ private module FlowExploration {
|
||||
|
||||
private newtype TSummaryCtx1 =
|
||||
TSummaryCtx1None() or
|
||||
TSummaryCtx1Param(ParameterNode p)
|
||||
TSummaryCtx1Param(ParamNode p)
|
||||
|
||||
private newtype TSummaryCtx2 =
|
||||
TSummaryCtx2None() or
|
||||
@@ -3594,7 +3582,7 @@ private module FlowExploration {
|
||||
cc instanceof CallContextAny and
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
not fullBarrier(node, config) and
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
@@ -3614,7 +3602,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not clearsContentCached(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
)
|
||||
@@ -3628,9 +3616,9 @@ private module FlowExploration {
|
||||
exists(PartialPathNodeFwd mid |
|
||||
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not clearsContent(node, ap.getHead().getContent()) and
|
||||
not clearsContentCached(node, ap.getHead().getContent()) and
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeType(node), ap.getType())
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
)
|
||||
}
|
||||
@@ -3786,7 +3774,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -3800,7 +3788,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
@@ -3816,7 +3804,7 @@ private module FlowExploration {
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
partialPathStoreStep(mid, _, _, node, ap) and
|
||||
@@ -3830,7 +3818,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
apConsFwd(ap, tc, ap0, config) and
|
||||
compatibleTypes(ap.getType(), getNodeType(node))
|
||||
compatibleTypes(ap.getType(), getNodeDataFlowType(node))
|
||||
)
|
||||
or
|
||||
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
|
||||
@@ -3927,7 +3915,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3946,7 +3934,7 @@ private module FlowExploration {
|
||||
}
|
||||
|
||||
private predicate partialPathIntoCallable(
|
||||
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
|
||||
PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
@@ -3983,7 +3971,7 @@ private module FlowExploration {
|
||||
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
|
||||
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
|
||||
)
|
||||
@@ -4040,7 +4028,7 @@ private module FlowExploration {
|
||||
apConsRev(ap, c, ap0, config)
|
||||
)
|
||||
or
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
mid.getNode() = p and
|
||||
viableParamArg(_, p, node) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4118,7 +4106,7 @@ private module FlowExploration {
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParameterNode p |
|
||||
exists(PartialPathNodeRev mid, ParamNode p |
|
||||
mid.getNode() = p and
|
||||
p.isParameterOf(_, pos) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4141,7 +4129,7 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
|
||||
PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
|
||||
@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
* 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) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
) and
|
||||
simpleLocalFlowStepExt(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
|
||||
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
|
||||
*/
|
||||
private predicate jumpStep(Node node1, Node node2, Configuration config) {
|
||||
jumpStep(node1, node2) and
|
||||
jumpStepCached(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -388,7 +385,7 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
@@ -515,24 +512,22 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
|
||||
exists(ParamNode p |
|
||||
revFlow(p, toReturn, config) and
|
||||
viableParamArgNodeCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
|
||||
revFlowIn(call, arg, true, config)
|
||||
}
|
||||
|
||||
@@ -597,7 +592,7 @@ private module Stage1 {
|
||||
* Holds if flow may enter through `p` and reach a return node making `p` a
|
||||
* candidate for the origin of a summary.
|
||||
*/
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnKindExt kind |
|
||||
throughFlowNodeCand(p, config) and
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgNodeCand1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
|
||||
Stage1::revFlow(arg, config)
|
||||
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
|
||||
) {
|
||||
viableParamArgNodeCand1(call, p, arg, config) and
|
||||
Stage1::revFlow(p, config) and
|
||||
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, arg, p, config) and
|
||||
exists(int b, int j |
|
||||
@@ -944,10 +938,10 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -992,7 +986,7 @@ private module Stage2 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
)
|
||||
@@ -1133,10 +1127,9 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1146,7 +1139,7 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1199,13 +1192,13 @@ private module Stage2 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand2(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
|
||||
*/
|
||||
private class FlowCheckNode extends Node {
|
||||
FlowCheckNode() {
|
||||
this instanceof CastNode or
|
||||
clearsContent(this, _)
|
||||
castNode(this) or
|
||||
clearsContentCached(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
|
||||
config.isSource(node) or
|
||||
jumpStep(_, node, config) or
|
||||
additionalJumpStep(_, node, config) or
|
||||
node instanceof ParameterNode or
|
||||
node instanceof ParamNode or
|
||||
node instanceof OutNodeExt or
|
||||
store(_, _, node, _) or
|
||||
read(_, _, node) or
|
||||
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getNodeType(node1)
|
||||
t = getNodeDataFlowType(node1)
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2)
|
||||
t = getNodeDataFlowType(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
t = getNodeDataFlowType(node2) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
@@ -1384,7 +1376,7 @@ private module Stage3 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -1443,7 +1435,9 @@ private module Stage3 {
|
||||
bindingset[node, ap]
|
||||
private predicate filter(Node node, Ap ap) {
|
||||
not ap.isClearedAt(node) and
|
||||
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any()
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -1583,10 +1577,10 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -1631,7 +1625,7 @@ private module Stage3 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -1772,10 +1766,9 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1785,7 +1778,7 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1838,13 +1831,13 @@ private module Stage3 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2088,7 +2081,7 @@ private module Stage4 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -2133,11 +2126,8 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(node))
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2158,8 +2148,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCall(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
@@ -2303,10 +2292,10 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -2351,7 +2340,7 @@ private module Stage4 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -2492,10 +2481,9 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -2505,7 +2493,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -2558,13 +2546,13 @@ private module Stage4 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2609,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
|
||||
|
||||
private newtype TSummaryCtx =
|
||||
TSummaryCtxNone() or
|
||||
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||
TSummaryCtxSome(ParamNode p, AccessPath ap) {
|
||||
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
|
||||
}
|
||||
|
||||
@@ -2630,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||
|
||||
/** A summary context from which a flow summary can be generated. */
|
||||
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
private ParameterNode p;
|
||||
private ParamNode p;
|
||||
private AccessPath ap;
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
@@ -2761,7 +2749,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2982,7 +2970,7 @@ class PathNode extends TPathNode {
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
nodeIsHidden(this.getNode()) and
|
||||
hiddenNode(this.getNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
}
|
||||
@@ -3132,7 +3120,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, getNodeEnclosingCallable(midnode)) and
|
||||
localCC = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(midnode)) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
@@ -3151,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -3238,7 +3226,7 @@ pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3251,7 +3239,7 @@ pragma[noinline]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
@@ -3275,7 +3263,7 @@ private predicate pathIntoCallable0(
|
||||
* respectively.
|
||||
*/
|
||||
private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
@@ -3571,7 +3559,7 @@ private module FlowExploration {
|
||||
|
||||
private newtype TSummaryCtx1 =
|
||||
TSummaryCtx1None() or
|
||||
TSummaryCtx1Param(ParameterNode p)
|
||||
TSummaryCtx1Param(ParamNode p)
|
||||
|
||||
private newtype TSummaryCtx2 =
|
||||
TSummaryCtx2None() or
|
||||
@@ -3594,7 +3582,7 @@ private module FlowExploration {
|
||||
cc instanceof CallContextAny and
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
not fullBarrier(node, config) and
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
@@ -3614,7 +3602,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not clearsContentCached(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
)
|
||||
@@ -3628,9 +3616,9 @@ private module FlowExploration {
|
||||
exists(PartialPathNodeFwd mid |
|
||||
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not clearsContent(node, ap.getHead().getContent()) and
|
||||
not clearsContentCached(node, ap.getHead().getContent()) and
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeType(node), ap.getType())
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
)
|
||||
}
|
||||
@@ -3786,7 +3774,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -3800,7 +3788,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
@@ -3816,7 +3804,7 @@ private module FlowExploration {
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
partialPathStoreStep(mid, _, _, node, ap) and
|
||||
@@ -3830,7 +3818,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
apConsFwd(ap, tc, ap0, config) and
|
||||
compatibleTypes(ap.getType(), getNodeType(node))
|
||||
compatibleTypes(ap.getType(), getNodeDataFlowType(node))
|
||||
)
|
||||
or
|
||||
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
|
||||
@@ -3927,7 +3915,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3946,7 +3934,7 @@ private module FlowExploration {
|
||||
}
|
||||
|
||||
private predicate partialPathIntoCallable(
|
||||
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
|
||||
PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
@@ -3983,7 +3971,7 @@ private module FlowExploration {
|
||||
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
|
||||
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
|
||||
)
|
||||
@@ -4040,7 +4028,7 @@ private module FlowExploration {
|
||||
apConsRev(ap, c, ap0, config)
|
||||
)
|
||||
or
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
mid.getNode() = p and
|
||||
viableParamArg(_, p, node) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4118,7 +4106,7 @@ private module FlowExploration {
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParameterNode p |
|
||||
exists(PartialPathNodeRev mid, ParamNode p |
|
||||
mid.getNode() = p and
|
||||
p.isParameterOf(_, pos) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4141,7 +4129,7 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
|
||||
PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
|
||||
@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
* 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) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
) and
|
||||
simpleLocalFlowStepExt(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
|
||||
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
|
||||
*/
|
||||
private predicate jumpStep(Node node1, Node node2, Configuration config) {
|
||||
jumpStep(node1, node2) and
|
||||
jumpStepCached(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -388,7 +385,7 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
@@ -515,24 +512,22 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
|
||||
exists(ParamNode p |
|
||||
revFlow(p, toReturn, config) and
|
||||
viableParamArgNodeCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
|
||||
revFlowIn(call, arg, true, config)
|
||||
}
|
||||
|
||||
@@ -597,7 +592,7 @@ private module Stage1 {
|
||||
* Holds if flow may enter through `p` and reach a return node making `p` a
|
||||
* candidate for the origin of a summary.
|
||||
*/
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnKindExt kind |
|
||||
throughFlowNodeCand(p, config) and
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgNodeCand1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
|
||||
Stage1::revFlow(arg, config)
|
||||
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
|
||||
) {
|
||||
viableParamArgNodeCand1(call, p, arg, config) and
|
||||
Stage1::revFlow(p, config) and
|
||||
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, arg, p, config) and
|
||||
exists(int b, int j |
|
||||
@@ -944,10 +938,10 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -992,7 +986,7 @@ private module Stage2 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
)
|
||||
@@ -1133,10 +1127,9 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1146,7 +1139,7 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1199,13 +1192,13 @@ private module Stage2 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand2(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
|
||||
*/
|
||||
private class FlowCheckNode extends Node {
|
||||
FlowCheckNode() {
|
||||
this instanceof CastNode or
|
||||
clearsContent(this, _)
|
||||
castNode(this) or
|
||||
clearsContentCached(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
|
||||
config.isSource(node) or
|
||||
jumpStep(_, node, config) or
|
||||
additionalJumpStep(_, node, config) or
|
||||
node instanceof ParameterNode or
|
||||
node instanceof ParamNode or
|
||||
node instanceof OutNodeExt or
|
||||
store(_, _, node, _) or
|
||||
read(_, _, node) or
|
||||
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getNodeType(node1)
|
||||
t = getNodeDataFlowType(node1)
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2)
|
||||
t = getNodeDataFlowType(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
t = getNodeDataFlowType(node2) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
@@ -1384,7 +1376,7 @@ private module Stage3 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -1443,7 +1435,9 @@ private module Stage3 {
|
||||
bindingset[node, ap]
|
||||
private predicate filter(Node node, Ap ap) {
|
||||
not ap.isClearedAt(node) and
|
||||
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any()
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -1583,10 +1577,10 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -1631,7 +1625,7 @@ private module Stage3 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -1772,10 +1766,9 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1785,7 +1778,7 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1838,13 +1831,13 @@ private module Stage3 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2088,7 +2081,7 @@ private module Stage4 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -2133,11 +2126,8 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(node))
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2158,8 +2148,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCall(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
@@ -2303,10 +2292,10 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -2351,7 +2340,7 @@ private module Stage4 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -2492,10 +2481,9 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -2505,7 +2493,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -2558,13 +2546,13 @@ private module Stage4 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2609,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
|
||||
|
||||
private newtype TSummaryCtx =
|
||||
TSummaryCtxNone() or
|
||||
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||
TSummaryCtxSome(ParamNode p, AccessPath ap) {
|
||||
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
|
||||
}
|
||||
|
||||
@@ -2630,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||
|
||||
/** A summary context from which a flow summary can be generated. */
|
||||
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
private ParameterNode p;
|
||||
private ParamNode p;
|
||||
private AccessPath ap;
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
@@ -2761,7 +2749,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2982,7 +2970,7 @@ class PathNode extends TPathNode {
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
nodeIsHidden(this.getNode()) and
|
||||
hiddenNode(this.getNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
}
|
||||
@@ -3132,7 +3120,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, getNodeEnclosingCallable(midnode)) and
|
||||
localCC = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(midnode)) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
@@ -3151,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -3238,7 +3226,7 @@ pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3251,7 +3239,7 @@ pragma[noinline]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
@@ -3275,7 +3263,7 @@ private predicate pathIntoCallable0(
|
||||
* respectively.
|
||||
*/
|
||||
private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
@@ -3571,7 +3559,7 @@ private module FlowExploration {
|
||||
|
||||
private newtype TSummaryCtx1 =
|
||||
TSummaryCtx1None() or
|
||||
TSummaryCtx1Param(ParameterNode p)
|
||||
TSummaryCtx1Param(ParamNode p)
|
||||
|
||||
private newtype TSummaryCtx2 =
|
||||
TSummaryCtx2None() or
|
||||
@@ -3594,7 +3582,7 @@ private module FlowExploration {
|
||||
cc instanceof CallContextAny and
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
not fullBarrier(node, config) and
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
@@ -3614,7 +3602,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not clearsContentCached(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
)
|
||||
@@ -3628,9 +3616,9 @@ private module FlowExploration {
|
||||
exists(PartialPathNodeFwd mid |
|
||||
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not clearsContent(node, ap.getHead().getContent()) and
|
||||
not clearsContentCached(node, ap.getHead().getContent()) and
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeType(node), ap.getType())
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
)
|
||||
}
|
||||
@@ -3786,7 +3774,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -3800,7 +3788,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
@@ -3816,7 +3804,7 @@ private module FlowExploration {
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
partialPathStoreStep(mid, _, _, node, ap) and
|
||||
@@ -3830,7 +3818,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
apConsFwd(ap, tc, ap0, config) and
|
||||
compatibleTypes(ap.getType(), getNodeType(node))
|
||||
compatibleTypes(ap.getType(), getNodeDataFlowType(node))
|
||||
)
|
||||
or
|
||||
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
|
||||
@@ -3927,7 +3915,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3946,7 +3934,7 @@ private module FlowExploration {
|
||||
}
|
||||
|
||||
private predicate partialPathIntoCallable(
|
||||
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
|
||||
PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
@@ -3983,7 +3971,7 @@ private module FlowExploration {
|
||||
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
|
||||
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
|
||||
)
|
||||
@@ -4040,7 +4028,7 @@ private module FlowExploration {
|
||||
apConsRev(ap, c, ap0, config)
|
||||
)
|
||||
or
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
mid.getNode() = p and
|
||||
viableParamArg(_, p, node) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4118,7 +4106,7 @@ private module FlowExploration {
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParameterNode p |
|
||||
exists(PartialPathNodeRev mid, ParamNode p |
|
||||
mid.getNode() = p and
|
||||
p.isParameterOf(_, pos) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4141,7 +4129,7 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
|
||||
PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
|
||||
@@ -31,26 +31,26 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
|
||||
* 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
|
||||
* of a call, we use the results of the analysis recursively to resolve lambda
|
||||
* 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) {
|
||||
private predicate viableParamNonLambda(DataFlowCall call, int i, ParamNode p) {
|
||||
p.isParameterOf(viableCallable(call), i)
|
||||
}
|
||||
|
||||
private predicate viableParamLambda(DataFlowCall call, int i, ParameterNode p) {
|
||||
private predicate viableParamLambda(DataFlowCall call, int i, ParamNode p) {
|
||||
p.isParameterOf(viableCallableLambda(call, _), i)
|
||||
}
|
||||
|
||||
private predicate viableParamArgNonLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
|
||||
private predicate viableParamArgNonLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||
exists(int i |
|
||||
viableParamNonLambda(call, i, p) and
|
||||
arg.argumentOf(call, i)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate viableParamArgLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
|
||||
private predicate viableParamArgLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||
exists(int i |
|
||||
viableParamLambda(call, i, p) and
|
||||
arg.argumentOf(call, i)
|
||||
@@ -118,8 +118,8 @@ private module LambdaFlow {
|
||||
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))
|
||||
if castNode(node) or node instanceof ArgNode or node instanceof ReturnNode
|
||||
then compatibleTypes(t, getNodeDataFlowType(node))
|
||||
else any()
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ private module LambdaFlow {
|
||||
boolean toJump, DataFlowCallOption lastCall
|
||||
) {
|
||||
lambdaCall(lambdaCall, kind, node) and
|
||||
t = getNodeType(node) and
|
||||
t = getNodeDataFlowType(node) and
|
||||
toReturn = false and
|
||||
toJump = false and
|
||||
lastCall = TDataFlowCallNone()
|
||||
@@ -146,7 +146,7 @@ private module LambdaFlow {
|
||||
getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid)
|
||||
|
|
||||
preservesValue = false and
|
||||
t = getNodeType(node)
|
||||
t = getNodeDataFlowType(node)
|
||||
or
|
||||
preservesValue = true and
|
||||
t = t0
|
||||
@@ -160,7 +160,7 @@ private module LambdaFlow {
|
||||
toJump = true and
|
||||
lastCall = TDataFlowCallNone()
|
||||
|
|
||||
jumpStep(node, mid) and
|
||||
jumpStepCached(node, mid) and
|
||||
t = t0
|
||||
or
|
||||
exists(boolean preservesValue |
|
||||
@@ -168,7 +168,7 @@ private module LambdaFlow {
|
||||
getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid)
|
||||
|
|
||||
preservesValue = false and
|
||||
t = getNodeType(node)
|
||||
t = getNodeDataFlowType(node)
|
||||
or
|
||||
preservesValue = true and
|
||||
t = t0
|
||||
@@ -176,7 +176,7 @@ private module LambdaFlow {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(ParameterNode p, DataFlowCallOption lastCall0, DataFlowCall call |
|
||||
exists(ParamNode p, DataFlowCallOption lastCall0, DataFlowCall call |
|
||||
revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and
|
||||
(
|
||||
if lastCall0 = TDataFlowCallNone() and toJump = false
|
||||
@@ -227,7 +227,7 @@ private module LambdaFlow {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlowIn(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, ParameterNode p, DataFlowType t, boolean toJump,
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, ParamNode p, DataFlowType t, boolean toJump,
|
||||
DataFlowCallOption lastCall
|
||||
) {
|
||||
revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall)
|
||||
@@ -242,6 +242,89 @@ private DataFlowCallable viableCallableExt(DataFlowCall call) {
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
/**
|
||||
* If needed, call this predicate from `DataFlowImplSpecific.qll` in order to
|
||||
* force a stage-dependency on the `DataFlowImplCommon.qll` stage and therby
|
||||
* collapsing the two stages.
|
||||
*/
|
||||
cached
|
||||
predicate forceCachingInSameStage() { any() }
|
||||
|
||||
cached
|
||||
predicate nodeEnclosingCallable(Node n, DataFlowCallable c) { c = n.getEnclosingCallable() }
|
||||
|
||||
cached
|
||||
predicate callEnclosingCallable(DataFlowCall call, DataFlowCallable c) {
|
||||
c = call.getEnclosingCallable()
|
||||
}
|
||||
|
||||
cached
|
||||
predicate nodeDataFlowType(Node n, DataFlowType t) { t = getNodeType(n) }
|
||||
|
||||
cached
|
||||
predicate jumpStepCached(Node node1, Node node2) { jumpStep(node1, node2) }
|
||||
|
||||
cached
|
||||
predicate clearsContentCached(Node n, Content c) { clearsContent(n, c) }
|
||||
|
||||
cached
|
||||
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
|
||||
|
||||
cached
|
||||
predicate outNodeExt(Node n) {
|
||||
n instanceof OutNode
|
||||
or
|
||||
n.(PostUpdateNode).getPreUpdateNode() instanceof ArgNode
|
||||
}
|
||||
|
||||
cached
|
||||
predicate hiddenNode(Node n) { nodeIsHidden(n) }
|
||||
|
||||
cached
|
||||
OutNodeExt getAnOutNodeExt(DataFlowCall call, ReturnKindExt k) {
|
||||
result = getAnOutNode(call, k.(ValueReturnKind).getKind())
|
||||
or
|
||||
exists(ArgNode arg |
|
||||
result.(PostUpdateNode).getPreUpdateNode() = arg and
|
||||
arg.argumentOf(call, k.(ParamUpdateReturnKind).getPosition())
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate returnNodeExt(Node n, ReturnKindExt k) {
|
||||
k = TValueReturn(n.(ReturnNode).getKind())
|
||||
or
|
||||
exists(ParamNode p, int pos |
|
||||
parameterValueFlowsToPreUpdate(p, n) and
|
||||
p.isParameterOf(_, pos) and
|
||||
k = TParamUpdate(pos)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate castNode(Node n) { n instanceof CastNode }
|
||||
|
||||
cached
|
||||
predicate castingNode(Node n) {
|
||||
castNode(n) or
|
||||
n instanceof ParamNode or
|
||||
n instanceof OutNodeExt or
|
||||
// For reads, `x.f`, we want to check that the tracked type after the read (which
|
||||
// is obtained by popping the head of the access path stack) is compatible with
|
||||
// the type of `x.f`.
|
||||
read(_, _, n)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate parameterNode(Node n, DataFlowCallable c, int i) {
|
||||
n.(ParameterNode).isParameterOf(c, i)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate argumentNode(Node n, DataFlowCall call, int pos) {
|
||||
n.(ArgumentNode).argumentOf(call, pos)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable target for the lambda call `call`.
|
||||
*
|
||||
@@ -261,7 +344,7 @@ private module Cached {
|
||||
* The instance parameter is considered to have index `-1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate viableParam(DataFlowCall call, int i, ParameterNode p) {
|
||||
private predicate viableParam(DataFlowCall call, int i, ParamNode p) {
|
||||
p.isParameterOf(viableCallableExt(call), i)
|
||||
}
|
||||
|
||||
@@ -270,11 +353,11 @@ private module Cached {
|
||||
* dispatch into account.
|
||||
*/
|
||||
cached
|
||||
predicate viableParamArg(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
|
||||
predicate viableParamArg(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||
exists(int i |
|
||||
viableParam(call, i, p) and
|
||||
arg.argumentOf(call, i) and
|
||||
compatibleTypes(getNodeType(arg), getNodeType(p))
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -312,7 +395,7 @@ private module Cached {
|
||||
* `read` indicates whether it is contents of `p` that can flow to `node`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate parameterValueFlowCand(ParameterNode p, Node node, boolean read) {
|
||||
private predicate parameterValueFlowCand(ParamNode p, Node node, boolean read) {
|
||||
p = node and
|
||||
read = false
|
||||
or
|
||||
@@ -325,30 +408,30 @@ private module Cached {
|
||||
// read
|
||||
exists(Node mid |
|
||||
parameterValueFlowCand(p, mid, false) and
|
||||
readStep(mid, _, node) and
|
||||
read(mid, _, node) and
|
||||
read = true
|
||||
)
|
||||
or
|
||||
// flow through: no prior read
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
parameterValueFlowArgCand(p, arg, false) and
|
||||
argumentValueFlowsThroughCand(arg, node, read)
|
||||
)
|
||||
or
|
||||
// flow through: no read inside method
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
parameterValueFlowArgCand(p, arg, read) and
|
||||
argumentValueFlowsThroughCand(arg, node, false)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterValueFlowArgCand(ParameterNode p, ArgumentNode arg, boolean read) {
|
||||
private predicate parameterValueFlowArgCand(ParamNode p, ArgNode arg, boolean read) {
|
||||
parameterValueFlowCand(p, arg, read)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate parameterValueFlowsToPreUpdateCand(ParameterNode p, PostUpdateNode n) {
|
||||
predicate parameterValueFlowsToPreUpdateCand(ParamNode p, PostUpdateNode n) {
|
||||
parameterValueFlowCand(p, n.getPreUpdateNode(), false)
|
||||
}
|
||||
|
||||
@@ -360,7 +443,7 @@ private module Cached {
|
||||
* `read` indicates whether it is contents of `p` that can flow to the return
|
||||
* node.
|
||||
*/
|
||||
predicate parameterValueFlowReturnCand(ParameterNode p, ReturnKind kind, boolean read) {
|
||||
predicate parameterValueFlowReturnCand(ParamNode p, ReturnKind kind, boolean read) {
|
||||
exists(ReturnNode ret |
|
||||
parameterValueFlowCand(p, ret, read) and
|
||||
kind = ret.getKind()
|
||||
@@ -369,9 +452,9 @@ private module Cached {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate argumentValueFlowsThroughCand0(
|
||||
DataFlowCall call, ArgumentNode arg, ReturnKind kind, boolean read
|
||||
DataFlowCall call, ArgNode arg, ReturnKind kind, boolean read
|
||||
) {
|
||||
exists(ParameterNode param | viableParamArg(call, param, arg) |
|
||||
exists(ParamNode param | viableParamArg(call, param, arg) |
|
||||
parameterValueFlowReturnCand(param, kind, read)
|
||||
)
|
||||
}
|
||||
@@ -382,14 +465,14 @@ private module Cached {
|
||||
*
|
||||
* `read` indicates whether it is contents of `arg` that can flow to `out`.
|
||||
*/
|
||||
predicate argumentValueFlowsThroughCand(ArgumentNode arg, Node out, boolean read) {
|
||||
predicate argumentValueFlowsThroughCand(ArgNode arg, Node out, boolean read) {
|
||||
exists(DataFlowCall call, ReturnKind kind |
|
||||
argumentValueFlowsThroughCand0(call, arg, kind, read) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
predicate cand(ParameterNode p, Node n) {
|
||||
predicate cand(ParamNode p, Node n) {
|
||||
parameterValueFlowCand(p, n, _) and
|
||||
(
|
||||
parameterValueFlowReturnCand(p, _, _)
|
||||
@@ -416,21 +499,21 @@ private module Cached {
|
||||
* If a read step was taken, then `read` captures the `Content`, the
|
||||
* container type, and the content type.
|
||||
*/
|
||||
predicate parameterValueFlow(ParameterNode p, Node node, ReadStepTypesOption read) {
|
||||
predicate parameterValueFlow(ParamNode p, Node node, ReadStepTypesOption read) {
|
||||
parameterValueFlow0(p, node, read) and
|
||||
if node instanceof CastingNode
|
||||
then
|
||||
// normal flow through
|
||||
read = TReadStepTypesNone() and
|
||||
compatibleTypes(getNodeType(p), getNodeType(node))
|
||||
compatibleTypes(getNodeDataFlowType(p), getNodeDataFlowType(node))
|
||||
or
|
||||
// getter
|
||||
compatibleTypes(read.getContentType(), getNodeType(node))
|
||||
compatibleTypes(read.getContentType(), getNodeDataFlowType(node))
|
||||
else any()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) {
|
||||
private predicate parameterValueFlow0(ParamNode p, Node node, ReadStepTypesOption read) {
|
||||
p = node and
|
||||
Cand::cand(p, _) and
|
||||
read = TReadStepTypesNone()
|
||||
@@ -447,7 +530,7 @@ private module Cached {
|
||||
readStepWithTypes(mid, read.getContainerType(), read.getContent(), node,
|
||||
read.getContentType()) and
|
||||
Cand::parameterValueFlowReturnCand(p, _, true) and
|
||||
compatibleTypes(getNodeType(p), read.getContainerType())
|
||||
compatibleTypes(getNodeDataFlowType(p), read.getContainerType())
|
||||
)
|
||||
or
|
||||
parameterValueFlow0_0(TReadStepTypesNone(), p, node, read)
|
||||
@@ -455,34 +538,32 @@ private module Cached {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterValueFlow0_0(
|
||||
ReadStepTypesOption mustBeNone, ParameterNode p, Node node, ReadStepTypesOption read
|
||||
ReadStepTypesOption mustBeNone, ParamNode p, Node node, ReadStepTypesOption read
|
||||
) {
|
||||
// flow through: no prior read
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
parameterValueFlowArg(p, arg, mustBeNone) and
|
||||
argumentValueFlowsThrough(arg, read, node)
|
||||
)
|
||||
or
|
||||
// flow through: no read inside method
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
parameterValueFlowArg(p, arg, read) and
|
||||
argumentValueFlowsThrough(arg, mustBeNone, node)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterValueFlowArg(
|
||||
ParameterNode p, ArgumentNode arg, ReadStepTypesOption read
|
||||
) {
|
||||
private predicate parameterValueFlowArg(ParamNode p, ArgNode arg, ReadStepTypesOption read) {
|
||||
parameterValueFlow(p, arg, read) and
|
||||
Cand::argumentValueFlowsThroughCand(arg, _, _)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate argumentValueFlowsThrough0(
|
||||
DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read
|
||||
DataFlowCall call, ArgNode arg, ReturnKind kind, ReadStepTypesOption read
|
||||
) {
|
||||
exists(ParameterNode param | viableParamArg(call, param, arg) |
|
||||
exists(ParamNode param | viableParamArg(call, param, arg) |
|
||||
parameterValueFlowReturn(param, kind, read)
|
||||
)
|
||||
}
|
||||
@@ -496,18 +577,18 @@ private module Cached {
|
||||
* container type, and the content type.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) {
|
||||
predicate argumentValueFlowsThrough(ArgNode arg, ReadStepTypesOption read, Node out) {
|
||||
exists(DataFlowCall call, ReturnKind kind |
|
||||
argumentValueFlowsThrough0(call, arg, kind, read) and
|
||||
out = getAnOutNode(call, kind)
|
||||
|
|
||||
// normal flow through
|
||||
read = TReadStepTypesNone() and
|
||||
compatibleTypes(getNodeType(arg), getNodeType(out))
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(out))
|
||||
or
|
||||
// getter
|
||||
compatibleTypes(getNodeType(arg), read.getContainerType()) and
|
||||
compatibleTypes(read.getContentType(), getNodeType(out))
|
||||
compatibleTypes(getNodeDataFlowType(arg), read.getContainerType()) and
|
||||
compatibleTypes(read.getContentType(), getNodeDataFlowType(out))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -516,7 +597,7 @@ private module Cached {
|
||||
* value-preserving steps and a single read step, not taking call
|
||||
* contexts into account, thus representing a getter-step.
|
||||
*/
|
||||
predicate getterStep(ArgumentNode arg, Content c, Node out) {
|
||||
predicate getterStep(ArgNode arg, Content c, Node out) {
|
||||
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
|
||||
}
|
||||
|
||||
@@ -529,7 +610,7 @@ private module Cached {
|
||||
* container type, and the content type.
|
||||
*/
|
||||
private predicate parameterValueFlowReturn(
|
||||
ParameterNode p, ReturnKind kind, ReadStepTypesOption read
|
||||
ParamNode p, ReturnKind kind, ReadStepTypesOption read
|
||||
) {
|
||||
exists(ReturnNode ret |
|
||||
parameterValueFlow(p, ret, read) and
|
||||
@@ -553,7 +634,7 @@ private module Cached {
|
||||
private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) {
|
||||
mayBenefitFromCallContext(call, callable)
|
||||
or
|
||||
callable = call.getEnclosingCallable() and
|
||||
callEnclosingCallable(call, callable) and
|
||||
exists(viableCallableLambda(call, TDataFlowCallSome(_)))
|
||||
}
|
||||
|
||||
@@ -611,7 +692,7 @@ private module Cached {
|
||||
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
|
||||
tgts = strictcount(DataFlowCall ctx | callEnclosingCallable(call, viableCallableExt(ctx))) and
|
||||
ctxtgts < tgts
|
||||
)
|
||||
}
|
||||
@@ -635,8 +716,7 @@ private module Cached {
|
||||
* Holds if `p` can flow to the pre-update node associated with post-update
|
||||
* node `n`, in the same callable, using only value-preserving steps.
|
||||
*/
|
||||
cached
|
||||
predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) {
|
||||
private predicate parameterValueFlowsToPreUpdate(ParamNode p, PostUpdateNode n) {
|
||||
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
|
||||
}
|
||||
|
||||
@@ -644,9 +724,9 @@ private module Cached {
|
||||
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
|
||||
) {
|
||||
storeStep(node1, c, node2) and
|
||||
readStep(_, c, _) and
|
||||
contentType = getNodeType(node1) and
|
||||
containerType = getNodeType(node2)
|
||||
read(_, c, _) and
|
||||
contentType = getNodeDataFlowType(node1) and
|
||||
containerType = getNodeDataFlowType(node2)
|
||||
or
|
||||
exists(Node n1, Node n2 |
|
||||
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
|
||||
@@ -654,12 +734,15 @@ private module Cached {
|
||||
|
|
||||
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
|
||||
or
|
||||
readStep(n2, c, n1) and
|
||||
contentType = getNodeType(n1) and
|
||||
containerType = getNodeType(n2)
|
||||
read(n2, c, n1) and
|
||||
contentType = getNodeDataFlowType(n1) and
|
||||
containerType = getNodeDataFlowType(n2)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate read(Node node1, Content c, Node node2) { readStep(node1, c, node2) }
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via a direct assignment to
|
||||
* `f`.
|
||||
@@ -678,8 +761,9 @@ private module Cached {
|
||||
* are aliases. A typical example is a function returning `this`, implementing a fluent
|
||||
* interface.
|
||||
*/
|
||||
cached
|
||||
predicate reverseStepThroughInputOutputAlias(PostUpdateNode fromNode, PostUpdateNode toNode) {
|
||||
private predicate reverseStepThroughInputOutputAlias(
|
||||
PostUpdateNode fromNode, PostUpdateNode toNode
|
||||
) {
|
||||
exists(Node fromPre, Node toPre |
|
||||
fromPre = fromNode.getPreUpdateNode() and
|
||||
toPre = toNode.getPreUpdateNode()
|
||||
@@ -688,14 +772,20 @@ private module Cached {
|
||||
// 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)
|
||||
toPre.(ArgNode).argumentOf(c, _) and
|
||||
simpleLocalFlowStep(toPre.(ArgNode), fromPre)
|
||||
)
|
||||
or
|
||||
argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate simpleLocalFlowStepExt(Node node1, Node node2) {
|
||||
simpleLocalFlowStep(node1, node2) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the call context `call` either improves virtual dispatch in
|
||||
* `callable` or if it allows us to prune unreachable nodes in `callable`.
|
||||
@@ -704,7 +794,7 @@ private module Cached {
|
||||
predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
|
||||
reducedViableImplInCallContext(_, callable, call)
|
||||
or
|
||||
exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCall(n, call))
|
||||
exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call))
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -726,12 +816,12 @@ private module Cached {
|
||||
cached
|
||||
newtype TLocalFlowCallContext =
|
||||
TAnyLocalCall() or
|
||||
TSpecificLocalCall(DataFlowCall call) { isUnreachableInCall(_, call) }
|
||||
TSpecificLocalCall(DataFlowCall call) { isUnreachableInCallCached(_, call) }
|
||||
|
||||
cached
|
||||
newtype TReturnKindExt =
|
||||
TValueReturn(ReturnKind kind) or
|
||||
TParamUpdate(int pos) { exists(ParameterNode p | p.isParameterOf(_, pos)) }
|
||||
TParamUpdate(int pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
|
||||
|
||||
cached
|
||||
newtype TBooleanOption =
|
||||
@@ -761,23 +851,15 @@ private module Cached {
|
||||
* A `Node` at which a cast can occur such that the type should be checked.
|
||||
*/
|
||||
class CastingNode extends Node {
|
||||
CastingNode() {
|
||||
this instanceof ParameterNode or
|
||||
this instanceof CastNode or
|
||||
this instanceof OutNodeExt or
|
||||
// For reads, `x.f`, we want to check that the tracked type after the read (which
|
||||
// is obtained by popping the head of the access path stack) is compatible with
|
||||
// the type of `x.f`.
|
||||
readStep(_, _, this)
|
||||
}
|
||||
CastingNode() { castingNode(this) }
|
||||
}
|
||||
|
||||
private predicate readStepWithTypes(
|
||||
Node n1, DataFlowType container, Content c, Node n2, DataFlowType content
|
||||
) {
|
||||
readStep(n1, c, n2) and
|
||||
container = getNodeType(n1) and
|
||||
content = getNodeType(n2)
|
||||
read(n1, c, n2) and
|
||||
container = getNodeDataFlowType(n1) and
|
||||
content = getNodeDataFlowType(n2)
|
||||
}
|
||||
|
||||
private newtype TReadStepTypesOption =
|
||||
@@ -854,7 +936,7 @@ class CallContextSomeCall extends CallContextCall, TSomeCall {
|
||||
override string toString() { result = "CcSomeCall" }
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) {
|
||||
exists(ParameterNode p | getNodeEnclosingCallable(p) = callable)
|
||||
exists(ParamNode p | getNodeEnclosingCallable(p) = callable)
|
||||
}
|
||||
|
||||
override predicate matchesCall(DataFlowCall call) { any() }
|
||||
@@ -866,7 +948,7 @@ class CallContextReturn extends CallContextNoCall, TReturn {
|
||||
}
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) {
|
||||
exists(DataFlowCall call | this = TReturn(_, call) and call.getEnclosingCallable() = callable)
|
||||
exists(DataFlowCall call | this = TReturn(_, call) and callEnclosingCallable(call, callable))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -899,7 +981,7 @@ class LocalCallContextSpecificCall extends LocalCallContext, TSpecificLocalCall
|
||||
}
|
||||
|
||||
private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) {
|
||||
exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCall(n, call))
|
||||
exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCallCached(n, call))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -913,26 +995,37 @@ LocalCallContext getLocalCallContext(CallContext ctx, DataFlowCallable callable)
|
||||
else result instanceof LocalCallContextAny
|
||||
}
|
||||
|
||||
/**
|
||||
* The value of a parameter at function entry, viewed as a node in a data
|
||||
* flow graph.
|
||||
*/
|
||||
class ParamNode extends Node {
|
||||
ParamNode() { parameterNode(this, _, _) }
|
||||
|
||||
/**
|
||||
* Holds if this node is the parameter of callable `c` at the specified
|
||||
* (zero-based) position.
|
||||
*/
|
||||
predicate isParameterOf(DataFlowCallable c, int i) { parameterNode(this, c, i) }
|
||||
}
|
||||
|
||||
/** A data-flow node that represents a call argument. */
|
||||
class ArgNode extends Node {
|
||||
ArgNode() { argumentNode(this, _, _) }
|
||||
|
||||
/** Holds if this argument occurs at the given position in the given call. */
|
||||
final predicate argumentOf(DataFlowCall call, int pos) { argumentNode(this, call, pos) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A node from which flow can return to the caller. This is either a regular
|
||||
* `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter.
|
||||
*/
|
||||
class ReturnNodeExt extends Node {
|
||||
ReturnNodeExt() {
|
||||
this instanceof ReturnNode or
|
||||
parameterValueFlowsToPreUpdate(_, this)
|
||||
}
|
||||
ReturnNodeExt() { returnNodeExt(this, _) }
|
||||
|
||||
/** Gets the kind of this returned value. */
|
||||
ReturnKindExt getKind() {
|
||||
result = TValueReturn(this.(ReturnNode).getKind())
|
||||
or
|
||||
exists(ParameterNode p, int pos |
|
||||
parameterValueFlowsToPreUpdate(p, this) and
|
||||
p.isParameterOf(_, pos) and
|
||||
result = TParamUpdate(pos)
|
||||
)
|
||||
}
|
||||
ReturnKindExt getKind() { returnNodeExt(this, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -940,11 +1033,7 @@ class ReturnNodeExt extends Node {
|
||||
* or a post-update node associated with a call argument.
|
||||
*/
|
||||
class OutNodeExt extends Node {
|
||||
OutNodeExt() {
|
||||
this instanceof OutNode
|
||||
or
|
||||
this.(PostUpdateNode).getPreUpdateNode() instanceof ArgumentNode
|
||||
}
|
||||
OutNodeExt() { outNodeExt(this) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -957,7 +1046,7 @@ abstract class ReturnKindExt extends TReturnKindExt {
|
||||
abstract string toString();
|
||||
|
||||
/** Gets a node corresponding to data flow out of `call`. */
|
||||
abstract OutNodeExt getAnOutNode(DataFlowCall call);
|
||||
final OutNodeExt getAnOutNode(DataFlowCall call) { result = getAnOutNodeExt(call, this) }
|
||||
}
|
||||
|
||||
class ValueReturnKind extends ReturnKindExt, TValueReturn {
|
||||
@@ -968,10 +1057,6 @@ class ValueReturnKind extends ReturnKindExt, TValueReturn {
|
||||
ReturnKind getKind() { result = kind }
|
||||
|
||||
override string toString() { result = kind.toString() }
|
||||
|
||||
override OutNodeExt getAnOutNode(DataFlowCall call) {
|
||||
result = getAnOutNode(call, this.getKind())
|
||||
}
|
||||
}
|
||||
|
||||
class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
|
||||
@@ -982,13 +1067,6 @@ class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
|
||||
int getPosition() { result = pos }
|
||||
|
||||
override string toString() { result = "param update " + pos }
|
||||
|
||||
override OutNodeExt getAnOutNode(DataFlowCall call) {
|
||||
exists(ArgumentNode arg |
|
||||
result.(PostUpdateNode).getPreUpdateNode() = arg and
|
||||
arg.argumentOf(call, this.getPosition())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A callable tagged with a relevant return kind. */
|
||||
@@ -1015,10 +1093,13 @@ class ReturnPosition extends TReturnPosition0 {
|
||||
*/
|
||||
pragma[inline]
|
||||
DataFlowCallable getNodeEnclosingCallable(Node n) {
|
||||
exists(Node n0 |
|
||||
pragma[only_bind_into](n0) = n and
|
||||
pragma[only_bind_into](result) = n0.getEnclosingCallable()
|
||||
)
|
||||
nodeEnclosingCallable(pragma[only_bind_out](n), pragma[only_bind_into](result))
|
||||
}
|
||||
|
||||
/** Gets the type of `n` used for type pruning. */
|
||||
pragma[inline]
|
||||
DataFlowType getNodeDataFlowType(Node n) {
|
||||
nodeDataFlowType(pragma[only_bind_out](n), pragma[only_bind_into](result))
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -1042,7 +1123,7 @@ predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall
|
||||
cc instanceof CallContextAny and callable = viableCallableExt(call)
|
||||
or
|
||||
exists(DataFlowCallable c0, DataFlowCall call0 |
|
||||
call0.getEnclosingCallable() = callable and
|
||||
callEnclosingCallable(call0, callable) and
|
||||
cc = TReturn(c0, call0) and
|
||||
c0 = prunedViableImplInCallContextReverse(call0, call)
|
||||
)
|
||||
@@ -1063,8 +1144,6 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
|
||||
result = viableCallableExt(call) and cc instanceof CallContextReturn
|
||||
}
|
||||
|
||||
predicate read = readStep/3;
|
||||
|
||||
/** An optional Boolean value. */
|
||||
class BooleanOption extends TBooleanOption {
|
||||
string toString() {
|
||||
@@ -1116,7 +1195,7 @@ abstract class AccessPathFront extends TAccessPathFront {
|
||||
|
||||
TypedContent getHead() { this = TFrontHead(result) }
|
||||
|
||||
predicate isClearedAt(Node n) { clearsContent(n, getHead().getContent()) }
|
||||
predicate isClearedAt(Node n) { clearsContentCached(n, getHead().getContent()) }
|
||||
}
|
||||
|
||||
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
|
||||
|
||||
@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
* 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) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
) and
|
||||
simpleLocalFlowStepExt(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
|
||||
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
|
||||
*/
|
||||
private predicate jumpStep(Node node1, Node node2, Configuration config) {
|
||||
jumpStep(node1, node2) and
|
||||
jumpStepCached(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -388,7 +385,7 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
@@ -515,24 +512,22 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
|
||||
exists(ParamNode p |
|
||||
revFlow(p, toReturn, config) and
|
||||
viableParamArgNodeCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
|
||||
revFlowIn(call, arg, true, config)
|
||||
}
|
||||
|
||||
@@ -597,7 +592,7 @@ private module Stage1 {
|
||||
* Holds if flow may enter through `p` and reach a return node making `p` a
|
||||
* candidate for the origin of a summary.
|
||||
*/
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnKindExt kind |
|
||||
throughFlowNodeCand(p, config) and
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgNodeCand1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
|
||||
Stage1::revFlow(arg, config)
|
||||
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
|
||||
) {
|
||||
viableParamArgNodeCand1(call, p, arg, config) and
|
||||
Stage1::revFlow(p, config) and
|
||||
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, arg, p, config) and
|
||||
exists(int b, int j |
|
||||
@@ -944,10 +938,10 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -992,7 +986,7 @@ private module Stage2 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
)
|
||||
@@ -1133,10 +1127,9 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1146,7 +1139,7 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1199,13 +1192,13 @@ private module Stage2 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand2(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
|
||||
*/
|
||||
private class FlowCheckNode extends Node {
|
||||
FlowCheckNode() {
|
||||
this instanceof CastNode or
|
||||
clearsContent(this, _)
|
||||
castNode(this) or
|
||||
clearsContentCached(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
|
||||
config.isSource(node) or
|
||||
jumpStep(_, node, config) or
|
||||
additionalJumpStep(_, node, config) or
|
||||
node instanceof ParameterNode or
|
||||
node instanceof ParamNode or
|
||||
node instanceof OutNodeExt or
|
||||
store(_, _, node, _) or
|
||||
read(_, _, node) or
|
||||
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getNodeType(node1)
|
||||
t = getNodeDataFlowType(node1)
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2)
|
||||
t = getNodeDataFlowType(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
t = getNodeDataFlowType(node2) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
@@ -1384,7 +1376,7 @@ private module Stage3 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -1443,7 +1435,9 @@ private module Stage3 {
|
||||
bindingset[node, ap]
|
||||
private predicate filter(Node node, Ap ap) {
|
||||
not ap.isClearedAt(node) and
|
||||
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any()
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -1583,10 +1577,10 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -1631,7 +1625,7 @@ private module Stage3 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -1772,10 +1766,9 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1785,7 +1778,7 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1838,13 +1831,13 @@ private module Stage3 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2088,7 +2081,7 @@ private module Stage4 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -2133,11 +2126,8 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(node))
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2158,8 +2148,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCall(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
@@ -2303,10 +2292,10 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -2351,7 +2340,7 @@ private module Stage4 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -2492,10 +2481,9 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -2505,7 +2493,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -2558,13 +2546,13 @@ private module Stage4 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2609,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
|
||||
|
||||
private newtype TSummaryCtx =
|
||||
TSummaryCtxNone() or
|
||||
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||
TSummaryCtxSome(ParamNode p, AccessPath ap) {
|
||||
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
|
||||
}
|
||||
|
||||
@@ -2630,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||
|
||||
/** A summary context from which a flow summary can be generated. */
|
||||
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
private ParameterNode p;
|
||||
private ParamNode p;
|
||||
private AccessPath ap;
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
@@ -2761,7 +2749,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2982,7 +2970,7 @@ class PathNode extends TPathNode {
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
nodeIsHidden(this.getNode()) and
|
||||
hiddenNode(this.getNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
}
|
||||
@@ -3132,7 +3120,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, getNodeEnclosingCallable(midnode)) and
|
||||
localCC = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(midnode)) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
@@ -3151,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -3238,7 +3226,7 @@ pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3251,7 +3239,7 @@ pragma[noinline]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
@@ -3275,7 +3263,7 @@ private predicate pathIntoCallable0(
|
||||
* respectively.
|
||||
*/
|
||||
private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
@@ -3571,7 +3559,7 @@ private module FlowExploration {
|
||||
|
||||
private newtype TSummaryCtx1 =
|
||||
TSummaryCtx1None() or
|
||||
TSummaryCtx1Param(ParameterNode p)
|
||||
TSummaryCtx1Param(ParamNode p)
|
||||
|
||||
private newtype TSummaryCtx2 =
|
||||
TSummaryCtx2None() or
|
||||
@@ -3594,7 +3582,7 @@ private module FlowExploration {
|
||||
cc instanceof CallContextAny and
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
not fullBarrier(node, config) and
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
@@ -3614,7 +3602,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not clearsContentCached(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
)
|
||||
@@ -3628,9 +3616,9 @@ private module FlowExploration {
|
||||
exists(PartialPathNodeFwd mid |
|
||||
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not clearsContent(node, ap.getHead().getContent()) and
|
||||
not clearsContentCached(node, ap.getHead().getContent()) and
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeType(node), ap.getType())
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
)
|
||||
}
|
||||
@@ -3786,7 +3774,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -3800,7 +3788,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
@@ -3816,7 +3804,7 @@ private module FlowExploration {
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
partialPathStoreStep(mid, _, _, node, ap) and
|
||||
@@ -3830,7 +3818,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
apConsFwd(ap, tc, ap0, config) and
|
||||
compatibleTypes(ap.getType(), getNodeType(node))
|
||||
compatibleTypes(ap.getType(), getNodeDataFlowType(node))
|
||||
)
|
||||
or
|
||||
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
|
||||
@@ -3927,7 +3915,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3946,7 +3934,7 @@ private module FlowExploration {
|
||||
}
|
||||
|
||||
private predicate partialPathIntoCallable(
|
||||
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
|
||||
PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
@@ -3983,7 +3971,7 @@ private module FlowExploration {
|
||||
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
|
||||
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
|
||||
)
|
||||
@@ -4040,7 +4028,7 @@ private module FlowExploration {
|
||||
apConsRev(ap, c, ap0, config)
|
||||
)
|
||||
or
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
mid.getNode() = p and
|
||||
viableParamArg(_, p, node) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4118,7 +4106,7 @@ private module FlowExploration {
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParameterNode p |
|
||||
exists(PartialPathNodeRev mid, ParamNode p |
|
||||
mid.getNode() = p and
|
||||
p.isParameterOf(_, pos) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4141,7 +4129,7 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
|
||||
PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
|
||||
@@ -321,5 +321,5 @@ predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c)
|
||||
/** 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. */
|
||||
/** Extra data-flow steps needed for lambda flow analysis. */
|
||||
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }
|
||||
|
||||
@@ -46,7 +46,7 @@ class Node extends TNode {
|
||||
/**
|
||||
* INTERNAL: Do not use. Alternative name for `getFunction`.
|
||||
*/
|
||||
final Function getEnclosingCallable() { result = unique(Function f | f = this.getFunction() | f) }
|
||||
final Function getEnclosingCallable() { result = this.getFunction() }
|
||||
|
||||
/** Gets the type of this node. */
|
||||
Type getType() { none() } // overridden in subclasses
|
||||
@@ -324,7 +324,7 @@ private class VariablePartialDefinitionNode extends PartialDefinitionNode {
|
||||
* A synthetic data flow node used for flow into a collection when an iterator
|
||||
* write occurs in a callee.
|
||||
*/
|
||||
class IteratorPartialDefinitionNode extends PartialDefinitionNode {
|
||||
private class IteratorPartialDefinitionNode extends PartialDefinitionNode {
|
||||
override IteratorPartialDefinition pd;
|
||||
|
||||
override Node getPreUpdateNode() { pd.definesExpressions(_, result.asExpr()) }
|
||||
@@ -526,7 +526,6 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
* This is the local flow predicate that's used as a building block in global
|
||||
* data flow. It may have less flow than the `localFlowStep` predicate.
|
||||
*/
|
||||
cached
|
||||
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
// Expr -> Expr
|
||||
exprToExprStep_nocfg(nodeFrom.asExpr(), nodeTo.asExpr())
|
||||
@@ -694,7 +693,12 @@ private predicate exprToExprStep_nocfg(Expr fromExpr, Expr toExpr) {
|
||||
fromExpr = call.getQualifier()
|
||||
) and
|
||||
call.getTarget() = f and
|
||||
outModel.isReturnValue()
|
||||
// AST dataflow treats a reference as if it were the referred-to object, while the dataflow
|
||||
// models treat references as pointers. If the return type of the call is a reference, then
|
||||
// look for data flow the the referred-to object, rather than the reference itself.
|
||||
if call.getType().getUnspecifiedType() instanceof ReferenceType
|
||||
then outModel.isReturnValueDeref()
|
||||
else outModel.isReturnValue()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -715,6 +719,7 @@ private predicate exprToDefinitionByReferenceStep(Expr exprIn, Expr argOut) {
|
||||
}
|
||||
|
||||
private module FieldFlow {
|
||||
private import DataFlowImplCommon
|
||||
private import DataFlowImplLocal
|
||||
private import DataFlowPrivate
|
||||
|
||||
@@ -747,7 +752,7 @@ private module FieldFlow {
|
||||
exists(FieldConfiguration cfg | cfg.hasFlow(node1, node2)) and
|
||||
// This configuration should not be able to cross function boundaries, but
|
||||
// we double-check here just to be sure.
|
||||
node1.getEnclosingCallable() = node2.getEnclosingCallable()
|
||||
getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ private import semmle.code.cpp.controlflow.SSA
|
||||
private import semmle.code.cpp.dataflow.internal.SubBasicBlocks
|
||||
private import semmle.code.cpp.dataflow.internal.AddressFlow
|
||||
private import semmle.code.cpp.models.implementations.Iterator
|
||||
private import semmle.code.cpp.models.interfaces.PointerWrapper
|
||||
|
||||
/**
|
||||
* A conceptual variable that is assigned only once, like an SSA variable. This
|
||||
@@ -158,18 +159,14 @@ private module PartialDefinitions {
|
||||
Expr innerDefinedExpr;
|
||||
|
||||
IteratorPartialDefinition() {
|
||||
exists(Expr convertedInner |
|
||||
not this instanceof Conversion and
|
||||
valueToUpdate(convertedInner, this.getFullyConverted(), node) and
|
||||
innerDefinedExpr = convertedInner.getUnconverted() and
|
||||
(
|
||||
innerDefinedExpr.(Call).getQualifier() = getAnIteratorAccess(collection)
|
||||
or
|
||||
innerDefinedExpr.(Call).getQualifier() = collection.getAnAccess() and
|
||||
collection instanceof IteratorParameter
|
||||
) and
|
||||
innerDefinedExpr.(Call).getTarget() instanceof IteratorPointerDereferenceMemberOperator
|
||||
)
|
||||
innerDefinedExpr = getInnerDefinedExpr(this, node) and
|
||||
(
|
||||
innerDefinedExpr.(Call).getQualifier() = getAnIteratorAccess(collection)
|
||||
or
|
||||
innerDefinedExpr.(Call).getQualifier() = collection.getAnAccess() and
|
||||
collection instanceof IteratorParameter
|
||||
) and
|
||||
innerDefinedExpr.(Call).getTarget() instanceof IteratorPointerDereferenceMemberOperator
|
||||
or
|
||||
// iterators passed by value without a copy constructor
|
||||
exists(Call call |
|
||||
@@ -207,16 +204,18 @@ private module PartialDefinitions {
|
||||
}
|
||||
}
|
||||
|
||||
private Expr getInnerDefinedExpr(Expr e, ControlFlowNode node) {
|
||||
not e instanceof Conversion and
|
||||
exists(Expr convertedInner |
|
||||
valueToUpdate(convertedInner, e.getFullyConverted(), node) and
|
||||
result = convertedInner.getUnconverted()
|
||||
)
|
||||
}
|
||||
|
||||
class VariablePartialDefinition extends PartialDefinition {
|
||||
Expr innerDefinedExpr;
|
||||
|
||||
VariablePartialDefinition() {
|
||||
not this instanceof Conversion and
|
||||
exists(Expr convertedInner |
|
||||
valueToUpdate(convertedInner, this.getFullyConverted(), node) and
|
||||
innerDefinedExpr = convertedInner.getUnconverted()
|
||||
)
|
||||
}
|
||||
VariablePartialDefinition() { innerDefinedExpr = getInnerDefinedExpr(this, node) }
|
||||
|
||||
deprecated override predicate partiallyDefines(Variable v) {
|
||||
innerDefinedExpr = v.getAnAccess()
|
||||
@@ -296,7 +295,8 @@ module FlowVar_internal {
|
||||
// treating them as immutable, but for data flow it gives better results in
|
||||
// practice to make the variable synonymous with its contents.
|
||||
not v.getUnspecifiedType() instanceof ReferenceType and
|
||||
not v instanceof IteratorParameter
|
||||
not v instanceof IteratorParameter and
|
||||
not v instanceof PointerWrapperParameter
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -644,10 +644,19 @@ module FlowVar_internal {
|
||||
predicate parameterIsNonConstReference(Parameter p) {
|
||||
exists(ReferenceType refType |
|
||||
refType = p.getUnderlyingType() and
|
||||
not refType.getBaseType().isConst()
|
||||
(
|
||||
not refType.getBaseType().isConst()
|
||||
or
|
||||
// A field of a parameter of type `const std::shared_ptr<A>& p` can still be changed even though
|
||||
// the base type of the reference is `const`.
|
||||
refType.getBaseType().getUnspecifiedType() =
|
||||
any(PointerWrapper wrapper | not wrapper.pointsToConst())
|
||||
)
|
||||
)
|
||||
or
|
||||
p instanceof IteratorParameter
|
||||
or
|
||||
p instanceof PointerWrapperParameter
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -836,6 +845,10 @@ module FlowVar_internal {
|
||||
IteratorParameter() { this.getUnspecifiedType() instanceof Iterator }
|
||||
}
|
||||
|
||||
class PointerWrapperParameter extends Parameter {
|
||||
PointerWrapperParameter() { this.getUnspecifiedType() instanceof PointerWrapper }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `v` is initialized to have value `assignedExpr`.
|
||||
*/
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
private import semmle.code.cpp.models.interfaces.DataFlow
|
||||
private import semmle.code.cpp.models.interfaces.Taint
|
||||
private import semmle.code.cpp.models.interfaces.Iterator
|
||||
private import semmle.code.cpp.models.interfaces.PointerWrapper
|
||||
|
||||
private module DataFlow {
|
||||
import semmle.code.cpp.dataflow.internal.DataFlowUtil
|
||||
@@ -44,6 +45,7 @@ predicate defaultTaintSanitizer(DataFlow::Node node) { none() }
|
||||
* local data flow steps. That is, `nodeFrom` and `nodeTo` are likely to represent
|
||||
* different objects.
|
||||
*/
|
||||
cached
|
||||
predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
// Taint can flow through expressions that alter the value but preserve
|
||||
// more than one bit of it _or_ expressions that follow data through
|
||||
@@ -141,7 +143,10 @@ private predicate noFlowFromChildExpr(Expr e) {
|
||||
or
|
||||
e instanceof LogicalOrExpr
|
||||
or
|
||||
e instanceof Call
|
||||
// Allow taint from `operator*` on smart pointers.
|
||||
exists(Call call | e = call |
|
||||
not call.getTarget() = any(PointerWrapper wrapper).getAnUnwrapperFunction()
|
||||
)
|
||||
or
|
||||
e instanceof SizeofOperator
|
||||
or
|
||||
|
||||
@@ -300,17 +300,25 @@ class FunctionCall extends Call, @funbindexpr {
|
||||
}
|
||||
}
|
||||
|
||||
/** A _user-defined_ unary `operator*` function. */
|
||||
class OverloadedPointerDereferenceFunction extends Function {
|
||||
OverloadedPointerDereferenceFunction() {
|
||||
this.hasName("operator*") and
|
||||
this.getEffectiveNumberOfParameters() = 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instance of a _user-defined_ unary `operator*` applied to its argument.
|
||||
* ```
|
||||
* T1 operator*(const T2 &);
|
||||
* T1 a; T2 b;
|
||||
* a = *b;
|
||||
* ```
|
||||
*/
|
||||
class OverloadedPointerDereferenceExpr extends FunctionCall {
|
||||
OverloadedPointerDereferenceExpr() {
|
||||
getTarget().hasName("operator*") and
|
||||
getTarget().getEffectiveNumberOfParameters() = 1
|
||||
this.getTarget() instanceof OverloadedPointerDereferenceFunction
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "OverloadedPointerDereferenceExpr" }
|
||||
|
||||
@@ -850,6 +850,24 @@ class NewOrNewArrayExpr extends Expr, @any_new_expr {
|
||||
this.getAllocatorCall()
|
||||
.getArgument(this.getAllocator().(OperatorNewAllocationFunction).getPlacementArgument())
|
||||
}
|
||||
|
||||
/**
|
||||
* For `operator new`, this gets the call or expression that initializes the allocated object, if any.
|
||||
*
|
||||
* As examples, for `new int(4)`, this will be `4`, and for `new std::vector(4)`, this will
|
||||
* be a call to the constructor `std::vector::vector(size_t)` with `4` as an argument.
|
||||
*
|
||||
* For `operator new[]`, this gets the call or expression that initializes the first element of the
|
||||
* array, if any.
|
||||
*
|
||||
* This will either be a call to the default constructor for the array's element type (as
|
||||
* in `new std::string[10]`), or a literal zero for arrays of scalars which are zero-initialized
|
||||
* due to extra parentheses (as in `new int[10]()`).
|
||||
*
|
||||
* At runtime, the constructor will be called once for each element in the array, but the
|
||||
* constructor call only exists once in the AST.
|
||||
*/
|
||||
final Expr getInitializer() { result = this.getChild(1) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -871,14 +889,6 @@ class NewExpr extends NewOrNewArrayExpr, @new_expr {
|
||||
override Type getAllocatedType() {
|
||||
new_allocated_type(underlyingElement(this), unresolveElement(result))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the call or expression that initializes the allocated object, if any.
|
||||
*
|
||||
* As examples, for `new int(4)`, this will be `4`, and for `new std::vector(4)`, this will
|
||||
* be a call to the constructor `std::vector::vector(size_t)` with `4` as an argument.
|
||||
*/
|
||||
Expr getInitializer() { result = this.getChild(1) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -909,18 +919,6 @@ class NewArrayExpr extends NewOrNewArrayExpr, @new_array_expr {
|
||||
result = getType().getUnderlyingType().(PointerType).getBaseType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the call or expression that initializes the first element of the array, if any.
|
||||
*
|
||||
* This will either be a call to the default constructor for the array's element type (as
|
||||
* in `new std::string[10]`), or a literal zero for arrays of scalars which are zero-initialized
|
||||
* due to extra parentheses (as in `new int[10]()`).
|
||||
*
|
||||
* At runtime, the constructor will be called once for each element in the array, but the
|
||||
* constructor call only exists once in the AST.
|
||||
*/
|
||||
Expr getInitializer() { result = this.getChild(1) }
|
||||
|
||||
/**
|
||||
* Gets the extent of the non-constant array dimension, if any.
|
||||
*
|
||||
@@ -1271,7 +1269,8 @@ private predicate convparents(Expr child, int idx, Element parent) {
|
||||
)
|
||||
}
|
||||
|
||||
// Pulled out for performance. See QL-796.
|
||||
// Pulled out for performance. See
|
||||
// https://github.com/github/codeql-coreql-team/issues/1044.
|
||||
private predicate hasNoConversions(Expr e) { not e.hasConversion() }
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,13 +2,16 @@ import cpp
|
||||
import semmle.code.cpp.security.Security
|
||||
private import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import semmle.code.cpp.ir.dataflow.DataFlow2
|
||||
private import semmle.code.cpp.ir.dataflow.DataFlow3
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowDispatch as Dispatch
|
||||
private import semmle.code.cpp.controlflow.IRGuards
|
||||
private import semmle.code.cpp.models.interfaces.Taint
|
||||
private import semmle.code.cpp.models.interfaces.DataFlow
|
||||
private import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||
private import semmle.code.cpp.ir.dataflow.TaintTracking2
|
||||
private import semmle.code.cpp.ir.dataflow.TaintTracking3
|
||||
private import semmle.code.cpp.ir.dataflow.internal.ModelUtil
|
||||
|
||||
/**
|
||||
* A predictable instruction is one where an external user can predict
|
||||
@@ -65,23 +68,19 @@ private DataFlow::Node getNodeForExpr(Expr node) {
|
||||
not argv(node.(VariableAccess).getTarget())
|
||||
}
|
||||
|
||||
private class DefaultTaintTrackingCfg extends DataFlow::Configuration {
|
||||
private class DefaultTaintTrackingCfg extends TaintTracking::Configuration {
|
||||
DefaultTaintTrackingCfg() { this = "DefaultTaintTrackingCfg" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source = getNodeForSource(_) }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { exists(adjustedSink(sink)) }
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
|
||||
commonTaintStep(n1, n2)
|
||||
}
|
||||
override predicate isSanitizer(DataFlow::Node node) { nodeIsBarrier(node) }
|
||||
|
||||
override predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) }
|
||||
|
||||
override predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
|
||||
override predicate isSanitizerIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
|
||||
}
|
||||
|
||||
private class ToGlobalVarTaintTrackingCfg extends DataFlow::Configuration {
|
||||
private class ToGlobalVarTaintTrackingCfg extends TaintTracking::Configuration {
|
||||
ToGlobalVarTaintTrackingCfg() { this = "GlobalVarTaintTrackingCfg" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source = getNodeForSource(_) }
|
||||
@@ -90,20 +89,18 @@ private class ToGlobalVarTaintTrackingCfg extends DataFlow::Configuration {
|
||||
sink.asVariable() instanceof GlobalOrNamespaceVariable
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
|
||||
commonTaintStep(n1, n2)
|
||||
or
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) {
|
||||
writesVariable(n1.asInstruction(), n2.asVariable().(GlobalOrNamespaceVariable))
|
||||
or
|
||||
readsVariable(n2.asInstruction(), n1.asVariable().(GlobalOrNamespaceVariable))
|
||||
}
|
||||
|
||||
override predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) }
|
||||
override predicate isSanitizer(DataFlow::Node node) { nodeIsBarrier(node) }
|
||||
|
||||
override predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
|
||||
override predicate isSanitizerIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
|
||||
}
|
||||
|
||||
private class FromGlobalVarTaintTrackingCfg extends DataFlow2::Configuration {
|
||||
private class FromGlobalVarTaintTrackingCfg extends TaintTracking2::Configuration {
|
||||
FromGlobalVarTaintTrackingCfg() { this = "FromGlobalVarTaintTrackingCfg" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
@@ -114,18 +111,16 @@ private class FromGlobalVarTaintTrackingCfg extends DataFlow2::Configuration {
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { exists(adjustedSink(sink)) }
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
|
||||
commonTaintStep(n1, n2)
|
||||
or
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) {
|
||||
// Additional step for flow out of variables. There is no flow _into_
|
||||
// variables in this configuration, so this step only serves to take flow
|
||||
// out of a variable that's a source.
|
||||
readsVariable(n2.asInstruction(), n1.asVariable())
|
||||
}
|
||||
|
||||
override predicate isBarrier(DataFlow::Node node) { nodeIsBarrier(node) }
|
||||
override predicate isSanitizer(DataFlow::Node node) { nodeIsBarrier(node) }
|
||||
|
||||
override predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
|
||||
override predicate isSanitizerIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
|
||||
}
|
||||
|
||||
private predicate readsVariable(LoadInstruction load, Variable var) {
|
||||
@@ -170,277 +165,132 @@ private predicate nodeIsBarrierEqualityCandidate(
|
||||
any(IRGuardCondition guard).ensuresEq(access, _, _, node.asInstruction().getBlock(), true)
|
||||
}
|
||||
|
||||
private predicate nodeIsBarrier(DataFlow::Node node) {
|
||||
exists(Variable checkedVar |
|
||||
readsVariable(node.asInstruction(), checkedVar) and
|
||||
hasUpperBoundsCheck(checkedVar)
|
||||
)
|
||||
or
|
||||
exists(Variable checkedVar, Operand access |
|
||||
/*
|
||||
* This node is guarded by a condition that forces the accessed variable
|
||||
* to equal something else. For example:
|
||||
* ```
|
||||
* x = taintsource()
|
||||
* if (x == 10) {
|
||||
* taintsink(x); // not considered tainted
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
|
||||
nodeIsBarrierEqualityCandidate(node, access, checkedVar) and
|
||||
readsVariable(access.getDef(), checkedVar)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate nodeIsBarrierIn(DataFlow::Node node) {
|
||||
// don't use dataflow into taint sources, as this leads to duplicate results.
|
||||
exists(Expr source | isUserInput(source, _) |
|
||||
node = DataFlow::exprNode(source)
|
||||
or
|
||||
// This case goes together with the similar (but not identical) rule in
|
||||
// `getNodeForSource`.
|
||||
node = DataFlow::definitionByReferenceNodeFromArgument(source)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
private predicate commonTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
|
||||
operandToInstructionTaintStep(fromNode.asOperand(), toNode.asInstruction())
|
||||
or
|
||||
instructionToOperandTaintStep(fromNode.asInstruction(), toNode.asOperand())
|
||||
}
|
||||
|
||||
private predicate instructionToOperandTaintStep(Instruction fromInstr, Operand toOperand) {
|
||||
// Propagate flow from the definition of an operand to the operand, even when the overlap is inexact.
|
||||
// We only do this in certain cases:
|
||||
// 1. The instruction's result must not be conflated, and
|
||||
// 2. The instruction's result type is one the types where we expect element-to-object flow. Currently
|
||||
// this is array types and union types. This matches the other two cases of element-to-object flow in
|
||||
// `DefaultTaintTracking`.
|
||||
toOperand.getAnyDef() = fromInstr and
|
||||
not fromInstr.isResultConflated() and
|
||||
(
|
||||
fromInstr.getResultType() instanceof ArrayType or
|
||||
fromInstr.getResultType() instanceof Union
|
||||
)
|
||||
or
|
||||
exists(ReadSideEffectInstruction readInstr |
|
||||
fromInstr = readInstr.getArgumentDef() and
|
||||
toOperand = readInstr.getSideEffectOperand()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate operandToInstructionTaintStep(Operand fromOperand, Instruction toInstr) {
|
||||
// Expressions computed from tainted data are also tainted
|
||||
exists(CallInstruction call, int argIndex | call = toInstr |
|
||||
isPureFunction(call.getStaticCallTarget().getName()) and
|
||||
fromOperand = getACallArgumentOrIndirection(call, argIndex) and
|
||||
forall(Operand argOperand | argOperand = call.getAnArgumentOperand() |
|
||||
argOperand = getACallArgumentOrIndirection(call, argIndex) or
|
||||
predictableInstruction(argOperand.getAnyDef())
|
||||
) and
|
||||
// flow through `strlen` tends to cause dubious results, if the length is
|
||||
// bounded.
|
||||
not call.getStaticCallTarget().getName() = "strlen"
|
||||
)
|
||||
or
|
||||
// Flow from argument to return value
|
||||
toInstr =
|
||||
any(CallInstruction call |
|
||||
exists(int indexIn |
|
||||
modelTaintToReturnValue(call.getStaticCallTarget(), indexIn) and
|
||||
fromOperand = getACallArgumentOrIndirection(call, indexIn) and
|
||||
not predictableOnlyFlow(call.getStaticCallTarget().getName())
|
||||
)
|
||||
private module Cached {
|
||||
cached
|
||||
predicate nodeIsBarrier(DataFlow::Node node) {
|
||||
exists(Variable checkedVar |
|
||||
readsVariable(node.asInstruction(), checkedVar) and
|
||||
hasUpperBoundsCheck(checkedVar)
|
||||
)
|
||||
or
|
||||
// Flow from input argument to output argument
|
||||
// TODO: This won't work in practice as long as all aliased memory is tracked
|
||||
// together in a single virtual variable.
|
||||
// TODO: Will this work on the test for `TaintedPath.ql`, where the output arg
|
||||
// is a pointer addition expression?
|
||||
toInstr =
|
||||
any(WriteSideEffectInstruction outInstr |
|
||||
exists(CallInstruction call, int indexIn, int indexOut |
|
||||
modelTaintToParameter(call.getStaticCallTarget(), indexIn, indexOut) and
|
||||
fromOperand = getACallArgumentOrIndirection(call, indexIn) and
|
||||
outInstr.getIndex() = indexOut and
|
||||
outInstr.getPrimaryInstruction() = call
|
||||
)
|
||||
)
|
||||
or
|
||||
// Flow through pointer dereference
|
||||
toInstr.(LoadInstruction).getSourceAddressOperand() = fromOperand
|
||||
or
|
||||
// Flow through partial reads of arrays and unions
|
||||
toInstr.(LoadInstruction).getSourceValueOperand() = fromOperand and
|
||||
exists(Instruction fromInstr | fromInstr = fromOperand.getAnyDef() |
|
||||
not fromInstr.isResultConflated() and
|
||||
(
|
||||
fromInstr.getResultType() instanceof ArrayType or
|
||||
fromInstr.getResultType() instanceof Union
|
||||
)
|
||||
)
|
||||
or
|
||||
// Unary instructions tend to preserve enough information in practice that we
|
||||
// want taint to flow through.
|
||||
// The exception is `FieldAddressInstruction`. Together with the rule for
|
||||
// `LoadInstruction` above and for `ChiInstruction` below, flow through
|
||||
// `FieldAddressInstruction` could cause flow into one field to come out an
|
||||
// unrelated field. This would happen across function boundaries, where the IR
|
||||
// would not be able to match loads to stores.
|
||||
toInstr.(UnaryInstruction).getUnaryOperand() = fromOperand and
|
||||
(
|
||||
not toInstr instanceof FieldAddressInstruction
|
||||
or
|
||||
toInstr.(FieldAddressInstruction).getField().getDeclaringType() instanceof Union
|
||||
)
|
||||
or
|
||||
// Flow from an element to an array or union that contains it.
|
||||
toInstr.(ChiInstruction).getPartialOperand() = fromOperand and
|
||||
not toInstr.isResultConflated() and
|
||||
exists(Type t | toInstr.getResultLanguageType().hasType(t, false) |
|
||||
t instanceof Union
|
||||
or
|
||||
t instanceof ArrayType
|
||||
)
|
||||
or
|
||||
exists(BinaryInstruction bin |
|
||||
bin = toInstr and
|
||||
predictableInstruction(toInstr.getAnOperand().getDef()) and
|
||||
fromOperand = toInstr.getAnOperand()
|
||||
)
|
||||
or
|
||||
// This is part of the translation of `a[i]`, where we want taint to flow
|
||||
// from `a`.
|
||||
toInstr.(PointerAddInstruction).getLeftOperand() = fromOperand
|
||||
or
|
||||
// Until we have flow through indirections across calls, we'll take flow out
|
||||
// of the indirection and into the argument.
|
||||
// When we get proper flow through indirections across calls, this code can be
|
||||
// moved to `adjusedSink` or possibly into the `DataFlow::ExprNode` class.
|
||||
exists(ReadSideEffectInstruction read |
|
||||
read.getSideEffectOperand() = fromOperand and
|
||||
read.getArgumentDef() = toInstr
|
||||
)
|
||||
or
|
||||
// Until we have from through indirections across calls, we'll take flow out
|
||||
// of the parameter and into its indirection.
|
||||
// `InitializeIndirectionInstruction` only has a single operand: the address of the
|
||||
// value whose indirection we are initializing. When initializing an indirection of a parameter `p`,
|
||||
// the IR looks like this:
|
||||
// ```
|
||||
// m1 = InitializeParameter[p] : &r1
|
||||
// r2 = Load[p] : r2, m1
|
||||
// m3 = InitializeIndirection[p] : &r2
|
||||
// ```
|
||||
// So by having flow from `r2` to `m3` we're enabling flow from `m1` to `m3`. This relies on the
|
||||
// `LoadOperand`'s overlap being exact.
|
||||
toInstr.(InitializeIndirectionInstruction).getAnOperand() = fromOperand
|
||||
}
|
||||
exists(Variable checkedVar, Operand access |
|
||||
/*
|
||||
* This node is guarded by a condition that forces the accessed variable
|
||||
* to equal something else. For example:
|
||||
* ```
|
||||
* x = taintsource()
|
||||
* if (x == 10) {
|
||||
* taintsink(x); // not considered tainted
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the index of the side effect instruction corresponding to the specified function output,
|
||||
* if one exists.
|
||||
*/
|
||||
private int getWriteSideEffectIndex(FunctionOutput output) {
|
||||
output.isParameterDeref(result)
|
||||
or
|
||||
output.isQualifierObject() and result = -1
|
||||
}
|
||||
nodeIsBarrierEqualityCandidate(node, access, checkedVar) and
|
||||
readsVariable(access.getDef(), checkedVar)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an operand that goes into argument `argumentIndex` of `call`. This
|
||||
* can be either directly or through one pointer indirection.
|
||||
*/
|
||||
private Operand getACallArgumentOrIndirection(CallInstruction call, int argumentIndex) {
|
||||
result = call.getPositionalArgumentOperand(argumentIndex)
|
||||
or
|
||||
exists(ReadSideEffectInstruction readSE |
|
||||
// TODO: why are read side effect operands imprecise?
|
||||
result = readSE.getSideEffectOperand() and
|
||||
readSE.getPrimaryInstruction() = call and
|
||||
readSE.getIndex() = argumentIndex
|
||||
)
|
||||
}
|
||||
|
||||
private predicate modelTaintToParameter(Function f, int parameterIn, int parameterOut) {
|
||||
exists(FunctionInput modelIn, FunctionOutput modelOut |
|
||||
(
|
||||
f.(DataFlowFunction).hasDataFlow(modelIn, modelOut)
|
||||
cached
|
||||
predicate nodeIsBarrierIn(DataFlow::Node node) {
|
||||
// don't use dataflow into taint sources, as this leads to duplicate results.
|
||||
exists(Expr source | isUserInput(source, _) |
|
||||
node = DataFlow::exprNode(source)
|
||||
or
|
||||
f.(TaintFunction).hasTaintFlow(modelIn, modelOut)
|
||||
) and
|
||||
(modelIn.isParameter(parameterIn) or modelIn.isParameterDeref(parameterIn)) and
|
||||
parameterOut = getWriteSideEffectIndex(modelOut)
|
||||
)
|
||||
// This case goes together with the similar (but not identical) rule in
|
||||
// `getNodeForSource`.
|
||||
node = DataFlow::definitionByReferenceNodeFromArgument(source)
|
||||
)
|
||||
or
|
||||
// don't use dataflow into binary instructions if both operands are unpredictable
|
||||
exists(BinaryInstruction iTo |
|
||||
iTo = node.asInstruction() and
|
||||
not predictableInstruction(iTo.getLeft()) and
|
||||
not predictableInstruction(iTo.getRight()) and
|
||||
// propagate taint from either the pointer or the offset, regardless of predictability
|
||||
not iTo instanceof PointerArithmeticInstruction
|
||||
)
|
||||
or
|
||||
// don't use dataflow through calls to pure functions if two or more operands
|
||||
// are unpredictable
|
||||
exists(Instruction iFrom1, Instruction iFrom2, CallInstruction iTo |
|
||||
iTo = node.asInstruction() and
|
||||
isPureFunction(iTo.getStaticCallTarget().getName()) and
|
||||
iFrom1 = iTo.getAnArgument() and
|
||||
iFrom2 = iTo.getAnArgument() and
|
||||
not predictableInstruction(iFrom1) and
|
||||
not predictableInstruction(iFrom2) and
|
||||
iFrom1 != iFrom2
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
Element adjustedSink(DataFlow::Node sink) {
|
||||
// TODO: is it more appropriate to use asConvertedExpr here and avoid
|
||||
// `getConversion*`? Or will that cause us to miss some cases where there's
|
||||
// flow to a conversion (like a `ReferenceDereferenceExpr`) and we want to
|
||||
// pretend there was flow to the converted `Expr` for the sake of
|
||||
// compatibility.
|
||||
sink.asExpr().getConversion*() = result
|
||||
or
|
||||
// For compatibility, send flow from arguments to parameters, even for
|
||||
// functions with no body.
|
||||
exists(FunctionCall call, int i |
|
||||
sink.asExpr() = call.getArgument(i) and
|
||||
result = resolveCall(call).getParameter(i)
|
||||
)
|
||||
or
|
||||
// For compatibility, send flow into a `Variable` if there is flow to any
|
||||
// Load or Store of that variable.
|
||||
exists(CopyInstruction copy |
|
||||
copy.getSourceValue() = sink.asInstruction() and
|
||||
(
|
||||
readsVariable(copy, result) or
|
||||
writesVariable(copy, result)
|
||||
) and
|
||||
not hasUpperBoundsCheck(result)
|
||||
)
|
||||
or
|
||||
// For compatibility, send flow into a `NotExpr` even if it's part of a
|
||||
// short-circuiting condition and thus might get skipped.
|
||||
result.(NotExpr).getOperand() = sink.asExpr()
|
||||
or
|
||||
// Taint postfix and prefix crement operations when their operand is tainted.
|
||||
result.(CrementOperation).getAnOperand() = sink.asExpr()
|
||||
or
|
||||
// Taint `e1 += e2`, `e &= e2` and friends when `e1` or `e2` is tainted.
|
||||
result.(AssignOperation).getAnOperand() = sink.asExpr()
|
||||
or
|
||||
result =
|
||||
sink.asOperand()
|
||||
.(SideEffectOperand)
|
||||
.getUse()
|
||||
.(ReadSideEffectInstruction)
|
||||
.getArgumentDef()
|
||||
.getUnconvertedResultExpression()
|
||||
}
|
||||
|
||||
/**
|
||||
* Step to return value of a modeled function when an input taints the
|
||||
* dereference of the return value.
|
||||
*/
|
||||
cached
|
||||
predicate additionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) {
|
||||
exists(CallInstruction call, Function func, FunctionInput modelIn, FunctionOutput modelOut |
|
||||
n1.asOperand() = callInput(call, modelIn) and
|
||||
(
|
||||
func.(TaintFunction).hasTaintFlow(modelIn, modelOut)
|
||||
or
|
||||
func.(DataFlowFunction).hasDataFlow(modelIn, modelOut)
|
||||
) and
|
||||
call.getStaticCallTarget() = func and
|
||||
modelOut.isReturnValueDeref() and
|
||||
call = n2.asInstruction()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate modelTaintToReturnValue(Function f, int parameterIn) {
|
||||
// Taint flow from parameter to return value
|
||||
exists(FunctionInput modelIn, FunctionOutput modelOut |
|
||||
f.(TaintFunction).hasTaintFlow(modelIn, modelOut) and
|
||||
(modelIn.isParameter(parameterIn) or modelIn.isParameterDeref(parameterIn)) and
|
||||
(modelOut.isReturnValue() or modelOut.isReturnValueDeref())
|
||||
)
|
||||
or
|
||||
// Data flow (not taint flow) to where the return value points. For the time
|
||||
// being we will conflate pointers and objects in taint tracking.
|
||||
exists(FunctionInput modelIn, FunctionOutput modelOut |
|
||||
f.(DataFlowFunction).hasDataFlow(modelIn, modelOut) and
|
||||
(modelIn.isParameter(parameterIn) or modelIn.isParameterDeref(parameterIn)) and
|
||||
modelOut.isReturnValueDeref()
|
||||
)
|
||||
or
|
||||
// Taint flow from one argument to another and data flow from an argument to a
|
||||
// return value. This happens in functions like `strcat` and `memcpy`. We
|
||||
// could model this flow in two separate steps, but that would add reverse
|
||||
// flow from the write side-effect to the call instruction, which may not be
|
||||
// desirable.
|
||||
exists(int parameterMid, InParameter modelMid, OutReturnValue returnOut |
|
||||
modelTaintToParameter(f, parameterIn, parameterMid) and
|
||||
modelMid.isParameter(parameterMid) and
|
||||
f.(DataFlowFunction).hasDataFlow(modelMid, returnOut)
|
||||
)
|
||||
}
|
||||
|
||||
private Element adjustedSink(DataFlow::Node sink) {
|
||||
// TODO: is it more appropriate to use asConvertedExpr here and avoid
|
||||
// `getConversion*`? Or will that cause us to miss some cases where there's
|
||||
// flow to a conversion (like a `ReferenceDereferenceExpr`) and we want to
|
||||
// pretend there was flow to the converted `Expr` for the sake of
|
||||
// compatibility.
|
||||
sink.asExpr().getConversion*() = result
|
||||
or
|
||||
// For compatibility, send flow from arguments to parameters, even for
|
||||
// functions with no body.
|
||||
exists(FunctionCall call, int i |
|
||||
sink.asExpr() = call.getArgument(i) and
|
||||
result = resolveCall(call).getParameter(i)
|
||||
)
|
||||
or
|
||||
// For compatibility, send flow into a `Variable` if there is flow to any
|
||||
// Load or Store of that variable.
|
||||
exists(CopyInstruction copy |
|
||||
copy.getSourceValue() = sink.asInstruction() and
|
||||
(
|
||||
readsVariable(copy, result) or
|
||||
writesVariable(copy, result)
|
||||
) and
|
||||
not hasUpperBoundsCheck(result)
|
||||
)
|
||||
or
|
||||
// For compatibility, send flow into a `NotExpr` even if it's part of a
|
||||
// short-circuiting condition and thus might get skipped.
|
||||
result.(NotExpr).getOperand() = sink.asExpr()
|
||||
or
|
||||
// Taint postfix and prefix crement operations when their operand is tainted.
|
||||
result.(CrementOperation).getAnOperand() = sink.asExpr()
|
||||
or
|
||||
// Taint `e1 += e2`, `e &= e2` and friends when `e1` or `e2` is tainted.
|
||||
result.(AssignOperation).getAnOperand() = sink.asExpr()
|
||||
}
|
||||
private import Cached
|
||||
|
||||
/**
|
||||
* Holds if `tainted` may contain taint from `source`.
|
||||
@@ -558,7 +408,7 @@ module TaintedWithPath {
|
||||
string toString() { result = "TaintTrackingConfiguration" }
|
||||
}
|
||||
|
||||
private class AdjustedConfiguration extends DataFlow3::Configuration {
|
||||
private class AdjustedConfiguration extends TaintTracking3::Configuration {
|
||||
AdjustedConfiguration() { this = "AdjustedConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
@@ -571,21 +421,22 @@ module TaintedWithPath {
|
||||
exists(TaintTrackingConfiguration cfg | cfg.isSink(adjustedSink(sink)))
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
|
||||
commonTaintStep(n1, n2)
|
||||
or
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) {
|
||||
// Steps into and out of global variables
|
||||
exists(TaintTrackingConfiguration cfg | cfg.taintThroughGlobals() |
|
||||
writesVariable(n1.asInstruction(), n2.asVariable().(GlobalOrNamespaceVariable))
|
||||
or
|
||||
readsVariable(n2.asInstruction(), n1.asVariable().(GlobalOrNamespaceVariable))
|
||||
)
|
||||
or
|
||||
additionalTaintStep(n1, n2)
|
||||
}
|
||||
|
||||
override predicate isBarrier(DataFlow::Node node) {
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
exists(TaintTrackingConfiguration cfg, Expr e | cfg.isBarrier(e) and node = getNodeForExpr(e))
|
||||
}
|
||||
|
||||
override predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
|
||||
override predicate isSanitizerIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
15
cpp/ql/src/semmle/code/cpp/ir/dataflow/TaintTracking3.qll
Normal file
15
cpp/ql/src/semmle/code/cpp/ir/dataflow/TaintTracking3.qll
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Provides a `TaintTracking3` module, which is a copy of the `TaintTracking`
|
||||
* module. Use this class when data-flow configurations or taint-tracking
|
||||
* configurations must depend on each other. Two classes extending
|
||||
* `DataFlow::Configuration` should never depend on each other, but one of them
|
||||
* should instead depend on a `DataFlow2::Configuration`, a
|
||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`. The
|
||||
* `TaintTracking::Configuration` class extends `DataFlow::Configuration`, and
|
||||
* `TaintTracking2::Configuration` extends `DataFlow2::Configuration`.
|
||||
*
|
||||
* See `semmle.code.cpp.ir.dataflow.TaintTracking` for the full documentation.
|
||||
*/
|
||||
module TaintTracking3 {
|
||||
import semmle.code.cpp.ir.dataflow.internal.tainttracking3.TaintTrackingImpl
|
||||
}
|
||||
@@ -2,11 +2,14 @@ private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
private import DataFlowImplCommon as DataFlowImplCommon
|
||||
|
||||
/**
|
||||
* Gets a function that might be called by `call`.
|
||||
*/
|
||||
cached
|
||||
Function viableCallable(CallInstruction call) {
|
||||
DataFlowImplCommon::forceCachingInSameStage() and
|
||||
result = call.getStaticCallTarget()
|
||||
or
|
||||
// If the target of the call does not have a body in the snapshot, it might
|
||||
@@ -43,7 +46,6 @@ private module VirtualDispatch {
|
||||
abstract DataFlow::Node getDispatchValue();
|
||||
|
||||
/** Gets a candidate target for this call. */
|
||||
cached
|
||||
abstract Function resolve();
|
||||
|
||||
/**
|
||||
|
||||
@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
* 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) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
) and
|
||||
simpleLocalFlowStepExt(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
|
||||
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
|
||||
*/
|
||||
private predicate jumpStep(Node node1, Node node2, Configuration config) {
|
||||
jumpStep(node1, node2) and
|
||||
jumpStepCached(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -388,7 +385,7 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
@@ -515,24 +512,22 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
|
||||
exists(ParamNode p |
|
||||
revFlow(p, toReturn, config) and
|
||||
viableParamArgNodeCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
|
||||
revFlowIn(call, arg, true, config)
|
||||
}
|
||||
|
||||
@@ -597,7 +592,7 @@ private module Stage1 {
|
||||
* Holds if flow may enter through `p` and reach a return node making `p` a
|
||||
* candidate for the origin of a summary.
|
||||
*/
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnKindExt kind |
|
||||
throughFlowNodeCand(p, config) and
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgNodeCand1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
|
||||
Stage1::revFlow(arg, config)
|
||||
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
|
||||
) {
|
||||
viableParamArgNodeCand1(call, p, arg, config) and
|
||||
Stage1::revFlow(p, config) and
|
||||
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, arg, p, config) and
|
||||
exists(int b, int j |
|
||||
@@ -944,10 +938,10 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -992,7 +986,7 @@ private module Stage2 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
)
|
||||
@@ -1133,10 +1127,9 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1146,7 +1139,7 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1199,13 +1192,13 @@ private module Stage2 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand2(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
|
||||
*/
|
||||
private class FlowCheckNode extends Node {
|
||||
FlowCheckNode() {
|
||||
this instanceof CastNode or
|
||||
clearsContent(this, _)
|
||||
castNode(this) or
|
||||
clearsContentCached(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
|
||||
config.isSource(node) or
|
||||
jumpStep(_, node, config) or
|
||||
additionalJumpStep(_, node, config) or
|
||||
node instanceof ParameterNode or
|
||||
node instanceof ParamNode or
|
||||
node instanceof OutNodeExt or
|
||||
store(_, _, node, _) or
|
||||
read(_, _, node) or
|
||||
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getNodeType(node1)
|
||||
t = getNodeDataFlowType(node1)
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2)
|
||||
t = getNodeDataFlowType(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
t = getNodeDataFlowType(node2) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
@@ -1384,7 +1376,7 @@ private module Stage3 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -1443,7 +1435,9 @@ private module Stage3 {
|
||||
bindingset[node, ap]
|
||||
private predicate filter(Node node, Ap ap) {
|
||||
not ap.isClearedAt(node) and
|
||||
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any()
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -1583,10 +1577,10 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -1631,7 +1625,7 @@ private module Stage3 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -1772,10 +1766,9 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1785,7 +1778,7 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1838,13 +1831,13 @@ private module Stage3 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2088,7 +2081,7 @@ private module Stage4 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -2133,11 +2126,8 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(node))
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2158,8 +2148,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCall(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
@@ -2303,10 +2292,10 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -2351,7 +2340,7 @@ private module Stage4 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -2492,10 +2481,9 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -2505,7 +2493,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -2558,13 +2546,13 @@ private module Stage4 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2609,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
|
||||
|
||||
private newtype TSummaryCtx =
|
||||
TSummaryCtxNone() or
|
||||
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||
TSummaryCtxSome(ParamNode p, AccessPath ap) {
|
||||
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
|
||||
}
|
||||
|
||||
@@ -2630,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||
|
||||
/** A summary context from which a flow summary can be generated. */
|
||||
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
private ParameterNode p;
|
||||
private ParamNode p;
|
||||
private AccessPath ap;
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
@@ -2761,7 +2749,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2982,7 +2970,7 @@ class PathNode extends TPathNode {
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
nodeIsHidden(this.getNode()) and
|
||||
hiddenNode(this.getNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
}
|
||||
@@ -3132,7 +3120,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, getNodeEnclosingCallable(midnode)) and
|
||||
localCC = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(midnode)) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
@@ -3151,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -3238,7 +3226,7 @@ pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3251,7 +3239,7 @@ pragma[noinline]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
@@ -3275,7 +3263,7 @@ private predicate pathIntoCallable0(
|
||||
* respectively.
|
||||
*/
|
||||
private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
@@ -3571,7 +3559,7 @@ private module FlowExploration {
|
||||
|
||||
private newtype TSummaryCtx1 =
|
||||
TSummaryCtx1None() or
|
||||
TSummaryCtx1Param(ParameterNode p)
|
||||
TSummaryCtx1Param(ParamNode p)
|
||||
|
||||
private newtype TSummaryCtx2 =
|
||||
TSummaryCtx2None() or
|
||||
@@ -3594,7 +3582,7 @@ private module FlowExploration {
|
||||
cc instanceof CallContextAny and
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
not fullBarrier(node, config) and
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
@@ -3614,7 +3602,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not clearsContentCached(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
)
|
||||
@@ -3628,9 +3616,9 @@ private module FlowExploration {
|
||||
exists(PartialPathNodeFwd mid |
|
||||
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not clearsContent(node, ap.getHead().getContent()) and
|
||||
not clearsContentCached(node, ap.getHead().getContent()) and
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeType(node), ap.getType())
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
)
|
||||
}
|
||||
@@ -3786,7 +3774,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -3800,7 +3788,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
@@ -3816,7 +3804,7 @@ private module FlowExploration {
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
partialPathStoreStep(mid, _, _, node, ap) and
|
||||
@@ -3830,7 +3818,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
apConsFwd(ap, tc, ap0, config) and
|
||||
compatibleTypes(ap.getType(), getNodeType(node))
|
||||
compatibleTypes(ap.getType(), getNodeDataFlowType(node))
|
||||
)
|
||||
or
|
||||
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
|
||||
@@ -3927,7 +3915,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3946,7 +3934,7 @@ private module FlowExploration {
|
||||
}
|
||||
|
||||
private predicate partialPathIntoCallable(
|
||||
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
|
||||
PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
@@ -3983,7 +3971,7 @@ private module FlowExploration {
|
||||
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
|
||||
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
|
||||
)
|
||||
@@ -4040,7 +4028,7 @@ private module FlowExploration {
|
||||
apConsRev(ap, c, ap0, config)
|
||||
)
|
||||
or
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
mid.getNode() = p and
|
||||
viableParamArg(_, p, node) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4118,7 +4106,7 @@ private module FlowExploration {
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParameterNode p |
|
||||
exists(PartialPathNodeRev mid, ParamNode p |
|
||||
mid.getNode() = p and
|
||||
p.isParameterOf(_, pos) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4141,7 +4129,7 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
|
||||
PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
|
||||
@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
* 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) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
) and
|
||||
simpleLocalFlowStepExt(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
|
||||
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
|
||||
*/
|
||||
private predicate jumpStep(Node node1, Node node2, Configuration config) {
|
||||
jumpStep(node1, node2) and
|
||||
jumpStepCached(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -388,7 +385,7 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
@@ -515,24 +512,22 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
|
||||
exists(ParamNode p |
|
||||
revFlow(p, toReturn, config) and
|
||||
viableParamArgNodeCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
|
||||
revFlowIn(call, arg, true, config)
|
||||
}
|
||||
|
||||
@@ -597,7 +592,7 @@ private module Stage1 {
|
||||
* Holds if flow may enter through `p` and reach a return node making `p` a
|
||||
* candidate for the origin of a summary.
|
||||
*/
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnKindExt kind |
|
||||
throughFlowNodeCand(p, config) and
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgNodeCand1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
|
||||
Stage1::revFlow(arg, config)
|
||||
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
|
||||
) {
|
||||
viableParamArgNodeCand1(call, p, arg, config) and
|
||||
Stage1::revFlow(p, config) and
|
||||
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, arg, p, config) and
|
||||
exists(int b, int j |
|
||||
@@ -944,10 +938,10 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -992,7 +986,7 @@ private module Stage2 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
)
|
||||
@@ -1133,10 +1127,9 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1146,7 +1139,7 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1199,13 +1192,13 @@ private module Stage2 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand2(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
|
||||
*/
|
||||
private class FlowCheckNode extends Node {
|
||||
FlowCheckNode() {
|
||||
this instanceof CastNode or
|
||||
clearsContent(this, _)
|
||||
castNode(this) or
|
||||
clearsContentCached(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
|
||||
config.isSource(node) or
|
||||
jumpStep(_, node, config) or
|
||||
additionalJumpStep(_, node, config) or
|
||||
node instanceof ParameterNode or
|
||||
node instanceof ParamNode or
|
||||
node instanceof OutNodeExt or
|
||||
store(_, _, node, _) or
|
||||
read(_, _, node) or
|
||||
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getNodeType(node1)
|
||||
t = getNodeDataFlowType(node1)
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2)
|
||||
t = getNodeDataFlowType(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
t = getNodeDataFlowType(node2) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
@@ -1384,7 +1376,7 @@ private module Stage3 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -1443,7 +1435,9 @@ private module Stage3 {
|
||||
bindingset[node, ap]
|
||||
private predicate filter(Node node, Ap ap) {
|
||||
not ap.isClearedAt(node) and
|
||||
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any()
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -1583,10 +1577,10 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -1631,7 +1625,7 @@ private module Stage3 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -1772,10 +1766,9 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1785,7 +1778,7 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1838,13 +1831,13 @@ private module Stage3 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2088,7 +2081,7 @@ private module Stage4 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -2133,11 +2126,8 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(node))
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2158,8 +2148,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCall(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
@@ -2303,10 +2292,10 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -2351,7 +2340,7 @@ private module Stage4 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -2492,10 +2481,9 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -2505,7 +2493,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -2558,13 +2546,13 @@ private module Stage4 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2609,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
|
||||
|
||||
private newtype TSummaryCtx =
|
||||
TSummaryCtxNone() or
|
||||
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||
TSummaryCtxSome(ParamNode p, AccessPath ap) {
|
||||
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
|
||||
}
|
||||
|
||||
@@ -2630,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||
|
||||
/** A summary context from which a flow summary can be generated. */
|
||||
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
private ParameterNode p;
|
||||
private ParamNode p;
|
||||
private AccessPath ap;
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
@@ -2761,7 +2749,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2982,7 +2970,7 @@ class PathNode extends TPathNode {
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
nodeIsHidden(this.getNode()) and
|
||||
hiddenNode(this.getNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
}
|
||||
@@ -3132,7 +3120,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, getNodeEnclosingCallable(midnode)) and
|
||||
localCC = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(midnode)) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
@@ -3151,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -3238,7 +3226,7 @@ pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3251,7 +3239,7 @@ pragma[noinline]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
@@ -3275,7 +3263,7 @@ private predicate pathIntoCallable0(
|
||||
* respectively.
|
||||
*/
|
||||
private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
@@ -3571,7 +3559,7 @@ private module FlowExploration {
|
||||
|
||||
private newtype TSummaryCtx1 =
|
||||
TSummaryCtx1None() or
|
||||
TSummaryCtx1Param(ParameterNode p)
|
||||
TSummaryCtx1Param(ParamNode p)
|
||||
|
||||
private newtype TSummaryCtx2 =
|
||||
TSummaryCtx2None() or
|
||||
@@ -3594,7 +3582,7 @@ private module FlowExploration {
|
||||
cc instanceof CallContextAny and
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
not fullBarrier(node, config) and
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
@@ -3614,7 +3602,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not clearsContentCached(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
)
|
||||
@@ -3628,9 +3616,9 @@ private module FlowExploration {
|
||||
exists(PartialPathNodeFwd mid |
|
||||
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not clearsContent(node, ap.getHead().getContent()) and
|
||||
not clearsContentCached(node, ap.getHead().getContent()) and
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeType(node), ap.getType())
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
)
|
||||
}
|
||||
@@ -3786,7 +3774,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -3800,7 +3788,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
@@ -3816,7 +3804,7 @@ private module FlowExploration {
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
partialPathStoreStep(mid, _, _, node, ap) and
|
||||
@@ -3830,7 +3818,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
apConsFwd(ap, tc, ap0, config) and
|
||||
compatibleTypes(ap.getType(), getNodeType(node))
|
||||
compatibleTypes(ap.getType(), getNodeDataFlowType(node))
|
||||
)
|
||||
or
|
||||
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
|
||||
@@ -3927,7 +3915,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3946,7 +3934,7 @@ private module FlowExploration {
|
||||
}
|
||||
|
||||
private predicate partialPathIntoCallable(
|
||||
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
|
||||
PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
@@ -3983,7 +3971,7 @@ private module FlowExploration {
|
||||
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
|
||||
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
|
||||
)
|
||||
@@ -4040,7 +4028,7 @@ private module FlowExploration {
|
||||
apConsRev(ap, c, ap0, config)
|
||||
)
|
||||
or
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
mid.getNode() = p and
|
||||
viableParamArg(_, p, node) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4118,7 +4106,7 @@ private module FlowExploration {
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParameterNode p |
|
||||
exists(PartialPathNodeRev mid, ParamNode p |
|
||||
mid.getNode() = p and
|
||||
p.isParameterOf(_, pos) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4141,7 +4129,7 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
|
||||
PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
|
||||
@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
* 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) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
) and
|
||||
simpleLocalFlowStepExt(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
|
||||
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
|
||||
*/
|
||||
private predicate jumpStep(Node node1, Node node2, Configuration config) {
|
||||
jumpStep(node1, node2) and
|
||||
jumpStepCached(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -388,7 +385,7 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
@@ -515,24 +512,22 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
|
||||
exists(ParamNode p |
|
||||
revFlow(p, toReturn, config) and
|
||||
viableParamArgNodeCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
|
||||
revFlowIn(call, arg, true, config)
|
||||
}
|
||||
|
||||
@@ -597,7 +592,7 @@ private module Stage1 {
|
||||
* Holds if flow may enter through `p` and reach a return node making `p` a
|
||||
* candidate for the origin of a summary.
|
||||
*/
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnKindExt kind |
|
||||
throughFlowNodeCand(p, config) and
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgNodeCand1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
|
||||
Stage1::revFlow(arg, config)
|
||||
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
|
||||
) {
|
||||
viableParamArgNodeCand1(call, p, arg, config) and
|
||||
Stage1::revFlow(p, config) and
|
||||
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, arg, p, config) and
|
||||
exists(int b, int j |
|
||||
@@ -944,10 +938,10 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -992,7 +986,7 @@ private module Stage2 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
)
|
||||
@@ -1133,10 +1127,9 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1146,7 +1139,7 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1199,13 +1192,13 @@ private module Stage2 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand2(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
|
||||
*/
|
||||
private class FlowCheckNode extends Node {
|
||||
FlowCheckNode() {
|
||||
this instanceof CastNode or
|
||||
clearsContent(this, _)
|
||||
castNode(this) or
|
||||
clearsContentCached(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
|
||||
config.isSource(node) or
|
||||
jumpStep(_, node, config) or
|
||||
additionalJumpStep(_, node, config) or
|
||||
node instanceof ParameterNode or
|
||||
node instanceof ParamNode or
|
||||
node instanceof OutNodeExt or
|
||||
store(_, _, node, _) or
|
||||
read(_, _, node) or
|
||||
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getNodeType(node1)
|
||||
t = getNodeDataFlowType(node1)
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2)
|
||||
t = getNodeDataFlowType(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
t = getNodeDataFlowType(node2) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
@@ -1384,7 +1376,7 @@ private module Stage3 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -1443,7 +1435,9 @@ private module Stage3 {
|
||||
bindingset[node, ap]
|
||||
private predicate filter(Node node, Ap ap) {
|
||||
not ap.isClearedAt(node) and
|
||||
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any()
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -1583,10 +1577,10 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -1631,7 +1625,7 @@ private module Stage3 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -1772,10 +1766,9 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1785,7 +1778,7 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1838,13 +1831,13 @@ private module Stage3 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2088,7 +2081,7 @@ private module Stage4 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -2133,11 +2126,8 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(node))
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2158,8 +2148,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCall(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
@@ -2303,10 +2292,10 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -2351,7 +2340,7 @@ private module Stage4 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -2492,10 +2481,9 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -2505,7 +2493,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -2558,13 +2546,13 @@ private module Stage4 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2609,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
|
||||
|
||||
private newtype TSummaryCtx =
|
||||
TSummaryCtxNone() or
|
||||
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||
TSummaryCtxSome(ParamNode p, AccessPath ap) {
|
||||
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
|
||||
}
|
||||
|
||||
@@ -2630,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||
|
||||
/** A summary context from which a flow summary can be generated. */
|
||||
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
private ParameterNode p;
|
||||
private ParamNode p;
|
||||
private AccessPath ap;
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
@@ -2761,7 +2749,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2982,7 +2970,7 @@ class PathNode extends TPathNode {
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
nodeIsHidden(this.getNode()) and
|
||||
hiddenNode(this.getNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
}
|
||||
@@ -3132,7 +3120,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, getNodeEnclosingCallable(midnode)) and
|
||||
localCC = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(midnode)) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
@@ -3151,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -3238,7 +3226,7 @@ pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3251,7 +3239,7 @@ pragma[noinline]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
@@ -3275,7 +3263,7 @@ private predicate pathIntoCallable0(
|
||||
* respectively.
|
||||
*/
|
||||
private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
@@ -3571,7 +3559,7 @@ private module FlowExploration {
|
||||
|
||||
private newtype TSummaryCtx1 =
|
||||
TSummaryCtx1None() or
|
||||
TSummaryCtx1Param(ParameterNode p)
|
||||
TSummaryCtx1Param(ParamNode p)
|
||||
|
||||
private newtype TSummaryCtx2 =
|
||||
TSummaryCtx2None() or
|
||||
@@ -3594,7 +3582,7 @@ private module FlowExploration {
|
||||
cc instanceof CallContextAny and
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
not fullBarrier(node, config) and
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
@@ -3614,7 +3602,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not clearsContentCached(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
)
|
||||
@@ -3628,9 +3616,9 @@ private module FlowExploration {
|
||||
exists(PartialPathNodeFwd mid |
|
||||
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not clearsContent(node, ap.getHead().getContent()) and
|
||||
not clearsContentCached(node, ap.getHead().getContent()) and
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeType(node), ap.getType())
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
)
|
||||
}
|
||||
@@ -3786,7 +3774,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -3800,7 +3788,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
@@ -3816,7 +3804,7 @@ private module FlowExploration {
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
partialPathStoreStep(mid, _, _, node, ap) and
|
||||
@@ -3830,7 +3818,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
apConsFwd(ap, tc, ap0, config) and
|
||||
compatibleTypes(ap.getType(), getNodeType(node))
|
||||
compatibleTypes(ap.getType(), getNodeDataFlowType(node))
|
||||
)
|
||||
or
|
||||
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
|
||||
@@ -3927,7 +3915,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3946,7 +3934,7 @@ private module FlowExploration {
|
||||
}
|
||||
|
||||
private predicate partialPathIntoCallable(
|
||||
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
|
||||
PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
@@ -3983,7 +3971,7 @@ private module FlowExploration {
|
||||
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
|
||||
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
|
||||
)
|
||||
@@ -4040,7 +4028,7 @@ private module FlowExploration {
|
||||
apConsRev(ap, c, ap0, config)
|
||||
)
|
||||
or
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
mid.getNode() = p and
|
||||
viableParamArg(_, p, node) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4118,7 +4106,7 @@ private module FlowExploration {
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParameterNode p |
|
||||
exists(PartialPathNodeRev mid, ParamNode p |
|
||||
mid.getNode() = p and
|
||||
p.isParameterOf(_, pos) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4141,7 +4129,7 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
|
||||
PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
|
||||
@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
|
||||
* 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) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
) and
|
||||
simpleLocalFlowStepExt(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
|
||||
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
|
||||
*/
|
||||
private predicate jumpStep(Node node1, Node node2, Configuration config) {
|
||||
jumpStep(node1, node2) and
|
||||
jumpStepCached(node1, node2) and
|
||||
not outBarrier(node1, config) and
|
||||
not inBarrier(node2, config) and
|
||||
not fullBarrier(node1, config) and
|
||||
@@ -388,7 +385,7 @@ private module Stage1 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
fwdFlow(arg, cc, config) and
|
||||
viableParamArg(call, _, arg)
|
||||
)
|
||||
@@ -515,24 +512,22 @@ private module Stage1 {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
viableParamArg(call, p, arg) and
|
||||
fwdFlow(arg, config)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
|
||||
exists(ParamNode p |
|
||||
revFlow(p, toReturn, config) and
|
||||
viableParamArgNodeCandFwd1(call, p, arg, config)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) {
|
||||
private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
|
||||
revFlowIn(call, arg, true, config)
|
||||
}
|
||||
|
||||
@@ -597,7 +592,7 @@ private module Stage1 {
|
||||
* Holds if flow may enter through `p` and reach a return node making `p` a
|
||||
* candidate for the origin of a summary.
|
||||
*/
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnKindExt kind |
|
||||
throughFlowNodeCand(p, config) and
|
||||
returnFlowCallableNodeCand(c, kind, config) and
|
||||
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate viableParamArgNodeCand1(
|
||||
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config
|
||||
DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
|
||||
) {
|
||||
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
|
||||
Stage1::revFlow(arg, config)
|
||||
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
|
||||
) {
|
||||
viableParamArgNodeCand1(call, p, arg, config) and
|
||||
Stage1::revFlow(p, config) and
|
||||
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand1(
|
||||
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, arg, p, config) and
|
||||
exists(int b, int j |
|
||||
@@ -944,10 +938,10 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -992,7 +986,7 @@ private module Stage2 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
)
|
||||
@@ -1133,10 +1127,9 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1146,7 +1139,7 @@ private module Stage2 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1199,13 +1192,13 @@ private module Stage2 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCallNodeCand2(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config)) and
|
||||
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
|
||||
*/
|
||||
private class FlowCheckNode extends Node {
|
||||
FlowCheckNode() {
|
||||
this instanceof CastNode or
|
||||
clearsContent(this, _)
|
||||
castNode(this) or
|
||||
clearsContentCached(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
|
||||
config.isSource(node) or
|
||||
jumpStep(_, node, config) or
|
||||
additionalJumpStep(_, node, config) or
|
||||
node instanceof ParameterNode or
|
||||
node instanceof ParamNode or
|
||||
node instanceof OutNodeExt or
|
||||
store(_, _, node, _) or
|
||||
read(_, _, node) or
|
||||
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
|
||||
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowEntry(node1, pragma[only_bind_into](config)) and
|
||||
(
|
||||
localFlowStepNodeCand1(node1, node2, config) and
|
||||
preservesValue = true and
|
||||
t = getNodeType(node1)
|
||||
t = getNodeDataFlowType(node1)
|
||||
or
|
||||
additionalLocalFlowStepNodeCand2(node1, node2, config) and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2)
|
||||
t = getNodeDataFlowType(node2)
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(getNodeEnclosingCallable(node1)) and
|
||||
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
or
|
||||
exists(Node mid |
|
||||
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
|
||||
additionalLocalFlowStepNodeCand2(mid, node2, config) and
|
||||
not mid instanceof FlowCheckNode and
|
||||
preservesValue = false and
|
||||
t = getNodeType(node2) and
|
||||
t = getNodeDataFlowType(node2) and
|
||||
Stage2::revFlow(node2, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
@@ -1384,7 +1376,7 @@ private module Stage3 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -1443,7 +1435,9 @@ private module Stage3 {
|
||||
bindingset[node, ap]
|
||||
private predicate filter(Node node, Ap ap) {
|
||||
not ap.isClearedAt(node) and
|
||||
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any()
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
}
|
||||
|
||||
bindingset[ap, contentType]
|
||||
@@ -1583,10 +1577,10 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -1631,7 +1625,7 @@ private module Stage3 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -1772,10 +1766,9 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -1785,7 +1778,7 @@ private module Stage3 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -1838,13 +1831,13 @@ private module Stage3 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2088,7 +2081,7 @@ private module Stage4 {
|
||||
private ApApprox getApprox(Ap ap) { result = ap.getFront() }
|
||||
|
||||
private ApNil getApNil(Node node) {
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node))
|
||||
PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
|
||||
}
|
||||
|
||||
bindingset[tc, tail]
|
||||
@@ -2133,11 +2126,8 @@ private module Stage4 {
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
|
||||
exists(Cc cc0 |
|
||||
cc = pragma[only_bind_into](cc0) and
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(cc0, getNodeEnclosingCallable(node))
|
||||
)
|
||||
localFlowEntry(node, config) and
|
||||
result = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(node))
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2158,8 +2148,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowIntoCall(
|
||||
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
|
||||
) {
|
||||
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
|
||||
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
|
||||
@@ -2303,10 +2292,10 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowIn(
|
||||
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg, boolean allowsFieldFlow |
|
||||
exists(ArgNode arg, boolean allowsFieldFlow |
|
||||
fwdFlow(arg, outercc, argAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
|
||||
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
|
||||
@@ -2351,7 +2340,7 @@ private module Stage4 {
|
||||
private predicate fwdFlowIsEntered(
|
||||
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
@@ -2492,10 +2481,9 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowIn(
|
||||
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap,
|
||||
Configuration config
|
||||
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, boolean allowsFieldFlow |
|
||||
exists(ParamNode p, boolean allowsFieldFlow |
|
||||
revFlow(p, toReturn, returnAp, ap, config) and
|
||||
flowIntoCall(call, arg, p, allowsFieldFlow, config)
|
||||
|
|
||||
@@ -2505,7 +2493,7 @@ private module Stage4 {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlowInToReturn(
|
||||
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
|
||||
}
|
||||
@@ -2558,13 +2546,13 @@ private module Stage4 {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate parameterFlow(
|
||||
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
|
||||
) {
|
||||
revFlow(p, true, apSome(ap0), ap, config) and
|
||||
c = getNodeEnclosingCallable(p)
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = getNodeEnclosingCallable(ret) and
|
||||
@@ -2609,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
|
||||
|
||||
private newtype TSummaryCtx =
|
||||
TSummaryCtxNone() or
|
||||
TSummaryCtxSome(ParameterNode p, AccessPath ap) {
|
||||
TSummaryCtxSome(ParamNode p, AccessPath ap) {
|
||||
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
|
||||
}
|
||||
|
||||
@@ -2630,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
|
||||
|
||||
/** A summary context from which a flow summary can be generated. */
|
||||
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
private ParameterNode p;
|
||||
private ParamNode p;
|
||||
private AccessPath ap;
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
@@ -2761,7 +2749,7 @@ private newtype TPathNode =
|
||||
config.isSource(node) and
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
exists(PathNodeMid mid |
|
||||
@@ -2982,7 +2970,7 @@ class PathNode extends TPathNode {
|
||||
Configuration getConfiguration() { none() }
|
||||
|
||||
private predicate isHidden() {
|
||||
nodeIsHidden(this.getNode()) and
|
||||
hiddenNode(this.getNode()) and
|
||||
not this.isSource() and
|
||||
not this instanceof PathNodeSink
|
||||
}
|
||||
@@ -3132,7 +3120,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, getNodeEnclosingCallable(midnode)) and
|
||||
localCC = getLocalCallContext(pragma[only_bind_out](cc), getNodeEnclosingCallable(midnode)) and
|
||||
ap0 = mid.getAp()
|
||||
|
|
||||
localFlowBigStep(midnode, node, true, _, conf, localCC) and
|
||||
@@ -3151,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
|
||||
cc instanceof CallContextAny and
|
||||
sc instanceof SummaryCtxNone and
|
||||
mid.getAp() instanceof AccessPathNil and
|
||||
ap = TAccessPathNil(getNodeType(node))
|
||||
ap = TAccessPathNil(getNodeDataFlowType(node))
|
||||
or
|
||||
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
|
||||
sc = mid.getSummaryCtx()
|
||||
@@ -3238,7 +3226,7 @@ pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3251,7 +3239,7 @@ pragma[noinline]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
)
|
||||
@@ -3275,7 +3263,7 @@ private predicate pathIntoCallable0(
|
||||
* respectively.
|
||||
*/
|
||||
private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
@@ -3571,7 +3559,7 @@ private module FlowExploration {
|
||||
|
||||
private newtype TSummaryCtx1 =
|
||||
TSummaryCtx1None() or
|
||||
TSummaryCtx1Param(ParameterNode p)
|
||||
TSummaryCtx1Param(ParamNode p)
|
||||
|
||||
private newtype TSummaryCtx2 =
|
||||
TSummaryCtx2None() or
|
||||
@@ -3594,7 +3582,7 @@ private module FlowExploration {
|
||||
cc instanceof CallContextAny and
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
not fullBarrier(node, config) and
|
||||
exists(config.explorationLimit())
|
||||
or
|
||||
@@ -3614,7 +3602,7 @@ private module FlowExploration {
|
||||
or
|
||||
exists(PartialPathNodeRev mid |
|
||||
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
|
||||
not clearsContent(node, ap.getHead()) and
|
||||
not clearsContentCached(node, ap.getHead()) and
|
||||
not fullBarrier(node, config) and
|
||||
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
|
||||
)
|
||||
@@ -3628,9 +3616,9 @@ private module FlowExploration {
|
||||
exists(PartialPathNodeFwd mid |
|
||||
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
|
||||
not fullBarrier(node, config) and
|
||||
not clearsContent(node, ap.getHead().getContent()) and
|
||||
not clearsContentCached(node, ap.getHead().getContent()) and
|
||||
if node instanceof CastingNode
|
||||
then compatibleTypes(getNodeType(node), ap.getType())
|
||||
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
|
||||
else any()
|
||||
)
|
||||
}
|
||||
@@ -3786,7 +3774,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
|
||||
(
|
||||
localFlowStep(mid.getNode(), node, config) and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -3800,7 +3788,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
)
|
||||
or
|
||||
@@ -3816,7 +3804,7 @@ private module FlowExploration {
|
||||
sc1 = TSummaryCtx1None() and
|
||||
sc2 = TSummaryCtx2None() and
|
||||
mid.getAp() instanceof PartialAccessPathNil and
|
||||
ap = TPartialNil(getNodeType(node)) and
|
||||
ap = TPartialNil(getNodeDataFlowType(node)) and
|
||||
config = mid.getConfiguration()
|
||||
or
|
||||
partialPathStoreStep(mid, _, _, node, ap) and
|
||||
@@ -3830,7 +3818,7 @@ private module FlowExploration {
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
apConsFwd(ap, tc, ap0, config) and
|
||||
compatibleTypes(ap.getType(), getNodeType(node))
|
||||
compatibleTypes(ap.getType(), getNodeDataFlowType(node))
|
||||
)
|
||||
or
|
||||
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
|
||||
@@ -3927,7 +3915,7 @@ private module FlowExploration {
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
arg = mid.getNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
@@ -3946,7 +3934,7 @@ private module FlowExploration {
|
||||
}
|
||||
|
||||
private predicate partialPathIntoCallable(
|
||||
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc,
|
||||
PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
@@ -3983,7 +3971,7 @@ private module FlowExploration {
|
||||
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
|
||||
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
|
||||
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
|
||||
)
|
||||
@@ -4040,7 +4028,7 @@ private module FlowExploration {
|
||||
apConsRev(ap, c, ap0, config)
|
||||
)
|
||||
or
|
||||
exists(ParameterNode p |
|
||||
exists(ParamNode p |
|
||||
mid.getNode() = p and
|
||||
viableParamArg(_, p, node) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4118,7 +4106,7 @@ private module FlowExploration {
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParameterNode p |
|
||||
exists(PartialPathNodeRev mid, ParamNode p |
|
||||
mid.getNode() = p and
|
||||
p.isParameterOf(_, pos) and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
@@ -4141,7 +4129,7 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config
|
||||
PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, int pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
|
||||
@@ -31,26 +31,26 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
|
||||
* 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
|
||||
* of a call, we use the results of the analysis recursively to resolve lambda
|
||||
* 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) {
|
||||
private predicate viableParamNonLambda(DataFlowCall call, int i, ParamNode p) {
|
||||
p.isParameterOf(viableCallable(call), i)
|
||||
}
|
||||
|
||||
private predicate viableParamLambda(DataFlowCall call, int i, ParameterNode p) {
|
||||
private predicate viableParamLambda(DataFlowCall call, int i, ParamNode p) {
|
||||
p.isParameterOf(viableCallableLambda(call, _), i)
|
||||
}
|
||||
|
||||
private predicate viableParamArgNonLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
|
||||
private predicate viableParamArgNonLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||
exists(int i |
|
||||
viableParamNonLambda(call, i, p) and
|
||||
arg.argumentOf(call, i)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate viableParamArgLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
|
||||
private predicate viableParamArgLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||
exists(int i |
|
||||
viableParamLambda(call, i, p) and
|
||||
arg.argumentOf(call, i)
|
||||
@@ -118,8 +118,8 @@ private module LambdaFlow {
|
||||
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))
|
||||
if castNode(node) or node instanceof ArgNode or node instanceof ReturnNode
|
||||
then compatibleTypes(t, getNodeDataFlowType(node))
|
||||
else any()
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ private module LambdaFlow {
|
||||
boolean toJump, DataFlowCallOption lastCall
|
||||
) {
|
||||
lambdaCall(lambdaCall, kind, node) and
|
||||
t = getNodeType(node) and
|
||||
t = getNodeDataFlowType(node) and
|
||||
toReturn = false and
|
||||
toJump = false and
|
||||
lastCall = TDataFlowCallNone()
|
||||
@@ -146,7 +146,7 @@ private module LambdaFlow {
|
||||
getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid)
|
||||
|
|
||||
preservesValue = false and
|
||||
t = getNodeType(node)
|
||||
t = getNodeDataFlowType(node)
|
||||
or
|
||||
preservesValue = true and
|
||||
t = t0
|
||||
@@ -160,7 +160,7 @@ private module LambdaFlow {
|
||||
toJump = true and
|
||||
lastCall = TDataFlowCallNone()
|
||||
|
|
||||
jumpStep(node, mid) and
|
||||
jumpStepCached(node, mid) and
|
||||
t = t0
|
||||
or
|
||||
exists(boolean preservesValue |
|
||||
@@ -168,7 +168,7 @@ private module LambdaFlow {
|
||||
getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid)
|
||||
|
|
||||
preservesValue = false and
|
||||
t = getNodeType(node)
|
||||
t = getNodeDataFlowType(node)
|
||||
or
|
||||
preservesValue = true and
|
||||
t = t0
|
||||
@@ -176,7 +176,7 @@ private module LambdaFlow {
|
||||
)
|
||||
or
|
||||
// flow into a callable
|
||||
exists(ParameterNode p, DataFlowCallOption lastCall0, DataFlowCall call |
|
||||
exists(ParamNode p, DataFlowCallOption lastCall0, DataFlowCall call |
|
||||
revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and
|
||||
(
|
||||
if lastCall0 = TDataFlowCallNone() and toJump = false
|
||||
@@ -227,7 +227,7 @@ private module LambdaFlow {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlowIn(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, ParameterNode p, DataFlowType t, boolean toJump,
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, ParamNode p, DataFlowType t, boolean toJump,
|
||||
DataFlowCallOption lastCall
|
||||
) {
|
||||
revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall)
|
||||
@@ -242,6 +242,89 @@ private DataFlowCallable viableCallableExt(DataFlowCall call) {
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
/**
|
||||
* If needed, call this predicate from `DataFlowImplSpecific.qll` in order to
|
||||
* force a stage-dependency on the `DataFlowImplCommon.qll` stage and therby
|
||||
* collapsing the two stages.
|
||||
*/
|
||||
cached
|
||||
predicate forceCachingInSameStage() { any() }
|
||||
|
||||
cached
|
||||
predicate nodeEnclosingCallable(Node n, DataFlowCallable c) { c = n.getEnclosingCallable() }
|
||||
|
||||
cached
|
||||
predicate callEnclosingCallable(DataFlowCall call, DataFlowCallable c) {
|
||||
c = call.getEnclosingCallable()
|
||||
}
|
||||
|
||||
cached
|
||||
predicate nodeDataFlowType(Node n, DataFlowType t) { t = getNodeType(n) }
|
||||
|
||||
cached
|
||||
predicate jumpStepCached(Node node1, Node node2) { jumpStep(node1, node2) }
|
||||
|
||||
cached
|
||||
predicate clearsContentCached(Node n, Content c) { clearsContent(n, c) }
|
||||
|
||||
cached
|
||||
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
|
||||
|
||||
cached
|
||||
predicate outNodeExt(Node n) {
|
||||
n instanceof OutNode
|
||||
or
|
||||
n.(PostUpdateNode).getPreUpdateNode() instanceof ArgNode
|
||||
}
|
||||
|
||||
cached
|
||||
predicate hiddenNode(Node n) { nodeIsHidden(n) }
|
||||
|
||||
cached
|
||||
OutNodeExt getAnOutNodeExt(DataFlowCall call, ReturnKindExt k) {
|
||||
result = getAnOutNode(call, k.(ValueReturnKind).getKind())
|
||||
or
|
||||
exists(ArgNode arg |
|
||||
result.(PostUpdateNode).getPreUpdateNode() = arg and
|
||||
arg.argumentOf(call, k.(ParamUpdateReturnKind).getPosition())
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate returnNodeExt(Node n, ReturnKindExt k) {
|
||||
k = TValueReturn(n.(ReturnNode).getKind())
|
||||
or
|
||||
exists(ParamNode p, int pos |
|
||||
parameterValueFlowsToPreUpdate(p, n) and
|
||||
p.isParameterOf(_, pos) and
|
||||
k = TParamUpdate(pos)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate castNode(Node n) { n instanceof CastNode }
|
||||
|
||||
cached
|
||||
predicate castingNode(Node n) {
|
||||
castNode(n) or
|
||||
n instanceof ParamNode or
|
||||
n instanceof OutNodeExt or
|
||||
// For reads, `x.f`, we want to check that the tracked type after the read (which
|
||||
// is obtained by popping the head of the access path stack) is compatible with
|
||||
// the type of `x.f`.
|
||||
read(_, _, n)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate parameterNode(Node n, DataFlowCallable c, int i) {
|
||||
n.(ParameterNode).isParameterOf(c, i)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate argumentNode(Node n, DataFlowCall call, int pos) {
|
||||
n.(ArgumentNode).argumentOf(call, pos)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a viable target for the lambda call `call`.
|
||||
*
|
||||
@@ -261,7 +344,7 @@ private module Cached {
|
||||
* The instance parameter is considered to have index `-1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate viableParam(DataFlowCall call, int i, ParameterNode p) {
|
||||
private predicate viableParam(DataFlowCall call, int i, ParamNode p) {
|
||||
p.isParameterOf(viableCallableExt(call), i)
|
||||
}
|
||||
|
||||
@@ -270,11 +353,11 @@ private module Cached {
|
||||
* dispatch into account.
|
||||
*/
|
||||
cached
|
||||
predicate viableParamArg(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
|
||||
predicate viableParamArg(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||
exists(int i |
|
||||
viableParam(call, i, p) and
|
||||
arg.argumentOf(call, i) and
|
||||
compatibleTypes(getNodeType(arg), getNodeType(p))
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -312,7 +395,7 @@ private module Cached {
|
||||
* `read` indicates whether it is contents of `p` that can flow to `node`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate parameterValueFlowCand(ParameterNode p, Node node, boolean read) {
|
||||
private predicate parameterValueFlowCand(ParamNode p, Node node, boolean read) {
|
||||
p = node and
|
||||
read = false
|
||||
or
|
||||
@@ -325,30 +408,30 @@ private module Cached {
|
||||
// read
|
||||
exists(Node mid |
|
||||
parameterValueFlowCand(p, mid, false) and
|
||||
readStep(mid, _, node) and
|
||||
read(mid, _, node) and
|
||||
read = true
|
||||
)
|
||||
or
|
||||
// flow through: no prior read
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
parameterValueFlowArgCand(p, arg, false) and
|
||||
argumentValueFlowsThroughCand(arg, node, read)
|
||||
)
|
||||
or
|
||||
// flow through: no read inside method
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
parameterValueFlowArgCand(p, arg, read) and
|
||||
argumentValueFlowsThroughCand(arg, node, false)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterValueFlowArgCand(ParameterNode p, ArgumentNode arg, boolean read) {
|
||||
private predicate parameterValueFlowArgCand(ParamNode p, ArgNode arg, boolean read) {
|
||||
parameterValueFlowCand(p, arg, read)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate parameterValueFlowsToPreUpdateCand(ParameterNode p, PostUpdateNode n) {
|
||||
predicate parameterValueFlowsToPreUpdateCand(ParamNode p, PostUpdateNode n) {
|
||||
parameterValueFlowCand(p, n.getPreUpdateNode(), false)
|
||||
}
|
||||
|
||||
@@ -360,7 +443,7 @@ private module Cached {
|
||||
* `read` indicates whether it is contents of `p` that can flow to the return
|
||||
* node.
|
||||
*/
|
||||
predicate parameterValueFlowReturnCand(ParameterNode p, ReturnKind kind, boolean read) {
|
||||
predicate parameterValueFlowReturnCand(ParamNode p, ReturnKind kind, boolean read) {
|
||||
exists(ReturnNode ret |
|
||||
parameterValueFlowCand(p, ret, read) and
|
||||
kind = ret.getKind()
|
||||
@@ -369,9 +452,9 @@ private module Cached {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate argumentValueFlowsThroughCand0(
|
||||
DataFlowCall call, ArgumentNode arg, ReturnKind kind, boolean read
|
||||
DataFlowCall call, ArgNode arg, ReturnKind kind, boolean read
|
||||
) {
|
||||
exists(ParameterNode param | viableParamArg(call, param, arg) |
|
||||
exists(ParamNode param | viableParamArg(call, param, arg) |
|
||||
parameterValueFlowReturnCand(param, kind, read)
|
||||
)
|
||||
}
|
||||
@@ -382,14 +465,14 @@ private module Cached {
|
||||
*
|
||||
* `read` indicates whether it is contents of `arg` that can flow to `out`.
|
||||
*/
|
||||
predicate argumentValueFlowsThroughCand(ArgumentNode arg, Node out, boolean read) {
|
||||
predicate argumentValueFlowsThroughCand(ArgNode arg, Node out, boolean read) {
|
||||
exists(DataFlowCall call, ReturnKind kind |
|
||||
argumentValueFlowsThroughCand0(call, arg, kind, read) and
|
||||
out = getAnOutNode(call, kind)
|
||||
)
|
||||
}
|
||||
|
||||
predicate cand(ParameterNode p, Node n) {
|
||||
predicate cand(ParamNode p, Node n) {
|
||||
parameterValueFlowCand(p, n, _) and
|
||||
(
|
||||
parameterValueFlowReturnCand(p, _, _)
|
||||
@@ -416,21 +499,21 @@ private module Cached {
|
||||
* If a read step was taken, then `read` captures the `Content`, the
|
||||
* container type, and the content type.
|
||||
*/
|
||||
predicate parameterValueFlow(ParameterNode p, Node node, ReadStepTypesOption read) {
|
||||
predicate parameterValueFlow(ParamNode p, Node node, ReadStepTypesOption read) {
|
||||
parameterValueFlow0(p, node, read) and
|
||||
if node instanceof CastingNode
|
||||
then
|
||||
// normal flow through
|
||||
read = TReadStepTypesNone() and
|
||||
compatibleTypes(getNodeType(p), getNodeType(node))
|
||||
compatibleTypes(getNodeDataFlowType(p), getNodeDataFlowType(node))
|
||||
or
|
||||
// getter
|
||||
compatibleTypes(read.getContentType(), getNodeType(node))
|
||||
compatibleTypes(read.getContentType(), getNodeDataFlowType(node))
|
||||
else any()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) {
|
||||
private predicate parameterValueFlow0(ParamNode p, Node node, ReadStepTypesOption read) {
|
||||
p = node and
|
||||
Cand::cand(p, _) and
|
||||
read = TReadStepTypesNone()
|
||||
@@ -447,7 +530,7 @@ private module Cached {
|
||||
readStepWithTypes(mid, read.getContainerType(), read.getContent(), node,
|
||||
read.getContentType()) and
|
||||
Cand::parameterValueFlowReturnCand(p, _, true) and
|
||||
compatibleTypes(getNodeType(p), read.getContainerType())
|
||||
compatibleTypes(getNodeDataFlowType(p), read.getContainerType())
|
||||
)
|
||||
or
|
||||
parameterValueFlow0_0(TReadStepTypesNone(), p, node, read)
|
||||
@@ -455,34 +538,32 @@ private module Cached {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterValueFlow0_0(
|
||||
ReadStepTypesOption mustBeNone, ParameterNode p, Node node, ReadStepTypesOption read
|
||||
ReadStepTypesOption mustBeNone, ParamNode p, Node node, ReadStepTypesOption read
|
||||
) {
|
||||
// flow through: no prior read
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
parameterValueFlowArg(p, arg, mustBeNone) and
|
||||
argumentValueFlowsThrough(arg, read, node)
|
||||
)
|
||||
or
|
||||
// flow through: no read inside method
|
||||
exists(ArgumentNode arg |
|
||||
exists(ArgNode arg |
|
||||
parameterValueFlowArg(p, arg, read) and
|
||||
argumentValueFlowsThrough(arg, mustBeNone, node)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterValueFlowArg(
|
||||
ParameterNode p, ArgumentNode arg, ReadStepTypesOption read
|
||||
) {
|
||||
private predicate parameterValueFlowArg(ParamNode p, ArgNode arg, ReadStepTypesOption read) {
|
||||
parameterValueFlow(p, arg, read) and
|
||||
Cand::argumentValueFlowsThroughCand(arg, _, _)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate argumentValueFlowsThrough0(
|
||||
DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read
|
||||
DataFlowCall call, ArgNode arg, ReturnKind kind, ReadStepTypesOption read
|
||||
) {
|
||||
exists(ParameterNode param | viableParamArg(call, param, arg) |
|
||||
exists(ParamNode param | viableParamArg(call, param, arg) |
|
||||
parameterValueFlowReturn(param, kind, read)
|
||||
)
|
||||
}
|
||||
@@ -496,18 +577,18 @@ private module Cached {
|
||||
* container type, and the content type.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) {
|
||||
predicate argumentValueFlowsThrough(ArgNode arg, ReadStepTypesOption read, Node out) {
|
||||
exists(DataFlowCall call, ReturnKind kind |
|
||||
argumentValueFlowsThrough0(call, arg, kind, read) and
|
||||
out = getAnOutNode(call, kind)
|
||||
|
|
||||
// normal flow through
|
||||
read = TReadStepTypesNone() and
|
||||
compatibleTypes(getNodeType(arg), getNodeType(out))
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(out))
|
||||
or
|
||||
// getter
|
||||
compatibleTypes(getNodeType(arg), read.getContainerType()) and
|
||||
compatibleTypes(read.getContentType(), getNodeType(out))
|
||||
compatibleTypes(getNodeDataFlowType(arg), read.getContainerType()) and
|
||||
compatibleTypes(read.getContentType(), getNodeDataFlowType(out))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -516,7 +597,7 @@ private module Cached {
|
||||
* value-preserving steps and a single read step, not taking call
|
||||
* contexts into account, thus representing a getter-step.
|
||||
*/
|
||||
predicate getterStep(ArgumentNode arg, Content c, Node out) {
|
||||
predicate getterStep(ArgNode arg, Content c, Node out) {
|
||||
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
|
||||
}
|
||||
|
||||
@@ -529,7 +610,7 @@ private module Cached {
|
||||
* container type, and the content type.
|
||||
*/
|
||||
private predicate parameterValueFlowReturn(
|
||||
ParameterNode p, ReturnKind kind, ReadStepTypesOption read
|
||||
ParamNode p, ReturnKind kind, ReadStepTypesOption read
|
||||
) {
|
||||
exists(ReturnNode ret |
|
||||
parameterValueFlow(p, ret, read) and
|
||||
@@ -553,7 +634,7 @@ private module Cached {
|
||||
private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) {
|
||||
mayBenefitFromCallContext(call, callable)
|
||||
or
|
||||
callable = call.getEnclosingCallable() and
|
||||
callEnclosingCallable(call, callable) and
|
||||
exists(viableCallableLambda(call, TDataFlowCallSome(_)))
|
||||
}
|
||||
|
||||
@@ -611,7 +692,7 @@ private module Cached {
|
||||
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
|
||||
tgts = strictcount(DataFlowCall ctx | callEnclosingCallable(call, viableCallableExt(ctx))) and
|
||||
ctxtgts < tgts
|
||||
)
|
||||
}
|
||||
@@ -635,8 +716,7 @@ private module Cached {
|
||||
* Holds if `p` can flow to the pre-update node associated with post-update
|
||||
* node `n`, in the same callable, using only value-preserving steps.
|
||||
*/
|
||||
cached
|
||||
predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) {
|
||||
private predicate parameterValueFlowsToPreUpdate(ParamNode p, PostUpdateNode n) {
|
||||
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
|
||||
}
|
||||
|
||||
@@ -644,9 +724,9 @@ private module Cached {
|
||||
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
|
||||
) {
|
||||
storeStep(node1, c, node2) and
|
||||
readStep(_, c, _) and
|
||||
contentType = getNodeType(node1) and
|
||||
containerType = getNodeType(node2)
|
||||
read(_, c, _) and
|
||||
contentType = getNodeDataFlowType(node1) and
|
||||
containerType = getNodeDataFlowType(node2)
|
||||
or
|
||||
exists(Node n1, Node n2 |
|
||||
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
|
||||
@@ -654,12 +734,15 @@ private module Cached {
|
||||
|
|
||||
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
|
||||
or
|
||||
readStep(n2, c, n1) and
|
||||
contentType = getNodeType(n1) and
|
||||
containerType = getNodeType(n2)
|
||||
read(n2, c, n1) and
|
||||
contentType = getNodeDataFlowType(n1) and
|
||||
containerType = getNodeDataFlowType(n2)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate read(Node node1, Content c, Node node2) { readStep(node1, c, node2) }
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via a direct assignment to
|
||||
* `f`.
|
||||
@@ -678,8 +761,9 @@ private module Cached {
|
||||
* are aliases. A typical example is a function returning `this`, implementing a fluent
|
||||
* interface.
|
||||
*/
|
||||
cached
|
||||
predicate reverseStepThroughInputOutputAlias(PostUpdateNode fromNode, PostUpdateNode toNode) {
|
||||
private predicate reverseStepThroughInputOutputAlias(
|
||||
PostUpdateNode fromNode, PostUpdateNode toNode
|
||||
) {
|
||||
exists(Node fromPre, Node toPre |
|
||||
fromPre = fromNode.getPreUpdateNode() and
|
||||
toPre = toNode.getPreUpdateNode()
|
||||
@@ -688,14 +772,20 @@ private module Cached {
|
||||
// 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)
|
||||
toPre.(ArgNode).argumentOf(c, _) and
|
||||
simpleLocalFlowStep(toPre.(ArgNode), fromPre)
|
||||
)
|
||||
or
|
||||
argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate simpleLocalFlowStepExt(Node node1, Node node2) {
|
||||
simpleLocalFlowStep(node1, node2) or
|
||||
reverseStepThroughInputOutputAlias(node1, node2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the call context `call` either improves virtual dispatch in
|
||||
* `callable` or if it allows us to prune unreachable nodes in `callable`.
|
||||
@@ -704,7 +794,7 @@ private module Cached {
|
||||
predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
|
||||
reducedViableImplInCallContext(_, callable, call)
|
||||
or
|
||||
exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCall(n, call))
|
||||
exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call))
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -726,12 +816,12 @@ private module Cached {
|
||||
cached
|
||||
newtype TLocalFlowCallContext =
|
||||
TAnyLocalCall() or
|
||||
TSpecificLocalCall(DataFlowCall call) { isUnreachableInCall(_, call) }
|
||||
TSpecificLocalCall(DataFlowCall call) { isUnreachableInCallCached(_, call) }
|
||||
|
||||
cached
|
||||
newtype TReturnKindExt =
|
||||
TValueReturn(ReturnKind kind) or
|
||||
TParamUpdate(int pos) { exists(ParameterNode p | p.isParameterOf(_, pos)) }
|
||||
TParamUpdate(int pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
|
||||
|
||||
cached
|
||||
newtype TBooleanOption =
|
||||
@@ -761,23 +851,15 @@ private module Cached {
|
||||
* A `Node` at which a cast can occur such that the type should be checked.
|
||||
*/
|
||||
class CastingNode extends Node {
|
||||
CastingNode() {
|
||||
this instanceof ParameterNode or
|
||||
this instanceof CastNode or
|
||||
this instanceof OutNodeExt or
|
||||
// For reads, `x.f`, we want to check that the tracked type after the read (which
|
||||
// is obtained by popping the head of the access path stack) is compatible with
|
||||
// the type of `x.f`.
|
||||
readStep(_, _, this)
|
||||
}
|
||||
CastingNode() { castingNode(this) }
|
||||
}
|
||||
|
||||
private predicate readStepWithTypes(
|
||||
Node n1, DataFlowType container, Content c, Node n2, DataFlowType content
|
||||
) {
|
||||
readStep(n1, c, n2) and
|
||||
container = getNodeType(n1) and
|
||||
content = getNodeType(n2)
|
||||
read(n1, c, n2) and
|
||||
container = getNodeDataFlowType(n1) and
|
||||
content = getNodeDataFlowType(n2)
|
||||
}
|
||||
|
||||
private newtype TReadStepTypesOption =
|
||||
@@ -854,7 +936,7 @@ class CallContextSomeCall extends CallContextCall, TSomeCall {
|
||||
override string toString() { result = "CcSomeCall" }
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) {
|
||||
exists(ParameterNode p | getNodeEnclosingCallable(p) = callable)
|
||||
exists(ParamNode p | getNodeEnclosingCallable(p) = callable)
|
||||
}
|
||||
|
||||
override predicate matchesCall(DataFlowCall call) { any() }
|
||||
@@ -866,7 +948,7 @@ class CallContextReturn extends CallContextNoCall, TReturn {
|
||||
}
|
||||
|
||||
override predicate relevantFor(DataFlowCallable callable) {
|
||||
exists(DataFlowCall call | this = TReturn(_, call) and call.getEnclosingCallable() = callable)
|
||||
exists(DataFlowCall call | this = TReturn(_, call) and callEnclosingCallable(call, callable))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -899,7 +981,7 @@ class LocalCallContextSpecificCall extends LocalCallContext, TSpecificLocalCall
|
||||
}
|
||||
|
||||
private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) {
|
||||
exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCall(n, call))
|
||||
exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCallCached(n, call))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -913,26 +995,37 @@ LocalCallContext getLocalCallContext(CallContext ctx, DataFlowCallable callable)
|
||||
else result instanceof LocalCallContextAny
|
||||
}
|
||||
|
||||
/**
|
||||
* The value of a parameter at function entry, viewed as a node in a data
|
||||
* flow graph.
|
||||
*/
|
||||
class ParamNode extends Node {
|
||||
ParamNode() { parameterNode(this, _, _) }
|
||||
|
||||
/**
|
||||
* Holds if this node is the parameter of callable `c` at the specified
|
||||
* (zero-based) position.
|
||||
*/
|
||||
predicate isParameterOf(DataFlowCallable c, int i) { parameterNode(this, c, i) }
|
||||
}
|
||||
|
||||
/** A data-flow node that represents a call argument. */
|
||||
class ArgNode extends Node {
|
||||
ArgNode() { argumentNode(this, _, _) }
|
||||
|
||||
/** Holds if this argument occurs at the given position in the given call. */
|
||||
final predicate argumentOf(DataFlowCall call, int pos) { argumentNode(this, call, pos) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A node from which flow can return to the caller. This is either a regular
|
||||
* `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter.
|
||||
*/
|
||||
class ReturnNodeExt extends Node {
|
||||
ReturnNodeExt() {
|
||||
this instanceof ReturnNode or
|
||||
parameterValueFlowsToPreUpdate(_, this)
|
||||
}
|
||||
ReturnNodeExt() { returnNodeExt(this, _) }
|
||||
|
||||
/** Gets the kind of this returned value. */
|
||||
ReturnKindExt getKind() {
|
||||
result = TValueReturn(this.(ReturnNode).getKind())
|
||||
or
|
||||
exists(ParameterNode p, int pos |
|
||||
parameterValueFlowsToPreUpdate(p, this) and
|
||||
p.isParameterOf(_, pos) and
|
||||
result = TParamUpdate(pos)
|
||||
)
|
||||
}
|
||||
ReturnKindExt getKind() { returnNodeExt(this, result) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -940,11 +1033,7 @@ class ReturnNodeExt extends Node {
|
||||
* or a post-update node associated with a call argument.
|
||||
*/
|
||||
class OutNodeExt extends Node {
|
||||
OutNodeExt() {
|
||||
this instanceof OutNode
|
||||
or
|
||||
this.(PostUpdateNode).getPreUpdateNode() instanceof ArgumentNode
|
||||
}
|
||||
OutNodeExt() { outNodeExt(this) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -957,7 +1046,7 @@ abstract class ReturnKindExt extends TReturnKindExt {
|
||||
abstract string toString();
|
||||
|
||||
/** Gets a node corresponding to data flow out of `call`. */
|
||||
abstract OutNodeExt getAnOutNode(DataFlowCall call);
|
||||
final OutNodeExt getAnOutNode(DataFlowCall call) { result = getAnOutNodeExt(call, this) }
|
||||
}
|
||||
|
||||
class ValueReturnKind extends ReturnKindExt, TValueReturn {
|
||||
@@ -968,10 +1057,6 @@ class ValueReturnKind extends ReturnKindExt, TValueReturn {
|
||||
ReturnKind getKind() { result = kind }
|
||||
|
||||
override string toString() { result = kind.toString() }
|
||||
|
||||
override OutNodeExt getAnOutNode(DataFlowCall call) {
|
||||
result = getAnOutNode(call, this.getKind())
|
||||
}
|
||||
}
|
||||
|
||||
class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
|
||||
@@ -982,13 +1067,6 @@ class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
|
||||
int getPosition() { result = pos }
|
||||
|
||||
override string toString() { result = "param update " + pos }
|
||||
|
||||
override OutNodeExt getAnOutNode(DataFlowCall call) {
|
||||
exists(ArgumentNode arg |
|
||||
result.(PostUpdateNode).getPreUpdateNode() = arg and
|
||||
arg.argumentOf(call, this.getPosition())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A callable tagged with a relevant return kind. */
|
||||
@@ -1015,10 +1093,13 @@ class ReturnPosition extends TReturnPosition0 {
|
||||
*/
|
||||
pragma[inline]
|
||||
DataFlowCallable getNodeEnclosingCallable(Node n) {
|
||||
exists(Node n0 |
|
||||
pragma[only_bind_into](n0) = n and
|
||||
pragma[only_bind_into](result) = n0.getEnclosingCallable()
|
||||
)
|
||||
nodeEnclosingCallable(pragma[only_bind_out](n), pragma[only_bind_into](result))
|
||||
}
|
||||
|
||||
/** Gets the type of `n` used for type pruning. */
|
||||
pragma[inline]
|
||||
DataFlowType getNodeDataFlowType(Node n) {
|
||||
nodeDataFlowType(pragma[only_bind_out](n), pragma[only_bind_into](result))
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -1042,7 +1123,7 @@ predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall
|
||||
cc instanceof CallContextAny and callable = viableCallableExt(call)
|
||||
or
|
||||
exists(DataFlowCallable c0, DataFlowCall call0 |
|
||||
call0.getEnclosingCallable() = callable and
|
||||
callEnclosingCallable(call0, callable) and
|
||||
cc = TReturn(c0, call0) and
|
||||
c0 = prunedViableImplInCallContextReverse(call0, call)
|
||||
)
|
||||
@@ -1063,8 +1144,6 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
|
||||
result = viableCallableExt(call) and cc instanceof CallContextReturn
|
||||
}
|
||||
|
||||
predicate read = readStep/3;
|
||||
|
||||
/** An optional Boolean value. */
|
||||
class BooleanOption extends TBooleanOption {
|
||||
string toString() {
|
||||
@@ -1116,7 +1195,7 @@ abstract class AccessPathFront extends TAccessPathFront {
|
||||
|
||||
TypedContent getHead() { this = TFrontHead(result) }
|
||||
|
||||
predicate isClearedAt(Node n) { clearsContent(n, getHead().getContent()) }
|
||||
predicate isClearedAt(Node n) { clearsContentCached(n, getHead().getContent()) }
|
||||
}
|
||||
|
||||
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
|
||||
|
||||
@@ -557,5 +557,5 @@ predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c)
|
||||
/** 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. */
|
||||
/** Extra data-flow steps needed for lambda flow analysis. */
|
||||
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }
|
||||
|
||||
@@ -12,10 +12,20 @@ private import semmle.code.cpp.controlflow.IRGuards
|
||||
private import semmle.code.cpp.models.interfaces.DataFlow
|
||||
|
||||
cached
|
||||
private newtype TIRDataFlowNode =
|
||||
TInstructionNode(Instruction i) or
|
||||
TOperandNode(Operand op) or
|
||||
TVariableNode(Variable var)
|
||||
private module Cached {
|
||||
cached
|
||||
newtype TIRDataFlowNode =
|
||||
TInstructionNode(Instruction i) or
|
||||
TOperandNode(Operand op) or
|
||||
TVariableNode(Variable var)
|
||||
|
||||
cached
|
||||
predicate localFlowStepCached(Node nodeFrom, Node nodeTo) {
|
||||
simpleLocalFlowStep(nodeFrom, nodeTo)
|
||||
}
|
||||
}
|
||||
|
||||
private import Cached
|
||||
|
||||
/**
|
||||
* A node in a data flow graph.
|
||||
@@ -362,15 +372,22 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
|
||||
|
||||
/**
|
||||
* Not every store instruction generates a chi instruction that we can attach a PostUpdateNode to.
|
||||
* For instance, an update to a field of a struct containing only one field. For these cases we
|
||||
* attach the PostUpdateNode to the store instruction. There's no obvious pre update node for this case
|
||||
* (as the entire memory is updated), so `getPreUpdateNode` is implemented as `none()`.
|
||||
* For instance, an update to a field of a struct containing only one field. Even if the store does
|
||||
* have a chi instruction, a subsequent use of the result of the store may be linked directly to the
|
||||
* result of the store as an inexact definition if the store totally overlaps the use. For these
|
||||
* cases we attach the PostUpdateNode to the store instruction. There's no obvious pre update node
|
||||
* for this case (as the entire memory is updated), so `getPreUpdateNode` is implemented as
|
||||
* `none()`.
|
||||
*/
|
||||
private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNode {
|
||||
override StoreInstruction instr;
|
||||
|
||||
ExplicitSingleFieldStoreQualifierNode() {
|
||||
not exists(ChiInstruction chi | chi.getPartial() = instr) and
|
||||
(
|
||||
instr.getAUse().isDefinitionInexact()
|
||||
or
|
||||
not exists(ChiInstruction chi | chi.getPartial() = instr)
|
||||
) and
|
||||
// Without this condition any store would create a `PostUpdateNode`.
|
||||
instr.getDestinationAddress() instanceof FieldAddressInstruction
|
||||
}
|
||||
@@ -583,7 +600,7 @@ Node uninitializedNode(LocalVariable v) { none() }
|
||||
* Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local
|
||||
* (intra-procedural) step.
|
||||
*/
|
||||
predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFrom, nodeTo) }
|
||||
predicate localFlowStep = localFlowStepCached/2;
|
||||
|
||||
/**
|
||||
* INTERNAL: do not use.
|
||||
@@ -591,7 +608,6 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFr
|
||||
* This is the local flow predicate that's used as a building block in global
|
||||
* data flow. It may have less flow than the `localFlowStep` predicate.
|
||||
*/
|
||||
cached
|
||||
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
// Operand -> Instruction flow
|
||||
simpleInstructionLocalFlowStep(nodeFrom.asOperand(), nodeTo.asInstruction())
|
||||
|
||||
@@ -9,30 +9,18 @@ private import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
/**
|
||||
* Gets the instruction that goes into `input` for `call`.
|
||||
*/
|
||||
DataFlow::Node callInput(CallInstruction call, FunctionInput input) {
|
||||
// A positional argument
|
||||
Operand callInput(CallInstruction call, FunctionInput input) {
|
||||
// An argument or qualifier
|
||||
exists(int index |
|
||||
result.asInstruction() = call.getPositionalArgument(index) and
|
||||
input.isParameter(index)
|
||||
result = call.getArgumentOperand(index) and
|
||||
input.isParameterOrQualifierAddress(index)
|
||||
)
|
||||
or
|
||||
// A value pointed to by a positional argument
|
||||
// A value pointed to by an argument or qualifier
|
||||
exists(ReadSideEffectInstruction read |
|
||||
result.asOperand() = read.getSideEffectOperand() and
|
||||
result = read.getSideEffectOperand() and
|
||||
read.getPrimaryInstruction() = call and
|
||||
input.isParameterDeref(read.getIndex())
|
||||
)
|
||||
or
|
||||
// The qualifier pointer
|
||||
result.asInstruction() = call.getThisArgument() and
|
||||
input.isQualifierAddress()
|
||||
or
|
||||
// The qualifier object
|
||||
exists(ReadSideEffectInstruction read |
|
||||
result.asOperand() = read.getSideEffectOperand() and
|
||||
read.getPrimaryInstruction() = call and
|
||||
read.getIndex() = -1 and
|
||||
input.isQualifierObject()
|
||||
input.isParameterDerefOrQualifierObject(read.getIndex())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -44,19 +32,11 @@ Instruction callOutput(CallInstruction call, FunctionOutput output) {
|
||||
result = call and
|
||||
output.isReturnValue()
|
||||
or
|
||||
// The side effect of a call on the value pointed to by a positional argument
|
||||
// The side effect of a call on the value pointed to by an argument or qualifier
|
||||
exists(WriteSideEffectInstruction effect |
|
||||
result = effect and
|
||||
effect.getPrimaryInstruction() = call and
|
||||
output.isParameterDeref(effect.getIndex())
|
||||
)
|
||||
or
|
||||
// The side effect of a call on the qualifier object
|
||||
exists(WriteSideEffectInstruction effect |
|
||||
result = effect and
|
||||
effect.getPrimaryInstruction() = call and
|
||||
effect.getIndex() = -1 and
|
||||
output.isQualifierObject()
|
||||
output.isParameterDerefOrQualifierObject(effect.getIndex())
|
||||
)
|
||||
// TODO: return value dereference
|
||||
}
|
||||
|
||||
@@ -6,34 +6,7 @@ private import semmle.code.cpp.ir.ValueNumbering
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
|
||||
/**
|
||||
* Gets a short ID for an IR dataflow node.
|
||||
* - For `Instruction`s, this is just the result ID of the instruction (e.g. `m128`).
|
||||
* - For `Operand`s, this is the label of the operand, prefixed with the result ID of the
|
||||
* instruction and a dot (e.g. `m128.left`).
|
||||
* - For `Variable`s, this is the qualified name of the variable.
|
||||
*/
|
||||
private string nodeId(DataFlow::Node node, int order1, int order2) {
|
||||
exists(Instruction instruction | instruction = node.asInstruction() |
|
||||
result = instruction.getResultId() and
|
||||
order1 = instruction.getBlock().getDisplayIndex() and
|
||||
order2 = instruction.getDisplayIndexInBlock()
|
||||
)
|
||||
or
|
||||
exists(Operand operand, Instruction instruction |
|
||||
operand = node.asOperand() and
|
||||
instruction = operand.getUse()
|
||||
|
|
||||
result = instruction.getResultId() + "." + operand.getDumpId() and
|
||||
order1 = instruction.getBlock().getDisplayIndex() and
|
||||
order2 = instruction.getDisplayIndexInBlock()
|
||||
)
|
||||
or
|
||||
result = "var(" + node.asVariable().getQualifiedName() + ")" and
|
||||
order1 = 1000000 and
|
||||
order2 = 0
|
||||
}
|
||||
private import PrintIRUtilities
|
||||
|
||||
/**
|
||||
* Gets the local dataflow from other nodes in the same function to this node.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user