mirror of
https://github.com/github/codeql.git
synced 2026-07-05 03:25:31 +02:00
Compare commits
1491 Commits
codeql-cli
...
esbena/pus
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11420a060b | ||
|
|
f66a08155b | ||
|
|
29cd346702 | ||
|
|
aa92fe8c90 | ||
|
|
f18492e39b | ||
|
|
9ffdfb263f | ||
|
|
313e0c63fd | ||
|
|
8b53cca3e8 | ||
|
|
ed006d7283 | ||
|
|
af47cba09a | ||
|
|
30f8894854 | ||
|
|
571995c929 | ||
|
|
31c8e4ed2a | ||
|
|
7a9e41c97d | ||
|
|
f44f33788f | ||
|
|
380d238c31 | ||
|
|
8fbd056b4e | ||
|
|
d612687ae7 | ||
|
|
f7f9b4d3f4 | ||
|
|
ea1ee68fe1 | ||
|
|
5717a216d3 | ||
|
|
4d12d8dd5e | ||
|
|
bebf4ca8fc | ||
|
|
d058d36b1f | ||
|
|
055432530f | ||
|
|
c1864531cd | ||
|
|
383437c571 | ||
|
|
dd12eab29b | ||
|
|
c03f189dec | ||
|
|
e6c60ebd41 | ||
|
|
28912c508f | ||
|
|
5054d5b555 | ||
|
|
9ad9b81327 | ||
|
|
83f87f0272 | ||
|
|
de4b655ddb | ||
|
|
45753e519f | ||
|
|
626009ea60 | ||
|
|
9866214ebe | ||
|
|
39ec7132af | ||
|
|
f3819e7b06 | ||
|
|
77fcb8a18f | ||
|
|
e4d9f5f29e | ||
|
|
a0311609d0 | ||
|
|
e47e824e16 | ||
|
|
4a331814a2 | ||
|
|
f5a47126b1 | ||
|
|
5bdfcc8436 | ||
|
|
c13d83ce40 | ||
|
|
0c9ca4546c | ||
|
|
7af9d75abc | ||
|
|
ab2e0fdb18 | ||
|
|
40043f13c6 | ||
|
|
c70a2bebda | ||
|
|
c1af8b93c2 | ||
|
|
83f1b2ca5d | ||
|
|
3adc0b57ed | ||
|
|
96aef9f63f | ||
|
|
89775428b4 | ||
|
|
3e6389cad6 | ||
|
|
95a93fe033 | ||
|
|
e2c6dd7d56 | ||
|
|
61cc84ba69 | ||
|
|
ce68a6d1c5 | ||
|
|
e7abe43e3e | ||
|
|
734bfbd7ae | ||
|
|
e309d8227c | ||
|
|
6f2d91a8ad | ||
|
|
d840796494 | ||
|
|
6c57cbba2b | ||
|
|
1d00730753 | ||
|
|
8d9a797b75 | ||
|
|
6f297f4e9c | ||
|
|
4b5599fe17 | ||
|
|
cb934e17b1 | ||
|
|
b1bca85162 | ||
|
|
5a7efd0fee | ||
|
|
2626b0b3dc | ||
|
|
be076dc2c8 | ||
|
|
53a1f935b7 | ||
|
|
8fabbd697e | ||
|
|
e3b2eed2d2 | ||
|
|
8eda061d2f | ||
|
|
579b58b8fa | ||
|
|
3ef707e358 | ||
|
|
cdbd8b27d3 | ||
|
|
6ce1524192 | ||
|
|
4a1e2ed408 | ||
|
|
e9ef53c31b | ||
|
|
7d6cba77a0 | ||
|
|
2e0ca6ce2b | ||
|
|
7d70b77141 | ||
|
|
407c265daf | ||
|
|
95d175e9e0 | ||
|
|
d777ba8a25 | ||
|
|
a26403b359 | ||
|
|
0e9c2377e3 | ||
|
|
348e3b74f3 | ||
|
|
f274f06d9b | ||
|
|
acbf7913b2 | ||
|
|
a5c055581e | ||
|
|
ddb7d722bc | ||
|
|
bdd44c1c46 | ||
|
|
034d45ddc0 | ||
|
|
440976fe63 | ||
|
|
cde98c7799 | ||
|
|
90d7b94b8a | ||
|
|
1cc5e54357 | ||
|
|
18489c0ded | ||
|
|
579de0c3f0 | ||
|
|
f8fc583af3 | ||
|
|
6f81685f48 | ||
|
|
a5bae30d81 | ||
|
|
4ccf9bf67c | ||
|
|
8f1b2b3bb5 | ||
|
|
b53e3499cb | ||
|
|
53b3581ed0 | ||
|
|
784991cce5 | ||
|
|
79e6dcaf68 | ||
|
|
8aa4d8227e | ||
|
|
3bc6247ad8 | ||
|
|
218b746f6f | ||
|
|
4d85799fc7 | ||
|
|
615b2ec539 | ||
|
|
b226f767ad | ||
|
|
0ca9feb854 | ||
|
|
1b20506947 | ||
|
|
995e33158f | ||
|
|
04bdba85ea | ||
|
|
c1bb40f439 | ||
|
|
b2016bddac | ||
|
|
b142a79a35 | ||
|
|
c6696adfde | ||
|
|
2187994f5c | ||
|
|
f82683cdf4 | ||
|
|
4891a649a2 | ||
|
|
7ddfc00655 | ||
|
|
8208f92f59 | ||
|
|
7e644d8d7b | ||
|
|
76dcfd479e | ||
|
|
133c496b94 | ||
|
|
4beaceec68 | ||
|
|
fb979231f3 | ||
|
|
0ac3e5c3ad | ||
|
|
8d91ba2a6e | ||
|
|
77cb822907 | ||
|
|
c1e4c05aa2 | ||
|
|
e2022f467c | ||
|
|
a3b25f0eb5 | ||
|
|
47002a3bd7 | ||
|
|
1426c5b406 | ||
|
|
7ce9b04941 | ||
|
|
5e80044f11 | ||
|
|
e64a6dc12a | ||
|
|
faaa74b1cd | ||
|
|
24c2578540 | ||
|
|
5d93309ada | ||
|
|
d89c41bae4 | ||
|
|
43ec721a87 | ||
|
|
9363d64166 | ||
|
|
65c301c39f | ||
|
|
0e7fdbeeab | ||
|
|
062f7fe390 | ||
|
|
a32711245f | ||
|
|
15caaa7ad6 | ||
|
|
5fa6ecc5f1 | ||
|
|
310353060e | ||
|
|
b2082cc3da | ||
|
|
9d14a85f3f | ||
|
|
dc9187778b | ||
|
|
861ae856b3 | ||
|
|
f5788b9441 | ||
|
|
edf472b9ed | ||
|
|
fdb15d6073 | ||
|
|
633597cc90 | ||
|
|
b73b60d431 | ||
|
|
08b06422ff | ||
|
|
a04920f241 | ||
|
|
4bf2a514ac | ||
|
|
376ee33707 | ||
|
|
4a71aa2165 | ||
|
|
fc3299801b | ||
|
|
2cac729598 | ||
|
|
c5728b2951 | ||
|
|
80b9ccff2b | ||
|
|
e882cdaca4 | ||
|
|
10b2a0a54a | ||
|
|
9ea8b20e77 | ||
|
|
68a0efaf0c | ||
|
|
8eac1dcf15 | ||
|
|
56a8cdb171 | ||
|
|
d06ac78e4d | ||
|
|
3262a14f22 | ||
|
|
b524a6104d | ||
|
|
b921fc62b8 | ||
|
|
f3dcccb64b | ||
|
|
c1cf44b342 | ||
|
|
16bcb4ec86 | ||
|
|
ca5c6923da | ||
|
|
d85ed9ea7a | ||
|
|
7e947b2a65 | ||
|
|
45e416b87b | ||
|
|
dd1ae0bbb5 | ||
|
|
85ff57bae6 | ||
|
|
a9c438924e | ||
|
|
8d607e6251 | ||
|
|
37d76f5e49 | ||
|
|
6fda5e8f5b | ||
|
|
1c79d1f985 | ||
|
|
0d7d60eebd | ||
|
|
81dedfe22f | ||
|
|
aee617f911 | ||
|
|
3c57602653 | ||
|
|
f21948d0ca | ||
|
|
1949a4e59a | ||
|
|
de4458346f | ||
|
|
1b761b3d12 | ||
|
|
ff2f5a5f91 | ||
|
|
d2dc19900f | ||
|
|
041c2c77b3 | ||
|
|
dc27089714 | ||
|
|
7732c0885f | ||
|
|
0669ef505e | ||
|
|
372f099850 | ||
|
|
b18f7a9bd7 | ||
|
|
cf2ee0672f | ||
|
|
c0b61d7f73 | ||
|
|
35cba17642 | ||
|
|
b68d280129 | ||
|
|
124aac23c6 | ||
|
|
1ff56d5143 | ||
|
|
4ae92667e1 | ||
|
|
ba23393c0d | ||
|
|
a6eba04793 | ||
|
|
c66d29998e | ||
|
|
88bb8a2704 | ||
|
|
d699ca9aa8 | ||
|
|
5ed7056707 | ||
|
|
3734e1ca4f | ||
|
|
06acaef43e | ||
|
|
a089898220 | ||
|
|
85de6dd667 | ||
|
|
88d65b8fcb | ||
|
|
2020786fb0 | ||
|
|
b0242dc55b | ||
|
|
160635ba3c | ||
|
|
a6cbe6f94c | ||
|
|
fb03561a31 | ||
|
|
aa68c51797 | ||
|
|
598f283715 | ||
|
|
26194be8b6 | ||
|
|
7ff2ee695d | ||
|
|
7bf285a52e | ||
|
|
efc9e67ec2 | ||
|
|
fad95d8935 | ||
|
|
08f6d1ab80 | ||
|
|
5de79b4ffe | ||
|
|
f32d464c0f | ||
|
|
327cf444f4 | ||
|
|
f3c0eadbce | ||
|
|
58f36e4b31 | ||
|
|
90e49508a3 | ||
|
|
a4bea05fa7 | ||
|
|
6f65f22db6 | ||
|
|
be1e75471e | ||
|
|
1cab177f8a | ||
|
|
0e0c3e3937 | ||
|
|
6301e726ee | ||
|
|
1cd37dddf5 | ||
|
|
07a4f5f748 | ||
|
|
679aad138e | ||
|
|
42bf866fb3 | ||
|
|
9604ed883c | ||
|
|
d804893a49 | ||
|
|
03fb244545 | ||
|
|
a6360215f3 | ||
|
|
0ca9852cc8 | ||
|
|
6223b166c2 | ||
|
|
e1d290d4c0 | ||
|
|
1857de1f33 | ||
|
|
b80a84c156 | ||
|
|
6a1aea740f | ||
|
|
c9a87234ef | ||
|
|
66c1629974 | ||
|
|
43a10457dd | ||
|
|
b6c5b4d213 | ||
|
|
d8857c7ce8 | ||
|
|
a46787ea07 | ||
|
|
bd9b96e154 | ||
|
|
8ee020f79c | ||
|
|
13288be7fc | ||
|
|
9ffc02944d | ||
|
|
cfd2dcffa0 | ||
|
|
b0f6cf1491 | ||
|
|
9df1ac7f75 | ||
|
|
10498c3643 | ||
|
|
a1ee900f50 | ||
|
|
6e167040f5 | ||
|
|
657cd89286 | ||
|
|
d2822c2acc | ||
|
|
704a5e4bbf | ||
|
|
8ccbcf1bf8 | ||
|
|
563b771163 | ||
|
|
0a0657ada1 | ||
|
|
1c230d0888 | ||
|
|
afa58f5676 | ||
|
|
13f7fd88f1 | ||
|
|
634ed91904 | ||
|
|
cf42427f54 | ||
|
|
f7f3890b40 | ||
|
|
70f76d06c7 | ||
|
|
45c0d4a3b2 | ||
|
|
b336c29283 | ||
|
|
4ef2a5f4f1 | ||
|
|
7e5bfa5aa0 | ||
|
|
271b23ba8f | ||
|
|
0c3daabc51 | ||
|
|
753d886b0d | ||
|
|
6d247bfdf9 | ||
|
|
e7209d1ee1 | ||
|
|
23d4d035e5 | ||
|
|
65f4ccce28 | ||
|
|
75f3ebf051 | ||
|
|
9f69c75c50 | ||
|
|
2cd70b96cd | ||
|
|
1a1a7413c2 | ||
|
|
d60b90acd3 | ||
|
|
e879ca7a3b | ||
|
|
15b4b218c8 | ||
|
|
bbab0e582a | ||
|
|
9e61dfb41f | ||
|
|
5a26346ba5 | ||
|
|
5376eb89b3 | ||
|
|
df482a9603 | ||
|
|
470256da85 | ||
|
|
8bba3eb2b6 | ||
|
|
f08f07e19e | ||
|
|
d0a19fffee | ||
|
|
7e99426141 | ||
|
|
2bf5966fe3 | ||
|
|
fd4915a564 | ||
|
|
9d288c90a5 | ||
|
|
a7b3f1370f | ||
|
|
d0aa307bd3 | ||
|
|
b887165005 | ||
|
|
3689481c18 | ||
|
|
660e52f2bf | ||
|
|
e9e3ef3ea2 | ||
|
|
799c945299 | ||
|
|
95f8f85aa2 | ||
|
|
aacba0b522 | ||
|
|
513fe09dbb | ||
|
|
d17c055139 | ||
|
|
44a615839d | ||
|
|
f08eb8e616 | ||
|
|
69f42b9c74 | ||
|
|
38250b0821 | ||
|
|
cbc96dba8a | ||
|
|
522a4bb9fa | ||
|
|
8e11c2c476 | ||
|
|
992801b7cb | ||
|
|
9ffa236c51 | ||
|
|
c0c40cc05b | ||
|
|
3a3c7fc59e | ||
|
|
f209ff4f76 | ||
|
|
b7f7c5ba20 | ||
|
|
f63ffb0630 | ||
|
|
069cf9d17f | ||
|
|
cbd21edc99 | ||
|
|
2f85735b6a | ||
|
|
69ba2e6f8c | ||
|
|
d46564caa6 | ||
|
|
f6a8b9a7e5 | ||
|
|
b871342e83 | ||
|
|
13347cd102 | ||
|
|
9f4b965202 | ||
|
|
d70d1fbf81 | ||
|
|
a43704ab43 | ||
|
|
063398f24d | ||
|
|
60f3ff8c33 | ||
|
|
8df5aaa797 | ||
|
|
e811ba1150 | ||
|
|
8bcbf8e30f | ||
|
|
8517eff0f7 | ||
|
|
0031ed39ec | ||
|
|
b49ca6a24c | ||
|
|
a18aad8536 | ||
|
|
38d0bb4a60 | ||
|
|
1d321c692b | ||
|
|
ede1503cc6 | ||
|
|
283173ad02 | ||
|
|
3145e8f9b7 | ||
|
|
1956405d17 | ||
|
|
5735bb698d | ||
|
|
0e33f730b1 | ||
|
|
5ee9684435 | ||
|
|
122f6385e6 | ||
|
|
6896b20dcd | ||
|
|
ea7063f3c6 | ||
|
|
490872173a | ||
|
|
07ca1c2ec0 | ||
|
|
fe1a473f07 | ||
|
|
a722aeb5e3 | ||
|
|
e7c298d903 | ||
|
|
b502ca1ea7 | ||
|
|
a716482c1f | ||
|
|
59bac04d8f | ||
|
|
ffc858e34d | ||
|
|
bf0ecded04 | ||
|
|
7437cd4d85 | ||
|
|
511bee7a1a | ||
|
|
f85a47d41f | ||
|
|
a2dc505c26 | ||
|
|
5183290439 | ||
|
|
322e39446d | ||
|
|
016727d6b6 | ||
|
|
b2c1b55c0c | ||
|
|
b17a93eaad | ||
|
|
4d797d6b3d | ||
|
|
da43984ba4 | ||
|
|
b82425a35c | ||
|
|
2d4a2e0d44 | ||
|
|
ee23799a59 | ||
|
|
6c739b67fa | ||
|
|
23480b2d8f | ||
|
|
614c80706f | ||
|
|
5559681916 | ||
|
|
635ac0a209 | ||
|
|
da8e67b7ee | ||
|
|
7492293c5b | ||
|
|
3cbe94ac0a | ||
|
|
64db70f3ac | ||
|
|
8af430d40f | ||
|
|
5f8ea3965d | ||
|
|
66b1612e5e | ||
|
|
b73219392b | ||
|
|
d0e94e655d | ||
|
|
400bf10cc3 | ||
|
|
71820569e1 | ||
|
|
cfb9265f0a | ||
|
|
5269933461 | ||
|
|
389a3c9073 | ||
|
|
16fa066636 | ||
|
|
3dd5d4d7b4 | ||
|
|
3ebf1e3c13 | ||
|
|
a3d11c61a8 | ||
|
|
d852b28653 | ||
|
|
44c3787457 | ||
|
|
aae4260819 | ||
|
|
e9575c3df6 | ||
|
|
3c59aa319e | ||
|
|
7cd9369d91 | ||
|
|
33a9f86f54 | ||
|
|
dd33f4f4d2 | ||
|
|
6f42153eac | ||
|
|
4e68a4670b | ||
|
|
4765772725 | ||
|
|
243b92b28c | ||
|
|
60c0bcf8f7 | ||
|
|
c39fe59a04 | ||
|
|
7ae1047fda | ||
|
|
ff9ed0d4fb | ||
|
|
5dbbb86d46 | ||
|
|
728e3abee5 | ||
|
|
36569f997f | ||
|
|
6b1ac73a46 | ||
|
|
de1269f18f | ||
|
|
c46ede02e6 | ||
|
|
6adfea2365 | ||
|
|
daf6a4ce07 | ||
|
|
f68a40f82b | ||
|
|
fac2769d85 | ||
|
|
0e31439b7e | ||
|
|
2a3b5fc2b2 | ||
|
|
d0840afb80 | ||
|
|
9f48ae656f | ||
|
|
0805daaa56 | ||
|
|
51998294ad | ||
|
|
4ae99592a3 | ||
|
|
205233b42f | ||
|
|
3e1ebb954f | ||
|
|
0cec59e043 | ||
|
|
8ffa195538 | ||
|
|
5a2ef8321c | ||
|
|
4128f56aa9 | ||
|
|
6c6113b85b | ||
|
|
802faf1197 | ||
|
|
7ad52e1365 | ||
|
|
f00b62df76 | ||
|
|
90baef83ee | ||
|
|
8eb041c172 | ||
|
|
520f598d49 | ||
|
|
d9704d7b39 | ||
|
|
42f6dfc197 | ||
|
|
404f4a81a7 | ||
|
|
50dd4e7ee7 | ||
|
|
f2800abee4 | ||
|
|
7f44cebed7 | ||
|
|
4138296ec6 | ||
|
|
991d659cb2 | ||
|
|
976faf97d1 | ||
|
|
19c34be1ea | ||
|
|
102b5e05e1 | ||
|
|
2b349b3024 | ||
|
|
2c4ccb79a1 | ||
|
|
3043ac850c | ||
|
|
f6c36b469a | ||
|
|
f190d60912 | ||
|
|
eccba57536 | ||
|
|
7aa6c62050 | ||
|
|
05415768c9 | ||
|
|
f10f053c36 | ||
|
|
913d8361ba | ||
|
|
4609b2060a | ||
|
|
8f3be9fbfd | ||
|
|
edf7724579 | ||
|
|
37644d30d2 | ||
|
|
6327fced6f | ||
|
|
ad281c0365 | ||
|
|
a8f673ffa4 | ||
|
|
e08c734c40 | ||
|
|
55c17f453f | ||
|
|
87b968f337 | ||
|
|
9f8326a3fa | ||
|
|
a077345227 | ||
|
|
73f2f52ed8 | ||
|
|
739906b60c | ||
|
|
9e10aee8a1 | ||
|
|
cc2914be3c | ||
|
|
de53727ab3 | ||
|
|
0a3d62c92a | ||
|
|
148da611c6 | ||
|
|
aad55ffbd6 | ||
|
|
75f9a947b3 | ||
|
|
ed706d9bc1 | ||
|
|
e41cd810d3 | ||
|
|
93e291cb3e | ||
|
|
cde853c095 | ||
|
|
6742beae1b | ||
|
|
31374b485c | ||
|
|
e410244fe0 | ||
|
|
bb8f4bb7c1 | ||
|
|
ae6501d906 | ||
|
|
08be8edbce | ||
|
|
4b221bd964 | ||
|
|
186ba428cf | ||
|
|
1243d40bb2 | ||
|
|
35a67845cf | ||
|
|
59b71df2d6 | ||
|
|
0b4d0d2772 | ||
|
|
bab8cfb62a | ||
|
|
a5b6889478 | ||
|
|
5dd2d20176 | ||
|
|
7d6664f14d | ||
|
|
540ecf3c21 | ||
|
|
755085e9fe | ||
|
|
2589034242 | ||
|
|
830908b5c8 | ||
|
|
3e914ef2ff | ||
|
|
fc05825c73 | ||
|
|
8a6a8fc28a | ||
|
|
0619453c2f | ||
|
|
b40c77d419 | ||
|
|
3f218c903b | ||
|
|
8f270b665c | ||
|
|
c91b6f7ce9 | ||
|
|
f4555ed1a2 | ||
|
|
66e086f92f | ||
|
|
1e026ef45e | ||
|
|
cbd7434a7e | ||
|
|
b68538376c | ||
|
|
3bcf6d68ce | ||
|
|
f8a62c4c82 | ||
|
|
58f92764f7 | ||
|
|
fd23fa94a5 | ||
|
|
e79b8f3e23 | ||
|
|
d2d5cce787 | ||
|
|
14590436f9 | ||
|
|
50d3592ad3 | ||
|
|
a91208fd2c | ||
|
|
36f14b31bc | ||
|
|
82602014ad | ||
|
|
88fb1a18cb | ||
|
|
fdcc144a98 | ||
|
|
591aeff906 | ||
|
|
19bbe6d276 | ||
|
|
d1a7feebc4 | ||
|
|
d946802057 | ||
|
|
57399b733e | ||
|
|
0e890fd788 | ||
|
|
eef3905c46 | ||
|
|
9ce248c829 | ||
|
|
c13cad7e87 | ||
|
|
d79337774d | ||
|
|
8e1b4e3a58 | ||
|
|
da5c2fb415 | ||
|
|
db04a0dadf | ||
|
|
6d339e50a3 | ||
|
|
74158f1e3a | ||
|
|
09a11f4166 | ||
|
|
6c3aabe1df | ||
|
|
c3e495efe9 | ||
|
|
03b6ee3833 | ||
|
|
6ff8d4de5c | ||
|
|
f96968975b | ||
|
|
e98ab5d2c2 | ||
|
|
e9ce29664e | ||
|
|
1d358c5f77 | ||
|
|
f5b40731d6 | ||
|
|
e801d9636a | ||
|
|
8b0bc677f4 | ||
|
|
dca1e34cd8 | ||
|
|
16e1e97ff0 | ||
|
|
af4c3122ca | ||
|
|
078a2aa03b | ||
|
|
ec0bd24b64 | ||
|
|
5b560b12e9 | ||
|
|
04a3f76a8b | ||
|
|
d36a7ed10e | ||
|
|
99c8b291b2 | ||
|
|
b8732859de | ||
|
|
31400df0d4 | ||
|
|
69690a2509 | ||
|
|
4438f8c58c | ||
|
|
4c5faaf985 | ||
|
|
8abaf1247a | ||
|
|
5ffbf563b8 | ||
|
|
72a03257e7 | ||
|
|
5eb814fd8b | ||
|
|
7869733ab5 | ||
|
|
88b6bd9478 | ||
|
|
ce2b86b9e3 | ||
|
|
2eae6a3e9a | ||
|
|
6afcbce421 | ||
|
|
5d0dfe8c04 | ||
|
|
e7524dea69 | ||
|
|
1411804e58 | ||
|
|
d493cfdf3a | ||
|
|
baafd9f8ba | ||
|
|
70081defdc | ||
|
|
62ae702e07 | ||
|
|
e9df860431 | ||
|
|
6060f2e3e3 | ||
|
|
c369b28a2a | ||
|
|
f39872e649 | ||
|
|
089d030bc2 | ||
|
|
df6ba43cca | ||
|
|
f63c768d9f | ||
|
|
6d27585b92 | ||
|
|
418adb824c | ||
|
|
e25f03fb56 | ||
|
|
172684ce6e | ||
|
|
a86f2c3ed1 | ||
|
|
70f6493d7a | ||
|
|
fd73f4094f | ||
|
|
1a0379a894 | ||
|
|
d89e430db2 | ||
|
|
15b56585f9 | ||
|
|
37c2db240c | ||
|
|
1ec935dee6 | ||
|
|
bd940712de | ||
|
|
036d749378 | ||
|
|
44ffc7e155 | ||
|
|
a0bf13007c | ||
|
|
9a6c9c4d77 | ||
|
|
e3c0e190d9 | ||
|
|
fe097783a7 | ||
|
|
61b71807df | ||
|
|
fa54855995 | ||
|
|
fb40b8a032 | ||
|
|
c07d55325e | ||
|
|
349b556c26 | ||
|
|
1b070f1dd8 | ||
|
|
38b925b19c | ||
|
|
d64c7fc638 | ||
|
|
89604deb8d | ||
|
|
d8bf7ed6e0 | ||
|
|
97461d1f11 | ||
|
|
12a3fa77f6 | ||
|
|
112cd9d29c | ||
|
|
1cbacc41d7 | ||
|
|
33d363eb94 | ||
|
|
f320414b1c | ||
|
|
45def1b124 | ||
|
|
28444c7e9c | ||
|
|
ac4476fa82 | ||
|
|
c3f362876b | ||
|
|
84d277dc94 | ||
|
|
0154f4eba4 | ||
|
|
9d308ba0bd | ||
|
|
7c82c5e378 | ||
|
|
5a76e7d4f8 | ||
|
|
1b19a3e320 | ||
|
|
9a74f18ac5 | ||
|
|
ce004e9c1e | ||
|
|
12a3251649 | ||
|
|
cc16fdecbb | ||
|
|
f54f70d707 | ||
|
|
7214d70ee7 | ||
|
|
fff1f1248a | ||
|
|
1f2b32fe87 | ||
|
|
3bc209ded8 | ||
|
|
631a503e55 | ||
|
|
c00e18f4b0 | ||
|
|
629605c075 | ||
|
|
ac78e26672 | ||
|
|
0760c1c13f | ||
|
|
769f787651 | ||
|
|
3f420c442e | ||
|
|
5fa1c04e2a | ||
|
|
b96ad387ef | ||
|
|
032a0dc6ae | ||
|
|
e851ba2bfd | ||
|
|
d49db9298c | ||
|
|
a089e0ed3f | ||
|
|
6cc14b16ba | ||
|
|
a9cef84b90 | ||
|
|
f29813b3f7 | ||
|
|
eded7b8da1 | ||
|
|
dc715af18b | ||
|
|
c200ec38f5 | ||
|
|
7e2b00e62c | ||
|
|
9d50511ea4 | ||
|
|
5deb996b33 | ||
|
|
509e77bbdb | ||
|
|
ef6ea195db | ||
|
|
9a73c36389 | ||
|
|
9e4e42847b | ||
|
|
ade206184c | ||
|
|
b317d73c83 | ||
|
|
09f60f20fc | ||
|
|
89979890ad | ||
|
|
18eede5597 | ||
|
|
48d4fcd064 | ||
|
|
9127fa533a | ||
|
|
4db6702caa | ||
|
|
dc354f8fbf | ||
|
|
9681119f68 | ||
|
|
055937eefb | ||
|
|
6cec64466f | ||
|
|
2af3fb5cca | ||
|
|
8ad5b34c07 | ||
|
|
9d9663d842 | ||
|
|
84d2cb84c1 | ||
|
|
74b1c19a20 | ||
|
|
1b9793d928 | ||
|
|
b31ea30e85 | ||
|
|
a65289253e | ||
|
|
f99ce113cb | ||
|
|
928b91d975 | ||
|
|
c43ff2f9d0 | ||
|
|
4c32b7e480 | ||
|
|
c1b011d47c | ||
|
|
34d4e55459 | ||
|
|
2a5d567041 | ||
|
|
e528c6ff90 | ||
|
|
6004ecc3a4 | ||
|
|
efff86e47b | ||
|
|
f19a229e6f | ||
|
|
865e4f0441 | ||
|
|
3b1c04b71c | ||
|
|
e060708367 | ||
|
|
145efa4a1a | ||
|
|
3252c04c38 | ||
|
|
f8138c92c5 | ||
|
|
1239b1aee1 | ||
|
|
7ce2750c8a | ||
|
|
c7aa89b1d8 | ||
|
|
535904e545 | ||
|
|
b40e30790a | ||
|
|
d0aa219652 | ||
|
|
8391580301 | ||
|
|
d950b59a4d | ||
|
|
9a02a223e3 | ||
|
|
299500fdaa | ||
|
|
24334e4a3a | ||
|
|
62355f3f0e | ||
|
|
0bfedc74fa | ||
|
|
dbc3b49777 | ||
|
|
188a6b19f0 | ||
|
|
df3d5aefc7 | ||
|
|
02c26037cb | ||
|
|
f5bb1d0124 | ||
|
|
4d5901a421 | ||
|
|
eb787ae321 | ||
|
|
d6dd752764 | ||
|
|
ed17bd9106 | ||
|
|
5dbeaa17d6 | ||
|
|
5b261d88bb | ||
|
|
1375e1d9fc | ||
|
|
684600cc54 | ||
|
|
370d75bedc | ||
|
|
8ceeb71c8e | ||
|
|
7745a13efb | ||
|
|
1469766994 | ||
|
|
21caef3d7d | ||
|
|
67b65b691e | ||
|
|
ed15ee8dfb | ||
|
|
30717310e7 | ||
|
|
1d331fc678 | ||
|
|
b0bbbc54d0 | ||
|
|
510f8253e5 | ||
|
|
1a79b13bdc | ||
|
|
8aa354c4c0 | ||
|
|
10aeadb889 | ||
|
|
24959a52d0 | ||
|
|
e185382c41 | ||
|
|
6f4370a684 | ||
|
|
1fb8a175f9 | ||
|
|
53cbde0c44 | ||
|
|
ccaef199bf | ||
|
|
9c82f72720 | ||
|
|
c9f80b1052 | ||
|
|
d90de13bdb | ||
|
|
5c70c6a19b | ||
|
|
4fe43155c0 | ||
|
|
44fff659bd | ||
|
|
85e5b689a3 | ||
|
|
2a0c29156f | ||
|
|
e5dab0185d | ||
|
|
bd5243884a | ||
|
|
4238a5be2f | ||
|
|
89d2f93a16 | ||
|
|
b75e19a446 | ||
|
|
6c70f5299d | ||
|
|
3fc0bed9b5 | ||
|
|
5ef7b9797e | ||
|
|
514f8f3344 | ||
|
|
310ea6b69c | ||
|
|
53e362c994 | ||
|
|
741e4a7a38 | ||
|
|
0954584743 | ||
|
|
7f80514144 | ||
|
|
8020040b4f | ||
|
|
816bfbe4ea | ||
|
|
9f4c829b3e | ||
|
|
e3d42a1fba | ||
|
|
6fe7579fc3 | ||
|
|
ee7ac53bf6 | ||
|
|
2f77b921a0 | ||
|
|
e6b07070f6 | ||
|
|
e862dfd3dc | ||
|
|
fed640b21f | ||
|
|
2352cf7a26 | ||
|
|
e1871a2508 | ||
|
|
8e6bc11197 | ||
|
|
541dcb365f | ||
|
|
ddc0ade28c | ||
|
|
29ebe7b13d | ||
|
|
f071da499b | ||
|
|
1641d0fa93 | ||
|
|
6cd11d2e13 | ||
|
|
f19dd78d40 | ||
|
|
74a7945995 | ||
|
|
c31bd7a1e8 | ||
|
|
153f8fec0e | ||
|
|
50e80dc8b7 | ||
|
|
f29457f4ca | ||
|
|
016ff2af63 | ||
|
|
f9d8ae588c | ||
|
|
71f69997e2 | ||
|
|
632d42fe68 | ||
|
|
c6a52ed2ea | ||
|
|
37e9024343 | ||
|
|
4016a8e458 | ||
|
|
187c24e260 | ||
|
|
0a3705b7af | ||
|
|
ecf27ff24b | ||
|
|
3e2fb5a64e | ||
|
|
9330fa0f69 | ||
|
|
9b786c27c0 | ||
|
|
be36de9b0a | ||
|
|
ec6a8b933c | ||
|
|
1013cb4ccb | ||
|
|
ec292dbffd | ||
|
|
dfa0e77e39 | ||
|
|
ab11bce776 | ||
|
|
72d1473581 | ||
|
|
76880e8f93 | ||
|
|
e510593aa0 | ||
|
|
d23de3dcd8 | ||
|
|
b611b5100b | ||
|
|
6af28e37ae | ||
|
|
6d313cfb6b | ||
|
|
9b52ad2d3d | ||
|
|
fe8b466ff0 | ||
|
|
a665e94805 | ||
|
|
df972eeb05 | ||
|
|
78caab4214 | ||
|
|
1762394b9b | ||
|
|
9a15feae29 | ||
|
|
4e73b9a30f | ||
|
|
a64660aae1 | ||
|
|
aeabe67812 | ||
|
|
d7fd1e0718 | ||
|
|
9a500eecb9 | ||
|
|
c0f1d365ba | ||
|
|
dfa6f285e5 | ||
|
|
cd3839f621 | ||
|
|
63b844856d | ||
|
|
b4a05804fa | ||
|
|
97db13beb4 | ||
|
|
0f71066aaa | ||
|
|
896eca684e | ||
|
|
fd3c53da9b | ||
|
|
f872ed13e3 | ||
|
|
323ccc8cea | ||
|
|
4cb4073dd7 | ||
|
|
350620d44a | ||
|
|
220f4b373c | ||
|
|
6b4dbc3fe5 | ||
|
|
2c01b54a49 | ||
|
|
ff3aba0f5d | ||
|
|
862706f709 | ||
|
|
ffc25f8f89 | ||
|
|
744c3447c9 | ||
|
|
41a0bf154f | ||
|
|
946968b37c | ||
|
|
7955a8b6c8 | ||
|
|
69cf373f21 | ||
|
|
3d0917e6fc | ||
|
|
09d727f343 | ||
|
|
6af27c23ec | ||
|
|
5fc1b8bb29 | ||
|
|
949ead913f | ||
|
|
e167554ad9 | ||
|
|
486fc453e7 | ||
|
|
b46dfc076d | ||
|
|
626ec4d209 | ||
|
|
7bcc906d67 | ||
|
|
3e3ad8e5d4 | ||
|
|
d4b9c36343 | ||
|
|
deffeff01c | ||
|
|
8e1494b91a | ||
|
|
2f7272d1ed | ||
|
|
f4d35f6afe | ||
|
|
c900118731 | ||
|
|
c9bfd85c0d | ||
|
|
9749f797c8 | ||
|
|
ed87d77bc5 | ||
|
|
ed5960e015 | ||
|
|
4406065807 | ||
|
|
7d9c408af4 | ||
|
|
dd6abdc06b | ||
|
|
5a519c5089 | ||
|
|
b5bef24ce2 | ||
|
|
f7ff83c2e7 | ||
|
|
fb491c392e | ||
|
|
11fd4f4997 | ||
|
|
56d9c351d5 | ||
|
|
bff9665866 | ||
|
|
1762b4fb91 | ||
|
|
f0a8c77095 | ||
|
|
2cedddfce8 | ||
|
|
a5fcc5c15a | ||
|
|
5d975089c1 | ||
|
|
455a34a1ec | ||
|
|
18c427cddc | ||
|
|
e46ccc072e | ||
|
|
238fba9b6e | ||
|
|
0ff2de9b5e | ||
|
|
b0cbb31895 | ||
|
|
98b359bd9a | ||
|
|
3039206eab | ||
|
|
53e17e7835 | ||
|
|
808fd78d96 | ||
|
|
9826e7df1d | ||
|
|
946c572413 | ||
|
|
d9f38826f7 | ||
|
|
d8e1e3e8c0 | ||
|
|
c5bcb7999e | ||
|
|
c21df48bcd | ||
|
|
5e7adc661f | ||
|
|
4958b8ba0d | ||
|
|
5b881c2151 | ||
|
|
ce3a531daf | ||
|
|
c3141125af | ||
|
|
a917f240cf | ||
|
|
2543b720e6 | ||
|
|
690b7ef617 | ||
|
|
c577817882 | ||
|
|
4795cbb849 | ||
|
|
4c4fd52347 | ||
|
|
d7f08703af | ||
|
|
31394878a2 | ||
|
|
b31f705ffc | ||
|
|
06ba078ef2 | ||
|
|
823c24a7ab | ||
|
|
1a1770fc06 | ||
|
|
bc74af7307 | ||
|
|
bd01d92500 | ||
|
|
cc43230244 | ||
|
|
0704ab7bd3 | ||
|
|
7c02b6a3b2 | ||
|
|
c8c23a6eb4 | ||
|
|
161461eb6f | ||
|
|
e6242fd349 | ||
|
|
d933bf6f24 | ||
|
|
dd4f6edd62 | ||
|
|
4b73c99c56 | ||
|
|
43b1185d82 | ||
|
|
366fc23938 | ||
|
|
3e7b82a02a | ||
|
|
64a3ffdca7 | ||
|
|
06f2345bbb | ||
|
|
236989f6fd | ||
|
|
aef394e2d1 | ||
|
|
d2222ee9f2 | ||
|
|
b8d26abbc2 | ||
|
|
d41331b28b | ||
|
|
85a35544af | ||
|
|
5e1f565b6a | ||
|
|
e524076045 | ||
|
|
d0cb1384a9 | ||
|
|
94dbf2b7b4 | ||
|
|
7d68020c7b | ||
|
|
bc5e0924d2 | ||
|
|
a0e2bd57a7 | ||
|
|
48cfa9665a | ||
|
|
fb5513c1c8 | ||
|
|
95ea619cc4 | ||
|
|
d1721d0bcd | ||
|
|
2d412d63e0 | ||
|
|
411faca6ef | ||
|
|
3dab87e6ca | ||
|
|
ca81110e4b | ||
|
|
4cb004c0c6 | ||
|
|
15679dfec6 | ||
|
|
705e24690f | ||
|
|
09862b9fe7 | ||
|
|
7034933cee | ||
|
|
30040680ec | ||
|
|
1b4130fe97 | ||
|
|
c3493d6fde | ||
|
|
584702058d | ||
|
|
932f00b43e | ||
|
|
33bd267eb0 | ||
|
|
d474a76cf0 | ||
|
|
1f6eb6e763 | ||
|
|
3ed7f9664c | ||
|
|
35f6c598e7 | ||
|
|
87910e80af | ||
|
|
ddc7794c8d | ||
|
|
1265c3fbed | ||
|
|
14fae833cb | ||
|
|
fed3d80a3d | ||
|
|
88c003681b | ||
|
|
6b901429d0 | ||
|
|
6e274f640f | ||
|
|
0060fcbfd7 | ||
|
|
79c51625a8 | ||
|
|
42bf00f17e | ||
|
|
754bf84abe | ||
|
|
9ae0aad46d | ||
|
|
256af31b38 | ||
|
|
bd6825833d | ||
|
|
af3ae3f1fa | ||
|
|
df20f84ae2 | ||
|
|
825c1c4407 | ||
|
|
9b36fdf9bd | ||
|
|
c3f9d584a4 | ||
|
|
6c7d848727 | ||
|
|
7bd0bf9908 | ||
|
|
01ef4d7060 | ||
|
|
81e88f8d34 | ||
|
|
e927c43222 | ||
|
|
812597505d | ||
|
|
b4d710d58f | ||
|
|
d99d02994a | ||
|
|
46789aecaa | ||
|
|
6c55a67f9a | ||
|
|
f86a827bb6 | ||
|
|
79485ec5da | ||
|
|
f71acdf9fe | ||
|
|
ed767b4a54 | ||
|
|
eb527a5494 | ||
|
|
f71881ef78 | ||
|
|
a8b1ef83f1 | ||
|
|
76144a7f7d | ||
|
|
54b7fa3944 | ||
|
|
ef538570c8 | ||
|
|
352c50c2e5 | ||
|
|
bb3e6399a4 | ||
|
|
fbb58f1954 | ||
|
|
8c6d139d67 | ||
|
|
db6551c22d | ||
|
|
d436be7e96 | ||
|
|
4694ab4773 | ||
|
|
7b61445f83 | ||
|
|
ca21f5800b | ||
|
|
b0a237bcc1 | ||
|
|
d6d626e932 | ||
|
|
91efb61e97 | ||
|
|
0325c07bd9 | ||
|
|
ffa77f0a76 | ||
|
|
588dedc265 | ||
|
|
1a04ad98bc | ||
|
|
9b1836e366 | ||
|
|
b719faa627 | ||
|
|
ba40a99ef8 | ||
|
|
b8a368a47f | ||
|
|
91b8c1c4a0 | ||
|
|
23b2d43440 | ||
|
|
feb1ab86f0 | ||
|
|
b45a793e28 | ||
|
|
23e3062c3b | ||
|
|
b385dfd5a8 | ||
|
|
e79ded9046 | ||
|
|
2515fc0ebc | ||
|
|
6d1dc24fa7 | ||
|
|
7a117caaea | ||
|
|
6bff0f48a2 | ||
|
|
2fa4424f71 | ||
|
|
b9238ea436 | ||
|
|
4c4a2658fe | ||
|
|
e3a4d3074c | ||
|
|
fb8f549d93 | ||
|
|
815337dde1 | ||
|
|
76b55c4a5a | ||
|
|
1e973f3681 | ||
|
|
8d17a95265 | ||
|
|
0ff0aecb22 | ||
|
|
602c9e720e | ||
|
|
bc2932383b | ||
|
|
08dd9477c2 | ||
|
|
35dccb5f3d | ||
|
|
75a959389c | ||
|
|
c2ecad7ddb | ||
|
|
22e4606358 | ||
|
|
9abe340a1f | ||
|
|
cbd0caa4ab | ||
|
|
3cdc6a18ae | ||
|
|
ada77a3c8b | ||
|
|
6b2c96615f | ||
|
|
17ef056579 | ||
|
|
1cbcf40637 | ||
|
|
855683e980 | ||
|
|
4bbd06f51f | ||
|
|
f2f6d34f21 | ||
|
|
b3e23bcc31 | ||
|
|
3ee642868d | ||
|
|
a286dc349a | ||
|
|
12627d19fa | ||
|
|
18b6216f78 | ||
|
|
7a4e4134da | ||
|
|
7d4611941a | ||
|
|
5e89bf99a8 | ||
|
|
a349fdd367 | ||
|
|
e47c4ff2ad | ||
|
|
6c5e33e3d2 | ||
|
|
1aa7cbb918 | ||
|
|
4e8157e3cb | ||
|
|
676bc5ee2a | ||
|
|
eaf6d8123d | ||
|
|
2bbf1e37fc | ||
|
|
5c80716724 | ||
|
|
01e420fd02 | ||
|
|
33ed98e8b7 | ||
|
|
63c7b21f4b | ||
|
|
c2c0a96f40 | ||
|
|
35fe816918 | ||
|
|
48170f5ce0 | ||
|
|
f1aa5ef804 | ||
|
|
bd86ffb35b | ||
|
|
5b1bab0921 | ||
|
|
8dc3948221 | ||
|
|
7a33225fd0 | ||
|
|
c8d0384907 | ||
|
|
04ca858e85 | ||
|
|
068c57acdd | ||
|
|
c78bae69c8 | ||
|
|
2d86b13d44 | ||
|
|
aceab25d9b | ||
|
|
5dcc161f2d | ||
|
|
3d50a4d254 | ||
|
|
fb50ba407d | ||
|
|
d9aa3bbdfa | ||
|
|
8ad05b778d | ||
|
|
1ba51013a4 | ||
|
|
4140ce0f10 | ||
|
|
bb418f9614 | ||
|
|
1345fa982a | ||
|
|
3f2690c3b3 | ||
|
|
18fc76fdb8 | ||
|
|
aae4a1e3f9 | ||
|
|
0b74535b4a | ||
|
|
1feb35efb7 | ||
|
|
5658abd716 | ||
|
|
4e060ce368 | ||
|
|
010bc39465 | ||
|
|
23e4281ddb | ||
|
|
7fa3645e5d | ||
|
|
3cd7594247 | ||
|
|
9b0b4df181 | ||
|
|
109f938968 | ||
|
|
3280f02d6a | ||
|
|
24230dc205 | ||
|
|
3a045ef4e5 | ||
|
|
7d597782b8 | ||
|
|
e57f9e9a1b | ||
|
|
1d4f6e0564 | ||
|
|
e401364fa1 | ||
|
|
03fcfdd53a | ||
|
|
9e6b085e81 | ||
|
|
33fcfdef3d | ||
|
|
dd598f8aa5 | ||
|
|
5a7f349bfa | ||
|
|
64a53f8ba0 | ||
|
|
51fbee69c2 | ||
|
|
764a5d1457 | ||
|
|
64d24c744a | ||
|
|
333e18a1da | ||
|
|
2736b0149c | ||
|
|
fd8fd0b70e | ||
|
|
775a0eebaa | ||
|
|
0c61c9d2b2 | ||
|
|
fe6e7a8ed8 | ||
|
|
074ea79b9a | ||
|
|
5dec75abf3 | ||
|
|
05d1788c1f | ||
|
|
ce13360f9b | ||
|
|
42df07c23a | ||
|
|
27d0af917a | ||
|
|
51230f6ee3 | ||
|
|
7e69931455 | ||
|
|
8d245e6bc2 | ||
|
|
22cd2844d3 | ||
|
|
f15ad39181 | ||
|
|
3515580889 | ||
|
|
d171ace902 | ||
|
|
249d209f45 | ||
|
|
c3344d0734 | ||
|
|
e456098a35 | ||
|
|
e89ed8a1f9 | ||
|
|
e62e72edfd | ||
|
|
fa8efb6ca9 | ||
|
|
45ae088fd8 | ||
|
|
3f133a7e84 | ||
|
|
236f413e01 | ||
|
|
3945dbfa54 | ||
|
|
87e39c7f23 | ||
|
|
671628484b | ||
|
|
28d2daea3f | ||
|
|
41a2e020bd | ||
|
|
17f6cad0e9 | ||
|
|
5112b49b94 | ||
|
|
4110810431 | ||
|
|
cee5dd0cba | ||
|
|
c33e0a5f30 | ||
|
|
26d0e9df5d | ||
|
|
933593223f | ||
|
|
5975ee4932 | ||
|
|
99a3a09033 | ||
|
|
ac35f348c4 | ||
|
|
f46dab6c84 | ||
|
|
c8de28c0a0 | ||
|
|
d65e0a9181 | ||
|
|
535fd73cc9 | ||
|
|
752194b19e | ||
|
|
cbcc4ead36 | ||
|
|
bac0e02fae | ||
|
|
2e02e15875 | ||
|
|
f0bb846345 | ||
|
|
9113469d9d | ||
|
|
de57b2bc9f | ||
|
|
cc60ddde1c | ||
|
|
a5f5fed695 | ||
|
|
2430dbfd04 | ||
|
|
e40d713878 | ||
|
|
d1c6660c32 | ||
|
|
96a9c3446f | ||
|
|
75d77b70cc | ||
|
|
50f5c83cf2 | ||
|
|
19e33b2e29 | ||
|
|
d8b6579f59 | ||
|
|
ebcd27e1b3 | ||
|
|
da6a915779 | ||
|
|
c2c1a9200e | ||
|
|
fac92ef2d0 | ||
|
|
dc5080c61d | ||
|
|
3e87a05de8 | ||
|
|
e5a9bcd786 | ||
|
|
36248cc803 | ||
|
|
0b1d109460 | ||
|
|
d4d7c6de64 | ||
|
|
6d6c1f343d | ||
|
|
3a3f8096e7 | ||
|
|
b20aa3fb07 | ||
|
|
ef69a46f00 | ||
|
|
f99dc7b266 | ||
|
|
43ec1a77cf | ||
|
|
28f2527f86 | ||
|
|
bf98e9636c | ||
|
|
391c8150f5 | ||
|
|
6f7cbf7194 | ||
|
|
d59f0df23f | ||
|
|
09463f4e72 | ||
|
|
16cf439f6b | ||
|
|
cb991fbf14 | ||
|
|
9103e2697f | ||
|
|
77758e5ba6 | ||
|
|
497f0cd48b | ||
|
|
913cf53617 | ||
|
|
79c99b0c61 | ||
|
|
136b046b38 | ||
|
|
e8cc0ee453 | ||
|
|
d88cc79736 | ||
|
|
967553d582 | ||
|
|
4f410f53b8 | ||
|
|
8c59edefb2 | ||
|
|
0eabd4fcd9 | ||
|
|
f713d8b13e | ||
|
|
2f74e3e765 | ||
|
|
e01fe66519 | ||
|
|
93fa56fe79 | ||
|
|
c8cb81d1f9 | ||
|
|
cdac3f9726 | ||
|
|
44c8e78873 | ||
|
|
dc11ec418b | ||
|
|
1e9d8d0ca1 | ||
|
|
05e2ec3f82 | ||
|
|
a4de52d135 | ||
|
|
0e38056a3a | ||
|
|
2abb79cd57 | ||
|
|
219b123271 | ||
|
|
fd3abe42bf | ||
|
|
625b9563bf | ||
|
|
0337a0dc18 | ||
|
|
b9ea00c372 | ||
|
|
59e85abe9e | ||
|
|
e36915b0ef | ||
|
|
da65f75372 | ||
|
|
8ce59ff073 | ||
|
|
c66e7de6a8 | ||
|
|
0aa936d2d2 | ||
|
|
45e6af2d14 | ||
|
|
c6b5130ad5 | ||
|
|
fe631a5eaf | ||
|
|
f61471c451 | ||
|
|
16005fa6cf | ||
|
|
cb3e971ebc | ||
|
|
719ef68aeb | ||
|
|
3a8e1779d9 | ||
|
|
2882f6d37c | ||
|
|
69b4d577d5 | ||
|
|
9580362332 | ||
|
|
5ec1068230 | ||
|
|
e09a012064 | ||
|
|
a1fc6391d7 | ||
|
|
fc2f9b5ab6 | ||
|
|
d5bf0cb33f | ||
|
|
97468a3935 | ||
|
|
158b50f482 | ||
|
|
359b7d6b39 | ||
|
|
192ac4cae3 | ||
|
|
59c4e170a8 | ||
|
|
bb50f90a64 | ||
|
|
20e72d3304 | ||
|
|
59c0c06a8e | ||
|
|
6aa64ba2cc | ||
|
|
b79e295c71 | ||
|
|
a99a6a4721 | ||
|
|
3211545a63 | ||
|
|
21e8993c71 | ||
|
|
b4f67c9d5f | ||
|
|
80761ba069 | ||
|
|
aa23ec0714 | ||
|
|
65bdb1722c | ||
|
|
b4a03fe3f0 | ||
|
|
871f4b1be8 | ||
|
|
e1501dc830 | ||
|
|
ebb1cd3f8f | ||
|
|
f3cae6bb25 | ||
|
|
0aa7127e47 | ||
|
|
b3844cb715 | ||
|
|
c89e924b67 | ||
|
|
5a3da4b9eb | ||
|
|
c449e45b72 | ||
|
|
ae164a6049 | ||
|
|
1d7f43206e | ||
|
|
ef83783d11 | ||
|
|
4921b6cf56 | ||
|
|
58fb239cf0 | ||
|
|
cdd9978c30 | ||
|
|
3ac7fa8369 | ||
|
|
be495b28da | ||
|
|
3aebdcce7b | ||
|
|
79789e28a1 | ||
|
|
a38d9a3cbf | ||
|
|
d9a7f10cfe | ||
|
|
83a38eebab | ||
|
|
14ee979bbe | ||
|
|
1aecd5738b | ||
|
|
8f031cda5f | ||
|
|
fb30a1c893 | ||
|
|
c4c0a63104 | ||
|
|
01ae97bf22 | ||
|
|
01d4b8a41c | ||
|
|
7b64df51ab | ||
|
|
509e789510 | ||
|
|
9f68fdfb61 | ||
|
|
aaa7973906 | ||
|
|
ff591a0c57 | ||
|
|
48c9e5f3b8 | ||
|
|
d941e7cdb8 | ||
|
|
09d0cdbaf8 | ||
|
|
197a36daf6 | ||
|
|
ab20f8f74e | ||
|
|
b83c19f27b | ||
|
|
fec3d745ca | ||
|
|
abec79cb0f | ||
|
|
ee9e1914b0 | ||
|
|
6f5499eefe | ||
|
|
a692794178 | ||
|
|
c075f370c7 | ||
|
|
ec98e8a82d | ||
|
|
9536e591fb | ||
|
|
4eb836ca9b | ||
|
|
d4782e67fe | ||
|
|
3057790071 | ||
|
|
ad7d35df2a | ||
|
|
2addbfabd0 | ||
|
|
0ddac5bcee | ||
|
|
eafbd15da0 | ||
|
|
cd15cec629 | ||
|
|
2443ad3314 | ||
|
|
e554fa8277 | ||
|
|
94c1321e43 | ||
|
|
29c32a924f | ||
|
|
28968163e0 | ||
|
|
20f495dfbf | ||
|
|
7a4a4e9cdd | ||
|
|
a453c32e71 | ||
|
|
9b8acdb37f | ||
|
|
88972f04f4 | ||
|
|
8fa3a425a5 | ||
|
|
9a9b6f71c2 | ||
|
|
cb49c1ec24 | ||
|
|
407a3b5d3d | ||
|
|
a4603a49a1 | ||
|
|
7f2c999b8e | ||
|
|
00b33acfe9 | ||
|
|
e820a5a1e2 | ||
|
|
344c19f049 | ||
|
|
e35ab675ba | ||
|
|
f2edd7724c | ||
|
|
c91a2b88fd | ||
|
|
e469ce171d | ||
|
|
955f4d4d24 | ||
|
|
80b508aa03 | ||
|
|
bae0c260d9 | ||
|
|
44311e2ace | ||
|
|
54e449f3c6 | ||
|
|
f916aa9a37 | ||
|
|
9772f35984 | ||
|
|
a015b9499a | ||
|
|
5494db9b33 | ||
|
|
4ca756ddf9 | ||
|
|
571b949a06 | ||
|
|
3addd03c29 | ||
|
|
fe6595ec02 | ||
|
|
f351100f86 | ||
|
|
36497ad50a | ||
|
|
0f6d6df745 | ||
|
|
6f8f0bb749 | ||
|
|
0c3ce12520 | ||
|
|
8493f515ee | ||
|
|
9e5a4b9fbb | ||
|
|
530df51e8f | ||
|
|
041c07463f | ||
|
|
1b8f702ec6 | ||
|
|
419e69b2b5 | ||
|
|
68e9f9657b | ||
|
|
5b830fdcd1 | ||
|
|
f9f8dfb619 | ||
|
|
f04005e4ca | ||
|
|
2df49aaae8 | ||
|
|
ecde34fdf4 | ||
|
|
786f756591 | ||
|
|
d7e53bfdb3 | ||
|
|
407f63b7d2 | ||
|
|
02e1d424b2 | ||
|
|
b0d86d466f | ||
|
|
021c0a03b4 | ||
|
|
6bb91f4080 | ||
|
|
815bd4fb92 | ||
|
|
cacefbe075 | ||
|
|
ec15ba8e9c | ||
|
|
f5c1b2e645 | ||
|
|
6d04ef46f4 | ||
|
|
823ab1076a | ||
|
|
7bac6a07b6 |
@@ -11,7 +11,9 @@
|
|||||||
"misc/legacy-support/*/qlpack.yml",
|
"misc/legacy-support/*/qlpack.yml",
|
||||||
"misc/suite-helpers/qlpack.yml",
|
"misc/suite-helpers/qlpack.yml",
|
||||||
"ruby/extractor-pack/codeql-extractor.yml",
|
"ruby/extractor-pack/codeql-extractor.yml",
|
||||||
"ruby/ql/consistency-queries/qlpack.yml"
|
"ruby/ql/consistency-queries/qlpack.yml",
|
||||||
|
"ql/ql/consistency-queries/qlpack.yml",
|
||||||
|
"ql/extractor-pack/codeql-extractor.yml"
|
||||||
],
|
],
|
||||||
"versionPolicies": {
|
"versionPolicies": {
|
||||||
"default": {
|
"default": {
|
||||||
|
|||||||
3
.github/labeler.yml
vendored
3
.github/labeler.yml
vendored
@@ -26,3 +26,6 @@ documentation:
|
|||||||
- "**/*.qhelp"
|
- "**/*.qhelp"
|
||||||
- "**/*.md"
|
- "**/*.md"
|
||||||
- docs/**/*
|
- docs/**/*
|
||||||
|
|
||||||
|
"QL-for-QL":
|
||||||
|
- ql/**/*
|
||||||
1
.github/workflows/check-change-note.yml
vendored
1
.github/workflows/check-change-note.yml
vendored
@@ -7,6 +7,7 @@ on:
|
|||||||
- "*/ql/src/**/*.ql"
|
- "*/ql/src/**/*.ql"
|
||||||
- "*/ql/src/**/*.qll"
|
- "*/ql/src/**/*.qll"
|
||||||
- "!**/experimental/**"
|
- "!**/experimental/**"
|
||||||
|
- "!ql/**"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check-change-note:
|
check-change-note:
|
||||||
|
|||||||
192
.github/workflows/ql-for-ql-build.yml
vendored
Normal file
192
.github/workflows/ql-for-ql-build.yml
vendored
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
name: Run QL for QL
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
env:
|
||||||
|
CARGO_TERM_COLOR: always
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
queries:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Find codeql
|
||||||
|
id: find-codeql
|
||||||
|
uses: github/codeql-action/init@erik-krogh/ql
|
||||||
|
with:
|
||||||
|
languages: javascript # does not matter
|
||||||
|
- name: Get CodeQL version
|
||||||
|
id: get-codeql-version
|
||||||
|
run: |
|
||||||
|
echo "::set-output name=version::$("${CODEQL}" --version | head -n 1 | rev | cut -d " " -f 1 | rev)"
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||||
|
- name: Cache queries
|
||||||
|
id: cache-queries
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: ${{ runner.temp }}/query-pack.zip
|
||||||
|
key: queries-${{ hashFiles('ql/**/*.ql*') }}-${{ hashFiles('ql/ql/src/ql.dbscheme*') }}-${{ steps.get-codeql-version.outputs.version }}
|
||||||
|
- name: Build query pack
|
||||||
|
if: steps.cache-queries.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
cd ql/ql/src
|
||||||
|
"${CODEQL}" pack create
|
||||||
|
cd .codeql/pack/codeql/ql-all/0.0.0
|
||||||
|
zip "${PACKZIP}" -r .
|
||||||
|
env:
|
||||||
|
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||||
|
PACKZIP: ${{ runner.temp }}/query-pack.zip
|
||||||
|
- name: Upload query pack
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: query-pack-zip
|
||||||
|
path: ${{ runner.temp }}/query-pack.zip
|
||||||
|
|
||||||
|
extractors:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Cache entire extractor
|
||||||
|
id: cache-extractor
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
ql/target/release/ql-autobuilder
|
||||||
|
ql/target/release/ql-autobuilder.exe
|
||||||
|
ql/target/release/ql-extractor
|
||||||
|
ql/target/release/ql-extractor.exe
|
||||||
|
key: ${{ runner.os }}-extractor-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }}
|
||||||
|
- name: Cache cargo
|
||||||
|
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.cargo/registry
|
||||||
|
~/.cargo/git
|
||||||
|
ql/target
|
||||||
|
key: ${{ runner.os }}-rust-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
|
||||||
|
- name: Check formatting
|
||||||
|
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||||
|
run: cd ql; cargo fmt --all -- --check
|
||||||
|
- name: Build
|
||||||
|
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||||
|
run: cd ql; cargo build --verbose
|
||||||
|
- name: Run tests
|
||||||
|
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||||
|
run: cd ql; cargo test --verbose
|
||||||
|
- name: Release build
|
||||||
|
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||||
|
run: cd ql; cargo build --release
|
||||||
|
- name: Generate dbscheme
|
||||||
|
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||||
|
run: ql/target/release/ql-generator --dbscheme ql/ql/src/ql.dbscheme --library ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: extractor-ubuntu-latest
|
||||||
|
path: |
|
||||||
|
ql/target/release/ql-autobuilder
|
||||||
|
ql/target/release/ql-autobuilder.exe
|
||||||
|
ql/target/release/ql-extractor
|
||||||
|
ql/target/release/ql-extractor.exe
|
||||||
|
retention-days: 1
|
||||||
|
package:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
needs:
|
||||||
|
- extractors
|
||||||
|
- queries
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/download-artifact@v2
|
||||||
|
with:
|
||||||
|
name: query-pack-zip
|
||||||
|
path: query-pack-zip
|
||||||
|
- uses: actions/download-artifact@v2
|
||||||
|
with:
|
||||||
|
name: extractor-ubuntu-latest
|
||||||
|
path: linux64
|
||||||
|
- run: |
|
||||||
|
unzip query-pack-zip/*.zip -d pack
|
||||||
|
cp -r ql/codeql-extractor.yml ql/tools ql/ql/src/ql.dbscheme.stats pack/
|
||||||
|
mkdir -p pack/tools/linux64
|
||||||
|
if [[ -f linux64/ql-autobuilder ]]; then
|
||||||
|
cp linux64/ql-autobuilder pack/tools/linux64/autobuilder
|
||||||
|
chmod +x pack/tools/linux64/autobuilder
|
||||||
|
fi
|
||||||
|
if [[ -f linux64/ql-extractor ]]; then
|
||||||
|
cp linux64/ql-extractor pack/tools/linux64/extractor
|
||||||
|
chmod +x pack/tools/linux64/extractor
|
||||||
|
fi
|
||||||
|
cd pack
|
||||||
|
zip -rq ../codeql-ql.zip .
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: codeql-ql-pack
|
||||||
|
path: codeql-ql.zip
|
||||||
|
retention-days: 1
|
||||||
|
analyze:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
folder: [cpp, csharp, java, javascript, python, ql, ruby]
|
||||||
|
|
||||||
|
needs:
|
||||||
|
- package
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Download pack
|
||||||
|
uses: actions/download-artifact@v2
|
||||||
|
with:
|
||||||
|
name: codeql-ql-pack
|
||||||
|
path: ${{ runner.temp }}/codeql-ql-pack-artifact
|
||||||
|
|
||||||
|
- name: Prepare pack
|
||||||
|
run: |
|
||||||
|
unzip "${PACK_ARTIFACT}/*.zip" -d "${PACK}"
|
||||||
|
env:
|
||||||
|
PACK_ARTIFACT: ${{ runner.temp }}/codeql-ql-pack-artifact
|
||||||
|
PACK: ${{ runner.temp }}/pack
|
||||||
|
- name: Hack codeql-action options
|
||||||
|
run: |
|
||||||
|
JSON=$(jq -nc --arg pack "${PACK}" '.resolve.queries=["--search-path", $pack] | .resolve.extractor=["--search-path", $pack] | .database.init=["--search-path", $pack]')
|
||||||
|
echo "CODEQL_ACTION_EXTRA_OPTIONS=${JSON}" >> ${GITHUB_ENV}
|
||||||
|
env:
|
||||||
|
PACK: ${{ runner.temp }}/pack
|
||||||
|
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Create CodeQL config file
|
||||||
|
run: |
|
||||||
|
echo "paths:" > ${CONF}
|
||||||
|
echo " - ${FOLDER}" >> ${CONF}
|
||||||
|
echo "paths-ignore:" >> ${CONF}
|
||||||
|
echo " - ql/ql/test" >> ${CONF}
|
||||||
|
echo "Config file: "
|
||||||
|
cat ${CONF}
|
||||||
|
env:
|
||||||
|
CONF: ./ql-for-ql-config.yml
|
||||||
|
FOLDER: ${{ matrix.folder }}
|
||||||
|
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@erik-krogh/ql
|
||||||
|
with:
|
||||||
|
languages: ql
|
||||||
|
db-location: ${{ runner.temp }}/db
|
||||||
|
config-file: ./ql-for-ql-config.yml
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@erik-krogh/ql
|
||||||
|
with:
|
||||||
|
category: "ql-for-ql-${{ matrix.folder }}"
|
||||||
|
|
||||||
84
.github/workflows/ql-for-ql-dataset_measure.yml
vendored
Normal file
84
.github/workflows/ql-for-ql-dataset_measure.yml
vendored
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
name: Collect database stats for QL for QL
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
paths:
|
||||||
|
- ql/ql/src/ql.dbscheme
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
paths:
|
||||||
|
- ql/ql/src/ql.dbscheme
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
measure:
|
||||||
|
env:
|
||||||
|
CODEQL_THREADS: 4 # TODO: remove this once it's set by the CLI
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
repo:
|
||||||
|
- github/codeql
|
||||||
|
- github/codeql-go
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Find codeql
|
||||||
|
id: find-codeql
|
||||||
|
uses: github/codeql-action/init@erik-krogh/ql
|
||||||
|
with:
|
||||||
|
languages: javascript # does not matter
|
||||||
|
- uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.cargo/registry
|
||||||
|
~/.cargo/git
|
||||||
|
ql/target
|
||||||
|
key: ${{ runner.os }}-qltest-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||||
|
- name: Build Extractor
|
||||||
|
run: cd ql; env "PATH=$PATH:`dirname ${CODEQL}`" ./create-extractor-pack.sh
|
||||||
|
env:
|
||||||
|
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||||
|
- name: Checkout ${{ matrix.repo }}
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
repository: ${{ matrix.repo }}
|
||||||
|
path: ${{ github.workspace }}/repo
|
||||||
|
- name: Create database
|
||||||
|
run: |
|
||||||
|
"${CODEQL}" database create \
|
||||||
|
--search-path "ql/extractor-pack" \
|
||||||
|
--threads 4 \
|
||||||
|
--language ql --source-root "${{ github.workspace }}/repo" \
|
||||||
|
"${{ runner.temp }}/database"
|
||||||
|
env:
|
||||||
|
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||||
|
- name: Measure database
|
||||||
|
run: |
|
||||||
|
mkdir -p "stats/${{ matrix.repo }}"
|
||||||
|
"${CODEQL}" dataset measure --threads 4 --output "stats/${{ matrix.repo }}/stats.xml" "${{ runner.temp }}/database/db-ql"
|
||||||
|
env:
|
||||||
|
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: measurements
|
||||||
|
path: stats
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
merge:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: measure
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/download-artifact@v2
|
||||||
|
with:
|
||||||
|
name: measurements
|
||||||
|
path: stats
|
||||||
|
- run: |
|
||||||
|
python -m pip install --user lxml
|
||||||
|
find stats -name 'stats.xml' -print0 | sort -z | xargs -0 python ql/scripts/merge_stats.py --output ql/ql/src/ql.dbscheme.stats --normalise ql_tokeninfo
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: ql.dbscheme.stats
|
||||||
|
path: ql/ql/src/ql.dbscheme.stats
|
||||||
52
.github/workflows/ql-for-ql-tests.yml
vendored
Normal file
52
.github/workflows/ql-for-ql-tests.yml
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
name: Run QL for QL Tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
paths:
|
||||||
|
- "ql/**"
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
paths:
|
||||||
|
- "ql/**"
|
||||||
|
|
||||||
|
env:
|
||||||
|
CARGO_TERM_COLOR: always
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
qltest:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Find codeql
|
||||||
|
id: find-codeql
|
||||||
|
uses: github/codeql-action/init@erik-krogh/ql
|
||||||
|
with:
|
||||||
|
languages: javascript # does not matter
|
||||||
|
- uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.cargo/registry
|
||||||
|
~/.cargo/git
|
||||||
|
ql/target
|
||||||
|
key: ${{ runner.os }}-qltest-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||||
|
- name: Build extractor
|
||||||
|
run: |
|
||||||
|
cd ql;
|
||||||
|
codeqlpath=$(dirname ${{ steps.find-codeql.outputs.codeql-path }});
|
||||||
|
env "PATH=$PATH:$codeqlpath" ./create-extractor-pack.sh
|
||||||
|
- name: Run QL tests
|
||||||
|
run: |
|
||||||
|
"${CODEQL}" test run --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --search-path "${{ github.workspace }}/ql/extractor-pack" --consistency-queries ql/ql/consistency-queries ql/ql/test
|
||||||
|
env:
|
||||||
|
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||||
|
- name: Check QL formatting
|
||||||
|
run: |
|
||||||
|
find ql/ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 "${CODEQL}" query format --check-only
|
||||||
|
env:
|
||||||
|
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||||
|
- name: Check QL compilation
|
||||||
|
run: |
|
||||||
|
"${CODEQL}" query compile --check-only --threads=4 --warnings=error --search-path "${{ github.workspace }}/ql/extractor-pack" "ql/ql/src" "ql/ql/examples"
|
||||||
|
env:
|
||||||
|
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||||
2
.github/workflows/ruby-dataset-measure.yml
vendored
2
.github/workflows/ruby-dataset-measure.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
repo: [rails/rails, discourse/discourse, spree/spree]
|
repo: [rails/rails, discourse/discourse, spree/spree, ruby/ruby]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|||||||
@@ -25,3 +25,6 @@
|
|||||||
/docs/codeql-for-visual-studio-code/ @github/codeql-vscode-reviewers
|
/docs/codeql-for-visual-studio-code/ @github/codeql-vscode-reviewers
|
||||||
/docs/ql-language-reference/ @github/codeql-frontend-reviewers
|
/docs/ql-language-reference/ @github/codeql-frontend-reviewers
|
||||||
/docs/query-*-style-guide.md @github/codeql-analysis-reviewers
|
/docs/query-*-style-guide.md @github/codeql-analysis-reviewers
|
||||||
|
|
||||||
|
# QL for QL reviewers
|
||||||
|
/ql/ @erik-krogh @tausbn
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Build" Version="16.9.0" />
|
<PackageReference Include="Microsoft.Build" Version="16.11.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
2
cpp/change-notes/2021-10-07-cleartext-transmission.md
Normal file
2
cpp/change-notes/2021-10-07-cleartext-transmission.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
lgtm,codescanning
|
||||||
|
* The "Cleartext transmission of sensitive information" (`cpp/cleartext-transmission`) query has been improved, reducing the number of false positive results when encryption is present.
|
||||||
2
cpp/change-notes/2021-11-25-certificate-not-checked.md
Normal file
2
cpp/change-notes/2021-11-25-certificate-not-checked.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
lgtm,codescanning
|
||||||
|
* A new query `cpp/certificate-not-checked` has been added for C/C++. The query flags unsafe use of OpenSSL and similar libraries.
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
lgtm,codescanning
|
||||||
|
* A new query `cpp/certificate-result-conflation` has been added for C/C++. The query flags unsafe use of OpenSSL and similar libraries.
|
||||||
@@ -73,7 +73,7 @@ class Options extends string {
|
|||||||
* __assume(0);
|
* __assume(0);
|
||||||
* ```
|
* ```
|
||||||
* (note that in this case if the hint is wrong and the expression is reached at
|
* (note that in this case if the hint is wrong and the expression is reached at
|
||||||
* runtime, the program's behaviour is undefined)
|
* runtime, the program's behavior is undefined)
|
||||||
*/
|
*/
|
||||||
predicate exprExits(Expr e) {
|
predicate exprExits(Expr e) {
|
||||||
e.(AssumeExpr).getChild(0).(CompileTimeConstantInt).getIntValue() = 0 or
|
e.(AssumeExpr).getChild(0).(CompileTimeConstantInt).getIntValue() = 0 or
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ class CustomOptions extends Options {
|
|||||||
* __assume(0);
|
* __assume(0);
|
||||||
* ```
|
* ```
|
||||||
* (note that in this case if the hint is wrong and the expression is reached at
|
* (note that in this case if the hint is wrong and the expression is reached at
|
||||||
* runtime, the program's behaviour is undefined)
|
* runtime, the program's behavior is undefined)
|
||||||
*/
|
*/
|
||||||
override predicate exprExits(Expr e) { Options.super.exprExits(e) }
|
override predicate exprExits(Expr e) { Options.super.exprExits(e) }
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* `Instruction` level), and then using the array length analysis and the range
|
* `Instruction` level), and then using the array length analysis and the range
|
||||||
* analysis together to prove that some of these pointer dereferences are safe.
|
* analysis together to prove that some of these pointer dereferences are safe.
|
||||||
*
|
*
|
||||||
* The analysis is soundy, i.e. it is sound if no undefined behaviour is present
|
* The analysis is soundy, i.e. it is sound if no undefined behavior is present
|
||||||
* in the program.
|
* in the program.
|
||||||
* Furthermore, it crucially depends on the soundiness of the range analysis and
|
* Furthermore, it crucially depends on the soundiness of the range analysis and
|
||||||
* the array length analysis.
|
* the array length analysis.
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
name: codeql/cpp-all
|
name: codeql/cpp-all
|
||||||
version: 0.0.4
|
version: 0.0.5-dev
|
||||||
groups: cpp
|
groups: cpp
|
||||||
dbscheme: semmlecode.cpp.dbscheme
|
dbscheme: semmlecode.cpp.dbscheme
|
||||||
extractor: cpp
|
extractor: cpp
|
||||||
library: true
|
library: true
|
||||||
dependencies:
|
dependencies:
|
||||||
codeql/cpp-upgrades: 0.0.3
|
codeql/cpp-upgrades: ^0.0.3
|
||||||
|
|||||||
@@ -9,6 +9,83 @@ import semmle.code.cpp.models.interfaces.FormattingFunction
|
|||||||
private import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
|
private import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
|
||||||
private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
|
private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
|
||||||
|
|
||||||
|
private newtype TBufferWriteEstimationReason =
|
||||||
|
TNoSpecifiedEstimateReason() or
|
||||||
|
TTypeBoundsAnalysis() or
|
||||||
|
TValueFlowAnalysis()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reason for a specific buffer write size estimate.
|
||||||
|
*/
|
||||||
|
abstract class BufferWriteEstimationReason extends TBufferWriteEstimationReason {
|
||||||
|
/**
|
||||||
|
* Returns the name of the concrete class.
|
||||||
|
*/
|
||||||
|
abstract string toString();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a human readable representation of this reason.
|
||||||
|
*/
|
||||||
|
abstract string getDescription();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combine estimate reasons. Used to give a reason for the size of a format string
|
||||||
|
* conversion given reasons coming from its individual specifiers.
|
||||||
|
*/
|
||||||
|
abstract BufferWriteEstimationReason combineWith(BufferWriteEstimationReason other);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No particular reason given. This is currently used for backward compatibility so that
|
||||||
|
* classes derived from BufferWrite and overriding `getMaxData/0` still work with the
|
||||||
|
* queries as intended.
|
||||||
|
*/
|
||||||
|
class NoSpecifiedEstimateReason extends BufferWriteEstimationReason, TNoSpecifiedEstimateReason {
|
||||||
|
override string toString() { result = "NoSpecifiedEstimateReason" }
|
||||||
|
|
||||||
|
override string getDescription() { result = "no reason specified" }
|
||||||
|
|
||||||
|
override BufferWriteEstimationReason combineWith(BufferWriteEstimationReason other) {
|
||||||
|
// this reason should not be used in format specifiers, so it should not be combined
|
||||||
|
// with other reasons
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The estimation comes from rough bounds just based on the type (e.g.
|
||||||
|
* `0 <= x < 2^32` for an unsigned 32 bit integer).
|
||||||
|
*/
|
||||||
|
class TypeBoundsAnalysis extends BufferWriteEstimationReason, TTypeBoundsAnalysis {
|
||||||
|
override string toString() { result = "TypeBoundsAnalysis" }
|
||||||
|
|
||||||
|
override string getDescription() { result = "based on type bounds" }
|
||||||
|
|
||||||
|
override BufferWriteEstimationReason combineWith(BufferWriteEstimationReason other) {
|
||||||
|
other != TNoSpecifiedEstimateReason() and result = TTypeBoundsAnalysis()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The estimation comes from non trivial bounds found via actual flow analysis.
|
||||||
|
* For example
|
||||||
|
* ```
|
||||||
|
* unsigned u = x;
|
||||||
|
* if (u < 1000) {
|
||||||
|
* //... <- estimation done here based on u
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
class ValueFlowAnalysis extends BufferWriteEstimationReason, TValueFlowAnalysis {
|
||||||
|
override string toString() { result = "ValueFlowAnalysis" }
|
||||||
|
|
||||||
|
override string getDescription() { result = "based on flow analysis of value bounds" }
|
||||||
|
|
||||||
|
override BufferWriteEstimationReason combineWith(BufferWriteEstimationReason other) {
|
||||||
|
other != TNoSpecifiedEstimateReason() and result = other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class PrintfFormatAttribute extends FormatAttribute {
|
class PrintfFormatAttribute extends FormatAttribute {
|
||||||
PrintfFormatAttribute() { this.getArchetype() = ["printf", "__printf__"] }
|
PrintfFormatAttribute() { this.getArchetype() = ["printf", "__printf__"] }
|
||||||
}
|
}
|
||||||
@@ -990,7 +1067,14 @@ class FormatLiteral extends Literal {
|
|||||||
* conversion specifier of this format string; has no result if this cannot
|
* conversion specifier of this format string; has no result if this cannot
|
||||||
* be determined.
|
* be determined.
|
||||||
*/
|
*/
|
||||||
int getMaxConvertedLength(int n) {
|
int getMaxConvertedLength(int n) { result = max(getMaxConvertedLength(n, _)) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the maximum length of the string that can be produced by the nth
|
||||||
|
* conversion specifier of this format string, specifying the estimation reason;
|
||||||
|
* has no result if this cannot be determined.
|
||||||
|
*/
|
||||||
|
int getMaxConvertedLength(int n, BufferWriteEstimationReason reason) {
|
||||||
exists(int len |
|
exists(int len |
|
||||||
(
|
(
|
||||||
(
|
(
|
||||||
@@ -1002,10 +1086,12 @@ class FormatLiteral extends Literal {
|
|||||||
) and
|
) and
|
||||||
(
|
(
|
||||||
this.getConversionChar(n) = "%" and
|
this.getConversionChar(n) = "%" and
|
||||||
len = 1
|
len = 1 and
|
||||||
|
reason = TValueFlowAnalysis()
|
||||||
or
|
or
|
||||||
this.getConversionChar(n).toLowerCase() = "c" and
|
this.getConversionChar(n).toLowerCase() = "c" and
|
||||||
len = 1 // e.g. 'a'
|
len = 1 and
|
||||||
|
reason = TValueFlowAnalysis() // e.g. 'a'
|
||||||
or
|
or
|
||||||
this.getConversionChar(n).toLowerCase() = "f" and
|
this.getConversionChar(n).toLowerCase() = "f" and
|
||||||
exists(int dot, int afterdot |
|
exists(int dot, int afterdot |
|
||||||
@@ -1019,7 +1105,8 @@ class FormatLiteral extends Literal {
|
|||||||
afterdot = 6
|
afterdot = 6
|
||||||
) and
|
) and
|
||||||
len = 1 + 309 + dot + afterdot
|
len = 1 + 309 + dot + afterdot
|
||||||
) // e.g. -1e308="-100000"...
|
) and
|
||||||
|
reason = TTypeBoundsAnalysis() // e.g. -1e308="-100000"...
|
||||||
or
|
or
|
||||||
this.getConversionChar(n).toLowerCase() = "e" and
|
this.getConversionChar(n).toLowerCase() = "e" and
|
||||||
exists(int dot, int afterdot |
|
exists(int dot, int afterdot |
|
||||||
@@ -1033,7 +1120,8 @@ class FormatLiteral extends Literal {
|
|||||||
afterdot = 6
|
afterdot = 6
|
||||||
) and
|
) and
|
||||||
len = 1 + 1 + dot + afterdot + 1 + 1 + 3
|
len = 1 + 1 + dot + afterdot + 1 + 1 + 3
|
||||||
) // -1e308="-1.000000e+308"
|
) and
|
||||||
|
reason = TTypeBoundsAnalysis() // -1e308="-1.000000e+308"
|
||||||
or
|
or
|
||||||
this.getConversionChar(n).toLowerCase() = "g" and
|
this.getConversionChar(n).toLowerCase() = "g" and
|
||||||
exists(int dot, int afterdot |
|
exists(int dot, int afterdot |
|
||||||
@@ -1056,67 +1144,80 @@ class FormatLiteral extends Literal {
|
|||||||
// (e.g. 123456, 0.000123456 are just OK)
|
// (e.g. 123456, 0.000123456 are just OK)
|
||||||
// so case %f can be at most P characters + 4 zeroes, sign, dot = P + 6
|
// so case %f can be at most P characters + 4 zeroes, sign, dot = P + 6
|
||||||
len = (afterdot.maximum(1) + 6).maximum(1 + 1 + dot + afterdot + 1 + 1 + 3)
|
len = (afterdot.maximum(1) + 6).maximum(1 + 1 + dot + afterdot + 1 + 1 + 3)
|
||||||
) // (e.g. "-1.59203e-319")
|
) and
|
||||||
|
reason = TTypeBoundsAnalysis() // (e.g. "-1.59203e-319")
|
||||||
or
|
or
|
||||||
this.getConversionChar(n).toLowerCase() = ["d", "i"] and
|
this.getConversionChar(n).toLowerCase() = ["d", "i"] and
|
||||||
// e.g. -2^31 = "-2147483648"
|
// e.g. -2^31 = "-2147483648"
|
||||||
len =
|
exists(float typeBasedBound, float valueBasedBound |
|
||||||
min(float cand |
|
// The first case handles length sub-specifiers
|
||||||
// The first case handles length sub-specifiers
|
// Subtract one in the exponent because one bit is for the sign.
|
||||||
// Subtract one in the exponent because one bit is for the sign.
|
// Add 1 to account for the possible sign in the output.
|
||||||
// Add 1 to account for the possible sign in the output.
|
typeBasedBound =
|
||||||
cand = 1 + lengthInBase10(2.pow(this.getIntegralDisplayType(n).getSize() * 8 - 1))
|
1 + lengthInBase10(2.pow(this.getIntegralDisplayType(n).getSize() * 8 - 1)) and
|
||||||
or
|
// The second case uses range analysis to deduce a length that's shorter than the length
|
||||||
// The second case uses range analysis to deduce a length that's shorter than the length
|
// of the number -2^31.
|
||||||
// of the number -2^31.
|
exists(Expr arg, float lower, float upper, float typeLower, float typeUpper |
|
||||||
exists(Expr arg, float lower, float upper |
|
arg = this.getUse().getConversionArgument(n) and
|
||||||
arg = this.getUse().getConversionArgument(n) and
|
lower = lowerBound(arg.getFullyConverted()) and
|
||||||
lower = lowerBound(arg.getFullyConverted()) and
|
upper = upperBound(arg.getFullyConverted()) and
|
||||||
upper = upperBound(arg.getFullyConverted())
|
typeLower = exprMinVal(arg.getFullyConverted()) and
|
||||||
|
|
typeUpper = exprMaxVal(arg.getFullyConverted())
|
||||||
cand =
|
|
|
||||||
max(int cand0 |
|
valueBasedBound =
|
||||||
// Include the sign bit in the length if it can be negative
|
max(int cand |
|
||||||
(
|
// Include the sign bit in the length if it can be negative
|
||||||
if lower < 0
|
(
|
||||||
then cand0 = 1 + lengthInBase10(lower.abs())
|
if lower < 0
|
||||||
else cand0 = lengthInBase10(lower)
|
then cand = 1 + lengthInBase10(lower.abs())
|
||||||
)
|
else cand = lengthInBase10(lower)
|
||||||
or
|
|
||||||
(
|
|
||||||
if upper < 0
|
|
||||||
then cand0 = 1 + lengthInBase10(upper.abs())
|
|
||||||
else cand0 = lengthInBase10(upper)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
(
|
||||||
|
if upper < 0
|
||||||
|
then cand = 1 + lengthInBase10(upper.abs())
|
||||||
|
else cand = lengthInBase10(upper)
|
||||||
|
)
|
||||||
|
) and
|
||||||
|
(
|
||||||
|
if lower > typeLower or upper < typeUpper
|
||||||
|
then reason = TValueFlowAnalysis()
|
||||||
|
else reason = TTypeBoundsAnalysis()
|
||||||
)
|
)
|
||||||
)
|
) and
|
||||||
|
len = valueBasedBound.minimum(typeBasedBound)
|
||||||
|
)
|
||||||
or
|
or
|
||||||
this.getConversionChar(n).toLowerCase() = "u" and
|
this.getConversionChar(n).toLowerCase() = "u" and
|
||||||
// e.g. 2^32 - 1 = "4294967295"
|
// e.g. 2^32 - 1 = "4294967295"
|
||||||
len =
|
exists(float typeBasedBound, float valueBasedBound |
|
||||||
min(float cand |
|
// The first case handles length sub-specifiers
|
||||||
// The first case handles length sub-specifiers
|
typeBasedBound = lengthInBase10(2.pow(this.getIntegralDisplayType(n).getSize() * 8) - 1) and
|
||||||
cand = 2.pow(this.getIntegralDisplayType(n).getSize() * 8)
|
// The second case uses range analysis to deduce a length that's shorter than
|
||||||
or
|
// the length of the number 2^31 - 1.
|
||||||
// The second case uses range analysis to deduce a length that's shorter than
|
exists(Expr arg, float lower, float upper, float typeLower, float typeUpper |
|
||||||
// the length of the number 2^31 - 1.
|
arg = this.getUse().getConversionArgument(n) and
|
||||||
exists(Expr arg, float lower |
|
lower = lowerBound(arg.getFullyConverted()) and
|
||||||
arg = this.getUse().getConversionArgument(n) and
|
upper = upperBound(arg.getFullyConverted()) and
|
||||||
lower = lowerBound(arg.getFullyConverted())
|
typeLower = exprMinVal(arg.getFullyConverted()) and
|
||||||
|
|
typeUpper = exprMaxVal(arg.getFullyConverted())
|
||||||
cand =
|
|
|
||||||
max(float cand0 |
|
valueBasedBound =
|
||||||
|
lengthInBase10(max(float cand |
|
||||||
// If lower can be negative we use `(unsigned)-1` as the candidate value.
|
// If lower can be negative we use `(unsigned)-1` as the candidate value.
|
||||||
lower < 0 and
|
lower < 0 and
|
||||||
cand0 = 2.pow(any(IntType t | t.isUnsigned()).getSize() * 8)
|
cand = 2.pow(any(IntType t | t.isUnsigned()).getSize() * 8)
|
||||||
or
|
or
|
||||||
cand0 = upperBound(arg.getFullyConverted())
|
cand = upper
|
||||||
)
|
)) and
|
||||||
|
(
|
||||||
|
if lower > typeLower or upper < typeUpper
|
||||||
|
then reason = TValueFlowAnalysis()
|
||||||
|
else reason = TTypeBoundsAnalysis()
|
||||||
)
|
)
|
||||||
|
|
) and
|
||||||
lengthInBase10(cand)
|
len = valueBasedBound.minimum(typeBasedBound)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
this.getConversionChar(n).toLowerCase() = "x" and
|
this.getConversionChar(n).toLowerCase() = "x" and
|
||||||
// e.g. "12345678"
|
// e.g. "12345678"
|
||||||
@@ -1135,7 +1236,8 @@ class FormatLiteral extends Literal {
|
|||||||
(
|
(
|
||||||
if this.hasAlternateFlag(n) then len = 2 + baseLen else len = baseLen // "0x"
|
if this.hasAlternateFlag(n) then len = 2 + baseLen else len = baseLen // "0x"
|
||||||
)
|
)
|
||||||
)
|
) and
|
||||||
|
reason = TTypeBoundsAnalysis()
|
||||||
or
|
or
|
||||||
this.getConversionChar(n).toLowerCase() = "p" and
|
this.getConversionChar(n).toLowerCase() = "p" and
|
||||||
exists(PointerType ptrType, int baseLen |
|
exists(PointerType ptrType, int baseLen |
|
||||||
@@ -1144,7 +1246,8 @@ class FormatLiteral extends Literal {
|
|||||||
(
|
(
|
||||||
if this.hasAlternateFlag(n) then len = 2 + baseLen else len = baseLen // "0x"
|
if this.hasAlternateFlag(n) then len = 2 + baseLen else len = baseLen // "0x"
|
||||||
)
|
)
|
||||||
)
|
) and
|
||||||
|
reason = TValueFlowAnalysis()
|
||||||
or
|
or
|
||||||
this.getConversionChar(n).toLowerCase() = "o" and
|
this.getConversionChar(n).toLowerCase() = "o" and
|
||||||
// e.g. 2^32 - 1 = "37777777777"
|
// e.g. 2^32 - 1 = "37777777777"
|
||||||
@@ -1163,14 +1266,16 @@ class FormatLiteral extends Literal {
|
|||||||
(
|
(
|
||||||
if this.hasAlternateFlag(n) then len = 1 + baseLen else len = baseLen // "0"
|
if this.hasAlternateFlag(n) then len = 1 + baseLen else len = baseLen // "0"
|
||||||
)
|
)
|
||||||
)
|
) and
|
||||||
|
reason = TTypeBoundsAnalysis()
|
||||||
or
|
or
|
||||||
this.getConversionChar(n).toLowerCase() = "s" and
|
this.getConversionChar(n).toLowerCase() = "s" and
|
||||||
len =
|
len =
|
||||||
min(int v |
|
min(int v |
|
||||||
v = this.getPrecision(n) or
|
v = this.getPrecision(n) or
|
||||||
v = this.getUse().getFormatArgument(n).(AnalysedString).getMaxLength() - 1 // (don't count null terminator)
|
v = this.getUse().getFormatArgument(n).(AnalysedString).getMaxLength() - 1 // (don't count null terminator)
|
||||||
)
|
) and
|
||||||
|
reason = TValueFlowAnalysis()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1182,10 +1287,19 @@ class FormatLiteral extends Literal {
|
|||||||
* determining whether a buffer overflow is caused by long float to string
|
* determining whether a buffer overflow is caused by long float to string
|
||||||
* conversions.
|
* conversions.
|
||||||
*/
|
*/
|
||||||
int getMaxConvertedLengthLimited(int n) {
|
int getMaxConvertedLengthLimited(int n) { result = max(getMaxConvertedLengthLimited(n, _)) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the maximum length of the string that can be produced by the nth
|
||||||
|
* conversion specifier of this format string, specifying the reason for the
|
||||||
|
* estimation, except that float to string conversions are assumed to be 8
|
||||||
|
* characters. This is helpful for determining whether a buffer overflow is
|
||||||
|
* caused by long float to string conversions.
|
||||||
|
*/
|
||||||
|
int getMaxConvertedLengthLimited(int n, BufferWriteEstimationReason reason) {
|
||||||
if this.getConversionChar(n).toLowerCase() = "f"
|
if this.getConversionChar(n).toLowerCase() = "f"
|
||||||
then result = this.getMaxConvertedLength(n).minimum(8)
|
then result = this.getMaxConvertedLength(n, reason).minimum(8)
|
||||||
else result = this.getMaxConvertedLength(n)
|
else result = this.getMaxConvertedLength(n, reason)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1225,29 +1339,35 @@ class FormatLiteral extends Literal {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getMaxConvertedLengthAfter(int n) {
|
private int getMaxConvertedLengthAfter(int n, BufferWriteEstimationReason reason) {
|
||||||
if n = this.getNumConvSpec()
|
if n = this.getNumConvSpec()
|
||||||
then result = this.getConstantSuffix().length() + 1
|
then result = this.getConstantSuffix().length() + 1 and reason = TValueFlowAnalysis()
|
||||||
else
|
else
|
||||||
result =
|
exists(BufferWriteEstimationReason headReason, BufferWriteEstimationReason tailReason |
|
||||||
this.getConstantPart(n).length() + this.getMaxConvertedLength(n) +
|
result =
|
||||||
this.getMaxConvertedLengthAfter(n + 1)
|
this.getConstantPart(n).length() + this.getMaxConvertedLength(n, headReason) +
|
||||||
|
this.getMaxConvertedLengthAfter(n + 1, tailReason) and
|
||||||
|
reason = headReason.combineWith(tailReason)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getMaxConvertedLengthAfterLimited(int n) {
|
private int getMaxConvertedLengthAfterLimited(int n, BufferWriteEstimationReason reason) {
|
||||||
if n = this.getNumConvSpec()
|
if n = this.getNumConvSpec()
|
||||||
then result = this.getConstantSuffix().length() + 1
|
then result = this.getConstantSuffix().length() + 1 and reason = TValueFlowAnalysis()
|
||||||
else
|
else
|
||||||
result =
|
exists(BufferWriteEstimationReason headReason, BufferWriteEstimationReason tailReason |
|
||||||
this.getConstantPart(n).length() + this.getMaxConvertedLengthLimited(n) +
|
result =
|
||||||
this.getMaxConvertedLengthAfterLimited(n + 1)
|
this.getConstantPart(n).length() + this.getMaxConvertedLengthLimited(n, headReason) +
|
||||||
|
this.getMaxConvertedLengthAfterLimited(n + 1, tailReason) and
|
||||||
|
reason = headReason.combineWith(tailReason)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the maximum length of the string that can be produced by this format
|
* Gets the maximum length of the string that can be produced by this format
|
||||||
* string. Has no result if this cannot be determined.
|
* string. Has no result if this cannot be determined.
|
||||||
*/
|
*/
|
||||||
int getMaxConvertedLength() { result = this.getMaxConvertedLengthAfter(0) }
|
int getMaxConvertedLength() { result = this.getMaxConvertedLengthAfter(0, _) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the maximum length of the string that can be produced by this format
|
* Gets the maximum length of the string that can be produced by this format
|
||||||
@@ -1255,5 +1375,24 @@ class FormatLiteral extends Literal {
|
|||||||
* characters. This is helpful for determining whether a buffer overflow
|
* characters. This is helpful for determining whether a buffer overflow
|
||||||
* is caused by long float to string conversions.
|
* is caused by long float to string conversions.
|
||||||
*/
|
*/
|
||||||
int getMaxConvertedLengthLimited() { result = this.getMaxConvertedLengthAfterLimited(0) }
|
int getMaxConvertedLengthLimited() { result = this.getMaxConvertedLengthAfterLimited(0, _) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the maximum length of the string that can be produced by this format
|
||||||
|
* string, specifying the reason for the estimate. Has no result if no estimate
|
||||||
|
* can be found.
|
||||||
|
*/
|
||||||
|
int getMaxConvertedLengthWithReason(BufferWriteEstimationReason reason) {
|
||||||
|
result = this.getMaxConvertedLengthAfter(0, reason)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the maximum length of the string that can be produced by this format
|
||||||
|
* string, specifying the reason for the estimate, except that float to string
|
||||||
|
* conversions are assumed to be 8 characters. This is helpful for determining
|
||||||
|
* whether a buffer overflow is caused by long float to string conversions.
|
||||||
|
*/
|
||||||
|
int getMaxConvertedLengthLimitedWithReason(BufferWriteEstimationReason reason) {
|
||||||
|
result = this.getMaxConvertedLengthAfterLimited(0, reason)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,9 +153,11 @@ library class SSAHelper extends int {
|
|||||||
* Modern Compiler Implementation by Andrew Appel.
|
* Modern Compiler Implementation by Andrew Appel.
|
||||||
*/
|
*/
|
||||||
private predicate frontier_phi_node(StackVariable v, BasicBlock b) {
|
private predicate frontier_phi_node(StackVariable v, BasicBlock b) {
|
||||||
exists(BasicBlock x | dominanceFrontier(x, b) and ssa_defn_rec(v, x)) and
|
exists(BasicBlock x |
|
||||||
|
dominanceFrontier(x, b) and ssa_defn_rec(pragma[only_bind_into](v), pragma[only_bind_into](x))
|
||||||
|
) and
|
||||||
/* We can also eliminate those nodes where the variable is not live on any incoming edge */
|
/* We can also eliminate those nodes where the variable is not live on any incoming edge */
|
||||||
live_at_start_of_bb(v, b)
|
live_at_start_of_bb(pragma[only_bind_into](v), b)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate ssa_defn_rec(StackVariable v, BasicBlock b) {
|
private predicate ssa_defn_rec(StackVariable v, BasicBlock b) {
|
||||||
|
|||||||
@@ -626,9 +626,9 @@ library class ExprEvaluator extends int {
|
|||||||
// All assignments must have the same int value
|
// All assignments must have the same int value
|
||||||
result =
|
result =
|
||||||
unique(Expr value |
|
unique(Expr value |
|
||||||
value = v.getAnAssignedValue() and not ignoreVariableAssignment(e, v, value)
|
value = v.getAnAssignedValue() and not this.ignoreVariableAssignment(e, v, value)
|
||||||
|
|
|
|
||||||
getValueInternalNonSubExpr(value)
|
this.getValueInternalNonSubExpr(value)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
private import cpp
|
private import cpp
|
||||||
|
private import semmle.code.cpp.dataflow.internal.DataFlowPrivate
|
||||||
|
private import semmle.code.cpp.dataflow.internal.DataFlowUtil
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a function that might be called by `call`.
|
* Gets a function that might be called by `call`.
|
||||||
@@ -63,3 +65,17 @@ predicate mayBenefitFromCallContext(Call call, Function f) { none() }
|
|||||||
* restricted to those `call`s for which a context might make a difference.
|
* restricted to those `call`s for which a context might make a difference.
|
||||||
*/
|
*/
|
||||||
Function viableImplInCallContext(Call call, Call ctx) { none() }
|
Function viableImplInCallContext(Call call, Call ctx) { none() }
|
||||||
|
|
||||||
|
/** A parameter position represented by an integer. */
|
||||||
|
class ParameterPosition extends int {
|
||||||
|
ParameterPosition() { any(ParameterNode p).isParameterOf(_, this) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** An argument position represented by an integer. */
|
||||||
|
class ArgumentPosition extends int {
|
||||||
|
ArgumentPosition() { any(ArgumentNode a).argumentOf(_, this) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
|
||||||
|
pragma[inline]
|
||||||
|
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
|
||||||
|
|||||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
|||||||
private class ParamNodeEx extends NodeEx {
|
private class ParamNodeEx extends NodeEx {
|
||||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||||
|
|
||||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
int getPosition() { this.isParameterOf(_, result) }
|
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||||
|
|
||||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||||
}
|
}
|
||||||
@@ -1012,6 +1012,9 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||||
|
|
||||||
|
bindingset[node, ap]
|
||||||
|
private predicate filter(NodeEx node, Ap ap) { any() }
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||||
|
|
||||||
@@ -1020,6 +1023,13 @@ private module Stage2 {
|
|||||||
PrevStage::revFlow(node, _, _, apa, config)
|
PrevStage::revFlow(node, _, _, apa, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bindingset[result, apa]
|
||||||
|
private ApApprox unbindApa(ApApprox apa) {
|
||||||
|
exists(ApApprox apa0 |
|
||||||
|
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughOutOfCall(
|
private predicate flowThroughOutOfCall(
|
||||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
@@ -1042,6 +1052,13 @@ private module Stage2 {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||||
|
fwdFlow0(node, cc, argAp, ap, config) and
|
||||||
|
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||||
|
filter(node, ap)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||||
flowCand(node, _, config) and
|
flowCand(node, _, config) and
|
||||||
sourceNode(node, config) and
|
sourceNode(node, config) and
|
||||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||||
@@ -1112,7 +1129,7 @@ private module Stage2 {
|
|||||||
) {
|
) {
|
||||||
exists(DataFlowType contentType |
|
exists(DataFlowType contentType |
|
||||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||||
typecheckStore(ap1, contentType)
|
typecheckStore(ap1, contentType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1189,7 +1206,7 @@ private module Stage2 {
|
|||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1430,7 +1447,7 @@ private module Stage2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||||
parameterFlow(p, ap, ap0, c, config) and
|
parameterFlow(p, ap, ap0, c, config) and
|
||||||
c = ret.getEnclosingCallable() and
|
c = ret.getEnclosingCallable() and
|
||||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||||
@@ -2125,7 +2142,7 @@ private module Stage3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||||
parameterFlow(p, ap, ap0, c, config) and
|
parameterFlow(p, ap, ap0, c, config) and
|
||||||
c = ret.getEnclosingCallable() and
|
c = ret.getEnclosingCallable() and
|
||||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||||
@@ -2891,7 +2908,7 @@ private module Stage4 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||||
parameterFlow(p, ap, ap0, c, config) and
|
parameterFlow(p, ap, ap0, c, config) and
|
||||||
c = ret.getEnclosingCallable() and
|
c = ret.getEnclosingCallable() and
|
||||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||||
@@ -2975,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
|||||||
|
|
||||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||||
|
|
||||||
int getParameterPos() { p.isParameterOf(_, result) }
|
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||||
|
|
||||||
ParamNodeEx getParamNode() { result = p }
|
ParamNodeEx getParamNode() { result = p }
|
||||||
|
|
||||||
@@ -3622,39 +3639,40 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate pathIntoArg(
|
private predicate pathIntoArg(
|
||||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||||
Configuration config
|
AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNode arg |
|
exists(ArgNode arg, ArgumentPosition apos |
|
||||||
arg = mid.getNodeEx().asNode() and
|
arg = mid.getNodeEx().asNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, apos) and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp() and
|
||||||
apa = ap.getApprox() and
|
apa = ap.getApprox() and
|
||||||
config = mid.getConfiguration()
|
config = mid.getConfiguration() and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parameterCand(
|
private predicate parameterCand(
|
||||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
Stage4::revFlow(p, _, _, apa, config) and
|
Stage4::revFlow(p, _, _, apa, config) and
|
||||||
p.isParameterOf(callable, i)
|
p.isParameterOf(callable, pos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate pathIntoCallable0(
|
private predicate pathIntoCallable0(
|
||||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||||
AccessPath ap, Configuration config
|
DataFlowCall call, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(AccessPathApprox apa |
|
exists(AccessPathApprox apa |
|
||||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||||
pragma[only_bind_into](config)) and
|
pragma[only_bind_into](config)) and
|
||||||
callable = resolveCall(call, outercc) and
|
callable = resolveCall(call, outercc) and
|
||||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||||
pragma[only_bind_into](config))
|
pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -3669,9 +3687,9 @@ private predicate pathIntoCallable(
|
|||||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||||
DataFlowCall call, Configuration config
|
DataFlowCall call, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, pos) and
|
||||||
(
|
(
|
||||||
sc = TSummaryCtxSome(p, ap)
|
sc = TSummaryCtxSome(p, ap)
|
||||||
or
|
or
|
||||||
@@ -3695,7 +3713,7 @@ private predicate paramFlowsThrough(
|
|||||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||||
mid.getNodeEx() = ret and
|
mid.getNodeEx() = ret and
|
||||||
kind = ret.getKind() and
|
kind = ret.getKind() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
@@ -4424,24 +4442,25 @@ private module FlowExploration {
|
|||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate partialPathIntoArg(
|
private predicate partialPathIntoArg(
|
||||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||||
Configuration config
|
PartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNode arg |
|
exists(ArgNode arg, ArgumentPosition apos |
|
||||||
arg = mid.getNodeEx().asNode() and
|
arg = mid.getNodeEx().asNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, apos) and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp() and
|
||||||
config = mid.getConfiguration()
|
config = mid.getConfiguration() and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate partialPathIntoCallable0(
|
private predicate partialPathIntoCallable0(
|
||||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||||
callable = resolveCall(call, outercc)
|
callable = resolveCall(call, outercc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4450,9 +4469,9 @@ private module FlowExploration {
|
|||||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable |
|
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, pos) and
|
||||||
sc1 = TSummaryCtx1Param(p) and
|
sc1 = TSummaryCtx1Param(p) and
|
||||||
sc2 = TSummaryCtx2Some(ap)
|
sc2 = TSummaryCtx2Some(ap)
|
||||||
|
|
|
|
||||||
@@ -4616,22 +4635,23 @@ private module FlowExploration {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revPartialPathFlowsThrough(
|
private predicate revPartialPathFlowsThrough(
|
||||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||||
Configuration config
|
RevPartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||||
mid.getNodeEx() = p and
|
mid.getNodeEx() = p and
|
||||||
p.getPosition() = pos and
|
p.getPosition() = ppos and
|
||||||
sc1 = mid.getSummaryCtx1() and
|
sc1 = mid.getSummaryCtx1() and
|
||||||
sc2 = mid.getSummaryCtx2() and
|
sc2 = mid.getSummaryCtx2() and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp() and
|
||||||
config = mid.getConfiguration()
|
config = mid.getConfiguration() and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revPartialPathThroughCallable0(
|
private predicate revPartialPathThroughCallable0(
|
||||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||||
@@ -4644,7 +4664,7 @@ private module FlowExploration {
|
|||||||
private predicate revPartialPathThroughCallable(
|
private predicate revPartialPathThroughCallable(
|
||||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCall call, int pos |
|
exists(DataFlowCall call, ArgumentPosition pos |
|
||||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
|||||||
private class ParamNodeEx extends NodeEx {
|
private class ParamNodeEx extends NodeEx {
|
||||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||||
|
|
||||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
int getPosition() { this.isParameterOf(_, result) }
|
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||||
|
|
||||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||||
}
|
}
|
||||||
@@ -1012,6 +1012,9 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||||
|
|
||||||
|
bindingset[node, ap]
|
||||||
|
private predicate filter(NodeEx node, Ap ap) { any() }
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||||
|
|
||||||
@@ -1020,6 +1023,13 @@ private module Stage2 {
|
|||||||
PrevStage::revFlow(node, _, _, apa, config)
|
PrevStage::revFlow(node, _, _, apa, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bindingset[result, apa]
|
||||||
|
private ApApprox unbindApa(ApApprox apa) {
|
||||||
|
exists(ApApprox apa0 |
|
||||||
|
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughOutOfCall(
|
private predicate flowThroughOutOfCall(
|
||||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
@@ -1042,6 +1052,13 @@ private module Stage2 {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||||
|
fwdFlow0(node, cc, argAp, ap, config) and
|
||||||
|
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||||
|
filter(node, ap)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||||
flowCand(node, _, config) and
|
flowCand(node, _, config) and
|
||||||
sourceNode(node, config) and
|
sourceNode(node, config) and
|
||||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||||
@@ -1112,7 +1129,7 @@ private module Stage2 {
|
|||||||
) {
|
) {
|
||||||
exists(DataFlowType contentType |
|
exists(DataFlowType contentType |
|
||||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||||
typecheckStore(ap1, contentType)
|
typecheckStore(ap1, contentType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1189,7 +1206,7 @@ private module Stage2 {
|
|||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1430,7 +1447,7 @@ private module Stage2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||||
parameterFlow(p, ap, ap0, c, config) and
|
parameterFlow(p, ap, ap0, c, config) and
|
||||||
c = ret.getEnclosingCallable() and
|
c = ret.getEnclosingCallable() and
|
||||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||||
@@ -2125,7 +2142,7 @@ private module Stage3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||||
parameterFlow(p, ap, ap0, c, config) and
|
parameterFlow(p, ap, ap0, c, config) and
|
||||||
c = ret.getEnclosingCallable() and
|
c = ret.getEnclosingCallable() and
|
||||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||||
@@ -2891,7 +2908,7 @@ private module Stage4 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||||
parameterFlow(p, ap, ap0, c, config) and
|
parameterFlow(p, ap, ap0, c, config) and
|
||||||
c = ret.getEnclosingCallable() and
|
c = ret.getEnclosingCallable() and
|
||||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||||
@@ -2975,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
|||||||
|
|
||||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||||
|
|
||||||
int getParameterPos() { p.isParameterOf(_, result) }
|
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||||
|
|
||||||
ParamNodeEx getParamNode() { result = p }
|
ParamNodeEx getParamNode() { result = p }
|
||||||
|
|
||||||
@@ -3622,39 +3639,40 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate pathIntoArg(
|
private predicate pathIntoArg(
|
||||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||||
Configuration config
|
AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNode arg |
|
exists(ArgNode arg, ArgumentPosition apos |
|
||||||
arg = mid.getNodeEx().asNode() and
|
arg = mid.getNodeEx().asNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, apos) and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp() and
|
||||||
apa = ap.getApprox() and
|
apa = ap.getApprox() and
|
||||||
config = mid.getConfiguration()
|
config = mid.getConfiguration() and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parameterCand(
|
private predicate parameterCand(
|
||||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
Stage4::revFlow(p, _, _, apa, config) and
|
Stage4::revFlow(p, _, _, apa, config) and
|
||||||
p.isParameterOf(callable, i)
|
p.isParameterOf(callable, pos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate pathIntoCallable0(
|
private predicate pathIntoCallable0(
|
||||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||||
AccessPath ap, Configuration config
|
DataFlowCall call, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(AccessPathApprox apa |
|
exists(AccessPathApprox apa |
|
||||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||||
pragma[only_bind_into](config)) and
|
pragma[only_bind_into](config)) and
|
||||||
callable = resolveCall(call, outercc) and
|
callable = resolveCall(call, outercc) and
|
||||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||||
pragma[only_bind_into](config))
|
pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -3669,9 +3687,9 @@ private predicate pathIntoCallable(
|
|||||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||||
DataFlowCall call, Configuration config
|
DataFlowCall call, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, pos) and
|
||||||
(
|
(
|
||||||
sc = TSummaryCtxSome(p, ap)
|
sc = TSummaryCtxSome(p, ap)
|
||||||
or
|
or
|
||||||
@@ -3695,7 +3713,7 @@ private predicate paramFlowsThrough(
|
|||||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||||
mid.getNodeEx() = ret and
|
mid.getNodeEx() = ret and
|
||||||
kind = ret.getKind() and
|
kind = ret.getKind() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
@@ -4424,24 +4442,25 @@ private module FlowExploration {
|
|||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate partialPathIntoArg(
|
private predicate partialPathIntoArg(
|
||||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||||
Configuration config
|
PartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNode arg |
|
exists(ArgNode arg, ArgumentPosition apos |
|
||||||
arg = mid.getNodeEx().asNode() and
|
arg = mid.getNodeEx().asNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, apos) and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp() and
|
||||||
config = mid.getConfiguration()
|
config = mid.getConfiguration() and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate partialPathIntoCallable0(
|
private predicate partialPathIntoCallable0(
|
||||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||||
callable = resolveCall(call, outercc)
|
callable = resolveCall(call, outercc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4450,9 +4469,9 @@ private module FlowExploration {
|
|||||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable |
|
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, pos) and
|
||||||
sc1 = TSummaryCtx1Param(p) and
|
sc1 = TSummaryCtx1Param(p) and
|
||||||
sc2 = TSummaryCtx2Some(ap)
|
sc2 = TSummaryCtx2Some(ap)
|
||||||
|
|
|
|
||||||
@@ -4616,22 +4635,23 @@ private module FlowExploration {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revPartialPathFlowsThrough(
|
private predicate revPartialPathFlowsThrough(
|
||||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||||
Configuration config
|
RevPartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||||
mid.getNodeEx() = p and
|
mid.getNodeEx() = p and
|
||||||
p.getPosition() = pos and
|
p.getPosition() = ppos and
|
||||||
sc1 = mid.getSummaryCtx1() and
|
sc1 = mid.getSummaryCtx1() and
|
||||||
sc2 = mid.getSummaryCtx2() and
|
sc2 = mid.getSummaryCtx2() and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp() and
|
||||||
config = mid.getConfiguration()
|
config = mid.getConfiguration() and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revPartialPathThroughCallable0(
|
private predicate revPartialPathThroughCallable0(
|
||||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||||
@@ -4644,7 +4664,7 @@ private module FlowExploration {
|
|||||||
private predicate revPartialPathThroughCallable(
|
private predicate revPartialPathThroughCallable(
|
||||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCall call, int pos |
|
exists(DataFlowCall call, ArgumentPosition pos |
|
||||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
|||||||
private class ParamNodeEx extends NodeEx {
|
private class ParamNodeEx extends NodeEx {
|
||||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||||
|
|
||||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
int getPosition() { this.isParameterOf(_, result) }
|
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||||
|
|
||||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||||
}
|
}
|
||||||
@@ -1012,6 +1012,9 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||||
|
|
||||||
|
bindingset[node, ap]
|
||||||
|
private predicate filter(NodeEx node, Ap ap) { any() }
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||||
|
|
||||||
@@ -1020,6 +1023,13 @@ private module Stage2 {
|
|||||||
PrevStage::revFlow(node, _, _, apa, config)
|
PrevStage::revFlow(node, _, _, apa, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bindingset[result, apa]
|
||||||
|
private ApApprox unbindApa(ApApprox apa) {
|
||||||
|
exists(ApApprox apa0 |
|
||||||
|
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughOutOfCall(
|
private predicate flowThroughOutOfCall(
|
||||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
@@ -1042,6 +1052,13 @@ private module Stage2 {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||||
|
fwdFlow0(node, cc, argAp, ap, config) and
|
||||||
|
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||||
|
filter(node, ap)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||||
flowCand(node, _, config) and
|
flowCand(node, _, config) and
|
||||||
sourceNode(node, config) and
|
sourceNode(node, config) and
|
||||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||||
@@ -1112,7 +1129,7 @@ private module Stage2 {
|
|||||||
) {
|
) {
|
||||||
exists(DataFlowType contentType |
|
exists(DataFlowType contentType |
|
||||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||||
typecheckStore(ap1, contentType)
|
typecheckStore(ap1, contentType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1189,7 +1206,7 @@ private module Stage2 {
|
|||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1430,7 +1447,7 @@ private module Stage2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||||
parameterFlow(p, ap, ap0, c, config) and
|
parameterFlow(p, ap, ap0, c, config) and
|
||||||
c = ret.getEnclosingCallable() and
|
c = ret.getEnclosingCallable() and
|
||||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||||
@@ -2125,7 +2142,7 @@ private module Stage3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||||
parameterFlow(p, ap, ap0, c, config) and
|
parameterFlow(p, ap, ap0, c, config) and
|
||||||
c = ret.getEnclosingCallable() and
|
c = ret.getEnclosingCallable() and
|
||||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||||
@@ -2891,7 +2908,7 @@ private module Stage4 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||||
parameterFlow(p, ap, ap0, c, config) and
|
parameterFlow(p, ap, ap0, c, config) and
|
||||||
c = ret.getEnclosingCallable() and
|
c = ret.getEnclosingCallable() and
|
||||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||||
@@ -2975,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
|||||||
|
|
||||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||||
|
|
||||||
int getParameterPos() { p.isParameterOf(_, result) }
|
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||||
|
|
||||||
ParamNodeEx getParamNode() { result = p }
|
ParamNodeEx getParamNode() { result = p }
|
||||||
|
|
||||||
@@ -3622,39 +3639,40 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate pathIntoArg(
|
private predicate pathIntoArg(
|
||||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||||
Configuration config
|
AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNode arg |
|
exists(ArgNode arg, ArgumentPosition apos |
|
||||||
arg = mid.getNodeEx().asNode() and
|
arg = mid.getNodeEx().asNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, apos) and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp() and
|
||||||
apa = ap.getApprox() and
|
apa = ap.getApprox() and
|
||||||
config = mid.getConfiguration()
|
config = mid.getConfiguration() and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parameterCand(
|
private predicate parameterCand(
|
||||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
Stage4::revFlow(p, _, _, apa, config) and
|
Stage4::revFlow(p, _, _, apa, config) and
|
||||||
p.isParameterOf(callable, i)
|
p.isParameterOf(callable, pos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate pathIntoCallable0(
|
private predicate pathIntoCallable0(
|
||||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||||
AccessPath ap, Configuration config
|
DataFlowCall call, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(AccessPathApprox apa |
|
exists(AccessPathApprox apa |
|
||||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||||
pragma[only_bind_into](config)) and
|
pragma[only_bind_into](config)) and
|
||||||
callable = resolveCall(call, outercc) and
|
callable = resolveCall(call, outercc) and
|
||||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||||
pragma[only_bind_into](config))
|
pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -3669,9 +3687,9 @@ private predicate pathIntoCallable(
|
|||||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||||
DataFlowCall call, Configuration config
|
DataFlowCall call, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, pos) and
|
||||||
(
|
(
|
||||||
sc = TSummaryCtxSome(p, ap)
|
sc = TSummaryCtxSome(p, ap)
|
||||||
or
|
or
|
||||||
@@ -3695,7 +3713,7 @@ private predicate paramFlowsThrough(
|
|||||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||||
mid.getNodeEx() = ret and
|
mid.getNodeEx() = ret and
|
||||||
kind = ret.getKind() and
|
kind = ret.getKind() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
@@ -4424,24 +4442,25 @@ private module FlowExploration {
|
|||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate partialPathIntoArg(
|
private predicate partialPathIntoArg(
|
||||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||||
Configuration config
|
PartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNode arg |
|
exists(ArgNode arg, ArgumentPosition apos |
|
||||||
arg = mid.getNodeEx().asNode() and
|
arg = mid.getNodeEx().asNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, apos) and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp() and
|
||||||
config = mid.getConfiguration()
|
config = mid.getConfiguration() and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate partialPathIntoCallable0(
|
private predicate partialPathIntoCallable0(
|
||||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||||
callable = resolveCall(call, outercc)
|
callable = resolveCall(call, outercc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4450,9 +4469,9 @@ private module FlowExploration {
|
|||||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable |
|
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, pos) and
|
||||||
sc1 = TSummaryCtx1Param(p) and
|
sc1 = TSummaryCtx1Param(p) and
|
||||||
sc2 = TSummaryCtx2Some(ap)
|
sc2 = TSummaryCtx2Some(ap)
|
||||||
|
|
|
|
||||||
@@ -4616,22 +4635,23 @@ private module FlowExploration {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revPartialPathFlowsThrough(
|
private predicate revPartialPathFlowsThrough(
|
||||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||||
Configuration config
|
RevPartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||||
mid.getNodeEx() = p and
|
mid.getNodeEx() = p and
|
||||||
p.getPosition() = pos and
|
p.getPosition() = ppos and
|
||||||
sc1 = mid.getSummaryCtx1() and
|
sc1 = mid.getSummaryCtx1() and
|
||||||
sc2 = mid.getSummaryCtx2() and
|
sc2 = mid.getSummaryCtx2() and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp() and
|
||||||
config = mid.getConfiguration()
|
config = mid.getConfiguration() and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revPartialPathThroughCallable0(
|
private predicate revPartialPathThroughCallable0(
|
||||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||||
@@ -4644,7 +4664,7 @@ private module FlowExploration {
|
|||||||
private predicate revPartialPathThroughCallable(
|
private predicate revPartialPathThroughCallable(
|
||||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCall call, int pos |
|
exists(DataFlowCall call, ArgumentPosition pos |
|
||||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
|||||||
private class ParamNodeEx extends NodeEx {
|
private class ParamNodeEx extends NodeEx {
|
||||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||||
|
|
||||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
int getPosition() { this.isParameterOf(_, result) }
|
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||||
|
|
||||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||||
}
|
}
|
||||||
@@ -1012,6 +1012,9 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||||
|
|
||||||
|
bindingset[node, ap]
|
||||||
|
private predicate filter(NodeEx node, Ap ap) { any() }
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||||
|
|
||||||
@@ -1020,6 +1023,13 @@ private module Stage2 {
|
|||||||
PrevStage::revFlow(node, _, _, apa, config)
|
PrevStage::revFlow(node, _, _, apa, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bindingset[result, apa]
|
||||||
|
private ApApprox unbindApa(ApApprox apa) {
|
||||||
|
exists(ApApprox apa0 |
|
||||||
|
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughOutOfCall(
|
private predicate flowThroughOutOfCall(
|
||||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
@@ -1042,6 +1052,13 @@ private module Stage2 {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||||
|
fwdFlow0(node, cc, argAp, ap, config) and
|
||||||
|
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||||
|
filter(node, ap)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||||
flowCand(node, _, config) and
|
flowCand(node, _, config) and
|
||||||
sourceNode(node, config) and
|
sourceNode(node, config) and
|
||||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||||
@@ -1112,7 +1129,7 @@ private module Stage2 {
|
|||||||
) {
|
) {
|
||||||
exists(DataFlowType contentType |
|
exists(DataFlowType contentType |
|
||||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||||
typecheckStore(ap1, contentType)
|
typecheckStore(ap1, contentType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1189,7 +1206,7 @@ private module Stage2 {
|
|||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1430,7 +1447,7 @@ private module Stage2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||||
parameterFlow(p, ap, ap0, c, config) and
|
parameterFlow(p, ap, ap0, c, config) and
|
||||||
c = ret.getEnclosingCallable() and
|
c = ret.getEnclosingCallable() and
|
||||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||||
@@ -2125,7 +2142,7 @@ private module Stage3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||||
parameterFlow(p, ap, ap0, c, config) and
|
parameterFlow(p, ap, ap0, c, config) and
|
||||||
c = ret.getEnclosingCallable() and
|
c = ret.getEnclosingCallable() and
|
||||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||||
@@ -2891,7 +2908,7 @@ private module Stage4 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||||
parameterFlow(p, ap, ap0, c, config) and
|
parameterFlow(p, ap, ap0, c, config) and
|
||||||
c = ret.getEnclosingCallable() and
|
c = ret.getEnclosingCallable() and
|
||||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||||
@@ -2975,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
|||||||
|
|
||||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||||
|
|
||||||
int getParameterPos() { p.isParameterOf(_, result) }
|
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||||
|
|
||||||
ParamNodeEx getParamNode() { result = p }
|
ParamNodeEx getParamNode() { result = p }
|
||||||
|
|
||||||
@@ -3622,39 +3639,40 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate pathIntoArg(
|
private predicate pathIntoArg(
|
||||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||||
Configuration config
|
AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNode arg |
|
exists(ArgNode arg, ArgumentPosition apos |
|
||||||
arg = mid.getNodeEx().asNode() and
|
arg = mid.getNodeEx().asNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, apos) and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp() and
|
||||||
apa = ap.getApprox() and
|
apa = ap.getApprox() and
|
||||||
config = mid.getConfiguration()
|
config = mid.getConfiguration() and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parameterCand(
|
private predicate parameterCand(
|
||||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
Stage4::revFlow(p, _, _, apa, config) and
|
Stage4::revFlow(p, _, _, apa, config) and
|
||||||
p.isParameterOf(callable, i)
|
p.isParameterOf(callable, pos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate pathIntoCallable0(
|
private predicate pathIntoCallable0(
|
||||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||||
AccessPath ap, Configuration config
|
DataFlowCall call, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(AccessPathApprox apa |
|
exists(AccessPathApprox apa |
|
||||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||||
pragma[only_bind_into](config)) and
|
pragma[only_bind_into](config)) and
|
||||||
callable = resolveCall(call, outercc) and
|
callable = resolveCall(call, outercc) and
|
||||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||||
pragma[only_bind_into](config))
|
pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -3669,9 +3687,9 @@ private predicate pathIntoCallable(
|
|||||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||||
DataFlowCall call, Configuration config
|
DataFlowCall call, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, pos) and
|
||||||
(
|
(
|
||||||
sc = TSummaryCtxSome(p, ap)
|
sc = TSummaryCtxSome(p, ap)
|
||||||
or
|
or
|
||||||
@@ -3695,7 +3713,7 @@ private predicate paramFlowsThrough(
|
|||||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||||
mid.getNodeEx() = ret and
|
mid.getNodeEx() = ret and
|
||||||
kind = ret.getKind() and
|
kind = ret.getKind() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
@@ -4424,24 +4442,25 @@ private module FlowExploration {
|
|||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate partialPathIntoArg(
|
private predicate partialPathIntoArg(
|
||||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||||
Configuration config
|
PartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNode arg |
|
exists(ArgNode arg, ArgumentPosition apos |
|
||||||
arg = mid.getNodeEx().asNode() and
|
arg = mid.getNodeEx().asNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, apos) and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp() and
|
||||||
config = mid.getConfiguration()
|
config = mid.getConfiguration() and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate partialPathIntoCallable0(
|
private predicate partialPathIntoCallable0(
|
||||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||||
callable = resolveCall(call, outercc)
|
callable = resolveCall(call, outercc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4450,9 +4469,9 @@ private module FlowExploration {
|
|||||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable |
|
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, pos) and
|
||||||
sc1 = TSummaryCtx1Param(p) and
|
sc1 = TSummaryCtx1Param(p) and
|
||||||
sc2 = TSummaryCtx2Some(ap)
|
sc2 = TSummaryCtx2Some(ap)
|
||||||
|
|
|
|
||||||
@@ -4616,22 +4635,23 @@ private module FlowExploration {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revPartialPathFlowsThrough(
|
private predicate revPartialPathFlowsThrough(
|
||||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||||
Configuration config
|
RevPartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||||
mid.getNodeEx() = p and
|
mid.getNodeEx() = p and
|
||||||
p.getPosition() = pos and
|
p.getPosition() = ppos and
|
||||||
sc1 = mid.getSummaryCtx1() and
|
sc1 = mid.getSummaryCtx1() and
|
||||||
sc2 = mid.getSummaryCtx2() and
|
sc2 = mid.getSummaryCtx2() and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp() and
|
||||||
config = mid.getConfiguration()
|
config = mid.getConfiguration() and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revPartialPathThroughCallable0(
|
private predicate revPartialPathThroughCallable0(
|
||||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||||
@@ -4644,7 +4664,7 @@ private module FlowExploration {
|
|||||||
private predicate revPartialPathThroughCallable(
|
private predicate revPartialPathThroughCallable(
|
||||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCall call, int pos |
|
exists(DataFlowCall call, ArgumentPosition pos |
|
||||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -62,6 +62,18 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
|
|||||||
tupleLimit = 1000
|
tupleLimit = 1000
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `arg` is an argument of `call` with an argument position that matches
|
||||||
|
* parameter position `ppos`.
|
||||||
|
*/
|
||||||
|
pragma[noinline]
|
||||||
|
predicate argumentPositionMatch(DataFlowCall call, ArgNode arg, ParameterPosition ppos) {
|
||||||
|
exists(ArgumentPosition apos |
|
||||||
|
arg.argumentOf(call, apos) and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a simple data-flow analysis for resolving lambda calls. The analysis
|
* Provides a simple data-flow analysis for resolving lambda calls. The analysis
|
||||||
* currently excludes read-steps, store-steps, and flow-through.
|
* currently excludes read-steps, store-steps, and flow-through.
|
||||||
@@ -71,25 +83,27 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
|
|||||||
* calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly.
|
* calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly.
|
||||||
*/
|
*/
|
||||||
private module LambdaFlow {
|
private module LambdaFlow {
|
||||||
private predicate viableParamNonLambda(DataFlowCall call, int i, ParamNode p) {
|
pragma[noinline]
|
||||||
p.isParameterOf(viableCallable(call), i)
|
private predicate viableParamNonLambda(DataFlowCall call, ParameterPosition ppos, ParamNode p) {
|
||||||
|
p.isParameterOf(viableCallable(call), ppos)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate viableParamLambda(DataFlowCall call, int i, ParamNode p) {
|
pragma[noinline]
|
||||||
p.isParameterOf(viableCallableLambda(call, _), i)
|
private predicate viableParamLambda(DataFlowCall call, ParameterPosition ppos, ParamNode p) {
|
||||||
|
p.isParameterOf(viableCallableLambda(call, _), ppos)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate viableParamArgNonLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
|
private predicate viableParamArgNonLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||||
exists(int i |
|
exists(ParameterPosition ppos |
|
||||||
viableParamNonLambda(call, i, p) and
|
viableParamNonLambda(call, ppos, p) and
|
||||||
arg.argumentOf(call, i)
|
argumentPositionMatch(call, arg, ppos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate viableParamArgLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
|
private predicate viableParamArgLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||||
exists(int i |
|
exists(ParameterPosition ppos |
|
||||||
viableParamLambda(call, i, p) and
|
viableParamLambda(call, ppos, p) and
|
||||||
arg.argumentOf(call, i)
|
argumentPositionMatch(call, arg, ppos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,7 +336,7 @@ private module Cached {
|
|||||||
or
|
or
|
||||||
exists(ArgNode arg |
|
exists(ArgNode arg |
|
||||||
result.(PostUpdateNode).getPreUpdateNode() = arg and
|
result.(PostUpdateNode).getPreUpdateNode() = arg and
|
||||||
arg.argumentOf(call, k.(ParamUpdateReturnKind).getPosition())
|
arg.argumentOf(call, k.(ParamUpdateReturnKind).getAMatchingArgumentPosition())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,7 +344,7 @@ private module Cached {
|
|||||||
predicate returnNodeExt(Node n, ReturnKindExt k) {
|
predicate returnNodeExt(Node n, ReturnKindExt k) {
|
||||||
k = TValueReturn(n.(ReturnNode).getKind())
|
k = TValueReturn(n.(ReturnNode).getKind())
|
||||||
or
|
or
|
||||||
exists(ParamNode p, int pos |
|
exists(ParamNode p, ParameterPosition pos |
|
||||||
parameterValueFlowsToPreUpdate(p, n) and
|
parameterValueFlowsToPreUpdate(p, n) and
|
||||||
p.isParameterOf(_, pos) and
|
p.isParameterOf(_, pos) and
|
||||||
k = TParamUpdate(pos)
|
k = TParamUpdate(pos)
|
||||||
@@ -352,11 +366,13 @@ private module Cached {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate parameterNode(Node p, DataFlowCallable c, int pos) { isParameterNode(p, c, pos) }
|
predicate parameterNode(Node p, DataFlowCallable c, ParameterPosition pos) {
|
||||||
|
isParameterNode(p, c, pos)
|
||||||
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate argumentNode(Node n, DataFlowCall call, int pos) {
|
predicate argumentNode(Node n, DataFlowCall call, ArgumentPosition pos) {
|
||||||
n.(ArgumentNode).argumentOf(call, pos)
|
isArgumentNode(n, call, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -374,12 +390,12 @@ private module Cached {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `p` is the `i`th parameter of a viable dispatch target of `call`.
|
* Holds if `p` is the parameter of a viable dispatch target of `call`,
|
||||||
* The instance parameter is considered to have index `-1`.
|
* and `p` has position `ppos`.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate viableParam(DataFlowCall call, int i, ParamNode p) {
|
private predicate viableParam(DataFlowCall call, ParameterPosition ppos, ParamNode p) {
|
||||||
p.isParameterOf(viableCallableExt(call), i)
|
p.isParameterOf(viableCallableExt(call), ppos)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -388,9 +404,9 @@ private module Cached {
|
|||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
predicate viableParamArg(DataFlowCall call, ParamNode p, ArgNode arg) {
|
predicate viableParamArg(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||||
exists(int i |
|
exists(ParameterPosition ppos |
|
||||||
viableParam(call, i, p) and
|
viableParam(call, ppos, p) and
|
||||||
arg.argumentOf(call, i) and
|
argumentPositionMatch(call, arg, ppos) and
|
||||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
|
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -862,7 +878,7 @@ private module Cached {
|
|||||||
cached
|
cached
|
||||||
newtype TReturnKindExt =
|
newtype TReturnKindExt =
|
||||||
TValueReturn(ReturnKind kind) or
|
TValueReturn(ReturnKind kind) or
|
||||||
TParamUpdate(int pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
|
TParamUpdate(ParameterPosition pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
|
||||||
|
|
||||||
cached
|
cached
|
||||||
newtype TBooleanOption =
|
newtype TBooleanOption =
|
||||||
@@ -1054,9 +1070,9 @@ class ParamNode extends Node {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if this node is the parameter of callable `c` at the specified
|
* Holds if this node is the parameter of callable `c` at the specified
|
||||||
* (zero-based) position.
|
* position.
|
||||||
*/
|
*/
|
||||||
predicate isParameterOf(DataFlowCallable c, int i) { parameterNode(this, c, i) }
|
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) { parameterNode(this, c, pos) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A data-flow node that represents a call argument. */
|
/** A data-flow node that represents a call argument. */
|
||||||
@@ -1064,7 +1080,9 @@ class ArgNode extends Node {
|
|||||||
ArgNode() { argumentNode(this, _, _) }
|
ArgNode() { argumentNode(this, _, _) }
|
||||||
|
|
||||||
/** Holds if this argument occurs at the given position in the given call. */
|
/** Holds if this argument occurs at the given position in the given call. */
|
||||||
final predicate argumentOf(DataFlowCall call, int pos) { argumentNode(this, call, pos) }
|
final predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
|
||||||
|
argumentNode(this, call, pos)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1110,11 +1128,14 @@ class ValueReturnKind extends ReturnKindExt, TValueReturn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
|
class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
|
||||||
private int pos;
|
private ParameterPosition pos;
|
||||||
|
|
||||||
ParamUpdateReturnKind() { this = TParamUpdate(pos) }
|
ParamUpdateReturnKind() { this = TParamUpdate(pos) }
|
||||||
|
|
||||||
int getPosition() { result = pos }
|
ParameterPosition getPosition() { result = pos }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
ArgumentPosition getAMatchingArgumentPosition() { parameterMatch(pos, result) }
|
||||||
|
|
||||||
override string toString() { result = "param update " + pos }
|
override string toString() { result = "param update " + pos }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,11 +15,23 @@ module Consistency {
|
|||||||
class ConsistencyConfiguration extends TConsistencyConfiguration {
|
class ConsistencyConfiguration extends TConsistencyConfiguration {
|
||||||
string toString() { none() }
|
string toString() { none() }
|
||||||
|
|
||||||
|
/** Holds if `n` should be excluded from the consistency test `uniqueEnclosingCallable`. */
|
||||||
|
predicate uniqueEnclosingCallableExclude(Node n) { none() }
|
||||||
|
|
||||||
|
/** Holds if `n` should be excluded from the consistency test `uniqueNodeLocation`. */
|
||||||
|
predicate uniqueNodeLocationExclude(Node n) { none() }
|
||||||
|
|
||||||
|
/** Holds if `n` should be excluded from the consistency test `missingLocation`. */
|
||||||
|
predicate missingLocationExclude(Node n) { none() }
|
||||||
|
|
||||||
/** Holds if `n` should be excluded from the consistency test `postWithInFlow`. */
|
/** Holds if `n` should be excluded from the consistency test `postWithInFlow`. */
|
||||||
predicate postWithInFlowExclude(Node n) { none() }
|
predicate postWithInFlowExclude(Node n) { none() }
|
||||||
|
|
||||||
/** Holds if `n` should be excluded from the consistency test `argHasPostUpdate`. */
|
/** Holds if `n` should be excluded from the consistency test `argHasPostUpdate`. */
|
||||||
predicate argHasPostUpdateExclude(ArgumentNode n) { none() }
|
predicate argHasPostUpdateExclude(ArgumentNode n) { none() }
|
||||||
|
|
||||||
|
/** Holds if `n` should be excluded from the consistency test `reverseRead`. */
|
||||||
|
predicate reverseReadExclude(Node n) { none() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class RelevantNode extends Node {
|
private class RelevantNode extends Node {
|
||||||
@@ -46,6 +58,7 @@ module Consistency {
|
|||||||
n instanceof RelevantNode and
|
n instanceof RelevantNode and
|
||||||
c = count(nodeGetEnclosingCallable(n)) and
|
c = count(nodeGetEnclosingCallable(n)) and
|
||||||
c != 1 and
|
c != 1 and
|
||||||
|
not any(ConsistencyConfiguration conf).uniqueEnclosingCallableExclude(n) and
|
||||||
msg = "Node should have one enclosing callable but has " + c + "."
|
msg = "Node should have one enclosing callable but has " + c + "."
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -66,6 +79,7 @@ module Consistency {
|
|||||||
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
) and
|
) and
|
||||||
c != 1 and
|
c != 1 and
|
||||||
|
not any(ConsistencyConfiguration conf).uniqueNodeLocationExclude(n) and
|
||||||
msg = "Node should have one location but has " + c + "."
|
msg = "Node should have one location but has " + c + "."
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -76,7 +90,8 @@ module Consistency {
|
|||||||
strictcount(Node n |
|
strictcount(Node n |
|
||||||
not exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
|
not exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
|
||||||
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
)
|
) and
|
||||||
|
not any(ConsistencyConfiguration conf).missingLocationExclude(n)
|
||||||
) and
|
) and
|
||||||
msg = "Nodes without location: " + c
|
msg = "Nodes without location: " + c
|
||||||
)
|
)
|
||||||
@@ -172,6 +187,7 @@ module Consistency {
|
|||||||
|
|
||||||
query predicate reverseRead(Node n, string msg) {
|
query predicate reverseRead(Node n, string msg) {
|
||||||
exists(Node n2 | readStep(n, _, n2) and hasPost(n2) and not hasPost(n)) and
|
exists(Node n2 | readStep(n, _, n2) and hasPost(n2) and not hasPost(n)) and
|
||||||
|
not any(ConsistencyConfiguration conf).reverseReadExclude(n) and
|
||||||
msg = "Origin of readStep is missing a PostUpdateNode."
|
msg = "Origin of readStep is missing a PostUpdateNode."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
|||||||
private class ParamNodeEx extends NodeEx {
|
private class ParamNodeEx extends NodeEx {
|
||||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||||
|
|
||||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
int getPosition() { this.isParameterOf(_, result) }
|
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||||
|
|
||||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||||
}
|
}
|
||||||
@@ -1012,6 +1012,9 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||||
|
|
||||||
|
bindingset[node, ap]
|
||||||
|
private predicate filter(NodeEx node, Ap ap) { any() }
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||||
|
|
||||||
@@ -1020,6 +1023,13 @@ private module Stage2 {
|
|||||||
PrevStage::revFlow(node, _, _, apa, config)
|
PrevStage::revFlow(node, _, _, apa, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bindingset[result, apa]
|
||||||
|
private ApApprox unbindApa(ApApprox apa) {
|
||||||
|
exists(ApApprox apa0 |
|
||||||
|
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughOutOfCall(
|
private predicate flowThroughOutOfCall(
|
||||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
@@ -1042,6 +1052,13 @@ private module Stage2 {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||||
|
fwdFlow0(node, cc, argAp, ap, config) and
|
||||||
|
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||||
|
filter(node, ap)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||||
flowCand(node, _, config) and
|
flowCand(node, _, config) and
|
||||||
sourceNode(node, config) and
|
sourceNode(node, config) and
|
||||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||||
@@ -1112,7 +1129,7 @@ private module Stage2 {
|
|||||||
) {
|
) {
|
||||||
exists(DataFlowType contentType |
|
exists(DataFlowType contentType |
|
||||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||||
typecheckStore(ap1, contentType)
|
typecheckStore(ap1, contentType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1189,7 +1206,7 @@ private module Stage2 {
|
|||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1430,7 +1447,7 @@ private module Stage2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||||
parameterFlow(p, ap, ap0, c, config) and
|
parameterFlow(p, ap, ap0, c, config) and
|
||||||
c = ret.getEnclosingCallable() and
|
c = ret.getEnclosingCallable() and
|
||||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||||
@@ -2125,7 +2142,7 @@ private module Stage3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||||
parameterFlow(p, ap, ap0, c, config) and
|
parameterFlow(p, ap, ap0, c, config) and
|
||||||
c = ret.getEnclosingCallable() and
|
c = ret.getEnclosingCallable() and
|
||||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||||
@@ -2891,7 +2908,7 @@ private module Stage4 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||||
parameterFlow(p, ap, ap0, c, config) and
|
parameterFlow(p, ap, ap0, c, config) and
|
||||||
c = ret.getEnclosingCallable() and
|
c = ret.getEnclosingCallable() and
|
||||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||||
@@ -2975,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
|||||||
|
|
||||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||||
|
|
||||||
int getParameterPos() { p.isParameterOf(_, result) }
|
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||||
|
|
||||||
ParamNodeEx getParamNode() { result = p }
|
ParamNodeEx getParamNode() { result = p }
|
||||||
|
|
||||||
@@ -3622,39 +3639,40 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate pathIntoArg(
|
private predicate pathIntoArg(
|
||||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||||
Configuration config
|
AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNode arg |
|
exists(ArgNode arg, ArgumentPosition apos |
|
||||||
arg = mid.getNodeEx().asNode() and
|
arg = mid.getNodeEx().asNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, apos) and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp() and
|
||||||
apa = ap.getApprox() and
|
apa = ap.getApprox() and
|
||||||
config = mid.getConfiguration()
|
config = mid.getConfiguration() and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parameterCand(
|
private predicate parameterCand(
|
||||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
Stage4::revFlow(p, _, _, apa, config) and
|
Stage4::revFlow(p, _, _, apa, config) and
|
||||||
p.isParameterOf(callable, i)
|
p.isParameterOf(callable, pos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate pathIntoCallable0(
|
private predicate pathIntoCallable0(
|
||||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||||
AccessPath ap, Configuration config
|
DataFlowCall call, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(AccessPathApprox apa |
|
exists(AccessPathApprox apa |
|
||||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||||
pragma[only_bind_into](config)) and
|
pragma[only_bind_into](config)) and
|
||||||
callable = resolveCall(call, outercc) and
|
callable = resolveCall(call, outercc) and
|
||||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||||
pragma[only_bind_into](config))
|
pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -3669,9 +3687,9 @@ private predicate pathIntoCallable(
|
|||||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||||
DataFlowCall call, Configuration config
|
DataFlowCall call, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, pos) and
|
||||||
(
|
(
|
||||||
sc = TSummaryCtxSome(p, ap)
|
sc = TSummaryCtxSome(p, ap)
|
||||||
or
|
or
|
||||||
@@ -3695,7 +3713,7 @@ private predicate paramFlowsThrough(
|
|||||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||||
mid.getNodeEx() = ret and
|
mid.getNodeEx() = ret and
|
||||||
kind = ret.getKind() and
|
kind = ret.getKind() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
@@ -4424,24 +4442,25 @@ private module FlowExploration {
|
|||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate partialPathIntoArg(
|
private predicate partialPathIntoArg(
|
||||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||||
Configuration config
|
PartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNode arg |
|
exists(ArgNode arg, ArgumentPosition apos |
|
||||||
arg = mid.getNodeEx().asNode() and
|
arg = mid.getNodeEx().asNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, apos) and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp() and
|
||||||
config = mid.getConfiguration()
|
config = mid.getConfiguration() and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate partialPathIntoCallable0(
|
private predicate partialPathIntoCallable0(
|
||||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||||
callable = resolveCall(call, outercc)
|
callable = resolveCall(call, outercc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4450,9 +4469,9 @@ private module FlowExploration {
|
|||||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable |
|
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, pos) and
|
||||||
sc1 = TSummaryCtx1Param(p) and
|
sc1 = TSummaryCtx1Param(p) and
|
||||||
sc2 = TSummaryCtx2Some(ap)
|
sc2 = TSummaryCtx2Some(ap)
|
||||||
|
|
|
|
||||||
@@ -4616,22 +4635,23 @@ private module FlowExploration {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revPartialPathFlowsThrough(
|
private predicate revPartialPathFlowsThrough(
|
||||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||||
Configuration config
|
RevPartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||||
mid.getNodeEx() = p and
|
mid.getNodeEx() = p and
|
||||||
p.getPosition() = pos and
|
p.getPosition() = ppos and
|
||||||
sc1 = mid.getSummaryCtx1() and
|
sc1 = mid.getSummaryCtx1() and
|
||||||
sc2 = mid.getSummaryCtx2() and
|
sc2 = mid.getSummaryCtx2() and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp() and
|
||||||
config = mid.getConfiguration()
|
config = mid.getConfiguration() and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revPartialPathThroughCallable0(
|
private predicate revPartialPathThroughCallable0(
|
||||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||||
@@ -4644,7 +4664,7 @@ private module FlowExploration {
|
|||||||
private predicate revPartialPathThroughCallable(
|
private predicate revPartialPathThroughCallable(
|
||||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCall call, int pos |
|
exists(DataFlowCall call, ArgumentPosition pos |
|
||||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,7 +8,14 @@ private import DataFlowImplConsistency
|
|||||||
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() }
|
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() }
|
||||||
|
|
||||||
/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */
|
/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */
|
||||||
predicate isParameterNode(ParameterNode p, DataFlowCallable c, int pos) { p.isParameterOf(c, pos) }
|
predicate isParameterNode(ParameterNode p, DataFlowCallable c, ParameterPosition pos) {
|
||||||
|
p.isParameterOf(c, pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if `arg` is an `ArgumentNode` of `c` with position `pos`. */
|
||||||
|
predicate isArgumentNode(ArgumentNode arg, DataFlowCall c, ArgumentPosition pos) {
|
||||||
|
arg.argumentOf(c, pos)
|
||||||
|
}
|
||||||
|
|
||||||
/** Gets the instance argument of a non-static call. */
|
/** Gets the instance argument of a non-static call. */
|
||||||
private Node getInstanceArgument(Call call) {
|
private Node getInstanceArgument(Call call) {
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ class LambdaCapture extends Locatable, @lambdacapture {
|
|||||||
* An identifier is captured by reference if:
|
* An identifier is captured by reference if:
|
||||||
* - It is explicitly captured by reference.
|
* - It is explicitly captured by reference.
|
||||||
* - It is implicitly captured, and the lambda's default capture mode is by-reference.
|
* - It is implicitly captured, and the lambda's default capture mode is by-reference.
|
||||||
* - The identifier is "this". [Said behaviour is dictated by the C++11 standard, but it
|
* - The identifier is "this". [Said behavior is dictated by the C++11 standard, but it
|
||||||
* is actually "*this" being captured rather than "this".]
|
* is actually "*this" being captured rather than "this".]
|
||||||
*/
|
*/
|
||||||
predicate isCapturedByReference() { lambda_capture(this, _, _, _, true, _, _) }
|
predicate isCapturedByReference() { lambda_capture(this, _, _, _, true, _, _) }
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ private import cpp
|
|||||||
private import semmle.code.cpp.ir.IR
|
private import semmle.code.cpp.ir.IR
|
||||||
private import semmle.code.cpp.ir.dataflow.DataFlow
|
private import semmle.code.cpp.ir.dataflow.DataFlow
|
||||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||||
|
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||||
private import DataFlowImplCommon as DataFlowImplCommon
|
private import DataFlowImplCommon as DataFlowImplCommon
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -266,3 +267,17 @@ Function viableImplInCallContext(CallInstruction call, CallInstruction ctx) {
|
|||||||
result = ctx.getArgument(i).getUnconvertedResultExpression().(FunctionAccess).getTarget()
|
result = ctx.getArgument(i).getUnconvertedResultExpression().(FunctionAccess).getTarget()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** A parameter position represented by an integer. */
|
||||||
|
class ParameterPosition extends int {
|
||||||
|
ParameterPosition() { any(ParameterNode p).isParameterOf(_, this) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** An argument position represented by an integer. */
|
||||||
|
class ArgumentPosition extends int {
|
||||||
|
ArgumentPosition() { any(ArgumentNode a).argumentOf(_, this) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
|
||||||
|
pragma[inline]
|
||||||
|
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
|
||||||
|
|||||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
|||||||
private class ParamNodeEx extends NodeEx {
|
private class ParamNodeEx extends NodeEx {
|
||||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||||
|
|
||||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
int getPosition() { this.isParameterOf(_, result) }
|
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||||
|
|
||||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||||
}
|
}
|
||||||
@@ -1012,6 +1012,9 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||||
|
|
||||||
|
bindingset[node, ap]
|
||||||
|
private predicate filter(NodeEx node, Ap ap) { any() }
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||||
|
|
||||||
@@ -1020,6 +1023,13 @@ private module Stage2 {
|
|||||||
PrevStage::revFlow(node, _, _, apa, config)
|
PrevStage::revFlow(node, _, _, apa, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bindingset[result, apa]
|
||||||
|
private ApApprox unbindApa(ApApprox apa) {
|
||||||
|
exists(ApApprox apa0 |
|
||||||
|
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughOutOfCall(
|
private predicate flowThroughOutOfCall(
|
||||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
@@ -1042,6 +1052,13 @@ private module Stage2 {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||||
|
fwdFlow0(node, cc, argAp, ap, config) and
|
||||||
|
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||||
|
filter(node, ap)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||||
flowCand(node, _, config) and
|
flowCand(node, _, config) and
|
||||||
sourceNode(node, config) and
|
sourceNode(node, config) and
|
||||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||||
@@ -1112,7 +1129,7 @@ private module Stage2 {
|
|||||||
) {
|
) {
|
||||||
exists(DataFlowType contentType |
|
exists(DataFlowType contentType |
|
||||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||||
typecheckStore(ap1, contentType)
|
typecheckStore(ap1, contentType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1189,7 +1206,7 @@ private module Stage2 {
|
|||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1430,7 +1447,7 @@ private module Stage2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||||
parameterFlow(p, ap, ap0, c, config) and
|
parameterFlow(p, ap, ap0, c, config) and
|
||||||
c = ret.getEnclosingCallable() and
|
c = ret.getEnclosingCallable() and
|
||||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||||
@@ -2125,7 +2142,7 @@ private module Stage3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||||
parameterFlow(p, ap, ap0, c, config) and
|
parameterFlow(p, ap, ap0, c, config) and
|
||||||
c = ret.getEnclosingCallable() and
|
c = ret.getEnclosingCallable() and
|
||||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||||
@@ -2891,7 +2908,7 @@ private module Stage4 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||||
parameterFlow(p, ap, ap0, c, config) and
|
parameterFlow(p, ap, ap0, c, config) and
|
||||||
c = ret.getEnclosingCallable() and
|
c = ret.getEnclosingCallable() and
|
||||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||||
@@ -2975,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
|||||||
|
|
||||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||||
|
|
||||||
int getParameterPos() { p.isParameterOf(_, result) }
|
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||||
|
|
||||||
ParamNodeEx getParamNode() { result = p }
|
ParamNodeEx getParamNode() { result = p }
|
||||||
|
|
||||||
@@ -3622,39 +3639,40 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate pathIntoArg(
|
private predicate pathIntoArg(
|
||||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||||
Configuration config
|
AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNode arg |
|
exists(ArgNode arg, ArgumentPosition apos |
|
||||||
arg = mid.getNodeEx().asNode() and
|
arg = mid.getNodeEx().asNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, apos) and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp() and
|
||||||
apa = ap.getApprox() and
|
apa = ap.getApprox() and
|
||||||
config = mid.getConfiguration()
|
config = mid.getConfiguration() and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parameterCand(
|
private predicate parameterCand(
|
||||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
Stage4::revFlow(p, _, _, apa, config) and
|
Stage4::revFlow(p, _, _, apa, config) and
|
||||||
p.isParameterOf(callable, i)
|
p.isParameterOf(callable, pos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate pathIntoCallable0(
|
private predicate pathIntoCallable0(
|
||||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||||
AccessPath ap, Configuration config
|
DataFlowCall call, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(AccessPathApprox apa |
|
exists(AccessPathApprox apa |
|
||||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||||
pragma[only_bind_into](config)) and
|
pragma[only_bind_into](config)) and
|
||||||
callable = resolveCall(call, outercc) and
|
callable = resolveCall(call, outercc) and
|
||||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||||
pragma[only_bind_into](config))
|
pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -3669,9 +3687,9 @@ private predicate pathIntoCallable(
|
|||||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||||
DataFlowCall call, Configuration config
|
DataFlowCall call, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, pos) and
|
||||||
(
|
(
|
||||||
sc = TSummaryCtxSome(p, ap)
|
sc = TSummaryCtxSome(p, ap)
|
||||||
or
|
or
|
||||||
@@ -3695,7 +3713,7 @@ private predicate paramFlowsThrough(
|
|||||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||||
mid.getNodeEx() = ret and
|
mid.getNodeEx() = ret and
|
||||||
kind = ret.getKind() and
|
kind = ret.getKind() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
@@ -4424,24 +4442,25 @@ private module FlowExploration {
|
|||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate partialPathIntoArg(
|
private predicate partialPathIntoArg(
|
||||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||||
Configuration config
|
PartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNode arg |
|
exists(ArgNode arg, ArgumentPosition apos |
|
||||||
arg = mid.getNodeEx().asNode() and
|
arg = mid.getNodeEx().asNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, apos) and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp() and
|
||||||
config = mid.getConfiguration()
|
config = mid.getConfiguration() and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate partialPathIntoCallable0(
|
private predicate partialPathIntoCallable0(
|
||||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||||
callable = resolveCall(call, outercc)
|
callable = resolveCall(call, outercc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4450,9 +4469,9 @@ private module FlowExploration {
|
|||||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable |
|
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, pos) and
|
||||||
sc1 = TSummaryCtx1Param(p) and
|
sc1 = TSummaryCtx1Param(p) and
|
||||||
sc2 = TSummaryCtx2Some(ap)
|
sc2 = TSummaryCtx2Some(ap)
|
||||||
|
|
|
|
||||||
@@ -4616,22 +4635,23 @@ private module FlowExploration {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revPartialPathFlowsThrough(
|
private predicate revPartialPathFlowsThrough(
|
||||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||||
Configuration config
|
RevPartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||||
mid.getNodeEx() = p and
|
mid.getNodeEx() = p and
|
||||||
p.getPosition() = pos and
|
p.getPosition() = ppos and
|
||||||
sc1 = mid.getSummaryCtx1() and
|
sc1 = mid.getSummaryCtx1() and
|
||||||
sc2 = mid.getSummaryCtx2() and
|
sc2 = mid.getSummaryCtx2() and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp() and
|
||||||
config = mid.getConfiguration()
|
config = mid.getConfiguration() and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revPartialPathThroughCallable0(
|
private predicate revPartialPathThroughCallable0(
|
||||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||||
@@ -4644,7 +4664,7 @@ private module FlowExploration {
|
|||||||
private predicate revPartialPathThroughCallable(
|
private predicate revPartialPathThroughCallable(
|
||||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCall call, int pos |
|
exists(DataFlowCall call, ArgumentPosition pos |
|
||||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
|||||||
private class ParamNodeEx extends NodeEx {
|
private class ParamNodeEx extends NodeEx {
|
||||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||||
|
|
||||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
int getPosition() { this.isParameterOf(_, result) }
|
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||||
|
|
||||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||||
}
|
}
|
||||||
@@ -1012,6 +1012,9 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||||
|
|
||||||
|
bindingset[node, ap]
|
||||||
|
private predicate filter(NodeEx node, Ap ap) { any() }
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||||
|
|
||||||
@@ -1020,6 +1023,13 @@ private module Stage2 {
|
|||||||
PrevStage::revFlow(node, _, _, apa, config)
|
PrevStage::revFlow(node, _, _, apa, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bindingset[result, apa]
|
||||||
|
private ApApprox unbindApa(ApApprox apa) {
|
||||||
|
exists(ApApprox apa0 |
|
||||||
|
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughOutOfCall(
|
private predicate flowThroughOutOfCall(
|
||||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
@@ -1042,6 +1052,13 @@ private module Stage2 {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||||
|
fwdFlow0(node, cc, argAp, ap, config) and
|
||||||
|
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||||
|
filter(node, ap)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||||
flowCand(node, _, config) and
|
flowCand(node, _, config) and
|
||||||
sourceNode(node, config) and
|
sourceNode(node, config) and
|
||||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||||
@@ -1112,7 +1129,7 @@ private module Stage2 {
|
|||||||
) {
|
) {
|
||||||
exists(DataFlowType contentType |
|
exists(DataFlowType contentType |
|
||||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||||
typecheckStore(ap1, contentType)
|
typecheckStore(ap1, contentType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1189,7 +1206,7 @@ private module Stage2 {
|
|||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1430,7 +1447,7 @@ private module Stage2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||||
parameterFlow(p, ap, ap0, c, config) and
|
parameterFlow(p, ap, ap0, c, config) and
|
||||||
c = ret.getEnclosingCallable() and
|
c = ret.getEnclosingCallable() and
|
||||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||||
@@ -2125,7 +2142,7 @@ private module Stage3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||||
parameterFlow(p, ap, ap0, c, config) and
|
parameterFlow(p, ap, ap0, c, config) and
|
||||||
c = ret.getEnclosingCallable() and
|
c = ret.getEnclosingCallable() and
|
||||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||||
@@ -2891,7 +2908,7 @@ private module Stage4 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||||
parameterFlow(p, ap, ap0, c, config) and
|
parameterFlow(p, ap, ap0, c, config) and
|
||||||
c = ret.getEnclosingCallable() and
|
c = ret.getEnclosingCallable() and
|
||||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||||
@@ -2975,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
|||||||
|
|
||||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||||
|
|
||||||
int getParameterPos() { p.isParameterOf(_, result) }
|
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||||
|
|
||||||
ParamNodeEx getParamNode() { result = p }
|
ParamNodeEx getParamNode() { result = p }
|
||||||
|
|
||||||
@@ -3622,39 +3639,40 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate pathIntoArg(
|
private predicate pathIntoArg(
|
||||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||||
Configuration config
|
AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNode arg |
|
exists(ArgNode arg, ArgumentPosition apos |
|
||||||
arg = mid.getNodeEx().asNode() and
|
arg = mid.getNodeEx().asNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, apos) and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp() and
|
||||||
apa = ap.getApprox() and
|
apa = ap.getApprox() and
|
||||||
config = mid.getConfiguration()
|
config = mid.getConfiguration() and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parameterCand(
|
private predicate parameterCand(
|
||||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
Stage4::revFlow(p, _, _, apa, config) and
|
Stage4::revFlow(p, _, _, apa, config) and
|
||||||
p.isParameterOf(callable, i)
|
p.isParameterOf(callable, pos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate pathIntoCallable0(
|
private predicate pathIntoCallable0(
|
||||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||||
AccessPath ap, Configuration config
|
DataFlowCall call, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(AccessPathApprox apa |
|
exists(AccessPathApprox apa |
|
||||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||||
pragma[only_bind_into](config)) and
|
pragma[only_bind_into](config)) and
|
||||||
callable = resolveCall(call, outercc) and
|
callable = resolveCall(call, outercc) and
|
||||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||||
pragma[only_bind_into](config))
|
pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -3669,9 +3687,9 @@ private predicate pathIntoCallable(
|
|||||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||||
DataFlowCall call, Configuration config
|
DataFlowCall call, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, pos) and
|
||||||
(
|
(
|
||||||
sc = TSummaryCtxSome(p, ap)
|
sc = TSummaryCtxSome(p, ap)
|
||||||
or
|
or
|
||||||
@@ -3695,7 +3713,7 @@ private predicate paramFlowsThrough(
|
|||||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||||
mid.getNodeEx() = ret and
|
mid.getNodeEx() = ret and
|
||||||
kind = ret.getKind() and
|
kind = ret.getKind() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
@@ -4424,24 +4442,25 @@ private module FlowExploration {
|
|||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate partialPathIntoArg(
|
private predicate partialPathIntoArg(
|
||||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||||
Configuration config
|
PartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNode arg |
|
exists(ArgNode arg, ArgumentPosition apos |
|
||||||
arg = mid.getNodeEx().asNode() and
|
arg = mid.getNodeEx().asNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, apos) and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp() and
|
||||||
config = mid.getConfiguration()
|
config = mid.getConfiguration() and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate partialPathIntoCallable0(
|
private predicate partialPathIntoCallable0(
|
||||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||||
callable = resolveCall(call, outercc)
|
callable = resolveCall(call, outercc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4450,9 +4469,9 @@ private module FlowExploration {
|
|||||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable |
|
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, pos) and
|
||||||
sc1 = TSummaryCtx1Param(p) and
|
sc1 = TSummaryCtx1Param(p) and
|
||||||
sc2 = TSummaryCtx2Some(ap)
|
sc2 = TSummaryCtx2Some(ap)
|
||||||
|
|
|
|
||||||
@@ -4616,22 +4635,23 @@ private module FlowExploration {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revPartialPathFlowsThrough(
|
private predicate revPartialPathFlowsThrough(
|
||||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||||
Configuration config
|
RevPartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||||
mid.getNodeEx() = p and
|
mid.getNodeEx() = p and
|
||||||
p.getPosition() = pos and
|
p.getPosition() = ppos and
|
||||||
sc1 = mid.getSummaryCtx1() and
|
sc1 = mid.getSummaryCtx1() and
|
||||||
sc2 = mid.getSummaryCtx2() and
|
sc2 = mid.getSummaryCtx2() and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp() and
|
||||||
config = mid.getConfiguration()
|
config = mid.getConfiguration() and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revPartialPathThroughCallable0(
|
private predicate revPartialPathThroughCallable0(
|
||||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||||
@@ -4644,7 +4664,7 @@ private module FlowExploration {
|
|||||||
private predicate revPartialPathThroughCallable(
|
private predicate revPartialPathThroughCallable(
|
||||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCall call, int pos |
|
exists(DataFlowCall call, ArgumentPosition pos |
|
||||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
|||||||
private class ParamNodeEx extends NodeEx {
|
private class ParamNodeEx extends NodeEx {
|
||||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||||
|
|
||||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
int getPosition() { this.isParameterOf(_, result) }
|
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||||
|
|
||||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||||
}
|
}
|
||||||
@@ -1012,6 +1012,9 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||||
|
|
||||||
|
bindingset[node, ap]
|
||||||
|
private predicate filter(NodeEx node, Ap ap) { any() }
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||||
|
|
||||||
@@ -1020,6 +1023,13 @@ private module Stage2 {
|
|||||||
PrevStage::revFlow(node, _, _, apa, config)
|
PrevStage::revFlow(node, _, _, apa, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bindingset[result, apa]
|
||||||
|
private ApApprox unbindApa(ApApprox apa) {
|
||||||
|
exists(ApApprox apa0 |
|
||||||
|
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughOutOfCall(
|
private predicate flowThroughOutOfCall(
|
||||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
@@ -1042,6 +1052,13 @@ private module Stage2 {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||||
|
fwdFlow0(node, cc, argAp, ap, config) and
|
||||||
|
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||||
|
filter(node, ap)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||||
flowCand(node, _, config) and
|
flowCand(node, _, config) and
|
||||||
sourceNode(node, config) and
|
sourceNode(node, config) and
|
||||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||||
@@ -1112,7 +1129,7 @@ private module Stage2 {
|
|||||||
) {
|
) {
|
||||||
exists(DataFlowType contentType |
|
exists(DataFlowType contentType |
|
||||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||||
typecheckStore(ap1, contentType)
|
typecheckStore(ap1, contentType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1189,7 +1206,7 @@ private module Stage2 {
|
|||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1430,7 +1447,7 @@ private module Stage2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||||
parameterFlow(p, ap, ap0, c, config) and
|
parameterFlow(p, ap, ap0, c, config) and
|
||||||
c = ret.getEnclosingCallable() and
|
c = ret.getEnclosingCallable() and
|
||||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||||
@@ -2125,7 +2142,7 @@ private module Stage3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||||
parameterFlow(p, ap, ap0, c, config) and
|
parameterFlow(p, ap, ap0, c, config) and
|
||||||
c = ret.getEnclosingCallable() and
|
c = ret.getEnclosingCallable() and
|
||||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||||
@@ -2891,7 +2908,7 @@ private module Stage4 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||||
parameterFlow(p, ap, ap0, c, config) and
|
parameterFlow(p, ap, ap0, c, config) and
|
||||||
c = ret.getEnclosingCallable() and
|
c = ret.getEnclosingCallable() and
|
||||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||||
@@ -2975,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
|||||||
|
|
||||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||||
|
|
||||||
int getParameterPos() { p.isParameterOf(_, result) }
|
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||||
|
|
||||||
ParamNodeEx getParamNode() { result = p }
|
ParamNodeEx getParamNode() { result = p }
|
||||||
|
|
||||||
@@ -3622,39 +3639,40 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate pathIntoArg(
|
private predicate pathIntoArg(
|
||||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||||
Configuration config
|
AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNode arg |
|
exists(ArgNode arg, ArgumentPosition apos |
|
||||||
arg = mid.getNodeEx().asNode() and
|
arg = mid.getNodeEx().asNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, apos) and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp() and
|
||||||
apa = ap.getApprox() and
|
apa = ap.getApprox() and
|
||||||
config = mid.getConfiguration()
|
config = mid.getConfiguration() and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parameterCand(
|
private predicate parameterCand(
|
||||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
Stage4::revFlow(p, _, _, apa, config) and
|
Stage4::revFlow(p, _, _, apa, config) and
|
||||||
p.isParameterOf(callable, i)
|
p.isParameterOf(callable, pos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate pathIntoCallable0(
|
private predicate pathIntoCallable0(
|
||||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||||
AccessPath ap, Configuration config
|
DataFlowCall call, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(AccessPathApprox apa |
|
exists(AccessPathApprox apa |
|
||||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||||
pragma[only_bind_into](config)) and
|
pragma[only_bind_into](config)) and
|
||||||
callable = resolveCall(call, outercc) and
|
callable = resolveCall(call, outercc) and
|
||||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||||
pragma[only_bind_into](config))
|
pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -3669,9 +3687,9 @@ private predicate pathIntoCallable(
|
|||||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||||
DataFlowCall call, Configuration config
|
DataFlowCall call, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, pos) and
|
||||||
(
|
(
|
||||||
sc = TSummaryCtxSome(p, ap)
|
sc = TSummaryCtxSome(p, ap)
|
||||||
or
|
or
|
||||||
@@ -3695,7 +3713,7 @@ private predicate paramFlowsThrough(
|
|||||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||||
mid.getNodeEx() = ret and
|
mid.getNodeEx() = ret and
|
||||||
kind = ret.getKind() and
|
kind = ret.getKind() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
@@ -4424,24 +4442,25 @@ private module FlowExploration {
|
|||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate partialPathIntoArg(
|
private predicate partialPathIntoArg(
|
||||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||||
Configuration config
|
PartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNode arg |
|
exists(ArgNode arg, ArgumentPosition apos |
|
||||||
arg = mid.getNodeEx().asNode() and
|
arg = mid.getNodeEx().asNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, apos) and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp() and
|
||||||
config = mid.getConfiguration()
|
config = mid.getConfiguration() and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate partialPathIntoCallable0(
|
private predicate partialPathIntoCallable0(
|
||||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||||
callable = resolveCall(call, outercc)
|
callable = resolveCall(call, outercc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4450,9 +4469,9 @@ private module FlowExploration {
|
|||||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable |
|
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, pos) and
|
||||||
sc1 = TSummaryCtx1Param(p) and
|
sc1 = TSummaryCtx1Param(p) and
|
||||||
sc2 = TSummaryCtx2Some(ap)
|
sc2 = TSummaryCtx2Some(ap)
|
||||||
|
|
|
|
||||||
@@ -4616,22 +4635,23 @@ private module FlowExploration {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revPartialPathFlowsThrough(
|
private predicate revPartialPathFlowsThrough(
|
||||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||||
Configuration config
|
RevPartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||||
mid.getNodeEx() = p and
|
mid.getNodeEx() = p and
|
||||||
p.getPosition() = pos and
|
p.getPosition() = ppos and
|
||||||
sc1 = mid.getSummaryCtx1() and
|
sc1 = mid.getSummaryCtx1() and
|
||||||
sc2 = mid.getSummaryCtx2() and
|
sc2 = mid.getSummaryCtx2() and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp() and
|
||||||
config = mid.getConfiguration()
|
config = mid.getConfiguration() and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revPartialPathThroughCallable0(
|
private predicate revPartialPathThroughCallable0(
|
||||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||||
@@ -4644,7 +4664,7 @@ private module FlowExploration {
|
|||||||
private predicate revPartialPathThroughCallable(
|
private predicate revPartialPathThroughCallable(
|
||||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCall call, int pos |
|
exists(DataFlowCall call, ArgumentPosition pos |
|
||||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
|||||||
private class ParamNodeEx extends NodeEx {
|
private class ParamNodeEx extends NodeEx {
|
||||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||||
|
|
||||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
int getPosition() { this.isParameterOf(_, result) }
|
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||||
|
|
||||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||||
}
|
}
|
||||||
@@ -1012,6 +1012,9 @@ private module Stage2 {
|
|||||||
|
|
||||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||||
|
|
||||||
|
bindingset[node, ap]
|
||||||
|
private predicate filter(NodeEx node, Ap ap) { any() }
|
||||||
|
|
||||||
bindingset[ap, contentType]
|
bindingset[ap, contentType]
|
||||||
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||||
|
|
||||||
@@ -1020,6 +1023,13 @@ private module Stage2 {
|
|||||||
PrevStage::revFlow(node, _, _, apa, config)
|
PrevStage::revFlow(node, _, _, apa, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bindingset[result, apa]
|
||||||
|
private ApApprox unbindApa(ApApprox apa) {
|
||||||
|
exists(ApApprox apa0 |
|
||||||
|
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowThroughOutOfCall(
|
private predicate flowThroughOutOfCall(
|
||||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||||
@@ -1042,6 +1052,13 @@ private module Stage2 {
|
|||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||||
|
fwdFlow0(node, cc, argAp, ap, config) and
|
||||||
|
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||||
|
filter(node, ap)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||||
flowCand(node, _, config) and
|
flowCand(node, _, config) and
|
||||||
sourceNode(node, config) and
|
sourceNode(node, config) and
|
||||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||||
@@ -1112,7 +1129,7 @@ private module Stage2 {
|
|||||||
) {
|
) {
|
||||||
exists(DataFlowType contentType |
|
exists(DataFlowType contentType |
|
||||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||||
typecheckStore(ap1, contentType)
|
typecheckStore(ap1, contentType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1189,7 +1206,7 @@ private module Stage2 {
|
|||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1430,7 +1447,7 @@ private module Stage2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||||
parameterFlow(p, ap, ap0, c, config) and
|
parameterFlow(p, ap, ap0, c, config) and
|
||||||
c = ret.getEnclosingCallable() and
|
c = ret.getEnclosingCallable() and
|
||||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||||
@@ -2125,7 +2142,7 @@ private module Stage3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||||
parameterFlow(p, ap, ap0, c, config) and
|
parameterFlow(p, ap, ap0, c, config) and
|
||||||
c = ret.getEnclosingCallable() and
|
c = ret.getEnclosingCallable() and
|
||||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||||
@@ -2891,7 +2908,7 @@ private module Stage4 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||||
parameterFlow(p, ap, ap0, c, config) and
|
parameterFlow(p, ap, ap0, c, config) and
|
||||||
c = ret.getEnclosingCallable() and
|
c = ret.getEnclosingCallable() and
|
||||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||||
@@ -2975,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
|||||||
|
|
||||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||||
|
|
||||||
int getParameterPos() { p.isParameterOf(_, result) }
|
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||||
|
|
||||||
ParamNodeEx getParamNode() { result = p }
|
ParamNodeEx getParamNode() { result = p }
|
||||||
|
|
||||||
@@ -3622,39 +3639,40 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate pathIntoArg(
|
private predicate pathIntoArg(
|
||||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||||
Configuration config
|
AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNode arg |
|
exists(ArgNode arg, ArgumentPosition apos |
|
||||||
arg = mid.getNodeEx().asNode() and
|
arg = mid.getNodeEx().asNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, apos) and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp() and
|
||||||
apa = ap.getApprox() and
|
apa = ap.getApprox() and
|
||||||
config = mid.getConfiguration()
|
config = mid.getConfiguration() and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate parameterCand(
|
private predicate parameterCand(
|
||||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ParamNodeEx p |
|
exists(ParamNodeEx p |
|
||||||
Stage4::revFlow(p, _, _, apa, config) and
|
Stage4::revFlow(p, _, _, apa, config) and
|
||||||
p.isParameterOf(callable, i)
|
p.isParameterOf(callable, pos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate pathIntoCallable0(
|
private predicate pathIntoCallable0(
|
||||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||||
AccessPath ap, Configuration config
|
DataFlowCall call, AccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(AccessPathApprox apa |
|
exists(AccessPathApprox apa |
|
||||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||||
pragma[only_bind_into](config)) and
|
pragma[only_bind_into](config)) and
|
||||||
callable = resolveCall(call, outercc) and
|
callable = resolveCall(call, outercc) and
|
||||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||||
pragma[only_bind_into](config))
|
pragma[only_bind_into](config))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -3669,9 +3687,9 @@ private predicate pathIntoCallable(
|
|||||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||||
DataFlowCall call, Configuration config
|
DataFlowCall call, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, pos) and
|
||||||
(
|
(
|
||||||
sc = TSummaryCtxSome(p, ap)
|
sc = TSummaryCtxSome(p, ap)
|
||||||
or
|
or
|
||||||
@@ -3695,7 +3713,7 @@ private predicate paramFlowsThrough(
|
|||||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||||
mid.getNodeEx() = ret and
|
mid.getNodeEx() = ret and
|
||||||
kind = ret.getKind() and
|
kind = ret.getKind() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
@@ -4424,24 +4442,25 @@ private module FlowExploration {
|
|||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate partialPathIntoArg(
|
private predicate partialPathIntoArg(
|
||||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||||
Configuration config
|
PartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(ArgNode arg |
|
exists(ArgNode arg, ArgumentPosition apos |
|
||||||
arg = mid.getNodeEx().asNode() and
|
arg = mid.getNodeEx().asNode() and
|
||||||
cc = mid.getCallContext() and
|
cc = mid.getCallContext() and
|
||||||
arg.argumentOf(call, i) and
|
arg.argumentOf(call, apos) and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp() and
|
||||||
config = mid.getConfiguration()
|
config = mid.getConfiguration() and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate partialPathIntoCallable0(
|
private predicate partialPathIntoCallable0(
|
||||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||||
callable = resolveCall(call, outercc)
|
callable = resolveCall(call, outercc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4450,9 +4469,9 @@ private module FlowExploration {
|
|||||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(int i, DataFlowCallable callable |
|
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||||
p.isParameterOf(callable, i) and
|
p.isParameterOf(callable, pos) and
|
||||||
sc1 = TSummaryCtx1Param(p) and
|
sc1 = TSummaryCtx1Param(p) and
|
||||||
sc2 = TSummaryCtx2Some(ap)
|
sc2 = TSummaryCtx2Some(ap)
|
||||||
|
|
|
|
||||||
@@ -4616,22 +4635,23 @@ private module FlowExploration {
|
|||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revPartialPathFlowsThrough(
|
private predicate revPartialPathFlowsThrough(
|
||||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||||
Configuration config
|
RevPartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||||
mid.getNodeEx() = p and
|
mid.getNodeEx() = p and
|
||||||
p.getPosition() = pos and
|
p.getPosition() = ppos and
|
||||||
sc1 = mid.getSummaryCtx1() and
|
sc1 = mid.getSummaryCtx1() and
|
||||||
sc2 = mid.getSummaryCtx2() and
|
sc2 = mid.getSummaryCtx2() and
|
||||||
ap = mid.getAp() and
|
ap = mid.getAp() and
|
||||||
config = mid.getConfiguration()
|
config = mid.getConfiguration() and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate revPartialPathThroughCallable0(
|
private predicate revPartialPathThroughCallable0(
|
||||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||||
Configuration config
|
Configuration config
|
||||||
) {
|
) {
|
||||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||||
@@ -4644,7 +4664,7 @@ private module FlowExploration {
|
|||||||
private predicate revPartialPathThroughCallable(
|
private predicate revPartialPathThroughCallable(
|
||||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||||
) {
|
) {
|
||||||
exists(DataFlowCall call, int pos |
|
exists(DataFlowCall call, ArgumentPosition pos |
|
||||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -62,6 +62,18 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
|
|||||||
tupleLimit = 1000
|
tupleLimit = 1000
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `arg` is an argument of `call` with an argument position that matches
|
||||||
|
* parameter position `ppos`.
|
||||||
|
*/
|
||||||
|
pragma[noinline]
|
||||||
|
predicate argumentPositionMatch(DataFlowCall call, ArgNode arg, ParameterPosition ppos) {
|
||||||
|
exists(ArgumentPosition apos |
|
||||||
|
arg.argumentOf(call, apos) and
|
||||||
|
parameterMatch(ppos, apos)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a simple data-flow analysis for resolving lambda calls. The analysis
|
* Provides a simple data-flow analysis for resolving lambda calls. The analysis
|
||||||
* currently excludes read-steps, store-steps, and flow-through.
|
* currently excludes read-steps, store-steps, and flow-through.
|
||||||
@@ -71,25 +83,27 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
|
|||||||
* calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly.
|
* calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly.
|
||||||
*/
|
*/
|
||||||
private module LambdaFlow {
|
private module LambdaFlow {
|
||||||
private predicate viableParamNonLambda(DataFlowCall call, int i, ParamNode p) {
|
pragma[noinline]
|
||||||
p.isParameterOf(viableCallable(call), i)
|
private predicate viableParamNonLambda(DataFlowCall call, ParameterPosition ppos, ParamNode p) {
|
||||||
|
p.isParameterOf(viableCallable(call), ppos)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate viableParamLambda(DataFlowCall call, int i, ParamNode p) {
|
pragma[noinline]
|
||||||
p.isParameterOf(viableCallableLambda(call, _), i)
|
private predicate viableParamLambda(DataFlowCall call, ParameterPosition ppos, ParamNode p) {
|
||||||
|
p.isParameterOf(viableCallableLambda(call, _), ppos)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate viableParamArgNonLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
|
private predicate viableParamArgNonLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||||
exists(int i |
|
exists(ParameterPosition ppos |
|
||||||
viableParamNonLambda(call, i, p) and
|
viableParamNonLambda(call, ppos, p) and
|
||||||
arg.argumentOf(call, i)
|
argumentPositionMatch(call, arg, ppos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate viableParamArgLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
|
private predicate viableParamArgLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||||
exists(int i |
|
exists(ParameterPosition ppos |
|
||||||
viableParamLambda(call, i, p) and
|
viableParamLambda(call, ppos, p) and
|
||||||
arg.argumentOf(call, i)
|
argumentPositionMatch(call, arg, ppos)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,7 +336,7 @@ private module Cached {
|
|||||||
or
|
or
|
||||||
exists(ArgNode arg |
|
exists(ArgNode arg |
|
||||||
result.(PostUpdateNode).getPreUpdateNode() = arg and
|
result.(PostUpdateNode).getPreUpdateNode() = arg and
|
||||||
arg.argumentOf(call, k.(ParamUpdateReturnKind).getPosition())
|
arg.argumentOf(call, k.(ParamUpdateReturnKind).getAMatchingArgumentPosition())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,7 +344,7 @@ private module Cached {
|
|||||||
predicate returnNodeExt(Node n, ReturnKindExt k) {
|
predicate returnNodeExt(Node n, ReturnKindExt k) {
|
||||||
k = TValueReturn(n.(ReturnNode).getKind())
|
k = TValueReturn(n.(ReturnNode).getKind())
|
||||||
or
|
or
|
||||||
exists(ParamNode p, int pos |
|
exists(ParamNode p, ParameterPosition pos |
|
||||||
parameterValueFlowsToPreUpdate(p, n) and
|
parameterValueFlowsToPreUpdate(p, n) and
|
||||||
p.isParameterOf(_, pos) and
|
p.isParameterOf(_, pos) and
|
||||||
k = TParamUpdate(pos)
|
k = TParamUpdate(pos)
|
||||||
@@ -352,11 +366,13 @@ private module Cached {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate parameterNode(Node p, DataFlowCallable c, int pos) { isParameterNode(p, c, pos) }
|
predicate parameterNode(Node p, DataFlowCallable c, ParameterPosition pos) {
|
||||||
|
isParameterNode(p, c, pos)
|
||||||
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate argumentNode(Node n, DataFlowCall call, int pos) {
|
predicate argumentNode(Node n, DataFlowCall call, ArgumentPosition pos) {
|
||||||
n.(ArgumentNode).argumentOf(call, pos)
|
isArgumentNode(n, call, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -374,12 +390,12 @@ private module Cached {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `p` is the `i`th parameter of a viable dispatch target of `call`.
|
* Holds if `p` is the parameter of a viable dispatch target of `call`,
|
||||||
* The instance parameter is considered to have index `-1`.
|
* and `p` has position `ppos`.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate viableParam(DataFlowCall call, int i, ParamNode p) {
|
private predicate viableParam(DataFlowCall call, ParameterPosition ppos, ParamNode p) {
|
||||||
p.isParameterOf(viableCallableExt(call), i)
|
p.isParameterOf(viableCallableExt(call), ppos)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -388,9 +404,9 @@ private module Cached {
|
|||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
predicate viableParamArg(DataFlowCall call, ParamNode p, ArgNode arg) {
|
predicate viableParamArg(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||||
exists(int i |
|
exists(ParameterPosition ppos |
|
||||||
viableParam(call, i, p) and
|
viableParam(call, ppos, p) and
|
||||||
arg.argumentOf(call, i) and
|
argumentPositionMatch(call, arg, ppos) and
|
||||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
|
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -862,7 +878,7 @@ private module Cached {
|
|||||||
cached
|
cached
|
||||||
newtype TReturnKindExt =
|
newtype TReturnKindExt =
|
||||||
TValueReturn(ReturnKind kind) or
|
TValueReturn(ReturnKind kind) or
|
||||||
TParamUpdate(int pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
|
TParamUpdate(ParameterPosition pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
|
||||||
|
|
||||||
cached
|
cached
|
||||||
newtype TBooleanOption =
|
newtype TBooleanOption =
|
||||||
@@ -1054,9 +1070,9 @@ class ParamNode extends Node {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if this node is the parameter of callable `c` at the specified
|
* Holds if this node is the parameter of callable `c` at the specified
|
||||||
* (zero-based) position.
|
* position.
|
||||||
*/
|
*/
|
||||||
predicate isParameterOf(DataFlowCallable c, int i) { parameterNode(this, c, i) }
|
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) { parameterNode(this, c, pos) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A data-flow node that represents a call argument. */
|
/** A data-flow node that represents a call argument. */
|
||||||
@@ -1064,7 +1080,9 @@ class ArgNode extends Node {
|
|||||||
ArgNode() { argumentNode(this, _, _) }
|
ArgNode() { argumentNode(this, _, _) }
|
||||||
|
|
||||||
/** Holds if this argument occurs at the given position in the given call. */
|
/** Holds if this argument occurs at the given position in the given call. */
|
||||||
final predicate argumentOf(DataFlowCall call, int pos) { argumentNode(this, call, pos) }
|
final predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
|
||||||
|
argumentNode(this, call, pos)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1110,11 +1128,14 @@ class ValueReturnKind extends ReturnKindExt, TValueReturn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
|
class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
|
||||||
private int pos;
|
private ParameterPosition pos;
|
||||||
|
|
||||||
ParamUpdateReturnKind() { this = TParamUpdate(pos) }
|
ParamUpdateReturnKind() { this = TParamUpdate(pos) }
|
||||||
|
|
||||||
int getPosition() { result = pos }
|
ParameterPosition getPosition() { result = pos }
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
ArgumentPosition getAMatchingArgumentPosition() { parameterMatch(pos, result) }
|
||||||
|
|
||||||
override string toString() { result = "param update " + pos }
|
override string toString() { result = "param update " + pos }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,11 +15,23 @@ module Consistency {
|
|||||||
class ConsistencyConfiguration extends TConsistencyConfiguration {
|
class ConsistencyConfiguration extends TConsistencyConfiguration {
|
||||||
string toString() { none() }
|
string toString() { none() }
|
||||||
|
|
||||||
|
/** Holds if `n` should be excluded from the consistency test `uniqueEnclosingCallable`. */
|
||||||
|
predicate uniqueEnclosingCallableExclude(Node n) { none() }
|
||||||
|
|
||||||
|
/** Holds if `n` should be excluded from the consistency test `uniqueNodeLocation`. */
|
||||||
|
predicate uniqueNodeLocationExclude(Node n) { none() }
|
||||||
|
|
||||||
|
/** Holds if `n` should be excluded from the consistency test `missingLocation`. */
|
||||||
|
predicate missingLocationExclude(Node n) { none() }
|
||||||
|
|
||||||
/** Holds if `n` should be excluded from the consistency test `postWithInFlow`. */
|
/** Holds if `n` should be excluded from the consistency test `postWithInFlow`. */
|
||||||
predicate postWithInFlowExclude(Node n) { none() }
|
predicate postWithInFlowExclude(Node n) { none() }
|
||||||
|
|
||||||
/** Holds if `n` should be excluded from the consistency test `argHasPostUpdate`. */
|
/** Holds if `n` should be excluded from the consistency test `argHasPostUpdate`. */
|
||||||
predicate argHasPostUpdateExclude(ArgumentNode n) { none() }
|
predicate argHasPostUpdateExclude(ArgumentNode n) { none() }
|
||||||
|
|
||||||
|
/** Holds if `n` should be excluded from the consistency test `reverseRead`. */
|
||||||
|
predicate reverseReadExclude(Node n) { none() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class RelevantNode extends Node {
|
private class RelevantNode extends Node {
|
||||||
@@ -46,6 +58,7 @@ module Consistency {
|
|||||||
n instanceof RelevantNode and
|
n instanceof RelevantNode and
|
||||||
c = count(nodeGetEnclosingCallable(n)) and
|
c = count(nodeGetEnclosingCallable(n)) and
|
||||||
c != 1 and
|
c != 1 and
|
||||||
|
not any(ConsistencyConfiguration conf).uniqueEnclosingCallableExclude(n) and
|
||||||
msg = "Node should have one enclosing callable but has " + c + "."
|
msg = "Node should have one enclosing callable but has " + c + "."
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -66,6 +79,7 @@ module Consistency {
|
|||||||
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
) and
|
) and
|
||||||
c != 1 and
|
c != 1 and
|
||||||
|
not any(ConsistencyConfiguration conf).uniqueNodeLocationExclude(n) and
|
||||||
msg = "Node should have one location but has " + c + "."
|
msg = "Node should have one location but has " + c + "."
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -76,7 +90,8 @@ module Consistency {
|
|||||||
strictcount(Node n |
|
strictcount(Node n |
|
||||||
not exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
|
not exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
|
||||||
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
)
|
) and
|
||||||
|
not any(ConsistencyConfiguration conf).missingLocationExclude(n)
|
||||||
) and
|
) and
|
||||||
msg = "Nodes without location: " + c
|
msg = "Nodes without location: " + c
|
||||||
)
|
)
|
||||||
@@ -172,6 +187,7 @@ module Consistency {
|
|||||||
|
|
||||||
query predicate reverseRead(Node n, string msg) {
|
query predicate reverseRead(Node n, string msg) {
|
||||||
exists(Node n2 | readStep(n, _, n2) and hasPost(n2) and not hasPost(n)) and
|
exists(Node n2 | readStep(n, _, n2) and hasPost(n2) and not hasPost(n)) and
|
||||||
|
not any(ConsistencyConfiguration conf).reverseReadExclude(n) and
|
||||||
msg = "Origin of readStep is missing a PostUpdateNode."
|
msg = "Origin of readStep is missing a PostUpdateNode."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,14 @@ private import DataFlowImplConsistency
|
|||||||
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() }
|
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() }
|
||||||
|
|
||||||
/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */
|
/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */
|
||||||
predicate isParameterNode(ParameterNode p, DataFlowCallable c, int pos) { p.isParameterOf(c, pos) }
|
predicate isParameterNode(ParameterNode p, DataFlowCallable c, ParameterPosition pos) {
|
||||||
|
p.isParameterOf(c, pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if `arg` is an `ArgumentNode` of `c` with position `pos`. */
|
||||||
|
predicate isArgumentNode(ArgumentNode arg, DataFlowCall c, ArgumentPosition pos) {
|
||||||
|
arg.argumentOf(c, pos)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A data flow node that occurs as the argument of a call and is passed as-is
|
* A data flow node that occurs as the argument of a call and is passed as-is
|
||||||
|
|||||||
@@ -452,7 +452,7 @@ class SsaPhiNode extends Node, TSsaPhiNode {
|
|||||||
|
|
||||||
/** Holds if this phi node has input from the `rnk`'th write operation in block `block`. */
|
/** Holds if this phi node has input from the `rnk`'th write operation in block `block`. */
|
||||||
final predicate hasInputAtRankInBlock(IRBlock block, int rnk) {
|
final predicate hasInputAtRankInBlock(IRBlock block, int rnk) {
|
||||||
hasInputAtRankInBlock(block, rnk, _)
|
this.hasInputAtRankInBlock(block, rnk, _)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -307,7 +307,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe
|
|||||||
final override string toString() { result = tag.toString() }
|
final override string toString() { result = tag.toString() }
|
||||||
|
|
||||||
final override Instruction getAnyDef() {
|
final override Instruction getAnyDef() {
|
||||||
result = unique(Instruction defInstr | hasDefinition(defInstr, _))
|
result = unique(Instruction defInstr | this.hasDefinition(defInstr, _))
|
||||||
}
|
}
|
||||||
|
|
||||||
final override Overlap getDefinitionOverlap() { this.hasDefinition(_, result) }
|
final override Overlap getDefinitionOverlap() { this.hasDefinition(_, result) }
|
||||||
|
|||||||
@@ -307,7 +307,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe
|
|||||||
final override string toString() { result = tag.toString() }
|
final override string toString() { result = tag.toString() }
|
||||||
|
|
||||||
final override Instruction getAnyDef() {
|
final override Instruction getAnyDef() {
|
||||||
result = unique(Instruction defInstr | hasDefinition(defInstr, _))
|
result = unique(Instruction defInstr | this.hasDefinition(defInstr, _))
|
||||||
}
|
}
|
||||||
|
|
||||||
final override Overlap getDefinitionOverlap() { this.hasDefinition(_, result) }
|
final override Overlap getDefinitionOverlap() { this.hasDefinition(_, result) }
|
||||||
|
|||||||
@@ -307,7 +307,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe
|
|||||||
final override string toString() { result = tag.toString() }
|
final override string toString() { result = tag.toString() }
|
||||||
|
|
||||||
final override Instruction getAnyDef() {
|
final override Instruction getAnyDef() {
|
||||||
result = unique(Instruction defInstr | hasDefinition(defInstr, _))
|
result = unique(Instruction defInstr | this.hasDefinition(defInstr, _))
|
||||||
}
|
}
|
||||||
|
|
||||||
final override Overlap getDefinitionOverlap() { this.hasDefinition(_, result) }
|
final override Overlap getDefinitionOverlap() { this.hasDefinition(_, result) }
|
||||||
|
|||||||
@@ -71,13 +71,30 @@ abstract class BufferWrite extends Expr {
|
|||||||
*/
|
*/
|
||||||
int getMaxData() { none() }
|
int getMaxData() { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an upper bound to the amount of data that's being written (if one
|
||||||
|
* can be found), specifying the reason for the estimation.
|
||||||
|
*/
|
||||||
|
int getMaxData(BufferWriteEstimationReason reason) {
|
||||||
|
reason instanceof NoSpecifiedEstimateReason and result = getMaxData()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets an upper bound to the amount of data that's being written (if one
|
* Gets an upper bound to the amount of data that's being written (if one
|
||||||
* can be found), except that float to string conversions are assumed to be
|
* can be found), except that float to string conversions are assumed to be
|
||||||
* much smaller (8 bytes) than their true maximum length. This can be
|
* much smaller (8 bytes) than their true maximum length. This can be
|
||||||
* helpful in determining the cause of a buffer overflow issue.
|
* helpful in determining the cause of a buffer overflow issue.
|
||||||
*/
|
*/
|
||||||
int getMaxDataLimited() { result = this.getMaxData() }
|
int getMaxDataLimited() { result = getMaxData() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an upper bound to the amount of data that's being written (if one
|
||||||
|
* can be found), specifying the reason for the estimation, except that
|
||||||
|
* float to string conversions are assumed to be much smaller (8 bytes)
|
||||||
|
* than their true maximum length. This can be helpful in determining the
|
||||||
|
* cause of a buffer overflow issue.
|
||||||
|
*/
|
||||||
|
int getMaxDataLimited(BufferWriteEstimationReason reason) { result = getMaxData(reason) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the size of a single character of the type this
|
* Gets the size of a single character of the type this
|
||||||
@@ -135,10 +152,16 @@ class StrCopyBW extends BufferWriteCall {
|
|||||||
result = this.getArgument(this.getParamSize()).getValue().toInt() * this.getCharSize()
|
result = this.getArgument(this.getParamSize()).getValue().toInt() * this.getCharSize()
|
||||||
}
|
}
|
||||||
|
|
||||||
override int getMaxData() {
|
private int getMaxDataImpl(BufferWriteEstimationReason reason) {
|
||||||
|
// when result exists, it is an exact flow analysis
|
||||||
|
reason instanceof ValueFlowAnalysis and
|
||||||
result =
|
result =
|
||||||
this.getArgument(this.getParamSrc()).(AnalysedString).getMaxLength() * this.getCharSize()
|
this.getArgument(this.getParamSrc()).(AnalysedString).getMaxLength() * this.getCharSize()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override int getMaxData(BufferWriteEstimationReason reason) { result = getMaxDataImpl(reason) }
|
||||||
|
|
||||||
|
override int getMaxData() { result = max(getMaxDataImpl(_)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -173,10 +196,16 @@ class StrCatBW extends BufferWriteCall {
|
|||||||
result = this.getArgument(this.getParamSize()).getValue().toInt() * this.getCharSize()
|
result = this.getArgument(this.getParamSize()).getValue().toInt() * this.getCharSize()
|
||||||
}
|
}
|
||||||
|
|
||||||
override int getMaxData() {
|
private int getMaxDataImpl(BufferWriteEstimationReason reason) {
|
||||||
|
// when result exists, it is an exact flow analysis
|
||||||
|
reason instanceof ValueFlowAnalysis and
|
||||||
result =
|
result =
|
||||||
this.getArgument(this.getParamSrc()).(AnalysedString).getMaxLength() * this.getCharSize()
|
this.getArgument(this.getParamSrc()).(AnalysedString).getMaxLength() * this.getCharSize()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override int getMaxData(BufferWriteEstimationReason reason) { result = getMaxDataImpl(reason) }
|
||||||
|
|
||||||
|
override int getMaxData() { result = max(getMaxDataImpl(_)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -233,19 +262,29 @@ class SprintfBW extends BufferWriteCall {
|
|||||||
|
|
||||||
override Expr getDest() { result = this.getArgument(f.getOutputParameterIndex(false)) }
|
override Expr getDest() { result = this.getArgument(f.getOutputParameterIndex(false)) }
|
||||||
|
|
||||||
override int getMaxData() {
|
private int getMaxDataImpl(BufferWriteEstimationReason reason) {
|
||||||
exists(FormatLiteral fl |
|
exists(FormatLiteral fl |
|
||||||
fl = this.(FormattingFunctionCall).getFormat() and
|
fl = this.(FormattingFunctionCall).getFormat() and
|
||||||
result = fl.getMaxConvertedLength() * this.getCharSize()
|
result = fl.getMaxConvertedLengthWithReason(reason) * this.getCharSize()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override int getMaxDataLimited() {
|
override int getMaxData(BufferWriteEstimationReason reason) { result = getMaxDataImpl(reason) }
|
||||||
|
|
||||||
|
override int getMaxData() { result = max(getMaxDataImpl(_)) }
|
||||||
|
|
||||||
|
private int getMaxDataLimitedImpl(BufferWriteEstimationReason reason) {
|
||||||
exists(FormatLiteral fl |
|
exists(FormatLiteral fl |
|
||||||
fl = this.(FormattingFunctionCall).getFormat() and
|
fl = this.(FormattingFunctionCall).getFormat() and
|
||||||
result = fl.getMaxConvertedLengthLimited() * this.getCharSize()
|
result = fl.getMaxConvertedLengthLimitedWithReason(reason) * this.getCharSize()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override int getMaxDataLimited(BufferWriteEstimationReason reason) {
|
||||||
|
result = getMaxDataLimitedImpl(reason)
|
||||||
|
}
|
||||||
|
|
||||||
|
override int getMaxDataLimited() { result = max(getMaxDataLimitedImpl(_)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -336,19 +375,29 @@ class SnprintfBW extends BufferWriteCall {
|
|||||||
result = this.getArgument(this.getParamSize()).getValue().toInt() * this.getCharSize()
|
result = this.getArgument(this.getParamSize()).getValue().toInt() * this.getCharSize()
|
||||||
}
|
}
|
||||||
|
|
||||||
override int getMaxData() {
|
private int getMaxDataImpl(BufferWriteEstimationReason reason) {
|
||||||
exists(FormatLiteral fl |
|
exists(FormatLiteral fl |
|
||||||
fl = this.(FormattingFunctionCall).getFormat() and
|
fl = this.(FormattingFunctionCall).getFormat() and
|
||||||
result = fl.getMaxConvertedLength() * this.getCharSize()
|
result = fl.getMaxConvertedLengthWithReason(reason) * this.getCharSize()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override int getMaxDataLimited() {
|
override int getMaxData(BufferWriteEstimationReason reason) { result = getMaxDataImpl(reason) }
|
||||||
|
|
||||||
|
override int getMaxData() { result = max(getMaxDataImpl(_)) }
|
||||||
|
|
||||||
|
private int getMaxDataLimitedImpl(BufferWriteEstimationReason reason) {
|
||||||
exists(FormatLiteral fl |
|
exists(FormatLiteral fl |
|
||||||
fl = this.(FormattingFunctionCall).getFormat() and
|
fl = this.(FormattingFunctionCall).getFormat() and
|
||||||
result = fl.getMaxConvertedLengthLimited() * this.getCharSize()
|
result = fl.getMaxConvertedLengthLimitedWithReason(reason) * this.getCharSize()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override int getMaxDataLimited(BufferWriteEstimationReason reason) {
|
||||||
|
result = getMaxDataLimitedImpl(reason)
|
||||||
|
}
|
||||||
|
|
||||||
|
override int getMaxDataLimited() { result = max(getMaxDataLimitedImpl(_)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -436,7 +485,9 @@ class ScanfBW extends BufferWrite {
|
|||||||
|
|
||||||
override Expr getDest() { result = this }
|
override Expr getDest() { result = this }
|
||||||
|
|
||||||
override int getMaxData() {
|
private int getMaxDataImpl(BufferWriteEstimationReason reason) {
|
||||||
|
// when this returns, it is based on exact flow analysis
|
||||||
|
reason instanceof ValueFlowAnalysis and
|
||||||
exists(ScanfFunctionCall fc, ScanfFormatLiteral fl, int arg |
|
exists(ScanfFunctionCall fc, ScanfFormatLiteral fl, int arg |
|
||||||
this = fc.getArgument(arg) and
|
this = fc.getArgument(arg) and
|
||||||
fl = fc.getFormat() and
|
fl = fc.getFormat() and
|
||||||
@@ -444,6 +495,10 @@ class ScanfBW extends BufferWrite {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override int getMaxData(BufferWriteEstimationReason reason) { result = getMaxDataImpl(reason) }
|
||||||
|
|
||||||
|
override int getMaxData() { result = max(getMaxDataImpl(_)) }
|
||||||
|
|
||||||
override string getBWDesc() {
|
override string getBWDesc() {
|
||||||
exists(FunctionCall fc |
|
exists(FunctionCall fc |
|
||||||
this = fc.getArgument(_) and
|
this = fc.getArgument(_) and
|
||||||
@@ -474,8 +529,14 @@ class RealpathBW extends BufferWriteCall {
|
|||||||
|
|
||||||
override Expr getASource() { result = this.getArgument(0) }
|
override Expr getASource() { result = this.getArgument(0) }
|
||||||
|
|
||||||
override int getMaxData() {
|
private int getMaxDataImpl(BufferWriteEstimationReason reason) {
|
||||||
|
// although there may be some unknown invariants guaranteeing that a real path is shorter than PATH_MAX, we can consider providing less than PATH_MAX a problem with high precision
|
||||||
|
reason instanceof ValueFlowAnalysis and
|
||||||
result = path_max() and
|
result = path_max() and
|
||||||
this = this // Suppress a compiler warning
|
this = this // Suppress a compiler warning
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override int getMaxData(BufferWriteEstimationReason reason) { result = getMaxDataImpl(reason) }
|
||||||
|
|
||||||
|
override int getMaxData() { result = max(getMaxDataImpl(_)) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,12 +18,12 @@ class SuppressionComment extends Comment {
|
|||||||
(
|
(
|
||||||
this instanceof CppStyleComment and
|
this instanceof CppStyleComment and
|
||||||
// strip the beginning slashes
|
// strip the beginning slashes
|
||||||
text = getContents().suffix(2)
|
text = this.getContents().suffix(2)
|
||||||
or
|
or
|
||||||
this instanceof CStyleComment and
|
this instanceof CStyleComment and
|
||||||
// strip both the beginning /* and the end */ the comment
|
// strip both the beginning /* and the end */ the comment
|
||||||
exists(string text0 |
|
exists(string text0 |
|
||||||
text0 = getContents().suffix(2) and
|
text0 = this.getContents().suffix(2) and
|
||||||
text = text0.prefix(text0.length() - 2)
|
text = text0.prefix(text0.length() - 2)
|
||||||
) and
|
) and
|
||||||
// The /* */ comment must be a single-line comment
|
// The /* */ comment must be a single-line comment
|
||||||
|
|||||||
@@ -153,12 +153,12 @@ class ExtClass extends Class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate hasLocationInfo(string path, int startline, int startcol, int endline, int endcol) {
|
predicate hasLocationInfo(string path, int startline, int startcol, int endline, int endcol) {
|
||||||
if hasOneVariableGroup()
|
if this.hasOneVariableGroup()
|
||||||
then
|
then
|
||||||
exists(VariableDeclarationGroup vdg | vdg.getClass() = this |
|
exists(VariableDeclarationGroup vdg | vdg.getClass() = this |
|
||||||
vdg.hasLocationInfo(path, startline, startcol, endline, endcol)
|
vdg.hasLocationInfo(path, startline, startcol, endline, endcol)
|
||||||
)
|
)
|
||||||
else getLocation().hasLocationInfo(path, startline, startcol, endline, endcol)
|
else this.getLocation().hasLocationInfo(path, startline, startcol, endline, endcol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,16 @@ predicate reachableThing(Thing t) {
|
|||||||
exists(Thing mid | reachableThing(mid) and mid.callsOrAccesses() = t)
|
exists(Thing mid | reachableThing(mid) and mid.callsOrAccesses() = t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate callsOrAccessesPlus(Thing thing1, FunctionToRemove thing2) {
|
||||||
|
thing1.callsOrAccesses() = thing2
|
||||||
|
or
|
||||||
|
exists(Thing mid |
|
||||||
|
thing1.callsOrAccesses() = mid and
|
||||||
|
callsOrAccessesPlus(mid, thing2)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
class Thing extends Locatable {
|
class Thing extends Locatable {
|
||||||
Thing() {
|
Thing() {
|
||||||
this instanceof Function or
|
this instanceof Function or
|
||||||
@@ -81,7 +91,7 @@ class FunctionToRemove extends Function {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Thing getOther() {
|
Thing getOther() {
|
||||||
result.callsOrAccesses+() = this and
|
callsOrAccessesPlus(result, this) and
|
||||||
this != result and
|
this != result and
|
||||||
// We will already be reporting the enclosing function of a
|
// We will already be reporting the enclosing function of a
|
||||||
// local variable, so don't also report the variable
|
// local variable, so don't also report the variable
|
||||||
|
|||||||
@@ -103,9 +103,9 @@ class CallWithBufferSize extends FunctionCall {
|
|||||||
// `upperBound(e)` defaults to `exprMaxVal(e)` when `e` isn't analyzable. So to get a meaningful
|
// `upperBound(e)` defaults to `exprMaxVal(e)` when `e` isn't analyzable. So to get a meaningful
|
||||||
// result in this case we pick the minimum value obtainable from dataflow and range analysis.
|
// result in this case we pick the minimum value obtainable from dataflow and range analysis.
|
||||||
result =
|
result =
|
||||||
upperBound(statedSizeExpr())
|
upperBound(this.statedSizeExpr())
|
||||||
.minimum(min(Expr statedSizeSrc |
|
.minimum(min(Expr statedSizeSrc |
|
||||||
DataFlow::localExprFlow(statedSizeSrc, statedSizeExpr())
|
DataFlow::localExprFlow(statedSizeSrc, this.statedSizeExpr())
|
||||||
|
|
|
|
||||||
statedSizeSrc.getValue().toInt()
|
statedSizeSrc.getValue().toInt()
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ abstract class LockOperation extends FunctionCall {
|
|||||||
ControlFlowNode getAReachedNode() {
|
ControlFlowNode getAReachedNode() {
|
||||||
result = this
|
result = this
|
||||||
or
|
or
|
||||||
exists(ControlFlowNode mid | mid = getAReachedNode() |
|
exists(ControlFlowNode mid | mid = this.getAReachedNode() |
|
||||||
not mid != this.getMatchingUnlock() and
|
not mid != this.getMatchingUnlock() and
|
||||||
result = mid.getASuccessor()
|
result = mid.getASuccessor()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -85,7 +85,8 @@ private predicate cancelingSubExprs(ComparisonOperation cmp, VariableAccess a1,
|
|||||||
exists(Variable v |
|
exists(Variable v |
|
||||||
exists(float m | m < 0 and cmpLinearSubVariable(cmp, v, a1, m)) and
|
exists(float m | m < 0 and cmpLinearSubVariable(cmp, v, a1, m)) and
|
||||||
exists(float m | m > 0 and cmpLinearSubVariable(cmp, v, a2, m))
|
exists(float m | m > 0 and cmpLinearSubVariable(cmp, v, a2, m))
|
||||||
)
|
) and
|
||||||
|
not any(ClassTemplateInstantiation inst).getATemplateArgument() = cmp.getParent*()
|
||||||
}
|
}
|
||||||
|
|
||||||
from ComparisonOperation cmp, VariableAccess a1, VariableAccess a2
|
from ComparisonOperation cmp, VariableAccess a1, VariableAccess a2
|
||||||
|
|||||||
@@ -29,7 +29,9 @@ predicate pointlessSelfComparison(ComparisonOperation cmp) {
|
|||||||
not exists(lhs.getQualifier()) and // Avoid structure fields
|
not exists(lhs.getQualifier()) and // Avoid structure fields
|
||||||
not exists(rhs.getQualifier()) and // Avoid structure fields
|
not exists(rhs.getQualifier()) and // Avoid structure fields
|
||||||
not convertedExprMightOverflow(lhs) and
|
not convertedExprMightOverflow(lhs) and
|
||||||
not convertedExprMightOverflow(rhs)
|
not convertedExprMightOverflow(rhs) and
|
||||||
|
// Don't warn if the comparison is part of a template argument.
|
||||||
|
not any(ClassTemplateInstantiation inst).getATemplateArgument() = cmp.getParent*()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"qhelp.dtd">
|
"qhelp.dtd">
|
||||||
<qhelp>
|
<qhelp>
|
||||||
<overview>
|
<overview>
|
||||||
<p>The return value of a call to <code>snprintf</code> is the number of characters that <i>would have</i> been written to the buffer assuming there was sufficient space. In the event that the operation reaches the end of the buffer and more than one character is discarded, the return value will be greater than the buffer size. This can cause incorrect behaviour, for example:
|
<p>The return value of a call to <code>snprintf</code> is the number of characters that <i>would have</i> been written to the buffer assuming there was sufficient space. In the event that the operation reaches the end of the buffer and more than one character is discarded, the return value will be greater than the buffer size. This can cause incorrect behavior, for example:
|
||||||
</p>
|
</p>
|
||||||
</overview>
|
</overview>
|
||||||
|
|
||||||
|
|||||||
@@ -156,8 +156,8 @@ abstract class LeapYearFieldAccess extends YearFieldAccess {
|
|||||||
//
|
//
|
||||||
// https://aa.usno.navy.mil/faq/docs/calendars.php
|
// https://aa.usno.navy.mil/faq/docs/calendars.php
|
||||||
this.isUsedInMod4Operation() and
|
this.isUsedInMod4Operation() and
|
||||||
additionalModulusCheckForLeapYear(400) and
|
this.additionalModulusCheckForLeapYear(400) and
|
||||||
additionalModulusCheckForLeapYear(100)
|
this.additionalModulusCheckForLeapYear(100)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,17 +176,17 @@ class StructTmLeapYearFieldAccess extends LeapYearFieldAccess {
|
|||||||
|
|
||||||
override predicate isUsedInCorrectLeapYearCheck() {
|
override predicate isUsedInCorrectLeapYearCheck() {
|
||||||
this.isUsedInMod4Operation() and
|
this.isUsedInMod4Operation() and
|
||||||
additionalModulusCheckForLeapYear(400) and
|
this.additionalModulusCheckForLeapYear(400) and
|
||||||
additionalModulusCheckForLeapYear(100) and
|
this.additionalModulusCheckForLeapYear(100) and
|
||||||
// tm_year represents years since 1900
|
// tm_year represents years since 1900
|
||||||
(
|
(
|
||||||
additionalAdditionOrSubstractionCheckForLeapYear(1900)
|
this.additionalAdditionOrSubstractionCheckForLeapYear(1900)
|
||||||
or
|
or
|
||||||
// some systems may use 2000 for 2-digit year conversions
|
// some systems may use 2000 for 2-digit year conversions
|
||||||
additionalAdditionOrSubstractionCheckForLeapYear(2000)
|
this.additionalAdditionOrSubstractionCheckForLeapYear(2000)
|
||||||
or
|
or
|
||||||
// converting from/to Unix epoch
|
// converting from/to Unix epoch
|
||||||
additionalAdditionOrSubstractionCheckForLeapYear(1970)
|
this.additionalAdditionOrSubstractionCheckForLeapYear(1970)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ class LoopWithAlloca extends Stmt {
|
|||||||
or
|
or
|
||||||
// `e == 0`
|
// `e == 0`
|
||||||
exists(EQExpr eq |
|
exists(EQExpr eq |
|
||||||
conditionRequires(eq, truth.booleanNot()) and
|
this.conditionRequires(eq, truth.booleanNot()) and
|
||||||
eq.getAnOperand().getValue().toInt() = 0 and
|
eq.getAnOperand().getValue().toInt() = 0 and
|
||||||
e = eq.getAnOperand() and
|
e = eq.getAnOperand() and
|
||||||
not exists(e.getValue())
|
not exists(e.getValue())
|
||||||
@@ -65,7 +65,7 @@ class LoopWithAlloca extends Stmt {
|
|||||||
or
|
or
|
||||||
// `e != 0`
|
// `e != 0`
|
||||||
exists(NEExpr eq |
|
exists(NEExpr eq |
|
||||||
conditionRequires(eq, truth) and
|
this.conditionRequires(eq, truth) and
|
||||||
eq.getAnOperand().getValue().toInt() = 0 and
|
eq.getAnOperand().getValue().toInt() = 0 and
|
||||||
e = eq.getAnOperand() and
|
e = eq.getAnOperand() and
|
||||||
not exists(e.getValue())
|
not exists(e.getValue())
|
||||||
@@ -73,7 +73,7 @@ class LoopWithAlloca extends Stmt {
|
|||||||
or
|
or
|
||||||
// `(bool)e == true`
|
// `(bool)e == true`
|
||||||
exists(EQExpr eq |
|
exists(EQExpr eq |
|
||||||
conditionRequires(eq, truth) and
|
this.conditionRequires(eq, truth) and
|
||||||
eq.getAnOperand().getValue().toInt() = 1 and
|
eq.getAnOperand().getValue().toInt() = 1 and
|
||||||
e = eq.getAnOperand() and
|
e = eq.getAnOperand() and
|
||||||
e.getUnspecifiedType() instanceof BoolType and
|
e.getUnspecifiedType() instanceof BoolType and
|
||||||
@@ -82,7 +82,7 @@ class LoopWithAlloca extends Stmt {
|
|||||||
or
|
or
|
||||||
// `(bool)e != true`
|
// `(bool)e != true`
|
||||||
exists(NEExpr eq |
|
exists(NEExpr eq |
|
||||||
conditionRequires(eq, truth.booleanNot()) and
|
this.conditionRequires(eq, truth.booleanNot()) and
|
||||||
eq.getAnOperand().getValue().toInt() = 1 and
|
eq.getAnOperand().getValue().toInt() = 1 and
|
||||||
e = eq.getAnOperand() and
|
e = eq.getAnOperand() and
|
||||||
e.getUnspecifiedType() instanceof BoolType and
|
e.getUnspecifiedType() instanceof BoolType and
|
||||||
@@ -90,7 +90,7 @@ class LoopWithAlloca extends Stmt {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NotExpr notExpr |
|
exists(NotExpr notExpr |
|
||||||
conditionRequires(notExpr, truth.booleanNot()) and
|
this.conditionRequires(notExpr, truth.booleanNot()) and
|
||||||
e = notExpr.getOperand()
|
e = notExpr.getOperand()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -98,7 +98,7 @@ class LoopWithAlloca extends Stmt {
|
|||||||
// requires both of its operand to be true as well.
|
// requires both of its operand to be true as well.
|
||||||
exists(LogicalAndExpr andExpr |
|
exists(LogicalAndExpr andExpr |
|
||||||
truth = true and
|
truth = true and
|
||||||
conditionRequires(andExpr, truth) and
|
this.conditionRequires(andExpr, truth) and
|
||||||
e = andExpr.getAnOperand()
|
e = andExpr.getAnOperand()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -106,7 +106,7 @@ class LoopWithAlloca extends Stmt {
|
|||||||
// it requires both of its operand to be false as well.
|
// it requires both of its operand to be false as well.
|
||||||
exists(LogicalOrExpr orExpr |
|
exists(LogicalOrExpr orExpr |
|
||||||
truth = false and
|
truth = false and
|
||||||
conditionRequires(orExpr, truth) and
|
this.conditionRequires(orExpr, truth) and
|
||||||
e = orExpr.getAnOperand()
|
e = orExpr.getAnOperand()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -141,9 +141,9 @@ class LoopWithAlloca extends Stmt {
|
|||||||
* `conditionRequiresInequality`.
|
* `conditionRequiresInequality`.
|
||||||
*/
|
*/
|
||||||
private Variable getAControllingVariable() {
|
private Variable getAControllingVariable() {
|
||||||
conditionRequires(result.getAnAccess(), _)
|
this.conditionRequires(result.getAnAccess(), _)
|
||||||
or
|
or
|
||||||
conditionRequiresInequality(result.getAnAccess(), _, _)
|
this.conditionRequiresInequality(result.getAnAccess(), _, _)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -61,72 +61,72 @@ class PointerArithmeticAccess extends BufferAccess, Expr {
|
|||||||
* A pair of buffer accesses through a call to memcpy.
|
* A pair of buffer accesses through a call to memcpy.
|
||||||
*/
|
*/
|
||||||
class MemCpy extends BufferAccess, FunctionCall {
|
class MemCpy extends BufferAccess, FunctionCall {
|
||||||
MemCpy() { getTarget().hasName("memcpy") }
|
MemCpy() { this.getTarget().hasName("memcpy") }
|
||||||
|
|
||||||
override Expr getPointer() {
|
override Expr getPointer() {
|
||||||
result = getArgument(0) or
|
result = this.getArgument(0) or
|
||||||
result = getArgument(1)
|
result = this.getArgument(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
override Expr getAccessedLength() { result = getArgument(2) }
|
override Expr getAccessedLength() { result = this.getArgument(2) }
|
||||||
}
|
}
|
||||||
|
|
||||||
class StrncpySizeExpr extends BufferAccess, FunctionCall {
|
class StrncpySizeExpr extends BufferAccess, FunctionCall {
|
||||||
StrncpySizeExpr() { getTarget().hasName("strncpy") }
|
StrncpySizeExpr() { this.getTarget().hasName("strncpy") }
|
||||||
|
|
||||||
override Expr getPointer() {
|
override Expr getPointer() {
|
||||||
result = getArgument(0) or
|
result = this.getArgument(0) or
|
||||||
result = getArgument(1)
|
result = this.getArgument(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
override Expr getAccessedLength() { result = getArgument(2) }
|
override Expr getAccessedLength() { result = this.getArgument(2) }
|
||||||
}
|
}
|
||||||
|
|
||||||
class RecvSizeExpr extends BufferAccess, FunctionCall {
|
class RecvSizeExpr extends BufferAccess, FunctionCall {
|
||||||
RecvSizeExpr() { getTarget().hasName("recv") }
|
RecvSizeExpr() { this.getTarget().hasName("recv") }
|
||||||
|
|
||||||
override Expr getPointer() { result = getArgument(1) }
|
override Expr getPointer() { result = this.getArgument(1) }
|
||||||
|
|
||||||
override Expr getAccessedLength() { result = getArgument(2) }
|
override Expr getAccessedLength() { result = this.getArgument(2) }
|
||||||
}
|
}
|
||||||
|
|
||||||
class SendSizeExpr extends BufferAccess, FunctionCall {
|
class SendSizeExpr extends BufferAccess, FunctionCall {
|
||||||
SendSizeExpr() { getTarget().hasName("send") }
|
SendSizeExpr() { this.getTarget().hasName("send") }
|
||||||
|
|
||||||
override Expr getPointer() { result = getArgument(1) }
|
override Expr getPointer() { result = this.getArgument(1) }
|
||||||
|
|
||||||
override Expr getAccessedLength() { result = getArgument(2) }
|
override Expr getAccessedLength() { result = this.getArgument(2) }
|
||||||
}
|
}
|
||||||
|
|
||||||
class SnprintfSizeExpr extends BufferAccess, FunctionCall {
|
class SnprintfSizeExpr extends BufferAccess, FunctionCall {
|
||||||
SnprintfSizeExpr() { getTarget().hasName("snprintf") }
|
SnprintfSizeExpr() { this.getTarget().hasName("snprintf") }
|
||||||
|
|
||||||
override Expr getPointer() { result = getArgument(0) }
|
override Expr getPointer() { result = this.getArgument(0) }
|
||||||
|
|
||||||
override Expr getAccessedLength() { result = getArgument(1) }
|
override Expr getAccessedLength() { result = this.getArgument(1) }
|
||||||
}
|
}
|
||||||
|
|
||||||
class MemcmpSizeExpr extends BufferAccess, FunctionCall {
|
class MemcmpSizeExpr extends BufferAccess, FunctionCall {
|
||||||
MemcmpSizeExpr() { getTarget().hasName("Memcmp") }
|
MemcmpSizeExpr() { this.getTarget().hasName("Memcmp") }
|
||||||
|
|
||||||
override Expr getPointer() {
|
override Expr getPointer() {
|
||||||
result = getArgument(0) or
|
result = this.getArgument(0) or
|
||||||
result = getArgument(1)
|
result = this.getArgument(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
override Expr getAccessedLength() { result = getArgument(2) }
|
override Expr getAccessedLength() { result = this.getArgument(2) }
|
||||||
}
|
}
|
||||||
|
|
||||||
class MallocSizeExpr extends BufferAccess, FunctionCall {
|
class MallocSizeExpr extends BufferAccess, FunctionCall {
|
||||||
MallocSizeExpr() { getTarget().hasName("malloc") }
|
MallocSizeExpr() { this.getTarget().hasName("malloc") }
|
||||||
|
|
||||||
override Expr getPointer() { none() }
|
override Expr getPointer() { none() }
|
||||||
|
|
||||||
override Expr getAccessedLength() { result = getArgument(0) }
|
override Expr getAccessedLength() { result = this.getArgument(0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
class NetworkFunctionCall extends FunctionCall {
|
class NetworkFunctionCall extends FunctionCall {
|
||||||
NetworkFunctionCall() { getTarget().hasName(["ntohd", "ntohf", "ntohl", "ntohll", "ntohs"]) }
|
NetworkFunctionCall() { this.getTarget().hasName(["ntohd", "ntohf", "ntohl", "ntohll", "ntohs"]) }
|
||||||
}
|
}
|
||||||
|
|
||||||
class NetworkToBufferSizeConfiguration extends DataFlow::Configuration {
|
class NetworkToBufferSizeConfiguration extends DataFlow::Configuration {
|
||||||
|
|||||||
@@ -3,8 +3,10 @@
|
|||||||
* @description Using the TLS or SSLv23 protocol from the boost::asio library, but not disabling deprecated protocols, or disabling minimum-recommended protocols.
|
* @description Using the TLS or SSLv23 protocol from the boost::asio library, but not disabling deprecated protocols, or disabling minimum-recommended protocols.
|
||||||
* @kind problem
|
* @kind problem
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
|
* @security-severity 7.5
|
||||||
* @id cpp/boost/tls-settings-misconfiguration
|
* @id cpp/boost/tls-settings-misconfiguration
|
||||||
* @tags security
|
* @tags security
|
||||||
|
* external/cwe/cwe-326
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
|
|||||||
@@ -3,8 +3,10 @@
|
|||||||
* @description Using a deprecated hard-coded protocol using the boost::asio library.
|
* @description Using a deprecated hard-coded protocol using the boost::asio library.
|
||||||
* @kind problem
|
* @kind problem
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
|
* @security-severity 7.5
|
||||||
* @id cpp/boost/use-of-deprecated-hardcoded-security-protocol
|
* @id cpp/boost/use-of-deprecated-hardcoded-security-protocol
|
||||||
* @tags security
|
* @tags security
|
||||||
|
* external/cwe/cwe-327
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import cpp
|
|||||||
|
|
||||||
class MacroFunctionCall extends MacroInvocation {
|
class MacroFunctionCall extends MacroInvocation {
|
||||||
MacroFunctionCall() {
|
MacroFunctionCall() {
|
||||||
not exists(getParentInvocation()) and
|
not exists(this.getParentInvocation()) and
|
||||||
this.getMacro().getHead().matches("%(%")
|
this.getMacro().getHead().matches("%(%")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import semmle.code.cpp.commons.Assertions
|
|||||||
|
|
||||||
class MacroFunctionCall extends MacroInvocation {
|
class MacroFunctionCall extends MacroInvocation {
|
||||||
MacroFunctionCall() {
|
MacroFunctionCall() {
|
||||||
not exists(getParentInvocation()) and
|
not exists(this.getParentInvocation()) and
|
||||||
this.getMacro().getHead().matches("%(%")
|
this.getMacro().getHead().matches("%(%")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class ExternalAPIDataNode extends DataFlow::Node {
|
|||||||
int getIndex() { result = i }
|
int getIndex() { result = i }
|
||||||
|
|
||||||
/** Gets the description of the function being called. */
|
/** Gets the description of the function being called. */
|
||||||
string getFunctionDescription() { result = getExternalFunction().toString() }
|
string getFunctionDescription() { result = this.getExternalFunction().toString() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalAPIDataNode`s. */
|
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalAPIDataNode`s. */
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class ExternalAPIDataNode extends DataFlow::Node {
|
|||||||
int getIndex() { result = i }
|
int getIndex() { result = i }
|
||||||
|
|
||||||
/** Gets the description of the function being called. */
|
/** Gets the description of the function being called. */
|
||||||
string getFunctionDescription() { result = getExternalFunction().toString() }
|
string getFunctionDescription() { result = this.getExternalFunction().toString() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalAPIDataNode`s. */
|
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalAPIDataNode`s. */
|
||||||
|
|||||||
@@ -21,14 +21,15 @@ import semmle.code.cpp.commons.Alloc
|
|||||||
* See CWE-120/UnboundedWrite.ql for a summary of CWE-120 alert cases.
|
* See CWE-120/UnboundedWrite.ql for a summary of CWE-120 alert cases.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
from BufferWrite bw, Expr dest, int destSize
|
from BufferWrite bw, Expr dest, int destSize, int estimated
|
||||||
where
|
where
|
||||||
not bw.hasExplicitLimit() and // has no explicit size limit
|
not bw.hasExplicitLimit() and // has no explicit size limit
|
||||||
dest = bw.getDest() and
|
dest = bw.getDest() and
|
||||||
destSize = getBufferSize(dest, _) and
|
destSize = getBufferSize(dest, _) and
|
||||||
|
estimated = bw.getMaxDataLimited(_) and
|
||||||
// we can deduce that too much data may be copied (even without
|
// we can deduce that too much data may be copied (even without
|
||||||
// long '%f' conversions)
|
// long '%f' conversions)
|
||||||
bw.getMaxDataLimited() > destSize
|
estimated > destSize
|
||||||
select bw,
|
select bw,
|
||||||
"This '" + bw.getBWDesc() + "' operation requires " + bw.getMaxData() +
|
"This '" + bw.getBWDesc() + "' operation requires " + estimated +
|
||||||
" bytes but the destination is only " + destSize + " bytes."
|
" bytes but the destination is only " + destSize + " bytes."
|
||||||
|
|||||||
@@ -21,14 +21,15 @@ import semmle.code.cpp.security.BufferWrite
|
|||||||
* See CWE-120/UnboundedWrite.ql for a summary of CWE-120 alert cases.
|
* See CWE-120/UnboundedWrite.ql for a summary of CWE-120 alert cases.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
from BufferWrite bw, int destSize
|
from BufferWrite bw, int destSize, int estimated, BufferWriteEstimationReason reason
|
||||||
where
|
where
|
||||||
not bw.hasExplicitLimit() and
|
not bw.hasExplicitLimit() and
|
||||||
// has no explicit size limit
|
// has no explicit size limit
|
||||||
destSize = getBufferSize(bw.getDest(), _) and
|
destSize = getBufferSize(bw.getDest(), _) and
|
||||||
bw.getMaxData() > destSize and
|
estimated = bw.getMaxData(reason) and
|
||||||
|
estimated > destSize and
|
||||||
// and we can deduce that too much data may be copied
|
// and we can deduce that too much data may be copied
|
||||||
bw.getMaxDataLimited() <= destSize // but it would fit without long '%f' conversions
|
bw.getMaxDataLimited(reason) <= destSize // but it would fit without long '%f' conversions
|
||||||
select bw,
|
select bw,
|
||||||
"This '" + bw.getBWDesc() + "' operation may require " + bw.getMaxData() +
|
"This '" + bw.getBWDesc() + "' operation may require " + estimated +
|
||||||
" bytes because of float conversions, but the target is only " + destSize + " bytes."
|
" bytes because of float conversions, but the target is only " + destSize + " bytes."
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ import TaintedWithPath
|
|||||||
|
|
||||||
predicate isUnboundedWrite(BufferWrite bw) {
|
predicate isUnboundedWrite(BufferWrite bw) {
|
||||||
not bw.hasExplicitLimit() and // has no explicit size limit
|
not bw.hasExplicitLimit() and // has no explicit size limit
|
||||||
not exists(bw.getMaxData()) // and we can't deduce an upper bound to the amount copied
|
not exists(bw.getMaxData(_)) // and we can't deduce an upper bound to the amount copied
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class VarargsFunction extends Function {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int trailingArgValueCount(string value) {
|
private int trailingArgValueCount(string value) {
|
||||||
result = strictcount(FunctionCall fc | trailingArgValue(fc) = value)
|
result = strictcount(FunctionCall fc | this.trailingArgValue(fc) = value)
|
||||||
}
|
}
|
||||||
|
|
||||||
string nonTrailingVarArgValue(FunctionCall fc, int index) {
|
string nonTrailingVarArgValue(FunctionCall fc, int index) {
|
||||||
@@ -58,11 +58,11 @@ class VarargsFunction extends Function {
|
|||||||
|
|
||||||
string normalTerminator(int cnt) {
|
string normalTerminator(int cnt) {
|
||||||
result = ["0", "-1"] and
|
result = ["0", "-1"] and
|
||||||
cnt = trailingArgValueCount(result) and
|
cnt = this.trailingArgValueCount(result) and
|
||||||
2 * cnt > totalCount() and
|
2 * cnt > this.totalCount() and
|
||||||
not exists(FunctionCall fc, int index |
|
not exists(FunctionCall fc, int index |
|
||||||
// terminator value is used in a non-terminating position
|
// terminator value is used in a non-terminating position
|
||||||
nonTrailingVarArgValue(fc, index) = result
|
this.nonTrailingVarArgValue(fc, index) = result
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class TaintSource extends VariableAccess {
|
|||||||
definitionUsePair(_, this, va)
|
definitionUsePair(_, this, va)
|
||||||
or
|
or
|
||||||
exists(VariableAccess mid, Expr def |
|
exists(VariableAccess mid, Expr def |
|
||||||
sourceReaches(mid) and
|
this.sourceReaches(mid) and
|
||||||
exprDefinition(_, def, mid) and
|
exprDefinition(_, def, mid) and
|
||||||
definitionUsePair(_, def, va)
|
definitionUsePair(_, def, va)
|
||||||
)
|
)
|
||||||
@@ -53,11 +53,11 @@ class TaintSource extends VariableAccess {
|
|||||||
* from `va`, possibly using intermediate reassignments.
|
* from `va`, possibly using intermediate reassignments.
|
||||||
*/
|
*/
|
||||||
private predicate reachesSink(VariableAccess va, VariableAccess sink) {
|
private predicate reachesSink(VariableAccess va, VariableAccess sink) {
|
||||||
isSink(sink) and
|
this.isSink(sink) and
|
||||||
va = sink
|
va = sink
|
||||||
or
|
or
|
||||||
exists(VariableAccess mid, Expr def |
|
exists(VariableAccess mid, Expr def |
|
||||||
reachesSink(mid, sink) and
|
this.reachesSink(mid, sink) and
|
||||||
exprDefinition(_, def, va) and
|
exprDefinition(_, def, va) and
|
||||||
definitionUsePair(_, def, mid)
|
definitionUsePair(_, def, mid)
|
||||||
)
|
)
|
||||||
@@ -71,15 +71,15 @@ class TaintSource extends VariableAccess {
|
|||||||
* this source to `sink` found via `tainted(source, sink)`.)
|
* this source to `sink` found via `tainted(source, sink)`.)
|
||||||
*/
|
*/
|
||||||
predicate reaches(VariableAccess sink) {
|
predicate reaches(VariableAccess sink) {
|
||||||
isSink(sink) and
|
this.isSink(sink) and
|
||||||
not exists(VariableAccess va |
|
not exists(VariableAccess va |
|
||||||
va != this and
|
va != this and
|
||||||
va != sink and
|
va != sink and
|
||||||
mayAddNullTerminator(_, va)
|
mayAddNullTerminator(_, va)
|
||||||
|
|
|
|
||||||
sourceReaches(va)
|
this.sourceReaches(va)
|
||||||
or
|
or
|
||||||
reachesSink(va, sink)
|
this.reachesSink(va, sink)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
28
cpp/ql/src/Security/CWE/CWE-295/SSLResultConflation.qhelp
Normal file
28
cpp/ql/src/Security/CWE/CWE-295/SSLResultConflation.qhelp
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<!DOCTYPE qhelp PUBLIC
|
||||||
|
"-//Semmle//qhelp//EN"
|
||||||
|
"qhelp.dtd">
|
||||||
|
<qhelp>
|
||||||
|
<overview>
|
||||||
|
<p>When checking the result of SSL certificate verification, accepting any error code may allow an attacker to impersonate someone who is trusted.</p>
|
||||||
|
|
||||||
|
</overview>
|
||||||
|
<recommendation>
|
||||||
|
|
||||||
|
<p>When checking an SSL certificate with <code>SSL_get_verify_result</code>, only <code>X509_V_OK</code> is a success code. If there is any other result the certificate should not be accepted.</p>
|
||||||
|
|
||||||
|
</recommendation>
|
||||||
|
<example>
|
||||||
|
|
||||||
|
<p>In this example the error code <code>X509_V_ERR_CERT_HAS_EXPIRED</code> is treated the same as an OK result. An expired certificate should not be accepted as it is more likely to be compromised than a valid certificate.</p>
|
||||||
|
|
||||||
|
<sample src="SSLResultConflationBad.cpp" />
|
||||||
|
|
||||||
|
<p>In the corrected example, only a result of <code>X509_V_OK</code> is accepted.</p>
|
||||||
|
|
||||||
|
<sample src="SSLResultConflationGood.cpp" />
|
||||||
|
|
||||||
|
</example>
|
||||||
|
<references>
|
||||||
|
|
||||||
|
</references>
|
||||||
|
</qhelp>
|
||||||
50
cpp/ql/src/Security/CWE/CWE-295/SSLResultConflation.ql
Normal file
50
cpp/ql/src/Security/CWE/CWE-295/SSLResultConflation.ql
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* @name Certificate result conflation
|
||||||
|
* @description Only accept SSL certificates that pass certificate verification.
|
||||||
|
* @kind problem
|
||||||
|
* @problem.severity error
|
||||||
|
* @security-severity 7.5
|
||||||
|
* @precision medium
|
||||||
|
* @id cpp/certificate-result-conflation
|
||||||
|
* @tags security
|
||||||
|
* external/cwe/cwe-295
|
||||||
|
*/
|
||||||
|
|
||||||
|
import cpp
|
||||||
|
import semmle.code.cpp.controlflow.Guards
|
||||||
|
import semmle.code.cpp.dataflow.DataFlow
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A call to `SSL_get_verify_result`.
|
||||||
|
*/
|
||||||
|
class SSLGetVerifyResultCall extends FunctionCall {
|
||||||
|
SSLGetVerifyResultCall() { getTarget().getName() = "SSL_get_verify_result" }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data flow from a call to `SSL_get_verify_result` to a guard condition
|
||||||
|
* that references the result.
|
||||||
|
*/
|
||||||
|
class VerifyResultConfig extends DataFlow::Configuration {
|
||||||
|
VerifyResultConfig() { this = "VerifyResultConfig" }
|
||||||
|
|
||||||
|
override predicate isSource(DataFlow::Node source) {
|
||||||
|
source.asExpr() instanceof SSLGetVerifyResultCall
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate isSink(DataFlow::Node sink) {
|
||||||
|
exists(GuardCondition guard | guard.getAChild*() = sink.asExpr())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
from
|
||||||
|
VerifyResultConfig config, DataFlow::Node source, DataFlow::Node sink1, DataFlow::Node sink2,
|
||||||
|
GuardCondition guard, Expr c1, Expr c2, boolean testIsTrue
|
||||||
|
where
|
||||||
|
config.hasFlow(source, sink1) and
|
||||||
|
config.hasFlow(source, sink2) and
|
||||||
|
guard.comparesEq(sink1.asExpr(), c1, 0, false, testIsTrue) and // (value != c1) => testIsTrue
|
||||||
|
guard.comparesEq(sink2.asExpr(), c2, 0, false, testIsTrue) and // (value != c2) => testIsTrue
|
||||||
|
c1.getValue().toInt() = 0 and
|
||||||
|
c2.getValue().toInt() != 0
|
||||||
|
select guard, "This expression conflates OK and non-OK results from $@.", source, source.toString()
|
||||||
13
cpp/ql/src/Security/CWE/CWE-295/SSLResultConflationBad.cpp
Normal file
13
cpp/ql/src/Security/CWE/CWE-295/SSLResultConflationBad.cpp
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
// ...
|
||||||
|
|
||||||
|
if (cert = SSL_get_peer_certificate(ssl))
|
||||||
|
{
|
||||||
|
result = SSL_get_verify_result(ssl);
|
||||||
|
|
||||||
|
if ((result == X509_V_OK) || (result == X509_V_ERR_CERT_HAS_EXPIRED)) // BAD (conflates OK and a non-OK codes)
|
||||||
|
{
|
||||||
|
do_ok();
|
||||||
|
} else {
|
||||||
|
do_error();
|
||||||
|
}
|
||||||
|
}
|
||||||
13
cpp/ql/src/Security/CWE/CWE-295/SSLResultConflationGood.cpp
Normal file
13
cpp/ql/src/Security/CWE/CWE-295/SSLResultConflationGood.cpp
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
// ...
|
||||||
|
|
||||||
|
if (cert = SSL_get_peer_certificate(ssl))
|
||||||
|
{
|
||||||
|
result = SSL_get_verify_result(ssl);
|
||||||
|
|
||||||
|
if (result == X509_V_OK) // GOOD
|
||||||
|
{
|
||||||
|
do_ok();
|
||||||
|
} else {
|
||||||
|
do_error();
|
||||||
|
}
|
||||||
|
}
|
||||||
28
cpp/ql/src/Security/CWE/CWE-295/SSLResultNotChecked.qhelp
Normal file
28
cpp/ql/src/Security/CWE/CWE-295/SSLResultNotChecked.qhelp
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<!DOCTYPE qhelp PUBLIC
|
||||||
|
"-//Semmle//qhelp//EN"
|
||||||
|
"qhelp.dtd">
|
||||||
|
<qhelp>
|
||||||
|
<overview>
|
||||||
|
<p>After fetching an SSL certificate, always check the result of certificate verification.</p>
|
||||||
|
|
||||||
|
</overview>
|
||||||
|
<recommendation>
|
||||||
|
|
||||||
|
<p>Always check the result of SSL certificate verification. A certificate that has been revoked may indicate that data is coming from an attacker, whereas a certificate that has expired or was self-signed may indicate an increased likelihood that the data is malicious.</p>
|
||||||
|
|
||||||
|
</recommendation>
|
||||||
|
<example>
|
||||||
|
|
||||||
|
<p>In this example, the <code>SSL_get_peer_certificate</code> function is used to get the certificate of a peer. However it is unsafe to use that information without checking if the certificate is valid.</p>
|
||||||
|
|
||||||
|
<sample src="SSLResultNotCheckedBad.cpp" />
|
||||||
|
|
||||||
|
<p>In the corrected example, we use <code>SSL_get_verify_result</code> to check that certificate verification was successful.</p>
|
||||||
|
|
||||||
|
<sample src="SSLResultNotCheckedGood.cpp" />
|
||||||
|
|
||||||
|
</example>
|
||||||
|
<references>
|
||||||
|
|
||||||
|
</references>
|
||||||
|
</qhelp>
|
||||||
120
cpp/ql/src/Security/CWE/CWE-295/SSLResultNotChecked.ql
Normal file
120
cpp/ql/src/Security/CWE/CWE-295/SSLResultNotChecked.ql
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
/**
|
||||||
|
* @name Certificate not checked
|
||||||
|
* @description Always check the result of certificate verification after fetching an SSL certificate.
|
||||||
|
* @kind problem
|
||||||
|
* @problem.severity error
|
||||||
|
* @security-severity 7.5
|
||||||
|
* @precision medium
|
||||||
|
* @id cpp/certificate-not-checked
|
||||||
|
* @tags security
|
||||||
|
* external/cwe/cwe-295
|
||||||
|
*/
|
||||||
|
|
||||||
|
import cpp
|
||||||
|
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||||
|
import semmle.code.cpp.controlflow.IRGuards
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A call to `SSL_get_peer_certificate`.
|
||||||
|
*/
|
||||||
|
class SSLGetPeerCertificateCall extends FunctionCall {
|
||||||
|
SSLGetPeerCertificateCall() {
|
||||||
|
getTarget().getName() = "SSL_get_peer_certificate" // SSL_get_peer_certificate(ssl)
|
||||||
|
}
|
||||||
|
|
||||||
|
Expr getSSLArgument() { result = getArgument(0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A call to `SSL_get_verify_result`.
|
||||||
|
*/
|
||||||
|
class SSLGetVerifyResultCall extends FunctionCall {
|
||||||
|
SSLGetVerifyResultCall() {
|
||||||
|
getTarget().getName() = "SSL_get_verify_result" // SSL_get_peer_certificate(ssl)
|
||||||
|
}
|
||||||
|
|
||||||
|
Expr getSSLArgument() { result = getArgument(0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the SSL object passed into `SSL_get_peer_certificate` is checked with
|
||||||
|
* `SSL_get_verify_result` entering `node`.
|
||||||
|
*/
|
||||||
|
predicate resultIsChecked(SSLGetPeerCertificateCall getCertCall, ControlFlowNode node) {
|
||||||
|
exists(Expr ssl, SSLGetVerifyResultCall check |
|
||||||
|
ssl = globalValueNumber(getCertCall.getSSLArgument()).getAnExpr() and
|
||||||
|
ssl = check.getSSLArgument() and
|
||||||
|
node = check
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the certificate returned by `SSL_get_peer_certificate` is found to be
|
||||||
|
* `0` on the edge `node1` to `node2`.
|
||||||
|
*/
|
||||||
|
predicate certIsZero(
|
||||||
|
SSLGetPeerCertificateCall getCertCall, ControlFlowNode node1, ControlFlowNode node2
|
||||||
|
) {
|
||||||
|
exists(Expr cert | cert = globalValueNumber(getCertCall).getAnExpr() |
|
||||||
|
exists(GuardCondition guard, Expr zero |
|
||||||
|
zero.getValue().toInt() = 0 and
|
||||||
|
node1 = guard and
|
||||||
|
(
|
||||||
|
// if (cert == zero) {
|
||||||
|
guard.comparesEq(cert, zero, 0, true, true) and
|
||||||
|
node2 = guard.getATrueSuccessor()
|
||||||
|
or
|
||||||
|
// if (cert != zero) { }
|
||||||
|
guard.comparesEq(cert, zero, 0, false, true) and
|
||||||
|
node2 = guard.getAFalseSuccessor()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
(
|
||||||
|
// if (cert) { }
|
||||||
|
node1 = cert
|
||||||
|
or
|
||||||
|
// if (!cert) {
|
||||||
|
node1.(NotExpr).getAChild() = cert
|
||||||
|
) and
|
||||||
|
node2 = node1.getASuccessor() and
|
||||||
|
not cert.(GuardCondition).controls(node2, true) // cert may be false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the SSL object passed into `SSL_get_peer_certificate` has not been checked with
|
||||||
|
* `SSL_get_verify_result` at `node`. Note that this is only computed at the call to
|
||||||
|
* `SSL_get_peer_certificate` and at the start and end of `BasicBlock`s.
|
||||||
|
*/
|
||||||
|
predicate certNotChecked(SSLGetPeerCertificateCall getCertCall, ControlFlowNode node) {
|
||||||
|
// cert is not checked at the call to `SSL_get_peer_certificate`
|
||||||
|
node = getCertCall
|
||||||
|
or
|
||||||
|
exists(BasicBlock bb, int pos |
|
||||||
|
// flow to end of a `BasicBlock`
|
||||||
|
certNotChecked(getCertCall, bb.getNode(pos)) and
|
||||||
|
node = bb.getEnd() and
|
||||||
|
// check for barrier node
|
||||||
|
not exists(int pos2 |
|
||||||
|
pos2 > pos and
|
||||||
|
resultIsChecked(getCertCall, bb.getNode(pos2))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
exists(BasicBlock pred, BasicBlock bb |
|
||||||
|
// flow from the end of one `BasicBlock` to the beginning of a successor
|
||||||
|
certNotChecked(getCertCall, pred.getEnd()) and
|
||||||
|
bb = pred.getASuccessor() and
|
||||||
|
node = bb.getStart() and
|
||||||
|
// check for barrier bb
|
||||||
|
not certIsZero(getCertCall, pred.getEnd(), bb.getStart())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
from SSLGetPeerCertificateCall getCertCall, ControlFlowNode node
|
||||||
|
where
|
||||||
|
certNotChecked(getCertCall, node) and
|
||||||
|
node instanceof Function // (function exit)
|
||||||
|
select getCertCall,
|
||||||
|
"This " + getCertCall.toString() + " is not followed by a call to SSL_get_verify_result."
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
// ...
|
||||||
|
|
||||||
|
X509 *cert = SSL_get_peer_certificate(ssl); // BAD (SSL_get_verify_result is never called)
|
||||||
|
|
||||||
|
// ...
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// ...
|
||||||
|
|
||||||
|
X509 *cert = SSL_get_peer_certificate(ssl); // GOOD
|
||||||
|
if (cert)
|
||||||
|
{
|
||||||
|
result = SSL_get_verify_result(ssl);
|
||||||
|
if (result == X509_V_OK)
|
||||||
|
{
|
||||||
|
// ...
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
* @precision high
|
* @precision high
|
||||||
* @id cpp/cleartext-storage-file
|
* @id cpp/cleartext-storage-file
|
||||||
* @tags security
|
* @tags security
|
||||||
|
* external/cwe/cwe-260
|
||||||
* external/cwe/cwe-313
|
* external/cwe/cwe-313
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -14,105 +14,188 @@
|
|||||||
import cpp
|
import cpp
|
||||||
import semmle.code.cpp.security.SensitiveExprs
|
import semmle.code.cpp.security.SensitiveExprs
|
||||||
import semmle.code.cpp.dataflow.TaintTracking
|
import semmle.code.cpp.dataflow.TaintTracking
|
||||||
|
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||||
import semmle.code.cpp.models.interfaces.FlowSource
|
import semmle.code.cpp.models.interfaces.FlowSource
|
||||||
import DataFlow::PathGraph
|
import DataFlow::PathGraph
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A function call that sends or receives data over a network.
|
* A DataFlow node corresponding to a variable or function call that
|
||||||
|
* might contain or return a password or other sensitive information.
|
||||||
*/
|
*/
|
||||||
abstract class NetworkSendRecv extends FunctionCall {
|
class SensitiveNode extends DataFlow::Node {
|
||||||
|
SensitiveNode() {
|
||||||
|
this.asExpr() = any(SensitiveVariable sv).getInitializer().getExpr() or
|
||||||
|
this.asExpr().(VariableAccess).getTarget() =
|
||||||
|
any(SensitiveVariable sv).(GlobalOrNamespaceVariable) or
|
||||||
|
this.asUninitialized() instanceof SensitiveVariable or
|
||||||
|
this.asParameter() instanceof SensitiveVariable or
|
||||||
|
this.asExpr().(FunctionCall).getTarget() instanceof SensitiveFunction
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function that sends or receives data over a network.
|
||||||
|
*/
|
||||||
|
abstract class SendRecv extends Function {
|
||||||
/**
|
/**
|
||||||
* Gets the expression for the socket or similar object used for sending or
|
* Gets the expression for the socket or similar object used for sending or
|
||||||
* receiving data (if any).
|
* receiving data through the function call `call` (if any).
|
||||||
*/
|
*/
|
||||||
abstract Expr getSocketExpr();
|
abstract Expr getSocketExpr(Call call);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the expression for the buffer to be sent from / received into.
|
* Gets the expression for the buffer to be sent from / received into through
|
||||||
|
* the function call `call`.
|
||||||
*/
|
*/
|
||||||
abstract Expr getDataExpr();
|
abstract Expr getDataExpr(Call call);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function that sends data over a network.
|
||||||
|
*/
|
||||||
|
class Send extends SendRecv instanceof RemoteFlowSinkFunction {
|
||||||
|
override Expr getSocketExpr(Call call) {
|
||||||
|
call.getTarget() = this and
|
||||||
|
exists(FunctionInput input, int arg |
|
||||||
|
super.hasSocketInput(input) and
|
||||||
|
input.isParameter(arg) and
|
||||||
|
result = call.getArgument(arg)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override Expr getDataExpr(Call call) {
|
||||||
|
call.getTarget() = this and
|
||||||
|
exists(FunctionInput input, int arg |
|
||||||
|
super.hasRemoteFlowSink(input, _) and
|
||||||
|
input.isParameterDeref(arg) and
|
||||||
|
result = call.getArgument(arg)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function that receives data over a network.
|
||||||
|
*/
|
||||||
|
class Recv extends SendRecv instanceof RemoteFlowSourceFunction {
|
||||||
|
override Expr getSocketExpr(Call call) {
|
||||||
|
call.getTarget() = this and
|
||||||
|
exists(FunctionInput input, int arg |
|
||||||
|
super.hasSocketInput(input) and
|
||||||
|
input.isParameter(arg) and
|
||||||
|
result = call.getArgument(arg)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override Expr getDataExpr(Call call) {
|
||||||
|
call.getTarget() = this and
|
||||||
|
exists(FunctionOutput output, int arg |
|
||||||
|
super.hasRemoteFlowSource(output, _) and
|
||||||
|
output.isParameterDeref(arg) and
|
||||||
|
result = call.getArgument(arg)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function call that sends or receives data over a network.
|
||||||
|
*
|
||||||
|
* note: function calls such as `write` may be writing to a network source
|
||||||
|
* or a file. We could attempt to determine which, and sort results into
|
||||||
|
* `cpp/cleartext-transmission` and perhaps `cpp/cleartext-storage-file`. In
|
||||||
|
* practice it usually isn't very important which query reports a result as
|
||||||
|
* long as its reported exactly once.
|
||||||
|
*
|
||||||
|
* We do exclude function calls that specify a constant socket, which is
|
||||||
|
* likely to mean standard input, standard output or a similar channel.
|
||||||
|
*/
|
||||||
|
abstract class NetworkSendRecv extends FunctionCall {
|
||||||
|
SendRecv target;
|
||||||
|
|
||||||
|
NetworkSendRecv() {
|
||||||
|
this.getTarget() = target and
|
||||||
|
// exclude calls based on the socket...
|
||||||
|
not exists(GVN g |
|
||||||
|
g = globalValueNumber(target.getSocketExpr(this)) and
|
||||||
|
(
|
||||||
|
// literal constant
|
||||||
|
globalValueNumber(any(Literal l)) = g
|
||||||
|
or
|
||||||
|
// variable (such as a global) initialized to a literal constant
|
||||||
|
exists(Variable v |
|
||||||
|
v.getInitializer().getExpr() instanceof Literal and
|
||||||
|
g = globalValueNumber(v.getAnAccess())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
final Expr getDataExpr() { result = target.getDataExpr(this) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A function call that sends data over a network.
|
* A function call that sends data over a network.
|
||||||
*
|
|
||||||
* note: functions such as `write` may be writing to a network source or a file. We could attempt to determine which, and sort results into `cpp/cleartext-transmission` and perhaps `cpp/cleartext-storage-file`. In practice it usually isn't very important which query reports a result as long as its reported exactly once.
|
|
||||||
*/
|
*/
|
||||||
class NetworkSend extends NetworkSendRecv {
|
class NetworkSend extends NetworkSendRecv {
|
||||||
RemoteFlowSinkFunction target;
|
override Send target;
|
||||||
|
|
||||||
NetworkSend() { target = this.getTarget() }
|
|
||||||
|
|
||||||
override Expr getSocketExpr() {
|
|
||||||
exists(FunctionInput input, int arg |
|
|
||||||
target.hasSocketInput(input) and
|
|
||||||
input.isParameter(arg) and
|
|
||||||
result = this.getArgument(arg)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override Expr getDataExpr() {
|
|
||||||
exists(FunctionInput input, int arg |
|
|
||||||
target.hasRemoteFlowSink(input, _) and
|
|
||||||
input.isParameterDeref(arg) and
|
|
||||||
result = this.getArgument(arg)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A function call that receives data over a network.
|
* A function call that receives data over a network.
|
||||||
*/
|
*/
|
||||||
class NetworkRecv extends NetworkSendRecv {
|
class NetworkRecv extends NetworkSendRecv {
|
||||||
RemoteFlowSourceFunction target;
|
override Recv target;
|
||||||
|
|
||||||
NetworkRecv() { target = this.getTarget() }
|
|
||||||
|
|
||||||
override Expr getSocketExpr() {
|
|
||||||
exists(FunctionInput input, int arg |
|
|
||||||
target.hasSocketInput(input) and
|
|
||||||
input.isParameter(arg) and
|
|
||||||
result = this.getArgument(arg)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override Expr getDataExpr() {
|
|
||||||
exists(FunctionOutput output, int arg |
|
|
||||||
target.hasRemoteFlowSource(output, _) and
|
|
||||||
output.isParameterDeref(arg) and
|
|
||||||
result = this.getArgument(arg)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Taint flow from a sensitive expression to a network operation with data
|
* An expression that is an argument or return value from an encryption or
|
||||||
* tainted by that expression.
|
* decryption call.
|
||||||
*/
|
*/
|
||||||
class SensitiveSendRecvConfiguration extends TaintTracking::Configuration {
|
class Encrypted extends Expr {
|
||||||
SensitiveSendRecvConfiguration() { this = "SensitiveSendRecvConfiguration" }
|
Encrypted() {
|
||||||
|
exists(FunctionCall fc |
|
||||||
override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof SensitiveExpr }
|
fc.getTarget().getName().toLowerCase().regexpMatch(".*(crypt|encode|decode).*") and
|
||||||
|
(
|
||||||
override predicate isSink(DataFlow::Node sink) {
|
this = fc or
|
||||||
exists(NetworkSendRecv transmission |
|
this = fc.getAnArgument()
|
||||||
sink.asExpr() = transmission.getDataExpr() and
|
|
||||||
// a zero socket descriptor is standard input, which is not interesting for this query.
|
|
||||||
not exists(Zero zero |
|
|
||||||
DataFlow::localFlow(DataFlow::exprNode(zero),
|
|
||||||
DataFlow::exprNode(transmission.getSocketExpr()))
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Taint flow from a sensitive expression.
|
||||||
|
*/
|
||||||
|
class FromSensitiveConfiguration extends TaintTracking::Configuration {
|
||||||
|
FromSensitiveConfiguration() { this = "FromSensitiveConfiguration" }
|
||||||
|
|
||||||
|
override predicate isSource(DataFlow::Node source) { source instanceof SensitiveNode }
|
||||||
|
|
||||||
|
override predicate isSink(DataFlow::Node sink) {
|
||||||
|
sink.asExpr() = any(NetworkSendRecv nsr).getDataExpr()
|
||||||
|
or
|
||||||
|
sink.asExpr() instanceof Encrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||||
|
// flow through encryption functions to the return value (in case we can reach other sinks)
|
||||||
|
node2.asExpr().(Encrypted).(FunctionCall).getAnArgument() = node1.asExpr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
from
|
from
|
||||||
SensitiveSendRecvConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink,
|
FromSensitiveConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink,
|
||||||
NetworkSendRecv transmission, string msg
|
NetworkSendRecv networkSendRecv, string msg
|
||||||
where
|
where
|
||||||
|
// flow from sensitive -> network data
|
||||||
config.hasFlowPath(source, sink) and
|
config.hasFlowPath(source, sink) and
|
||||||
sink.getNode().asExpr() = transmission.getDataExpr() and
|
sink.getNode().asExpr() = networkSendRecv.getDataExpr() and
|
||||||
if transmission instanceof NetworkSend
|
// no flow from sensitive -> evidence of encryption
|
||||||
|
not exists(DataFlow::Node encrypted |
|
||||||
|
config.hasFlow(source.getNode(), encrypted) and
|
||||||
|
encrypted.asExpr() instanceof Encrypted
|
||||||
|
) and
|
||||||
|
// construct result
|
||||||
|
if networkSendRecv instanceof NetworkSend
|
||||||
then
|
then
|
||||||
msg =
|
msg =
|
||||||
"This operation transmits '" + sink.toString() +
|
"This operation transmits '" + sink.toString() +
|
||||||
@@ -121,4 +204,4 @@ where
|
|||||||
msg =
|
msg =
|
||||||
"This operation receives into '" + sink.toString() +
|
"This operation receives into '" + sink.toString() +
|
||||||
"', which may put unencrypted sensitive data into $@"
|
"', which may put unencrypted sensitive data into $@"
|
||||||
select transmission, source, sink, msg, source, source.getNode().asExpr().toString()
|
select networkSendRecv, source, sink, msg, source, source.getNode().toString()
|
||||||
|
|||||||
@@ -28,6 +28,11 @@ class PrivateHostName extends string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
predicate privateHostNameFlowsToExpr(Expr e) {
|
||||||
|
TaintTracking::localExprTaint(any(StringLiteral p | p.getValue() instanceof PrivateHostName), e)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A string containing an HTTP URL not in a private domain.
|
* A string containing an HTTP URL not in a private domain.
|
||||||
*/
|
*/
|
||||||
@@ -38,11 +43,9 @@ class HttpStringLiteral extends StringLiteral {
|
|||||||
or
|
or
|
||||||
exists(string tail |
|
exists(string tail |
|
||||||
tail = s.regexpCapture("http://(.*)", 1) and not tail instanceof PrivateHostName
|
tail = s.regexpCapture("http://(.*)", 1) and not tail instanceof PrivateHostName
|
||||||
) and
|
)
|
||||||
not TaintTracking::localExprTaint(any(StringLiteral p |
|
) and
|
||||||
p.getValue() instanceof PrivateHostName
|
not privateHostNameFlowsToExpr(this.getParent*())
|
||||||
), this.getParent*())
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -84,8 +84,8 @@ class ParameterNullCheck extends ParameterCheck {
|
|||||||
p.getFunction() instanceof InitializationFunction and
|
p.getFunction() instanceof InitializationFunction and
|
||||||
p.getType().getUnspecifiedType() instanceof PointerType and
|
p.getType().getUnspecifiedType() instanceof PointerType and
|
||||||
exists(VariableAccess va | va = p.getAnAccess() |
|
exists(VariableAccess va | va = p.getAnAccess() |
|
||||||
nullSuccessor = getATrueSuccessor() and
|
nullSuccessor = this.getATrueSuccessor() and
|
||||||
notNullSuccessor = getAFalseSuccessor() and
|
notNullSuccessor = this.getAFalseSuccessor() and
|
||||||
(
|
(
|
||||||
va = this.(NotExpr).getOperand() or
|
va = this.(NotExpr).getOperand() or
|
||||||
va = any(EQExpr eq | eq = this and eq.getAnOperand().getValue() = "0").getAnOperand() or
|
va = any(EQExpr eq | eq = this and eq.getAnOperand().getValue() = "0").getAnOperand() or
|
||||||
@@ -95,8 +95,8 @@ class ParameterNullCheck extends ParameterCheck {
|
|||||||
.getAnOperand()
|
.getAnOperand()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
nullSuccessor = getAFalseSuccessor() and
|
nullSuccessor = this.getAFalseSuccessor() and
|
||||||
notNullSuccessor = getATrueSuccessor() and
|
notNullSuccessor = this.getATrueSuccessor() and
|
||||||
(
|
(
|
||||||
va = this or
|
va = this or
|
||||||
va = any(NEExpr eq | eq = this and eq.getAnOperand().getValue() = "0").getAnOperand() or
|
va = any(NEExpr eq | eq = this and eq.getAnOperand().getValue() = "0").getAnOperand() or
|
||||||
@@ -132,7 +132,7 @@ class ValidatedExternalCondInitFunction extends ExternalData {
|
|||||||
ValidatedExternalCondInitFunction() { this.getDataPath().matches("%cond-init%.csv") }
|
ValidatedExternalCondInitFunction() { this.getDataPath().matches("%cond-init%.csv") }
|
||||||
|
|
||||||
predicate isExternallyVerified(Function f, int param) {
|
predicate isExternallyVerified(Function f, int param) {
|
||||||
functionSignature(f, getField(1), getField(2)) and param = getFieldAsInt(3)
|
functionSignature(f, this.getField(1), this.getField(2)) and param = this.getFieldAsInt(3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,7 +193,7 @@ class InitializationFunction extends Function {
|
|||||||
.getAnOverridingFunction+()
|
.getAnOverridingFunction+()
|
||||||
.(InitializationFunction)
|
.(InitializationFunction)
|
||||||
.initializedParameter() or
|
.initializedParameter() or
|
||||||
getParameter(i) = any(InitializationFunctionCall c).getAnInitParameter()
|
this.getParameter(i) = any(InitializationFunctionCall c).getAnInitParameter()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// If we have no definition, we look at SAL annotations
|
// If we have no definition, we look at SAL annotations
|
||||||
@@ -227,7 +227,7 @@ class InitializationFunction extends Function {
|
|||||||
result = getAnInitializedArgument(any(Call c))
|
result = getAnInitializedArgument(any(Call c))
|
||||||
or
|
or
|
||||||
exists(IfStmt check | result = check.getCondition().getAChild*() |
|
exists(IfStmt check | result = check.getCondition().getAChild*() |
|
||||||
paramReassignmentCondition(check)
|
this.paramReassignmentCondition(check)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
@@ -249,15 +249,15 @@ class InitializationFunction extends Function {
|
|||||||
|
|
||||||
/** Holds if `n` can be reached without the parameter at `index` being reassigned. */
|
/** Holds if `n` can be reached without the parameter at `index` being reassigned. */
|
||||||
predicate paramNotReassignedAt(ControlFlowNode n, int index, Context c) {
|
predicate paramNotReassignedAt(ControlFlowNode n, int index, Context c) {
|
||||||
c = getAContext(index) and
|
c = this.getAContext(index) and
|
||||||
(
|
(
|
||||||
not exists(this.getEntryPoint()) and index = i and n = this
|
not exists(this.getEntryPoint()) and index = i and n = this
|
||||||
or
|
or
|
||||||
n = this.getEntryPoint() and index = i
|
n = this.getEntryPoint() and index = i
|
||||||
or
|
or
|
||||||
exists(ControlFlowNode mid | paramNotReassignedAt(mid, index, c) |
|
exists(ControlFlowNode mid | this.paramNotReassignedAt(mid, index, c) |
|
||||||
n = mid.getASuccessor() and
|
n = mid.getASuccessor() and
|
||||||
not n = paramReassignment(index) and
|
not n = this.paramReassignment(index) and
|
||||||
/*
|
/*
|
||||||
* Ignore successor edges where the parameter is null, because it is then confirmed to be
|
* Ignore successor edges where the parameter is null, because it is then confirmed to be
|
||||||
* initialized.
|
* initialized.
|
||||||
@@ -265,7 +265,7 @@ class InitializationFunction extends Function {
|
|||||||
|
|
||||||
not exists(ParameterNullCheck nullCheck |
|
not exists(ParameterNullCheck nullCheck |
|
||||||
nullCheck = mid and
|
nullCheck = mid and
|
||||||
nullCheck = getANullCheck(index) and
|
nullCheck = this.getANullCheck(index) and
|
||||||
n = nullCheck.getNullSuccessor()
|
n = nullCheck.getNullSuccessor()
|
||||||
) and
|
) and
|
||||||
/*
|
/*
|
||||||
@@ -281,13 +281,13 @@ class InitializationFunction extends Function {
|
|||||||
|
|
||||||
/** Gets a null-check on the parameter at `index`. */
|
/** Gets a null-check on the parameter at `index`. */
|
||||||
private ParameterNullCheck getANullCheck(int index) {
|
private ParameterNullCheck getANullCheck(int index) {
|
||||||
getParameter(index) = result.getParameter()
|
this.getParameter(index) = result.getParameter()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets a parameter which is not at the given index. */
|
/** Gets a parameter which is not at the given index. */
|
||||||
private Parameter getOtherParameter(int index) {
|
private Parameter getOtherParameter(int index) {
|
||||||
index = i and
|
index = i and
|
||||||
result = getAParameter() and
|
result = this.getAParameter() and
|
||||||
not result.getIndex() = index
|
not result.getIndex() = index
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,10 +306,10 @@ class InitializationFunction extends Function {
|
|||||||
if
|
if
|
||||||
strictcount(Parameter p |
|
strictcount(Parameter p |
|
||||||
exists(Context c | c = ParamNull(p) or c = ParamNotNull(p)) and
|
exists(Context c | c = ParamNull(p) or c = ParamNotNull(p)) and
|
||||||
p = getOtherParameter(index)
|
p = this.getOtherParameter(index)
|
||||||
) = 1
|
) = 1
|
||||||
then
|
then
|
||||||
exists(Parameter p | p = getOtherParameter(index) |
|
exists(Parameter p | p = this.getOtherParameter(index) |
|
||||||
result = ParamNull(p) or result = ParamNotNull(p)
|
result = ParamNull(p) or result = ParamNotNull(p)
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
@@ -424,8 +424,8 @@ class ConditionalInitializationCall extends FunctionCall {
|
|||||||
|
|
||||||
/** Gets the argument passed for the given parameter to this call. */
|
/** Gets the argument passed for the given parameter to this call. */
|
||||||
Expr getArgumentForParameter(Parameter p) {
|
Expr getArgumentForParameter(Parameter p) {
|
||||||
p = getTarget().getAParameter() and
|
p = this.getTarget().getAParameter() and
|
||||||
result = getArgument(p.getIndex())
|
result = this.getArgument(p.getIndex())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -442,7 +442,7 @@ class ConditionalInitializationCall extends FunctionCall {
|
|||||||
context = ParamNotNull(otherP) or
|
context = ParamNotNull(otherP) or
|
||||||
context = ParamNull(otherP)
|
context = ParamNull(otherP)
|
||||||
|
|
|
|
||||||
otherArg = getArgumentForParameter(otherP) and
|
otherArg = this.getArgumentForParameter(otherP) and
|
||||||
(otherArg instanceof AddressOfExpr implies context = ParamNotNull(otherP)) and
|
(otherArg instanceof AddressOfExpr implies context = ParamNotNull(otherP)) and
|
||||||
(otherArg.getType() instanceof ArrayType implies context = ParamNotNull(otherP)) and
|
(otherArg.getType() instanceof ArrayType implies context = ParamNotNull(otherP)) and
|
||||||
(otherArg.getValue() = "0" implies context = ParamNull(otherP))
|
(otherArg.getValue() = "0" implies context = ParamNull(otherP))
|
||||||
@@ -511,8 +511,8 @@ class ConditionalInitializationCall extends FunctionCall {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(ControlFlowNode mid | mid = uncheckedReaches(var) |
|
exists(ControlFlowNode mid | mid = this.uncheckedReaches(var) |
|
||||||
not mid = getStatusVariable().getAnAccess() and
|
not mid = this.getStatusVariable().getAnAccess() and
|
||||||
not mid = var.getAnAccess() and
|
not mid = var.getAnAccess() and
|
||||||
not exists(VariableAccess write | result = write and write = var.getAnAccess() |
|
not exists(VariableAccess write | result = write and write = var.getAnAccess() |
|
||||||
write = any(AssignExpr a).getLValue() or
|
write = any(AssignExpr a).getLValue() or
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class ConditionallyInitializedVariable extends LocalVariable {
|
|||||||
// Find a call that conditionally initializes this variable
|
// Find a call that conditionally initializes this variable
|
||||||
hasConditionalInitialization(f, call, this, initAccess, e) and
|
hasConditionalInitialization(f, call, this, initAccess, e) and
|
||||||
// Ignore cases where the variable is assigned prior to the call
|
// Ignore cases where the variable is assigned prior to the call
|
||||||
not reaches(getAnAssignedValue(), initAccess) and
|
not reaches(this.getAnAssignedValue(), initAccess) and
|
||||||
// Ignore cases where the variable is assigned field-wise prior to the call.
|
// Ignore cases where the variable is assigned field-wise prior to the call.
|
||||||
not exists(FieldAccess fa |
|
not exists(FieldAccess fa |
|
||||||
exists(Assignment a |
|
exists(Assignment a |
|
||||||
@@ -56,7 +56,7 @@ class ConditionallyInitializedVariable extends LocalVariable {
|
|||||||
) and
|
) and
|
||||||
// Ignore cases where the variable is assigned by a prior call to an initialization function
|
// Ignore cases where the variable is assigned by a prior call to an initialization function
|
||||||
not exists(Call c |
|
not exists(Call c |
|
||||||
getAnAccess() = getAnInitializedArgument(c).(AddressOfExpr).getOperand() and
|
this.getAnAccess() = getAnInitializedArgument(c).(AddressOfExpr).getOperand() and
|
||||||
reaches(c, initAccess)
|
reaches(c, initAccess)
|
||||||
) and
|
) and
|
||||||
/*
|
/*
|
||||||
@@ -64,7 +64,7 @@ class ConditionallyInitializedVariable extends LocalVariable {
|
|||||||
* the CFG, but should always be considered as initialized, so exclude them.
|
* the CFG, but should always be considered as initialized, so exclude them.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
not exists(getInitializer().getExpr())
|
not exists(this.getInitializer().getExpr())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -90,7 +90,7 @@ class ConditionallyInitializedVariable extends LocalVariable {
|
|||||||
// Variable associated with this particular call
|
// Variable associated with this particular call
|
||||||
call = initializingCall and
|
call = initializingCall and
|
||||||
// Access is a meaningful read access
|
// Access is a meaningful read access
|
||||||
result = getAReadAccess() and
|
result = this.getAReadAccess() and
|
||||||
// Which occurs after the call
|
// Which occurs after the call
|
||||||
reaches(call, result) and
|
reaches(call, result) and
|
||||||
/*
|
/*
|
||||||
@@ -124,7 +124,7 @@ class ConditionallyInitializedVariable extends LocalVariable {
|
|||||||
call = initializingCall and
|
call = initializingCall and
|
||||||
initializingFunction = f and
|
initializingFunction = f and
|
||||||
e = evidence and
|
e = evidence and
|
||||||
result = getAReadAccessAfterCall(initializingCall) and
|
result = this.getAReadAccessAfterCall(initializingCall) and
|
||||||
(
|
(
|
||||||
// Access is risky because status return code ignored completely
|
// Access is risky because status return code ignored completely
|
||||||
call instanceof ExprInVoidContext
|
call instanceof ExprInVoidContext
|
||||||
@@ -148,7 +148,7 @@ class ConditionallyInitializedVariable extends LocalVariable {
|
|||||||
call = initializingCall and
|
call = initializingCall and
|
||||||
initializingFunction = f and
|
initializingFunction = f and
|
||||||
e = evidence and
|
e = evidence and
|
||||||
result = getAReadAccessAfterCall(initializingCall) and
|
result = this.getAReadAccessAfterCall(initializingCall) and
|
||||||
exists(LocalVariable status, Assignment a |
|
exists(LocalVariable status, Assignment a |
|
||||||
a.getRValue() = call and
|
a.getRValue() = call and
|
||||||
call = status.getAnAssignedValue() and
|
call = status.getAnAssignedValue() and
|
||||||
@@ -184,7 +184,7 @@ class ConditionallyInitializedVariable extends LocalVariable {
|
|||||||
ConditionalInitializationFunction initializingFunction,
|
ConditionalInitializationFunction initializingFunction,
|
||||||
ConditionalInitializationCall initializingCall, Evidence evidence
|
ConditionalInitializationCall initializingCall, Evidence evidence
|
||||||
) {
|
) {
|
||||||
result = getARiskyAccessBeforeStatusCheck(initializingFunction, initializingCall, evidence) or
|
result = this.getARiskyAccessBeforeStatusCheck(initializingFunction, initializingCall, evidence) or
|
||||||
result = getARiskyAccessWithNoStatusCheck(initializingFunction, initializingCall, evidence)
|
result = this.getARiskyAccessWithNoStatusCheck(initializingFunction, initializingCall, evidence)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,15 +31,15 @@ abstract class SystemData extends Element {
|
|||||||
*/
|
*/
|
||||||
Expr getAnExprIndirect() {
|
Expr getAnExprIndirect() {
|
||||||
// direct SystemData
|
// direct SystemData
|
||||||
result = getAnExpr() or
|
result = this.getAnExpr() or
|
||||||
// flow via global or member variable (conservative approximation)
|
// flow via global or member variable (conservative approximation)
|
||||||
result = getAnAffectedVar().getAnAccess() or
|
result = this.getAnAffectedVar().getAnAccess() or
|
||||||
// flow via stack variable
|
// flow via stack variable
|
||||||
definitionUsePair(_, getAnExprIndirect(), result) or
|
definitionUsePair(_, this.getAnExprIndirect(), result) or
|
||||||
useUsePair(_, getAnExprIndirect(), result) or
|
useUsePair(_, this.getAnExprIndirect(), result) or
|
||||||
useUsePair(_, result, getAnExprIndirect()) or
|
useUsePair(_, result, this.getAnExprIndirect()) or
|
||||||
// flow from assigned value to assignment expression
|
// flow from assigned value to assignment expression
|
||||||
result.(AssignExpr).getRValue() = getAnExprIndirect()
|
result.(AssignExpr).getRValue() = this.getAnExprIndirect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -67,16 +67,16 @@ class IFStream extends Type {
|
|||||||
*/
|
*/
|
||||||
class CinVariable extends NamespaceVariable {
|
class CinVariable extends NamespaceVariable {
|
||||||
CinVariable() {
|
CinVariable() {
|
||||||
getName() = ["cin", "wcin"] and
|
this.getName() = ["cin", "wcin"] and
|
||||||
getNamespace().getName() = "std"
|
this.getNamespace().getName() = "std"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A call to `std::operator>>`. */
|
/** A call to `std::operator>>`. */
|
||||||
class OperatorRShiftCall extends FunctionCall {
|
class OperatorRShiftCall extends FunctionCall {
|
||||||
OperatorRShiftCall() {
|
OperatorRShiftCall() {
|
||||||
getTarget().getNamespace().getName() = "std" and
|
this.getTarget().getNamespace().getName() = "std" and
|
||||||
getTarget().hasName("operator>>")
|
this.getTarget().hasName("operator>>")
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -87,15 +87,15 @@ class OperatorRShiftCall extends FunctionCall {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Expr getSource() {
|
Expr getSource() {
|
||||||
if getTarget() instanceof MemberFunction
|
if this.getTarget() instanceof MemberFunction
|
||||||
then result = getQualifier()
|
then result = this.getQualifier()
|
||||||
else result = getArgument(0)
|
else result = this.getArgument(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr getDest() {
|
Expr getDest() {
|
||||||
if getTarget() instanceof MemberFunction
|
if this.getTarget() instanceof MemberFunction
|
||||||
then result = getArgument(0)
|
then result = this.getArgument(0)
|
||||||
else result = getArgument(1)
|
else result = this.getArgument(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,7 +119,7 @@ abstract class PotentiallyDangerousInput extends Expr {
|
|||||||
* Gets the width restriction that applies to the input stream
|
* Gets the width restriction that applies to the input stream
|
||||||
* for this expression, if any.
|
* for this expression, if any.
|
||||||
*/
|
*/
|
||||||
Expr getWidth() { result = getPreviousAccess().getWidthAfter() }
|
Expr getWidth() { result = this.getPreviousAccess().getWidthAfter() }
|
||||||
|
|
||||||
private Expr getWidthSetHere() {
|
private Expr getWidthSetHere() {
|
||||||
exists(FunctionCall widthCall |
|
exists(FunctionCall widthCall |
|
||||||
@@ -154,11 +154,11 @@ abstract class PotentiallyDangerousInput extends Expr {
|
|||||||
* after this expression, if any.
|
* after this expression, if any.
|
||||||
*/
|
*/
|
||||||
Expr getWidthAfter() {
|
Expr getWidthAfter() {
|
||||||
result = getWidthSetHere()
|
result = this.getWidthSetHere()
|
||||||
or
|
or
|
||||||
not exists(getWidthSetHere()) and
|
not exists(this.getWidthSetHere()) and
|
||||||
not isWidthConsumedHere() and
|
not this.isWidthConsumedHere() and
|
||||||
result = getWidth()
|
result = this.getWidth()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ predicate argumentMayBeRoot(Expr e) {
|
|||||||
|
|
||||||
class SetuidLikeFunctionCall extends FunctionCall {
|
class SetuidLikeFunctionCall extends FunctionCall {
|
||||||
SetuidLikeFunctionCall() {
|
SetuidLikeFunctionCall() {
|
||||||
(getTarget().hasGlobalName("setuid") or getTarget().hasGlobalName("setresuid")) and
|
(this.getTarget().hasGlobalName("setuid") or this.getTarget().hasGlobalName("setresuid")) and
|
||||||
// setuid/setresuid with the root user are false positives.
|
// setuid/setresuid with the root user are false positives.
|
||||||
not argumentMayBeRoot(getArgument(0))
|
not argumentMayBeRoot(this.getArgument(0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ class SetuidLikeWrapperCall extends FunctionCall {
|
|||||||
|
|
||||||
class CallBeforeSetuidFunctionCall extends FunctionCall {
|
class CallBeforeSetuidFunctionCall extends FunctionCall {
|
||||||
CallBeforeSetuidFunctionCall() {
|
CallBeforeSetuidFunctionCall() {
|
||||||
getTarget()
|
this.getTarget()
|
||||||
.hasGlobalName([
|
.hasGlobalName([
|
||||||
"setgid", "setresgid",
|
"setgid", "setresgid",
|
||||||
// Compatibility may require skipping initgroups and setgroups return checks.
|
// Compatibility may require skipping initgroups and setgroups return checks.
|
||||||
@@ -52,7 +52,7 @@ class CallBeforeSetuidFunctionCall extends FunctionCall {
|
|||||||
"initgroups", "setgroups"
|
"initgroups", "setgroups"
|
||||||
]) and
|
]) and
|
||||||
// setgid/setresgid/etc with the root group are false positives.
|
// setgid/setresgid/etc with the root group are false positives.
|
||||||
not argumentMayBeRoot(getArgument(0))
|
not argumentMayBeRoot(this.getArgument(0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class CallMayNotReturn extends FunctionCall {
|
|||||||
not exists(this.(ControlFlowNode).getASuccessor())
|
not exists(this.(ControlFlowNode).getASuccessor())
|
||||||
or
|
or
|
||||||
// call to another function that may not return
|
// call to another function that may not return
|
||||||
exists(CallMayNotReturn exit | getTarget() = exit.getEnclosingFunction())
|
exists(CallMayNotReturn exit | this.getTarget() = exit.getEnclosingFunction())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,13 +38,7 @@ where
|
|||||||
fc.getTargetType().(Class).getABaseClass+().hasGlobalOrStdName("exception") or
|
fc.getTargetType().(Class).getABaseClass+().hasGlobalOrStdName("exception") or
|
||||||
fc.getTargetType().(Class).getABaseClass+().hasGlobalOrStdName("CException")
|
fc.getTargetType().(Class).getABaseClass+().hasGlobalOrStdName("CException")
|
||||||
) and
|
) and
|
||||||
|
fc instanceof ExprInVoidContext and
|
||||||
not fc.isInMacroExpansion() and
|
not fc.isInMacroExpansion() and
|
||||||
not exists(ThrowExpr texp | fc.getEnclosingStmt() = texp.getEnclosingStmt()) and
|
msg = "Object creation of exception type on stack. Did you forget the throw keyword?"
|
||||||
not exists(FunctionCall fctmp | fctmp.getAnArgument() = fc) and
|
|
||||||
not fc instanceof ConstructorDirectInit and
|
|
||||||
not fc.getEnclosingStmt() instanceof DeclStmt and
|
|
||||||
not fc instanceof ConstructorDelegationInit and
|
|
||||||
not fc.getParent() instanceof Initializer and
|
|
||||||
not fc.getParent() instanceof AllocationExpr and
|
|
||||||
msg = "This object does not generate an exception."
|
|
||||||
select fc, msg
|
select fc, msg
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ private predicate exprReleases(Expr e, Expr released, string kind) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Resource extends MemberVariable {
|
class Resource extends MemberVariable {
|
||||||
Resource() { not isStatic() }
|
Resource() { not this.isStatic() }
|
||||||
|
|
||||||
// Check that an expr is somewhere in this class - does not have to be a constructor
|
// Check that an expr is somewhere in this class - does not have to be a constructor
|
||||||
predicate inSameClass(Expr e) {
|
predicate inSameClass(Expr e) {
|
||||||
@@ -129,7 +129,7 @@ class Resource extends MemberVariable {
|
|||||||
f instanceof Destructor and f.getDeclaringType() = this.getDeclaringType()
|
f instanceof Destructor and f.getDeclaringType() = this.getDeclaringType()
|
||||||
or
|
or
|
||||||
exists(Function mid, FunctionCall fc |
|
exists(Function mid, FunctionCall fc |
|
||||||
calledFromDestructor(mid) and
|
this.calledFromDestructor(mid) and
|
||||||
fc.getEnclosingFunction() = mid and
|
fc.getEnclosingFunction() = mid and
|
||||||
fc.getTarget() = f and
|
fc.getTarget() = f and
|
||||||
f.getDeclaringType() = this.getDeclaringType()
|
f.getDeclaringType() = this.getDeclaringType()
|
||||||
@@ -137,7 +137,7 @@ class Resource extends MemberVariable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate inDestructor(Expr e) {
|
predicate inDestructor(Expr e) {
|
||||||
exists(Function f | f = e.getEnclosingFunction() | calledFromDestructor(f))
|
exists(Function f | f = e.getEnclosingFunction() | this.calledFromDestructor(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate acquisitionWithRequiredKind(Assignment acquireAssign, string kind) {
|
predicate acquisitionWithRequiredKind(Assignment acquireAssign, string kind) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/cpp-queries
|
name: codeql/cpp-queries
|
||||||
version: 0.0.4
|
version: 0.0.5-dev
|
||||||
groups: cpp
|
groups: cpp
|
||||||
dependencies:
|
dependencies:
|
||||||
codeql/cpp-all: "*"
|
codeql/cpp-all: "*"
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ class CustomAddFunctionCall extends SimpleRangeAnalysisExpr, FunctionCall {
|
|||||||
|
|
||||||
class SelfSub extends SimpleRangeAnalysisExpr, SubExpr {
|
class SelfSub extends SimpleRangeAnalysisExpr, SubExpr {
|
||||||
SelfSub() {
|
SelfSub() {
|
||||||
getLeftOperand().(VariableAccess).getTarget() = getRightOperand().(VariableAccess).getTarget()
|
this.getLeftOperand().(VariableAccess).getTarget() =
|
||||||
|
this.getRightOperand().(VariableAccess).getTarget()
|
||||||
}
|
}
|
||||||
|
|
||||||
override float getLowerBounds() { result = 0 }
|
override float getLowerBounds() { result = 0 }
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
| test.cpp:35:3:35:33 | call to runtime_error | This object does not generate an exception. |
|
| test.cpp:35:3:35:33 | call to runtime_error | Object creation of exception type on stack. Did you forget the throw keyword? |
|
||||||
| test.cpp:41:3:41:11 | call to funcTest1 | There is an exception in the function that requires your attention. |
|
| test.cpp:41:3:41:11 | call to funcTest1 | There is an exception in the function that requires your attention. |
|
||||||
| test.cpp:42:3:42:9 | call to DllMain | DllMain contains an exeption not wrapped in a try..catch block. |
|
| test.cpp:42:3:42:9 | call to DllMain | DllMain contains an exeption not wrapped in a try..catch block. |
|
||||||
|
|||||||
@@ -20,3 +20,22 @@ bool compareValues() {
|
|||||||
bool callCompareValues() {
|
bool callCompareValues() {
|
||||||
return compareValues<C1, C2> || compareValues<C1, C1>();
|
return compareValues<C1, C2> || compareValues<C1, C1>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <bool C, typename T = void>
|
||||||
|
struct enable_if {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct enable_if<true, T> { typedef T type; };
|
||||||
|
|
||||||
|
template<typename T1, typename T2>
|
||||||
|
typename enable_if<T1::value <= T2::value, bool>::type constant_comparison() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Value0 {
|
||||||
|
const static int value = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
void instantiation_with_pointless_comparison() {
|
||||||
|
constant_comparison<Value0, Value0>(); // GOOD
|
||||||
|
}
|
||||||
@@ -3,13 +3,17 @@
|
|||||||
| tests.cpp:272:2:272:8 | call to sprintf | This 'call to sprintf' operation requires 9 bytes but the destination is only 8 bytes. |
|
| tests.cpp:272:2:272:8 | call to sprintf | This 'call to sprintf' operation requires 9 bytes but the destination is only 8 bytes. |
|
||||||
| tests.cpp:273:2:273:8 | call to sprintf | This 'call to sprintf' operation requires 9 bytes but the destination is only 8 bytes. |
|
| tests.cpp:273:2:273:8 | call to sprintf | This 'call to sprintf' operation requires 9 bytes but the destination is only 8 bytes. |
|
||||||
| tests.cpp:308:3:308:9 | call to sprintf | This 'call to sprintf' operation requires 9 bytes but the destination is only 8 bytes. |
|
| tests.cpp:308:3:308:9 | call to sprintf | This 'call to sprintf' operation requires 9 bytes but the destination is only 8 bytes. |
|
||||||
| tests.cpp:315:2:315:8 | call to sprintf | This 'call to sprintf' operation requires 11 bytes but the destination is only 2 bytes. |
|
| tests.cpp:315:2:315:8 | call to sprintf | This 'call to sprintf' operation requires 11 bytes but the destination is only 4 bytes. |
|
||||||
| tests.cpp:316:2:316:8 | call to sprintf | This 'call to sprintf' operation requires 11 bytes but the destination is only 2 bytes. |
|
| tests.cpp:316:2:316:8 | call to sprintf | This 'call to sprintf' operation requires 11 bytes but the destination is only 4 bytes. |
|
||||||
| tests.cpp:321:2:321:8 | call to sprintf | This 'call to sprintf' operation requires 11 bytes but the destination is only 2 bytes. |
|
| tests.cpp:321:2:321:8 | call to sprintf | This 'call to sprintf' operation requires 11 bytes but the destination is only 4 bytes. |
|
||||||
| tests.cpp:324:3:324:9 | call to sprintf | This 'call to sprintf' operation requires 11 bytes but the destination is only 2 bytes. |
|
| tests.cpp:324:3:324:9 | call to sprintf | This 'call to sprintf' operation requires 11 bytes but the destination is only 4 bytes. |
|
||||||
| tests.cpp:327:2:327:8 | call to sprintf | This 'call to sprintf' operation requires 12 bytes but the destination is only 2 bytes. |
|
| tests.cpp:327:2:327:8 | call to sprintf | This 'call to sprintf' operation requires 12 bytes but the destination is only 4 bytes. |
|
||||||
| tests.cpp:329:3:329:9 | call to sprintf | This 'call to sprintf' operation requires 12 bytes but the destination is only 2 bytes. |
|
| tests.cpp:329:3:329:9 | call to sprintf | This 'call to sprintf' operation requires 12 bytes but the destination is only 4 bytes. |
|
||||||
| tests.cpp:341:2:341:8 | call to sprintf | This 'call to sprintf' operation requires 3 bytes but the destination is only 2 bytes. |
|
| tests.cpp:341:2:341:8 | call to sprintf | This 'call to sprintf' operation requires 3 bytes but the destination is only 2 bytes. |
|
||||||
| tests.cpp:343:2:343:8 | call to sprintf | This 'call to sprintf' operation requires 3 bytes but the destination is only 2 bytes. |
|
| tests.cpp:343:2:343:8 | call to sprintf | This 'call to sprintf' operation requires 3 bytes but the destination is only 2 bytes. |
|
||||||
| tests.cpp:345:2:345:8 | call to sprintf | This 'call to sprintf' operation requires 11 bytes but the destination is only 2 bytes. |
|
| tests.cpp:345:2:345:8 | call to sprintf | This 'call to sprintf' operation requires 11 bytes but the destination is only 2 bytes. |
|
||||||
| tests.cpp:347:2:347:8 | call to sprintf | This 'call to sprintf' operation requires 3 bytes but the destination is only 2 bytes. |
|
| tests.cpp:347:2:347:8 | call to sprintf | This 'call to sprintf' operation requires 3 bytes but the destination is only 2 bytes. |
|
||||||
|
| tests.cpp:350:2:350:8 | call to sprintf | This 'call to sprintf' operation requires 4 bytes but the destination is only 3 bytes. |
|
||||||
|
| tests.cpp:354:2:354:8 | call to sprintf | This 'call to sprintf' operation requires 4 bytes but the destination is only 3 bytes. |
|
||||||
|
| tests.cpp:358:2:358:8 | call to sprintf | This 'call to sprintf' operation requires 4 bytes but the destination is only 3 bytes. |
|
||||||
|
| tests.cpp:363:2:363:8 | call to sprintf | This 'call to sprintf' operation requires 5 bytes but the destination is only 4 bytes. |
|
||||||
|
|||||||
@@ -310,39 +310,56 @@ namespace custom_sprintf_impl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void test6(unsigned unsigned_value, int value) {
|
void test6(unsigned unsigned_value, int value) {
|
||||||
char buffer[2];
|
char buffer2[2], buffer3[3], buffer4[4], buffer5[5];
|
||||||
|
|
||||||
sprintf(buffer, "%u", unsigned_value); // BAD: buffer overflow
|
sprintf(buffer4, "%u", unsigned_value); // BAD: buffer overflow
|
||||||
sprintf(buffer, "%d", unsigned_value); // BAD: buffer overflow
|
sprintf(buffer4, "%d", unsigned_value); // BAD: buffer overflow
|
||||||
if (unsigned_value < 10) {
|
if (unsigned_value < 1000) {
|
||||||
sprintf(buffer, "%u", unsigned_value); // GOOD
|
sprintf(buffer4, "%u", unsigned_value); // GOOD
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(buffer, "%u", -10); // BAD: buffer overflow
|
sprintf(buffer4, "%u", -100); // BAD: buffer overflow
|
||||||
|
|
||||||
if(unsigned_value == (unsigned)-10) {
|
if(unsigned_value == (unsigned)-100) {
|
||||||
sprintf(buffer, "%u", unsigned_value); // BAD: buffer overflow
|
sprintf(buffer4, "%u", unsigned_value); // BAD: buffer overflow
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(buffer, "%d", value); // BAD: buffer overflow
|
sprintf(buffer4, "%d", value); // BAD: buffer overflow
|
||||||
if (value < 10) {
|
if (value < 1000) {
|
||||||
sprintf(buffer, "%d", value); // BAD: buffer overflow
|
sprintf(buffer4, "%d", value); // BAD: buffer overflow
|
||||||
|
|
||||||
if(value > 0) {
|
if(value > -100) {
|
||||||
sprintf(buffer, "%d", value); // GOOD
|
sprintf(buffer4, "%d", value); // GOOD
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(buffer, "%u", 0); // GOOD
|
sprintf(buffer2, "%u", 0); // GOOD
|
||||||
sprintf(buffer, "%d", 0); // GOOD
|
sprintf(buffer2, "%d", 0); // GOOD
|
||||||
sprintf(buffer, "%u", 5); // GOOD
|
sprintf(buffer2, "%u", 5); // GOOD
|
||||||
sprintf(buffer, "%d", 5); // GOOD
|
sprintf(buffer2, "%d", 5); // GOOD
|
||||||
|
|
||||||
sprintf(buffer, "%d", -1); // BAD
|
sprintf(buffer2, "%d", -1); // BAD
|
||||||
sprintf(buffer, "%d", 9); // GOOD
|
sprintf(buffer2, "%d", 9); // GOOD
|
||||||
sprintf(buffer, "%d", 10); // BAD
|
sprintf(buffer2, "%d", 10); // BAD
|
||||||
|
|
||||||
sprintf(buffer, "%u", -1); // BAD
|
sprintf(buffer2, "%u", -1); // BAD
|
||||||
sprintf(buffer, "%u", 9); // GOOD
|
sprintf(buffer2, "%u", 9); // GOOD
|
||||||
sprintf(buffer, "%u", 10); // BAD
|
sprintf(buffer2, "%u", 10); // BAD
|
||||||
|
|
||||||
|
unsigned char unsigned_char = unsigned_value;
|
||||||
|
sprintf(buffer3, "%u", (unsigned)unsigned_char); // BAD
|
||||||
|
sprintf(buffer4, "%u", (unsigned)unsigned_char); // GOOD: 0..255 fits
|
||||||
|
|
||||||
|
unsigned small = unsigned_value >> (sizeof(unsigned_value) * 8 - 9); // in range 0..511
|
||||||
|
sprintf(buffer3, "%u", small); // BAD
|
||||||
|
sprintf(buffer4, "%u", small); // GOOD
|
||||||
|
|
||||||
|
small = unsigned_value & ((1u << 9) - 1); // in range 0..511
|
||||||
|
sprintf(buffer3, "%u", small); // BAD
|
||||||
|
sprintf(buffer4, "%u", small); // GOOD: 0..511 fits
|
||||||
|
|
||||||
|
char c = value;
|
||||||
|
|
||||||
|
sprintf(buffer4, "%d", (int)c); // BAD: e.g. -127 does not fit
|
||||||
|
sprintf(buffer5, "%d", (int)c); // GOOD: -127..128 fits
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
| test.cpp:18:9:18:38 | ... \|\| ... | This expression conflates OK and non-OK results from $@. | test.cpp:100:18:100:38 | call to SSL_get_verify_result | call to SSL_get_verify_result |
|
||||||
|
| test.cpp:38:7:38:36 | ... \|\| ... | This expression conflates OK and non-OK results from $@. | test.cpp:36:16:36:36 | call to SSL_get_verify_result | call to SSL_get_verify_result |
|
||||||
|
| test.cpp:54:7:54:47 | ... \|\| ... | This expression conflates OK and non-OK results from $@. | test.cpp:52:16:52:36 | call to SSL_get_verify_result | call to SSL_get_verify_result |
|
||||||
|
| test.cpp:62:7:62:36 | ... \|\| ... | This expression conflates OK and non-OK results from $@. | test.cpp:60:16:60:36 | call to SSL_get_verify_result | call to SSL_get_verify_result |
|
||||||
|
| test.cpp:70:7:70:36 | ... && ... | This expression conflates OK and non-OK results from $@. | test.cpp:68:16:68:36 | call to SSL_get_verify_result | call to SSL_get_verify_result |
|
||||||
|
| test.cpp:83:7:83:40 | ... \|\| ... | This expression conflates OK and non-OK results from $@. | test.cpp:78:16:78:36 | call to SSL_get_verify_result | call to SSL_get_verify_result |
|
||||||
|
| test.cpp:87:7:87:38 | ... \|\| ... | This expression conflates OK and non-OK results from $@. | test.cpp:7:57:7:77 | call to SSL_get_verify_result | call to SSL_get_verify_result |
|
||||||
|
| test.cpp:107:13:107:42 | ... \|\| ... | This expression conflates OK and non-OK results from $@. | test.cpp:105:16:105:36 | call to SSL_get_verify_result | call to SSL_get_verify_result |
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Security/CWE/CWE-295/SSLResultConflation.ql
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
| test2.cpp:13:13:13:36 | call to SSL_get_peer_certificate | This call to SSL_get_peer_certificate is not followed by a call to SSL_get_verify_result. |
|
||||||
|
| test2.cpp:28:13:28:36 | call to SSL_get_peer_certificate | This call to SSL_get_peer_certificate is not followed by a call to SSL_get_verify_result. |
|
||||||
|
| test2.cpp:61:9:61:32 | call to SSL_get_peer_certificate | This call to SSL_get_peer_certificate is not followed by a call to SSL_get_verify_result. |
|
||||||
|
| test2.cpp:89:9:89:32 | call to SSL_get_peer_certificate | This call to SSL_get_peer_certificate is not followed by a call to SSL_get_verify_result. |
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Security/CWE/CWE-295/SSLResultNotChecked.ql
|
||||||
149
cpp/ql/test/query-tests/Security/CWE/CWE-295/test.cpp
Normal file
149
cpp/ql/test/query-tests/Security/CWE/CWE-295/test.cpp
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
|
||||||
|
struct SSL {
|
||||||
|
// ...
|
||||||
|
};
|
||||||
|
|
||||||
|
int SSL_get_verify_result(const SSL *ssl);
|
||||||
|
int get_verify_result_indirect(const SSL *ssl) { return SSL_get_verify_result(ssl); }
|
||||||
|
|
||||||
|
int something_else(const SSL *ssl);
|
||||||
|
|
||||||
|
bool is_ok(int result)
|
||||||
|
{
|
||||||
|
return (result == 0); // GOOD
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_maybe_ok(int result)
|
||||||
|
{
|
||||||
|
return (result == 0) || (result == 1); // BAD (conflates OK and a non-OK codes)
|
||||||
|
}
|
||||||
|
|
||||||
|
void test1_1(SSL *ssl)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
int result = SSL_get_verify_result(ssl);
|
||||||
|
|
||||||
|
if (result == 0) // GOOD
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == 1) // GOOD
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int result = SSL_get_verify_result(ssl);
|
||||||
|
|
||||||
|
if ((result == 0) || (result == 1)) // BAD (conflates OK and a non-OK codes)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int result = SSL_get_verify_result(ssl);
|
||||||
|
|
||||||
|
if ((result == 1) || (result == 2)) // GOOD (both results are non-OK)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int result = SSL_get_verify_result(ssl);
|
||||||
|
|
||||||
|
if ((result == 0) || (false) || (result == 2)) // BAD (conflates OK and a non-OK codes)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int result = SSL_get_verify_result(ssl);
|
||||||
|
|
||||||
|
if ((0 == result) || (1 == result)) // BAD (conflates OK and a non-OK codes)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int result = SSL_get_verify_result(ssl);
|
||||||
|
|
||||||
|
if ((result != 0) && (result != 1)) // BAD (conflates OK and a non-OK codes)
|
||||||
|
{
|
||||||
|
} else {
|
||||||
|
// conflation occurs here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int result = SSL_get_verify_result(ssl);
|
||||||
|
int result_cpy = result;
|
||||||
|
int result2 = get_verify_result_indirect(ssl);
|
||||||
|
int result3 = something_else(ssl);
|
||||||
|
|
||||||
|
if ((result == 0) || (result_cpy == 1)) // BAD (conflates OK and a non-OK codes)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((result2 == 0) || (result2 == 1)) // BAD (conflates OK and a non-OK codes)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((result3 == 0) || (result3 == 1)) // GOOD (not an SSL result)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_ok(SSL_get_verify_result(ssl)))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_maybe_ok(SSL_get_verify_result(ssl)))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int result = SSL_get_verify_result(ssl);
|
||||||
|
|
||||||
|
bool ok = (result == 0) || (result == 1); // BAD (conflates OK and a non-OK codes)
|
||||||
|
|
||||||
|
if (ok) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int result = SSL_get_verify_result(ssl);
|
||||||
|
|
||||||
|
if (result == 1) // BAD (conflates OK and a non-OK codes in `else`) [NOT DETECTED]
|
||||||
|
{
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_good();
|
||||||
|
|
||||||
|
void test1_2(SSL *ssl)
|
||||||
|
{
|
||||||
|
int result = SSL_get_verify_result(ssl);
|
||||||
|
|
||||||
|
if (result == 0) { // GOOD
|
||||||
|
do_good();
|
||||||
|
} else if (result == 1) {
|
||||||
|
throw 1;
|
||||||
|
} else {
|
||||||
|
throw 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test1_3(SSL *ssl)
|
||||||
|
{
|
||||||
|
int result = SSL_get_verify_result(ssl);
|
||||||
|
|
||||||
|
if (result == 0) { // BAD (error code 1 is treated as OK, not as non-OK) [NOT DETECTED]
|
||||||
|
do_good();
|
||||||
|
} else if (result == 1) {
|
||||||
|
do_good();
|
||||||
|
} else {
|
||||||
|
throw 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
147
cpp/ql/test/query-tests/Security/CWE/CWE-295/test2.cpp
Normal file
147
cpp/ql/test/query-tests/Security/CWE/CWE-295/test2.cpp
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
|
||||||
|
struct SSL {
|
||||||
|
// ...
|
||||||
|
};
|
||||||
|
|
||||||
|
int SSL_get_peer_certificate(const SSL *ssl);
|
||||||
|
int SSL_get_verify_result(const SSL *ssl);
|
||||||
|
|
||||||
|
bool maybe();
|
||||||
|
|
||||||
|
bool test2_1(SSL *ssl)
|
||||||
|
{
|
||||||
|
int cert = SSL_get_peer_certificate(ssl); // BAD (SSL_get_verify_result is never called)
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool test2_2(SSL *ssl)
|
||||||
|
{
|
||||||
|
int cert = SSL_get_peer_certificate(ssl); // GOOD (SSL_get_verify_result is always called)
|
||||||
|
int result = SSL_get_verify_result(ssl);
|
||||||
|
|
||||||
|
return (result == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool test2_3(SSL *ssl)
|
||||||
|
{
|
||||||
|
int cert = SSL_get_peer_certificate(ssl); // BAD (SSL_get_verify_result may not be called)
|
||||||
|
|
||||||
|
if (maybe())
|
||||||
|
{
|
||||||
|
int result = SSL_get_verify_result(ssl);
|
||||||
|
|
||||||
|
return (result == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool test2_4(SSL *ssl)
|
||||||
|
{
|
||||||
|
int cert, result;
|
||||||
|
|
||||||
|
cert = SSL_get_peer_certificate(ssl); // GOOD (SSL_get_verify_result is called when there is a cert)
|
||||||
|
if (cert != 0)
|
||||||
|
{
|
||||||
|
result = SSL_get_verify_result(ssl);
|
||||||
|
if (result == 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool test2_5(SSL *ssl)
|
||||||
|
{
|
||||||
|
int cert, result;
|
||||||
|
|
||||||
|
cert = SSL_get_peer_certificate(ssl); // BAD (SSL_get_verify_result is not used reliably)
|
||||||
|
if ((cert != 0) && (maybe()))
|
||||||
|
{
|
||||||
|
result = SSL_get_verify_result(ssl);
|
||||||
|
if (result == 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool test2_6(SSL *ssl)
|
||||||
|
{
|
||||||
|
int cert;
|
||||||
|
|
||||||
|
cert = SSL_get_peer_certificate(ssl); // GOOD (SSL_get_verify_result is called when there is a cert)
|
||||||
|
if (cert == 0) return false;
|
||||||
|
if (SSL_get_verify_result(ssl) != 0) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool test2_7(SSL *ssl)
|
||||||
|
{
|
||||||
|
int cert;
|
||||||
|
|
||||||
|
cert = SSL_get_peer_certificate(ssl); // BAD (SSL_get_verify_result is only called when there is not a cert)
|
||||||
|
if (cert != 0) return false;
|
||||||
|
if (SSL_get_verify_result(ssl) != 0) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool test2_8(SSL *ssl)
|
||||||
|
{
|
||||||
|
int cert;
|
||||||
|
|
||||||
|
cert = SSL_get_peer_certificate(ssl); // GOOD (SSL_get_verify_result is called when there is a cert)
|
||||||
|
if (!cert) return false;
|
||||||
|
if (!SSL_get_verify_result(ssl)) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool test2_9(SSL *ssl)
|
||||||
|
{
|
||||||
|
int cert;
|
||||||
|
|
||||||
|
cert = SSL_get_peer_certificate(ssl); // GOOD (SSL_get_verify_result is called when there is a cert)
|
||||||
|
if ((!cert) || (SSL_get_verify_result(ssl) != 0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool test2_10(SSL *ssl)
|
||||||
|
{
|
||||||
|
int cert = SSL_get_peer_certificate(ssl); // GOOD (SSL_get_verify_result is called when there is a cert)
|
||||||
|
|
||||||
|
if (cert)
|
||||||
|
{
|
||||||
|
int result = SSL_get_verify_result(ssl);
|
||||||
|
|
||||||
|
if (result == 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool test2_11(SSL *ssl)
|
||||||
|
{
|
||||||
|
int cert;
|
||||||
|
|
||||||
|
cert = SSL_get_peer_certificate(ssl); // GOOD (SSL_get_verify_result is called when there is a cert)
|
||||||
|
|
||||||
|
if ((cert) && (SSL_get_verify_result(ssl) == 0)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
@@ -1,49 +1,228 @@
|
|||||||
edges
|
edges
|
||||||
| test3.cpp:68:21:68:29 | password1 | test3.cpp:70:15:70:17 | ptr |
|
| test3.cpp:17:28:17:36 | password1 | test3.cpp:22:15:22:23 | password1 |
|
||||||
| test3.cpp:75:15:75:22 | password | test3.cpp:77:15:77:17 | ptr |
|
| test3.cpp:17:51:17:59 | password2 | test3.cpp:26:15:26:23 | password2 |
|
||||||
| test3.cpp:106:20:106:25 | buffer | test3.cpp:108:14:108:19 | buffer |
|
| test3.cpp:45:8:45:15 | password | test3.cpp:47:15:47:22 | password |
|
||||||
| test3.cpp:111:28:111:33 | buffer | test3.cpp:113:9:113:14 | buffer |
|
| test3.cpp:53:8:53:15 | password | test3.cpp:55:15:55:22 | password |
|
||||||
| test3.cpp:120:9:120:23 | global_password | test3.cpp:138:16:138:29 | call to get_global_str |
|
| test3.cpp:71:32:71:40 | password1 | test3.cpp:76:15:76:17 | ptr |
|
||||||
| test3.cpp:128:11:128:18 | password | test3.cpp:106:20:106:25 | buffer |
|
| test3.cpp:80:8:80:15 | password | test3.cpp:83:15:83:17 | ptr |
|
||||||
| test3.cpp:132:21:132:22 | call to id | test3.cpp:134:15:134:17 | ptr |
|
| test3.cpp:98:8:98:15 | password | test3.cpp:101:12:101:19 | password |
|
||||||
| test3.cpp:132:24:132:32 | password1 | test3.cpp:111:28:111:33 | buffer |
|
| test3.cpp:112:20:112:25 | buffer | test3.cpp:114:14:114:19 | buffer |
|
||||||
| test3.cpp:132:24:132:32 | password1 | test3.cpp:132:21:132:22 | call to id |
|
| test3.cpp:117:28:117:33 | buffer | test3.cpp:119:9:119:14 | buffer |
|
||||||
| test3.cpp:138:16:138:29 | call to get_global_str | test3.cpp:140:15:140:18 | data |
|
| test3.cpp:126:9:126:23 | global_password | test3.cpp:144:16:144:29 | call to get_global_str |
|
||||||
| test3.cpp:151:19:151:26 | password | test3.cpp:153:15:153:20 | buffer |
|
| test3.cpp:129:39:129:47 | password1 | test3.cpp:138:24:138:32 | password1 |
|
||||||
|
| test3.cpp:132:8:132:15 | password | test3.cpp:134:11:134:18 | password |
|
||||||
|
| test3.cpp:134:11:134:18 | password | test3.cpp:112:20:112:25 | buffer |
|
||||||
|
| test3.cpp:138:21:138:22 | call to id | test3.cpp:140:15:140:17 | ptr |
|
||||||
|
| test3.cpp:138:24:138:32 | password1 | test3.cpp:117:28:117:33 | buffer |
|
||||||
|
| test3.cpp:138:24:138:32 | password1 | test3.cpp:138:21:138:22 | call to id |
|
||||||
|
| test3.cpp:144:16:144:29 | call to get_global_str | test3.cpp:146:15:146:18 | data |
|
||||||
|
| test3.cpp:152:29:152:36 | password | test3.cpp:159:15:159:20 | buffer |
|
||||||
|
| test3.cpp:171:8:171:15 | password | test3.cpp:173:15:173:22 | password |
|
||||||
|
| test3.cpp:171:8:171:15 | password | test3.cpp:175:3:175:17 | call to decrypt_inplace |
|
||||||
|
| test3.cpp:171:8:171:15 | password | test3.cpp:175:19:175:26 | password |
|
||||||
|
| test3.cpp:179:8:179:15 | password | test3.cpp:181:15:181:22 | password |
|
||||||
|
| test3.cpp:179:8:179:15 | password | test3.cpp:184:3:184:17 | call to decrypt_inplace |
|
||||||
|
| test3.cpp:179:8:179:15 | password | test3.cpp:184:19:184:26 | password |
|
||||||
|
| test3.cpp:188:8:188:15 | password | test3.cpp:191:15:191:22 | password |
|
||||||
|
| test3.cpp:188:8:188:15 | password | test3.cpp:193:18:193:28 | call to rtn_decrypt |
|
||||||
|
| test3.cpp:188:8:188:15 | password | test3.cpp:193:30:193:37 | password |
|
||||||
|
| test3.cpp:197:8:197:15 | password | test3.cpp:199:3:199:17 | call to encrypt_inplace |
|
||||||
|
| test3.cpp:197:8:197:15 | password | test3.cpp:199:19:199:26 | password |
|
||||||
|
| test3.cpp:197:8:197:15 | password | test3.cpp:201:15:201:22 | password |
|
||||||
|
| test3.cpp:205:8:205:15 | password | test3.cpp:207:3:207:17 | call to encrypt_inplace |
|
||||||
|
| test3.cpp:205:8:205:15 | password | test3.cpp:207:19:207:26 | password |
|
||||||
|
| test3.cpp:205:8:205:15 | password | test3.cpp:210:15:210:22 | password |
|
||||||
|
| test3.cpp:214:8:214:15 | password | test3.cpp:217:18:217:28 | call to rtn_encrypt |
|
||||||
|
| test3.cpp:214:8:214:15 | password | test3.cpp:217:18:217:28 | call to rtn_encrypt |
|
||||||
|
| test3.cpp:214:8:214:15 | password | test3.cpp:217:30:217:37 | password |
|
||||||
|
| test3.cpp:214:8:214:15 | password | test3.cpp:219:15:219:26 | password_ptr |
|
||||||
|
| test3.cpp:217:18:217:28 | call to rtn_encrypt | test3.cpp:219:15:219:26 | password_ptr |
|
||||||
|
| test3.cpp:225:34:225:41 | password | test3.cpp:227:22:227:29 | password |
|
||||||
|
| test3.cpp:225:34:225:41 | password | test3.cpp:228:26:228:33 | password |
|
||||||
|
| test3.cpp:239:7:239:14 | password | test3.cpp:241:8:241:15 | password |
|
||||||
|
| test3.cpp:239:7:239:14 | password | test3.cpp:242:8:242:15 | password |
|
||||||
|
| test3.cpp:252:8:252:16 | password1 | test3.cpp:254:15:254:23 | password1 |
|
||||||
|
| test3.cpp:252:8:252:16 | password1 | test3.cpp:256:3:256:19 | call to decrypt_to_buffer |
|
||||||
|
| test3.cpp:252:8:252:16 | password1 | test3.cpp:256:21:256:29 | password1 |
|
||||||
|
| test3.cpp:252:24:252:32 | password2 | test3.cpp:256:3:256:19 | call to decrypt_to_buffer |
|
||||||
|
| test3.cpp:252:24:252:32 | password2 | test3.cpp:256:32:256:40 | password2 |
|
||||||
|
| test3.cpp:260:8:260:16 | password1 | test3.cpp:262:3:262:19 | call to encrypt_to_buffer |
|
||||||
|
| test3.cpp:260:8:260:16 | password1 | test3.cpp:262:21:262:29 | password1 |
|
||||||
|
| test3.cpp:260:24:260:32 | password2 | test3.cpp:262:3:262:19 | call to encrypt_to_buffer |
|
||||||
|
| test3.cpp:260:24:260:32 | password2 | test3.cpp:262:32:262:40 | password2 |
|
||||||
|
| test3.cpp:260:24:260:32 | password2 | test3.cpp:264:15:264:23 | password2 |
|
||||||
|
| test3.cpp:268:19:268:26 | password | test3.cpp:272:15:272:18 | data |
|
||||||
|
| test3.cpp:278:20:278:23 | data | test3.cpp:278:20:278:23 | data |
|
||||||
|
| test3.cpp:278:20:278:23 | data | test3.cpp:280:14:280:17 | data |
|
||||||
|
| test3.cpp:283:20:283:23 | data | test3.cpp:283:20:283:23 | data |
|
||||||
|
| test3.cpp:283:20:283:23 | data | test3.cpp:285:14:285:17 | data |
|
||||||
|
| test3.cpp:288:20:288:23 | data | test3.cpp:290:14:290:17 | data |
|
||||||
|
| test3.cpp:293:20:293:23 | data | test3.cpp:293:20:293:23 | data |
|
||||||
|
| test3.cpp:293:20:293:23 | data | test3.cpp:295:14:295:17 | data |
|
||||||
|
| test3.cpp:298:20:298:23 | data | test3.cpp:300:14:300:17 | data |
|
||||||
|
| test3.cpp:308:41:308:49 | password1 | test3.cpp:312:3:312:17 | call to encrypt_inplace |
|
||||||
|
| test3.cpp:308:41:308:49 | password1 | test3.cpp:312:19:312:27 | password1 |
|
||||||
|
| test3.cpp:308:41:308:49 | password1 | test3.cpp:313:11:313:19 | password1 |
|
||||||
|
| test3.cpp:308:41:308:49 | password1 | test3.cpp:314:11:314:19 | password1 |
|
||||||
|
| test3.cpp:308:41:308:49 | password1 | test3.cpp:316:11:316:19 | password1 |
|
||||||
|
| test3.cpp:308:41:308:49 | password1 | test3.cpp:317:11:317:19 | password1 |
|
||||||
|
| test3.cpp:308:58:308:66 | password2 | test3.cpp:324:11:324:14 | data |
|
||||||
|
| test3.cpp:308:58:308:66 | password2 | test3.cpp:325:11:325:14 | data |
|
||||||
|
| test3.cpp:313:11:313:19 | password1 | test3.cpp:278:20:278:23 | data |
|
||||||
|
| test3.cpp:313:11:313:19 | password1 | test3.cpp:313:11:313:19 | ref arg password1 |
|
||||||
|
| test3.cpp:313:11:313:19 | ref arg password1 | test3.cpp:314:11:314:19 | password1 |
|
||||||
|
| test3.cpp:314:11:314:19 | password1 | test3.cpp:283:20:283:23 | data |
|
||||||
|
| test3.cpp:316:11:316:19 | password1 | test3.cpp:283:20:283:23 | data |
|
||||||
|
| test3.cpp:316:11:316:19 | password1 | test3.cpp:316:11:316:19 | ref arg password1 |
|
||||||
|
| test3.cpp:316:11:316:19 | ref arg password1 | test3.cpp:317:11:317:19 | password1 |
|
||||||
|
| test3.cpp:317:11:317:19 | password1 | test3.cpp:288:20:288:23 | data |
|
||||||
|
| test3.cpp:324:11:324:14 | data | test3.cpp:293:20:293:23 | data |
|
||||||
|
| test3.cpp:324:11:324:14 | data | test3.cpp:324:11:324:14 | ref arg data |
|
||||||
|
| test3.cpp:324:11:324:14 | ref arg data | test3.cpp:325:11:325:14 | data |
|
||||||
|
| test3.cpp:325:11:325:14 | data | test3.cpp:298:20:298:23 | data |
|
||||||
|
| test3.cpp:339:9:339:16 | password | test3.cpp:341:16:341:23 | password |
|
||||||
|
| test3.cpp:350:9:350:16 | password | test3.cpp:352:16:352:23 | password |
|
||||||
|
| test3.cpp:350:9:350:16 | password | test3.cpp:353:4:353:18 | call to decrypt_inplace |
|
||||||
|
| test3.cpp:350:9:350:16 | password | test3.cpp:353:20:353:27 | password |
|
||||||
|
| test.cpp:41:23:41:43 | cleartext password! | test.cpp:48:21:48:27 | call to encrypt |
|
||||||
|
| test.cpp:41:23:41:43 | cleartext password! | test.cpp:48:29:48:39 | thePassword |
|
||||||
|
| test.cpp:66:23:66:43 | cleartext password! | test.cpp:76:21:76:27 | call to encrypt |
|
||||||
|
| test.cpp:66:23:66:43 | cleartext password! | test.cpp:76:29:76:39 | thePassword |
|
||||||
nodes
|
nodes
|
||||||
| test3.cpp:20:15:20:23 | password1 | semmle.label | password1 |
|
| test3.cpp:17:28:17:36 | password1 | semmle.label | password1 |
|
||||||
| test3.cpp:24:15:24:23 | password2 | semmle.label | password2 |
|
| test3.cpp:17:51:17:59 | password2 | semmle.label | password2 |
|
||||||
| test3.cpp:41:15:41:22 | password | semmle.label | password |
|
| test3.cpp:22:15:22:23 | password1 | semmle.label | password1 |
|
||||||
| test3.cpp:49:15:49:22 | password | semmle.label | password |
|
| test3.cpp:26:15:26:23 | password2 | semmle.label | password2 |
|
||||||
| test3.cpp:68:21:68:29 | password1 | semmle.label | password1 |
|
| test3.cpp:45:8:45:15 | password | semmle.label | password |
|
||||||
| test3.cpp:70:15:70:17 | ptr | semmle.label | ptr |
|
| test3.cpp:47:15:47:22 | password | semmle.label | password |
|
||||||
| test3.cpp:75:15:75:22 | password | semmle.label | password |
|
| test3.cpp:53:8:53:15 | password | semmle.label | password |
|
||||||
| test3.cpp:77:15:77:17 | ptr | semmle.label | ptr |
|
| test3.cpp:55:15:55:22 | password | semmle.label | password |
|
||||||
| test3.cpp:95:12:95:19 | password | semmle.label | password |
|
| test3.cpp:71:32:71:40 | password1 | semmle.label | password1 |
|
||||||
| test3.cpp:106:20:106:25 | buffer | semmle.label | buffer |
|
| test3.cpp:76:15:76:17 | ptr | semmle.label | ptr |
|
||||||
| test3.cpp:108:14:108:19 | buffer | semmle.label | buffer |
|
| test3.cpp:80:8:80:15 | password | semmle.label | password |
|
||||||
| test3.cpp:111:28:111:33 | buffer | semmle.label | buffer |
|
| test3.cpp:83:15:83:17 | ptr | semmle.label | ptr |
|
||||||
| test3.cpp:113:9:113:14 | buffer | semmle.label | buffer |
|
| test3.cpp:98:8:98:15 | password | semmle.label | password |
|
||||||
| test3.cpp:120:9:120:23 | global_password | semmle.label | global_password |
|
| test3.cpp:101:12:101:19 | password | semmle.label | password |
|
||||||
| test3.cpp:128:11:128:18 | password | semmle.label | password |
|
| test3.cpp:112:20:112:25 | buffer | semmle.label | buffer |
|
||||||
| test3.cpp:132:21:132:22 | call to id | semmle.label | call to id |
|
| test3.cpp:114:14:114:19 | buffer | semmle.label | buffer |
|
||||||
| test3.cpp:132:24:132:32 | password1 | semmle.label | password1 |
|
| test3.cpp:117:28:117:33 | buffer | semmle.label | buffer |
|
||||||
| test3.cpp:134:15:134:17 | ptr | semmle.label | ptr |
|
| test3.cpp:119:9:119:14 | buffer | semmle.label | buffer |
|
||||||
| test3.cpp:138:16:138:29 | call to get_global_str | semmle.label | call to get_global_str |
|
| test3.cpp:126:9:126:23 | global_password | semmle.label | global_password |
|
||||||
| test3.cpp:140:15:140:18 | data | semmle.label | data |
|
| test3.cpp:129:39:129:47 | password1 | semmle.label | password1 |
|
||||||
| test3.cpp:151:19:151:26 | password | semmle.label | password |
|
| test3.cpp:132:8:132:15 | password | semmle.label | password |
|
||||||
| test3.cpp:153:15:153:20 | buffer | semmle.label | buffer |
|
| test3.cpp:134:11:134:18 | password | semmle.label | password |
|
||||||
|
| test3.cpp:138:21:138:22 | call to id | semmle.label | call to id |
|
||||||
|
| test3.cpp:138:24:138:32 | password1 | semmle.label | password1 |
|
||||||
|
| test3.cpp:140:15:140:17 | ptr | semmle.label | ptr |
|
||||||
|
| test3.cpp:144:16:144:29 | call to get_global_str | semmle.label | call to get_global_str |
|
||||||
|
| test3.cpp:146:15:146:18 | data | semmle.label | data |
|
||||||
|
| test3.cpp:152:29:152:36 | password | semmle.label | password |
|
||||||
|
| test3.cpp:159:15:159:20 | buffer | semmle.label | buffer |
|
||||||
|
| test3.cpp:171:8:171:15 | password | semmle.label | password |
|
||||||
|
| test3.cpp:173:15:173:22 | password | semmle.label | password |
|
||||||
|
| test3.cpp:175:3:175:17 | call to decrypt_inplace | semmle.label | call to decrypt_inplace |
|
||||||
|
| test3.cpp:175:19:175:26 | password | semmle.label | password |
|
||||||
|
| test3.cpp:179:8:179:15 | password | semmle.label | password |
|
||||||
|
| test3.cpp:181:15:181:22 | password | semmle.label | password |
|
||||||
|
| test3.cpp:184:3:184:17 | call to decrypt_inplace | semmle.label | call to decrypt_inplace |
|
||||||
|
| test3.cpp:184:19:184:26 | password | semmle.label | password |
|
||||||
|
| test3.cpp:188:8:188:15 | password | semmle.label | password |
|
||||||
|
| test3.cpp:191:15:191:22 | password | semmle.label | password |
|
||||||
|
| test3.cpp:193:18:193:28 | call to rtn_decrypt | semmle.label | call to rtn_decrypt |
|
||||||
|
| test3.cpp:193:30:193:37 | password | semmle.label | password |
|
||||||
|
| test3.cpp:197:8:197:15 | password | semmle.label | password |
|
||||||
|
| test3.cpp:199:3:199:17 | call to encrypt_inplace | semmle.label | call to encrypt_inplace |
|
||||||
|
| test3.cpp:199:19:199:26 | password | semmle.label | password |
|
||||||
|
| test3.cpp:201:15:201:22 | password | semmle.label | password |
|
||||||
|
| test3.cpp:205:8:205:15 | password | semmle.label | password |
|
||||||
|
| test3.cpp:207:3:207:17 | call to encrypt_inplace | semmle.label | call to encrypt_inplace |
|
||||||
|
| test3.cpp:207:19:207:26 | password | semmle.label | password |
|
||||||
|
| test3.cpp:210:15:210:22 | password | semmle.label | password |
|
||||||
|
| test3.cpp:214:8:214:15 | password | semmle.label | password |
|
||||||
|
| test3.cpp:217:18:217:28 | call to rtn_encrypt | semmle.label | call to rtn_encrypt |
|
||||||
|
| test3.cpp:217:18:217:28 | call to rtn_encrypt | semmle.label | call to rtn_encrypt |
|
||||||
|
| test3.cpp:217:30:217:37 | password | semmle.label | password |
|
||||||
|
| test3.cpp:219:15:219:26 | password_ptr | semmle.label | password_ptr |
|
||||||
|
| test3.cpp:225:34:225:41 | password | semmle.label | password |
|
||||||
|
| test3.cpp:227:22:227:29 | password | semmle.label | password |
|
||||||
|
| test3.cpp:228:26:228:33 | password | semmle.label | password |
|
||||||
|
| test3.cpp:239:7:239:14 | password | semmle.label | password |
|
||||||
|
| test3.cpp:241:8:241:15 | password | semmle.label | password |
|
||||||
|
| test3.cpp:242:8:242:15 | password | semmle.label | password |
|
||||||
|
| test3.cpp:252:8:252:16 | password1 | semmle.label | password1 |
|
||||||
|
| test3.cpp:252:24:252:32 | password2 | semmle.label | password2 |
|
||||||
|
| test3.cpp:254:15:254:23 | password1 | semmle.label | password1 |
|
||||||
|
| test3.cpp:256:3:256:19 | call to decrypt_to_buffer | semmle.label | call to decrypt_to_buffer |
|
||||||
|
| test3.cpp:256:21:256:29 | password1 | semmle.label | password1 |
|
||||||
|
| test3.cpp:256:32:256:40 | password2 | semmle.label | password2 |
|
||||||
|
| test3.cpp:260:8:260:16 | password1 | semmle.label | password1 |
|
||||||
|
| test3.cpp:260:24:260:32 | password2 | semmle.label | password2 |
|
||||||
|
| test3.cpp:262:3:262:19 | call to encrypt_to_buffer | semmle.label | call to encrypt_to_buffer |
|
||||||
|
| test3.cpp:262:21:262:29 | password1 | semmle.label | password1 |
|
||||||
|
| test3.cpp:262:32:262:40 | password2 | semmle.label | password2 |
|
||||||
|
| test3.cpp:264:15:264:23 | password2 | semmle.label | password2 |
|
||||||
|
| test3.cpp:268:19:268:26 | password | semmle.label | password |
|
||||||
|
| test3.cpp:272:15:272:18 | data | semmle.label | data |
|
||||||
|
| test3.cpp:278:20:278:23 | data | semmle.label | data |
|
||||||
|
| test3.cpp:278:20:278:23 | data | semmle.label | data |
|
||||||
|
| test3.cpp:280:14:280:17 | data | semmle.label | data |
|
||||||
|
| test3.cpp:283:20:283:23 | data | semmle.label | data |
|
||||||
|
| test3.cpp:283:20:283:23 | data | semmle.label | data |
|
||||||
|
| test3.cpp:285:14:285:17 | data | semmle.label | data |
|
||||||
|
| test3.cpp:288:20:288:23 | data | semmle.label | data |
|
||||||
|
| test3.cpp:290:14:290:17 | data | semmle.label | data |
|
||||||
|
| test3.cpp:293:20:293:23 | data | semmle.label | data |
|
||||||
|
| test3.cpp:293:20:293:23 | data | semmle.label | data |
|
||||||
|
| test3.cpp:295:14:295:17 | data | semmle.label | data |
|
||||||
|
| test3.cpp:298:20:298:23 | data | semmle.label | data |
|
||||||
|
| test3.cpp:300:14:300:17 | data | semmle.label | data |
|
||||||
|
| test3.cpp:308:41:308:49 | password1 | semmle.label | password1 |
|
||||||
|
| test3.cpp:308:58:308:66 | password2 | semmle.label | password2 |
|
||||||
|
| test3.cpp:312:3:312:17 | call to encrypt_inplace | semmle.label | call to encrypt_inplace |
|
||||||
|
| test3.cpp:312:19:312:27 | password1 | semmle.label | password1 |
|
||||||
|
| test3.cpp:313:11:313:19 | password1 | semmle.label | password1 |
|
||||||
|
| test3.cpp:313:11:313:19 | ref arg password1 | semmle.label | ref arg password1 |
|
||||||
|
| test3.cpp:314:11:314:19 | password1 | semmle.label | password1 |
|
||||||
|
| test3.cpp:316:11:316:19 | password1 | semmle.label | password1 |
|
||||||
|
| test3.cpp:316:11:316:19 | ref arg password1 | semmle.label | ref arg password1 |
|
||||||
|
| test3.cpp:317:11:317:19 | password1 | semmle.label | password1 |
|
||||||
|
| test3.cpp:324:11:324:14 | data | semmle.label | data |
|
||||||
|
| test3.cpp:324:11:324:14 | ref arg data | semmle.label | ref arg data |
|
||||||
|
| test3.cpp:325:11:325:14 | data | semmle.label | data |
|
||||||
|
| test3.cpp:339:9:339:16 | password | semmle.label | password |
|
||||||
|
| test3.cpp:341:16:341:23 | password | semmle.label | password |
|
||||||
|
| test3.cpp:350:9:350:16 | password | semmle.label | password |
|
||||||
|
| test3.cpp:352:16:352:23 | password | semmle.label | password |
|
||||||
|
| test3.cpp:353:4:353:18 | call to decrypt_inplace | semmle.label | call to decrypt_inplace |
|
||||||
|
| test3.cpp:353:20:353:27 | password | semmle.label | password |
|
||||||
|
| test.cpp:41:23:41:43 | cleartext password! | semmle.label | cleartext password! |
|
||||||
|
| test.cpp:48:21:48:27 | call to encrypt | semmle.label | call to encrypt |
|
||||||
|
| test.cpp:48:29:48:39 | thePassword | semmle.label | thePassword |
|
||||||
|
| test.cpp:66:23:66:43 | cleartext password! | semmle.label | cleartext password! |
|
||||||
|
| test.cpp:76:21:76:27 | call to encrypt | semmle.label | call to encrypt |
|
||||||
|
| test.cpp:76:29:76:39 | thePassword | semmle.label | thePassword |
|
||||||
subpaths
|
subpaths
|
||||||
| test3.cpp:132:24:132:32 | password1 | test3.cpp:111:28:111:33 | buffer | test3.cpp:113:9:113:14 | buffer | test3.cpp:132:21:132:22 | call to id |
|
| test3.cpp:138:24:138:32 | password1 | test3.cpp:117:28:117:33 | buffer | test3.cpp:119:9:119:14 | buffer | test3.cpp:138:21:138:22 | call to id |
|
||||||
|
| test3.cpp:313:11:313:19 | password1 | test3.cpp:278:20:278:23 | data | test3.cpp:278:20:278:23 | data | test3.cpp:313:11:313:19 | ref arg password1 |
|
||||||
|
| test3.cpp:316:11:316:19 | password1 | test3.cpp:283:20:283:23 | data | test3.cpp:283:20:283:23 | data | test3.cpp:316:11:316:19 | ref arg password1 |
|
||||||
|
| test3.cpp:324:11:324:14 | data | test3.cpp:293:20:293:23 | data | test3.cpp:293:20:293:23 | data | test3.cpp:324:11:324:14 | ref arg data |
|
||||||
#select
|
#select
|
||||||
| test3.cpp:20:3:20:6 | call to send | test3.cpp:20:15:20:23 | password1 | test3.cpp:20:15:20:23 | password1 | This operation transmits 'password1', which may contain unencrypted sensitive data from $@ | test3.cpp:20:15:20:23 | password1 | password1 |
|
| test3.cpp:22:3:22:6 | call to send | test3.cpp:17:28:17:36 | password1 | test3.cpp:22:15:22:23 | password1 | This operation transmits 'password1', which may contain unencrypted sensitive data from $@ | test3.cpp:17:28:17:36 | password1 | password1 |
|
||||||
| test3.cpp:24:3:24:6 | call to send | test3.cpp:24:15:24:23 | password2 | test3.cpp:24:15:24:23 | password2 | This operation transmits 'password2', which may contain unencrypted sensitive data from $@ | test3.cpp:24:15:24:23 | password2 | password2 |
|
| test3.cpp:26:3:26:6 | call to send | test3.cpp:17:51:17:59 | password2 | test3.cpp:26:15:26:23 | password2 | This operation transmits 'password2', which may contain unencrypted sensitive data from $@ | test3.cpp:17:51:17:59 | password2 | password2 |
|
||||||
| test3.cpp:41:3:41:6 | call to recv | test3.cpp:41:15:41:22 | password | test3.cpp:41:15:41:22 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:41:15:41:22 | password | password |
|
| test3.cpp:47:3:47:6 | call to recv | test3.cpp:45:8:45:15 | password | test3.cpp:47:15:47:22 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:45:8:45:15 | password | password |
|
||||||
| test3.cpp:49:3:49:6 | call to recv | test3.cpp:49:15:49:22 | password | test3.cpp:49:15:49:22 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:49:15:49:22 | password | password |
|
| test3.cpp:55:3:55:6 | call to recv | test3.cpp:53:8:53:15 | password | test3.cpp:55:15:55:22 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:53:8:53:15 | password | password |
|
||||||
| test3.cpp:70:3:70:6 | call to send | test3.cpp:68:21:68:29 | password1 | test3.cpp:70:15:70:17 | ptr | This operation transmits 'ptr', which may contain unencrypted sensitive data from $@ | test3.cpp:68:21:68:29 | password1 | password1 |
|
| test3.cpp:76:3:76:6 | call to send | test3.cpp:71:32:71:40 | password1 | test3.cpp:76:15:76:17 | ptr | This operation transmits 'ptr', which may contain unencrypted sensitive data from $@ | test3.cpp:71:32:71:40 | password1 | password1 |
|
||||||
| test3.cpp:77:3:77:6 | call to recv | test3.cpp:75:15:75:22 | password | test3.cpp:77:15:77:17 | ptr | This operation receives into 'ptr', which may put unencrypted sensitive data into $@ | test3.cpp:75:15:75:22 | password | password |
|
| test3.cpp:83:3:83:6 | call to recv | test3.cpp:80:8:80:15 | password | test3.cpp:83:15:83:17 | ptr | This operation receives into 'ptr', which may put unencrypted sensitive data into $@ | test3.cpp:80:8:80:15 | password | password |
|
||||||
| test3.cpp:95:3:95:6 | call to read | test3.cpp:95:12:95:19 | password | test3.cpp:95:12:95:19 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:95:12:95:19 | password | password |
|
| test3.cpp:101:3:101:6 | call to read | test3.cpp:98:8:98:15 | password | test3.cpp:101:12:101:19 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:98:8:98:15 | password | password |
|
||||||
| test3.cpp:108:2:108:5 | call to recv | test3.cpp:128:11:128:18 | password | test3.cpp:108:14:108:19 | buffer | This operation receives into 'buffer', which may put unencrypted sensitive data into $@ | test3.cpp:128:11:128:18 | password | password |
|
| test3.cpp:114:2:114:5 | call to recv | test3.cpp:132:8:132:15 | password | test3.cpp:114:14:114:19 | buffer | This operation receives into 'buffer', which may put unencrypted sensitive data into $@ | test3.cpp:132:8:132:15 | password | password |
|
||||||
| test3.cpp:134:3:134:6 | call to send | test3.cpp:132:24:132:32 | password1 | test3.cpp:134:15:134:17 | ptr | This operation transmits 'ptr', which may contain unencrypted sensitive data from $@ | test3.cpp:132:24:132:32 | password1 | password1 |
|
| test3.cpp:140:3:140:6 | call to send | test3.cpp:129:39:129:47 | password1 | test3.cpp:140:15:140:17 | ptr | This operation transmits 'ptr', which may contain unencrypted sensitive data from $@ | test3.cpp:129:39:129:47 | password1 | password1 |
|
||||||
| test3.cpp:140:3:140:6 | call to send | test3.cpp:120:9:120:23 | global_password | test3.cpp:140:15:140:18 | data | This operation transmits 'data', which may contain unencrypted sensitive data from $@ | test3.cpp:120:9:120:23 | global_password | global_password |
|
| test3.cpp:146:3:146:6 | call to send | test3.cpp:126:9:126:23 | global_password | test3.cpp:146:15:146:18 | data | This operation transmits 'data', which may contain unencrypted sensitive data from $@ | test3.cpp:126:9:126:23 | global_password | global_password |
|
||||||
| test3.cpp:153:3:153:6 | call to send | test3.cpp:151:19:151:26 | password | test3.cpp:153:15:153:20 | buffer | This operation transmits 'buffer', which may contain unencrypted sensitive data from $@ | test3.cpp:151:19:151:26 | password | password |
|
| test3.cpp:159:3:159:6 | call to send | test3.cpp:152:29:152:36 | password | test3.cpp:159:15:159:20 | buffer | This operation transmits 'buffer', which may contain unencrypted sensitive data from $@ | test3.cpp:152:29:152:36 | password | password |
|
||||||
|
| test3.cpp:227:2:227:5 | call to send | test3.cpp:225:34:225:41 | password | test3.cpp:227:22:227:29 | password | This operation transmits 'password', which may contain unencrypted sensitive data from $@ | test3.cpp:225:34:225:41 | password | password |
|
||||||
|
| test3.cpp:228:2:228:5 | call to send | test3.cpp:225:34:225:41 | password | test3.cpp:228:26:228:33 | password | This operation transmits 'password', which may contain unencrypted sensitive data from $@ | test3.cpp:225:34:225:41 | password | password |
|
||||||
|
| test3.cpp:241:2:241:6 | call to fgets | test3.cpp:239:7:239:14 | password | test3.cpp:241:8:241:15 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:239:7:239:14 | password | password |
|
||||||
|
| test3.cpp:242:2:242:6 | call to fgets | test3.cpp:239:7:239:14 | password | test3.cpp:242:8:242:15 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:239:7:239:14 | password | password |
|
||||||
|
| test3.cpp:272:3:272:6 | call to send | test3.cpp:268:19:268:26 | password | test3.cpp:272:15:272:18 | data | This operation transmits 'data', which may contain unencrypted sensitive data from $@ | test3.cpp:268:19:268:26 | password | password |
|
||||||
|
| test3.cpp:295:2:295:5 | call to send | test3.cpp:308:58:308:66 | password2 | test3.cpp:295:14:295:17 | data | This operation transmits 'data', which may contain unencrypted sensitive data from $@ | test3.cpp:308:58:308:66 | password2 | password2 |
|
||||||
|
| test3.cpp:300:2:300:5 | call to send | test3.cpp:308:58:308:66 | password2 | test3.cpp:300:14:300:17 | data | This operation transmits 'data', which may contain unencrypted sensitive data from $@ | test3.cpp:308:58:308:66 | password2 | password2 |
|
||||||
|
| test3.cpp:341:4:341:7 | call to recv | test3.cpp:339:9:339:16 | password | test3.cpp:341:16:341:23 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:339:9:339:16 | password | password |
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
|
||||||
typedef unsigned long size_t;
|
typedef unsigned long size_t;
|
||||||
#define STDIN_FILENO (0)
|
#define STDIN_FILENO (0)
|
||||||
|
#define STDOUT_FILENO (1)
|
||||||
|
int stdout_fileno = STDOUT_FILENO;
|
||||||
|
|
||||||
size_t strlen(const char *s);
|
size_t strlen(const char *s);
|
||||||
|
|
||||||
@@ -31,6 +33,10 @@ void test_send(const char *password1, const char *password2, const char *passwor
|
|||||||
{
|
{
|
||||||
send(val(), message, strlen(message), val()); // GOOD: `message` is not a password
|
send(val(), message, strlen(message), val()); // GOOD: `message` is not a password
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
send(stdout_fileno, password2, strlen(password2), val()); // GOOD: `password2` is sent to stdout, not a network socket (this may be an issue but is not within the scope of the `cpp/cleartext-transmission` query)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_receive()
|
void test_receive()
|
||||||
@@ -125,7 +131,7 @@ void test_interprocedural(const char *password1)
|
|||||||
{
|
{
|
||||||
char password[256];
|
char password[256];
|
||||||
|
|
||||||
my_recv(password, 256); // BAD: `password` is received plaintext [detected on line 108]
|
my_recv(password, 256); // BAD: `password` is received plaintext [detected in `my_recv`]
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -153,3 +159,200 @@ void test_taint(const char *password)
|
|||||||
send(val(), buffer, 16, val()); // BAD: `password` is (partially) sent plaintext
|
send(val(), buffer, 16, val()); // BAD: `password` is (partially) sent plaintext
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void encrypt_inplace(char *buffer);
|
||||||
|
void decrypt_inplace(char *buffer);
|
||||||
|
char *rtn_encrypt(const char *buffer);
|
||||||
|
char *rtn_decrypt(const char *buffer);
|
||||||
|
|
||||||
|
void test_decrypt()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
char password[256];
|
||||||
|
|
||||||
|
recv(val(), password, 256, val()); // GOOD: password is encrypted
|
||||||
|
|
||||||
|
decrypt_inplace(password); // proof that `password` was in fact encrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char password[256];
|
||||||
|
|
||||||
|
recv(val(), password, 256, val()); // GOOD: password is encrypted
|
||||||
|
password[255] = 0;
|
||||||
|
|
||||||
|
decrypt_inplace(password); // proof that `password` was in fact encrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char password[256];
|
||||||
|
char *password_ptr;
|
||||||
|
|
||||||
|
recv(val(), password, 256, val()); // GOOD: password is encrypted
|
||||||
|
|
||||||
|
password_ptr = rtn_decrypt(password); // proof that `password` was in fact encrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char password[256];
|
||||||
|
|
||||||
|
encrypt_inplace(password); // proof that `password` is in fact encrypted
|
||||||
|
|
||||||
|
send(val(), password, strlen(password), val()); // GOOD: password is encrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char password[256];
|
||||||
|
|
||||||
|
encrypt_inplace(password); // proof that `password` is in fact encrypted
|
||||||
|
password[255] = 0;
|
||||||
|
|
||||||
|
send(val(), password, strlen(password), val()); // GOOD: password is encrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char password[256];
|
||||||
|
char *password_ptr;
|
||||||
|
|
||||||
|
password_ptr = rtn_encrypt(password); // proof that `password` is in fact encrypted
|
||||||
|
|
||||||
|
send(val(), password_ptr, strlen(password_ptr), val()); // GOOD: password is encrypted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_socket(int from);
|
||||||
|
|
||||||
|
void test_more_stdio(const char *password)
|
||||||
|
{
|
||||||
|
send(get_socket(1), password, 128, val()); // GOOD: `getsocket(1)` is probably standard output [FALSE POSITIVE]
|
||||||
|
send(get_socket(val()), password, 128, val()); // BAD
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {} FILE;
|
||||||
|
char *fgets(char *s, int n, FILE *stream);
|
||||||
|
|
||||||
|
FILE *get_stdstream(int index);
|
||||||
|
#define STDIN_STREAM (get_stdstream(0))
|
||||||
|
|
||||||
|
void test_fgets(FILE *stream)
|
||||||
|
{
|
||||||
|
char password[128];
|
||||||
|
|
||||||
|
fgets(password, 128, stream); // BAD
|
||||||
|
fgets(password, 128, STDIN_STREAM); // GOOD: `STDIN_STREAM` is probably standard input [FALSE POSITIVE]
|
||||||
|
}
|
||||||
|
|
||||||
|
void encrypt_to_buffer(const char *input, char* output);
|
||||||
|
void decrypt_to_buffer(const char *input, char* output);
|
||||||
|
char *strcpy(char *s1, const char *s2);
|
||||||
|
|
||||||
|
void test_crypt_more()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
char password1[256], password2[256];
|
||||||
|
|
||||||
|
recv(val(), password1, 256, val()); // GOOD: password is encrypted
|
||||||
|
|
||||||
|
decrypt_to_buffer(password1, password2); // proof that `password1` was in fact encrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char password1[256], password2[256];
|
||||||
|
|
||||||
|
encrypt_to_buffer(password1, password2); // proof that `password2` is in fact encrypted
|
||||||
|
|
||||||
|
send(val(), password2, strlen(password2), val()); // GOOD: password is encrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char data[256], password[256];
|
||||||
|
|
||||||
|
strcpy(data, password); // not proof of anything
|
||||||
|
|
||||||
|
send(val(), data, strlen(data), val()); // BAD: password is sent plaintext
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cond();
|
||||||
|
|
||||||
|
void target1(char *data)
|
||||||
|
{
|
||||||
|
send(val(), data, strlen(data), val()); // GOOD: encrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
void target2(char *data)
|
||||||
|
{
|
||||||
|
send(val(), data, strlen(data), val()); // BAD: from one source this is a plaintext password [NOT DETECTED]
|
||||||
|
}
|
||||||
|
|
||||||
|
void target3(char *data)
|
||||||
|
{
|
||||||
|
send(val(), data, strlen(data), val()); // BAD: data is a plaintext password [NOT DETECTED]
|
||||||
|
}
|
||||||
|
|
||||||
|
void target4(char *data)
|
||||||
|
{
|
||||||
|
send(val(), data, strlen(data), val()); // BAD: data is a plaintext password
|
||||||
|
}
|
||||||
|
|
||||||
|
void target5(char *data)
|
||||||
|
{
|
||||||
|
send(val(), data, strlen(data), val()); // BAD: from one source this is a plaintext password
|
||||||
|
}
|
||||||
|
|
||||||
|
void target6(char *data)
|
||||||
|
{
|
||||||
|
send(val(), data, strlen(data), val()); // GOOD: not a password
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_multiple_sources_source(char *password1, char *password2)
|
||||||
|
{
|
||||||
|
if (cond())
|
||||||
|
{
|
||||||
|
encrypt_inplace(password1);
|
||||||
|
target1(password1);
|
||||||
|
target2(password1);
|
||||||
|
} else {
|
||||||
|
target2(password1);
|
||||||
|
target3(password1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cond())
|
||||||
|
{
|
||||||
|
char *data = password2;
|
||||||
|
|
||||||
|
target4(data);
|
||||||
|
target5(data);
|
||||||
|
} else {
|
||||||
|
char *data = "harmless";
|
||||||
|
|
||||||
|
target5(data);
|
||||||
|
target6(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_loops()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
while (cond())
|
||||||
|
{
|
||||||
|
char password[256];
|
||||||
|
|
||||||
|
recv(val(), password, 256, val()); // BAD: not encrypted
|
||||||
|
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
while (cond())
|
||||||
|
{
|
||||||
|
char password[256];
|
||||||
|
|
||||||
|
recv(val(), password, 256, val()); // GOOD: password is encrypted
|
||||||
|
decrypt_inplace(password); // proof that `password` was in fact encrypted
|
||||||
|
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/cpp-upgrades
|
name: codeql/cpp-upgrades
|
||||||
groups: cpp
|
groups: cpp
|
||||||
upgrades: .
|
upgrades: .
|
||||||
version: 0.0.4
|
version: 0.0.5-dev
|
||||||
library: true
|
library: true
|
||||||
|
|||||||
@@ -1,25 +1,22 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
<PropertyGroup>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
<TargetFramework>net5.0</TargetFramework>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
<Nullable>enable</Nullable>
|
||||||
<Nullable>enable</Nullable>
|
</PropertyGroup>
|
||||||
</PropertyGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="System.IO.FileSystem" Version="4.3.0"/>
|
||||||
<ItemGroup>
|
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0"/>
|
||||||
<PackageReference Include="System.IO.FileSystem" Version="4.3.0" />
|
<PackageReference Include="xunit" Version="2.4.1"/>
|
||||||
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||||
<PackageReference Include="xunit" Version="2.4.1" />
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||||
<PrivateAssets>all</PrivateAssets>
|
</PackageReference>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0"/>
|
||||||
</PackageReference>
|
</ItemGroup>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
|
<ItemGroup>
|
||||||
</ItemGroup>
|
<ProjectReference Include="..\Semmle.Autobuild.CSharp\Semmle.Autobuild.CSharp.csproj"/>
|
||||||
|
<ProjectReference Include="..\Semmle.Autobuild.Shared\Semmle.Autobuild.Shared.csproj"/>
|
||||||
<ItemGroup>
|
</ItemGroup>
|
||||||
<ProjectReference Include="..\Semmle.Autobuild.CSharp\Semmle.Autobuild.CSharp.csproj" />
|
</Project>
|
||||||
<ProjectReference Include="..\Semmle.Autobuild.Shared\Semmle.Autobuild.Shared.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
||||||
@@ -1,30 +1,25 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
<PropertyGroup>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
<TargetFramework>net5.0</TargetFramework>
|
<AssemblyName>Semmle.Autobuild.CSharp</AssemblyName>
|
||||||
<AssemblyName>Semmle.Autobuild.CSharp</AssemblyName>
|
<RootNamespace>Semmle.Autobuild.CSharp</RootNamespace>
|
||||||
<RootNamespace>Semmle.Autobuild.CSharp</RootNamespace>
|
<ApplicationIcon/>
|
||||||
<ApplicationIcon />
|
<OutputType>Exe</OutputType>
|
||||||
<OutputType>Exe</OutputType>
|
<StartupObject/>
|
||||||
<StartupObject />
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
||||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
|
<Nullable>enable</Nullable>
|
||||||
<Nullable>enable</Nullable>
|
</PropertyGroup>
|
||||||
</PropertyGroup>
|
<ItemGroup>
|
||||||
|
<Folder Include="Properties\"/>
|
||||||
<ItemGroup>
|
</ItemGroup>
|
||||||
<Folder Include="Properties\" />
|
<ItemGroup>
|
||||||
</ItemGroup>
|
<PackageReference Include="Microsoft.Build" Version="16.11.0"/>
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1"/>
|
||||||
<ItemGroup>
|
</ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Build" Version="16.9.0" />
|
<ItemGroup>
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<ProjectReference Include="..\..\extractor\Semmle.Util\Semmle.Util.csproj"/>
|
||||||
</ItemGroup>
|
<ProjectReference Include="..\..\extractor\Semmle.Extraction.CSharp\Semmle.Extraction.CSharp.csproj"/>
|
||||||
|
<ProjectReference Include="..\Semmle.Autobuild.Shared\Semmle.Autobuild.Shared.csproj"/>
|
||||||
<ItemGroup>
|
</ItemGroup>
|
||||||
<ProjectReference Include="..\..\extractor\Semmle.Util\Semmle.Util.csproj" />
|
</Project>
|
||||||
<ProjectReference Include="..\..\extractor\Semmle.Extraction.CSharp\Semmle.Extraction.CSharp.csproj" />
|
|
||||||
<ProjectReference Include="..\Semmle.Autobuild.Shared\Semmle.Autobuild.Shared.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user