mirror of
https://github.com/github/codeql.git
synced 2026-07-05 11:35:30 +02:00
Compare commits
1184 Commits
codeql-cli
...
hackathon-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1ce091de96 | ||
|
|
deaef2e9da | ||
|
|
2cb100393e | ||
|
|
753d0eec89 | ||
|
|
cb3954e16d | ||
|
|
6b515dc051 | ||
|
|
9a004d8b51 | ||
|
|
f42cfb0f84 | ||
|
|
e7439e636e | ||
|
|
1f062baf06 | ||
|
|
ffa73c39a6 | ||
|
|
db3f8b1b21 | ||
|
|
6d27375f52 | ||
|
|
b2070af9d6 | ||
|
|
be6f0e9b96 | ||
|
|
4575583ebf | ||
|
|
0521851011 | ||
|
|
410a60c2c2 | ||
|
|
174a4f9712 | ||
|
|
5e424ff962 | ||
|
|
01bc801217 | ||
|
|
38cb350103 | ||
|
|
099751b761 | ||
|
|
0be9d0de1f | ||
|
|
ebe27a231f | ||
|
|
011d2b9caa | ||
|
|
19933ca2f8 | ||
|
|
b7b73d4de7 | ||
|
|
e0f368a513 | ||
|
|
6e1f80f597 | ||
|
|
ec10d05964 | ||
|
|
2c0f8e5d0a | ||
|
|
b0a3671040 | ||
|
|
f532961ca7 | ||
|
|
eed4031e05 | ||
|
|
2dcda65a65 | ||
|
|
f5f0d45226 | ||
|
|
e9d1d91823 | ||
|
|
bf40878668 | ||
|
|
785bfaf6f2 | ||
|
|
1bc854850c | ||
|
|
89c16ed22a | ||
|
|
823fefcb7a | ||
|
|
3c0a5260b1 | ||
|
|
685ec84bff | ||
|
|
a639e3eef8 | ||
|
|
78598fc9e8 | ||
|
|
b9234e3603 | ||
|
|
4469acfd8d | ||
|
|
91e0c3df79 | ||
|
|
79a64412cc | ||
|
|
77d4d95714 | ||
|
|
43116d556a | ||
|
|
1e16ea0d75 | ||
|
|
39de0d41dd | ||
|
|
f1688f5c7d | ||
|
|
7d260192c3 | ||
|
|
2e1bccf198 | ||
|
|
445df836f9 | ||
|
|
9878c52ad9 | ||
|
|
a3ec05e45d | ||
|
|
7aff31d669 | ||
|
|
263aecf553 | ||
|
|
b446982fae | ||
|
|
050a18f240 | ||
|
|
658fa944ed | ||
|
|
03473c2147 | ||
|
|
34b21af46f | ||
|
|
cef3ce1cde | ||
|
|
17234d3939 | ||
|
|
9b6d00b737 | ||
|
|
267f9acc4c | ||
|
|
e349611f86 | ||
|
|
c12053287e | ||
|
|
3c82653b63 | ||
|
|
d2cad03e28 | ||
|
|
f05c86239f | ||
|
|
7560573b89 | ||
|
|
70e0b33ce6 | ||
|
|
d1c4e772f0 | ||
|
|
68a7734e08 | ||
|
|
59ee3e16b4 | ||
|
|
865cbab242 | ||
|
|
dfdc502525 | ||
|
|
2e93c1d7b6 | ||
|
|
73138f1913 | ||
|
|
e89d8e2967 | ||
|
|
04338215cd | ||
|
|
06ae374206 | ||
|
|
1638796173 | ||
|
|
2b481bbb48 | ||
|
|
ee35bfb290 | ||
|
|
a7d820ce62 | ||
|
|
14031bf351 | ||
|
|
60b27a4e69 | ||
|
|
e438671846 | ||
|
|
631dc98d72 | ||
|
|
2e5971bb57 | ||
|
|
9eaebfcf60 | ||
|
|
d239a30866 | ||
|
|
fc2142feb4 | ||
|
|
04c90a684c | ||
|
|
b33fcf3719 | ||
|
|
8ccce5891d | ||
|
|
6b48b3643e | ||
|
|
2681617f28 | ||
|
|
0c924c2b27 | ||
|
|
e1c326642c | ||
|
|
6f9a70475d | ||
|
|
22bdcad0c6 | ||
|
|
2783c6dcd0 | ||
|
|
7676ad316c | ||
|
|
a4da1a0748 | ||
|
|
20e95137f4 | ||
|
|
d7d546e97f | ||
|
|
6a673e700b | ||
|
|
5cd74213cc | ||
|
|
cca05e0a82 | ||
|
|
ba098c3b1b | ||
|
|
6045f59721 | ||
|
|
b514bd8d1c | ||
|
|
cc6da2829c | ||
|
|
0b57ecf0c7 | ||
|
|
2d34fec0a2 | ||
|
|
9264b2a6d6 | ||
|
|
abb8d65483 | ||
|
|
43c76468c9 | ||
|
|
0d0152f892 | ||
|
|
1b615e25d8 | ||
|
|
a8fcfd154f | ||
|
|
5604fd7d80 | ||
|
|
97319854e2 | ||
|
|
6f5cfca84c | ||
|
|
cc261bfabb | ||
|
|
98bf748e64 | ||
|
|
7364634a6b | ||
|
|
3af3a72161 | ||
|
|
257d94be20 | ||
|
|
a18f1ef7cd | ||
|
|
f5ea133067 | ||
|
|
f6f6c98306 | ||
|
|
f77fd812a9 | ||
|
|
149fb7bbc2 | ||
|
|
c4d3d505ca | ||
|
|
2c99e70e2b | ||
|
|
401a378598 | ||
|
|
b774ae07c8 | ||
|
|
7834626e26 | ||
|
|
436fd9e736 | ||
|
|
197e5d0267 | ||
|
|
25a2aef623 | ||
|
|
79adc9bfe9 | ||
|
|
25d5104468 | ||
|
|
561b769a79 | ||
|
|
4e0cca9a41 | ||
|
|
60b422a35c | ||
|
|
7588813864 | ||
|
|
69cfc79561 | ||
|
|
befb1ccd84 | ||
|
|
e4edb19f43 | ||
|
|
f24c042d04 | ||
|
|
aa3fd6add0 | ||
|
|
33186ac797 | ||
|
|
82fbae3e5a | ||
|
|
26c048a650 | ||
|
|
e2e4642037 | ||
|
|
7a098dde50 | ||
|
|
9af44ed0a2 | ||
|
|
052166f17e | ||
|
|
96bddde7c1 | ||
|
|
ef15980bb6 | ||
|
|
2416040854 | ||
|
|
047f8e485a | ||
|
|
0ed7b3c3ad | ||
|
|
7371751801 | ||
|
|
826111dc08 | ||
|
|
f2c3d83d9e | ||
|
|
7bd7cc5dbe | ||
|
|
f1b0f1a35d | ||
|
|
7194113a64 | ||
|
|
7691cbce87 | ||
|
|
f84b2a96af | ||
|
|
4f5ecb899b | ||
|
|
ac3f642b45 | ||
|
|
12a579e0aa | ||
|
|
40a7223620 | ||
|
|
d056706af5 | ||
|
|
ef8d38e9e0 | ||
|
|
3d46129bbf | ||
|
|
dd1e71ace9 | ||
|
|
ff529c34b4 | ||
|
|
ca56b0157d | ||
|
|
257fe1ad6b | ||
|
|
a130c0f6b3 | ||
|
|
dd8fb29a65 | ||
|
|
98ddbe0d83 | ||
|
|
bcf76b1ac0 | ||
|
|
1fbe23228e | ||
|
|
bb1945f899 | ||
|
|
640e2f56d5 | ||
|
|
306440ce6e | ||
|
|
29c950035d | ||
|
|
012dc59bf3 | ||
|
|
5723a75f3c | ||
|
|
1f2d9dc95c | ||
|
|
0783758bd1 | ||
|
|
979bcf4ef3 | ||
|
|
94cb09e539 | ||
|
|
3dee16c50c | ||
|
|
288fbfd2ec | ||
|
|
369431125e | ||
|
|
f5633be837 | ||
|
|
418118fc89 | ||
|
|
30891ca4aa | ||
|
|
ace633cb1d | ||
|
|
1a6886cf99 | ||
|
|
eb552b7c93 | ||
|
|
0328a2986d | ||
|
|
999ec7053e | ||
|
|
45bbcccd1a | ||
|
|
30161b0f12 | ||
|
|
d659709695 | ||
|
|
e40c53a340 | ||
|
|
7ba199a8c3 | ||
|
|
d288c4a709 | ||
|
|
4f7fde7b87 | ||
|
|
1fb19191ba | ||
|
|
f48cc1a526 | ||
|
|
b4fd95bd6a | ||
|
|
5b724a7aaf | ||
|
|
dd6c5ba383 | ||
|
|
7b74478e47 | ||
|
|
63fcaca82f | ||
|
|
a0867b4f66 | ||
|
|
c552bc5eb1 | ||
|
|
077e51c6c6 | ||
|
|
4857960f72 | ||
|
|
1998e29639 | ||
|
|
6bd269502f | ||
|
|
f2de449ce4 | ||
|
|
b9952618ff | ||
|
|
b269b79bb3 | ||
|
|
2c5ce3216e | ||
|
|
dde2ad1290 | ||
|
|
f138fc0d2d | ||
|
|
37d03ee0f3 | ||
|
|
1bc8a6de61 | ||
|
|
08383eaea5 | ||
|
|
2c2dccabe9 | ||
|
|
36a846ee32 | ||
|
|
c51c15ae74 | ||
|
|
d26dc68baa | ||
|
|
5f26790b90 | ||
|
|
0668b71538 | ||
|
|
dfffa1e237 | ||
|
|
d8e7c9c986 | ||
|
|
253c658ad2 | ||
|
|
f0e20fa69e | ||
|
|
71c017f053 | ||
|
|
7263d4d650 | ||
|
|
5611a3e417 | ||
|
|
10b3efa667 | ||
|
|
dde9a7cd7e | ||
|
|
75f860595a | ||
|
|
c8301fc5f0 | ||
|
|
95de7495d1 | ||
|
|
72bafd86df | ||
|
|
452b68c0ca | ||
|
|
db1499d5b0 | ||
|
|
b5c92408f4 | ||
|
|
620e8dcb37 | ||
|
|
5b4a8884b4 | ||
|
|
737aab66f5 | ||
|
|
ab6260600e | ||
|
|
10b72a0c39 | ||
|
|
36201105b9 | ||
|
|
e34a9de008 | ||
|
|
9bdc2d1c02 | ||
|
|
212a515fa9 | ||
|
|
d84501d65c | ||
|
|
dcba8e5408 | ||
|
|
8039e117ba | ||
|
|
27a2781954 | ||
|
|
b8a2716ced | ||
|
|
d147faba4e | ||
|
|
1bed9f9003 | ||
|
|
fab6813a49 | ||
|
|
cf696f2639 | ||
|
|
a9a55dfcd6 | ||
|
|
d3e047f078 | ||
|
|
db180d9872 | ||
|
|
e5cc540475 | ||
|
|
c65c2489cf | ||
|
|
db76681744 | ||
|
|
5c36e63dfe | ||
|
|
7531852ea6 | ||
|
|
cd9786a952 | ||
|
|
bad499e360 | ||
|
|
7c3122aade | ||
|
|
007f181ff5 | ||
|
|
90ba3812fe | ||
|
|
e63ddd2071 | ||
|
|
8f8f5f8826 | ||
|
|
584ba80ec7 | ||
|
|
4ad874a089 | ||
|
|
a3ed965032 | ||
|
|
2bd18ab41d | ||
|
|
713695f8f9 | ||
|
|
bb1d5d3c8c | ||
|
|
737e9d8844 | ||
|
|
02ed6e03e2 | ||
|
|
0a4ba8e8c7 | ||
|
|
081a4ad021 | ||
|
|
23d881baa4 | ||
|
|
91a48856c5 | ||
|
|
b97f4401c0 | ||
|
|
11a664d707 | ||
|
|
46e155d327 | ||
|
|
5ab2e30ba3 | ||
|
|
b4534fe9ff | ||
|
|
8099a8c851 | ||
|
|
0f9afca2ab | ||
|
|
2151b6d8c5 | ||
|
|
ad1906e871 | ||
|
|
400f892376 | ||
|
|
5db6afa84a | ||
|
|
da606dd77b | ||
|
|
fc59b7f3a7 | ||
|
|
4fafed2542 | ||
|
|
366b919107 | ||
|
|
2b24298d7f | ||
|
|
7a49d6e9bd | ||
|
|
cb088c3ee1 | ||
|
|
3a0c4c4d6f | ||
|
|
d52f2e510b | ||
|
|
ed8e105452 | ||
|
|
f1cfc5d1b8 | ||
|
|
e3f4bb84d4 | ||
|
|
905583e00a | ||
|
|
e6f31c965e | ||
|
|
b2c8049a77 | ||
|
|
9e5a80ac59 | ||
|
|
ff65ffafb0 | ||
|
|
7bf7e59017 | ||
|
|
97402fdf36 | ||
|
|
2662a4c651 | ||
|
|
8a8031df0e | ||
|
|
b7b10ce549 | ||
|
|
49b2209c62 | ||
|
|
890cba6e95 | ||
|
|
e89fe8ddde | ||
|
|
98dbbe907e | ||
|
|
7b75a30851 | ||
|
|
20b31d0b4e | ||
|
|
4f6421946c | ||
|
|
9a8ad7d590 | ||
|
|
43f100fd69 | ||
|
|
96646abab9 | ||
|
|
0091b83258 | ||
|
|
8ff38321a3 | ||
|
|
d7760de4c6 | ||
|
|
cca78ca190 | ||
|
|
dce03569e5 | ||
|
|
93eaeaec75 | ||
|
|
9b840aa20c | ||
|
|
8b6a9180dc | ||
|
|
cb7213d87a | ||
|
|
9a4b56162e | ||
|
|
f3482684a6 | ||
|
|
a10f94af81 | ||
|
|
de3d15b277 | ||
|
|
114b694553 | ||
|
|
216cd88225 | ||
|
|
c5d2866948 | ||
|
|
635bcd4fa2 | ||
|
|
74a195b4f4 | ||
|
|
e9800d11b6 | ||
|
|
40a07de566 | ||
|
|
ca334021ad | ||
|
|
69ab389d9f | ||
|
|
da2215e7e5 | ||
|
|
30f0b8ab2b | ||
|
|
6ec9b95072 | ||
|
|
641646ac08 | ||
|
|
b2f1022e5c | ||
|
|
75f42f4614 | ||
|
|
0c1fb8c881 | ||
|
|
4f9303eb02 | ||
|
|
078f223052 | ||
|
|
2c23dacca1 | ||
|
|
a5e7ef424e | ||
|
|
84e58b77aa | ||
|
|
3092640115 | ||
|
|
143e1680bd | ||
|
|
de83929a60 | ||
|
|
d7c97d9d92 | ||
|
|
30925da7d9 | ||
|
|
d25c24b64d | ||
|
|
5a7cb8f25a | ||
|
|
799873113f | ||
|
|
f8feb84958 | ||
|
|
6a1504b91c | ||
|
|
f1001374fd | ||
|
|
25d3af9236 | ||
|
|
1f3f1b5ec4 | ||
|
|
947b094387 | ||
|
|
009d58034f | ||
|
|
fd750a3bf0 | ||
|
|
5c0fb2030d | ||
|
|
2eb67549e6 | ||
|
|
afe318edbe | ||
|
|
71ef98584d | ||
|
|
6bba191407 | ||
|
|
df144f3a1e | ||
|
|
8b628e3ad3 | ||
|
|
c49f05aa2b | ||
|
|
96b4a12af7 | ||
|
|
697c3df74a | ||
|
|
1040561ec1 | ||
|
|
a46dc55e84 | ||
|
|
615a128770 | ||
|
|
14268f3c63 | ||
|
|
408ba517e5 | ||
|
|
4d4ca6b948 | ||
|
|
a6fe620bcb | ||
|
|
3a38f3b947 | ||
|
|
0ae04de7f0 | ||
|
|
8a24daf293 | ||
|
|
d443354651 | ||
|
|
72af41b196 | ||
|
|
57f6859ddc | ||
|
|
5f087f0084 | ||
|
|
f66f7ce8d7 | ||
|
|
64bf6cc62b | ||
|
|
1ac3a9e8d3 | ||
|
|
e0879969c9 | ||
|
|
f22979f4b6 | ||
|
|
aaa8f9c41f | ||
|
|
2b897a9825 | ||
|
|
5af3e119a6 | ||
|
|
46e6e72593 | ||
|
|
92c18960c5 | ||
|
|
e349891cff | ||
|
|
e02c32f3d4 | ||
|
|
7877082869 | ||
|
|
7129ffc199 | ||
|
|
1f5be03137 | ||
|
|
423c85377b | ||
|
|
8b126fe51a | ||
|
|
1ed4d2ada7 | ||
|
|
1e915720e9 | ||
|
|
0f1dc9b2d9 | ||
|
|
ae6c95ff95 | ||
|
|
d5f254781e | ||
|
|
fa1fa0d19d | ||
|
|
74f1344ac5 | ||
|
|
bae7e10e46 | ||
|
|
ec63099c54 | ||
|
|
2b8b5cf1b8 | ||
|
|
6730f57d5c | ||
|
|
118d50236f | ||
|
|
a46a7fadb2 | ||
|
|
7a001f4905 | ||
|
|
803ed20962 | ||
|
|
4256fbf11a | ||
|
|
f3dd002ba9 | ||
|
|
f9e9ae91f7 | ||
|
|
23419ee634 | ||
|
|
b8f0f85840 | ||
|
|
69453aa144 | ||
|
|
55f5b26ba6 | ||
|
|
721bde1ce8 | ||
|
|
2e9d548083 | ||
|
|
fdefcd6a84 | ||
|
|
9178cec0e6 | ||
|
|
83d1fc33e1 | ||
|
|
14e51627c5 | ||
|
|
b1702ab87e | ||
|
|
52540b42fc | ||
|
|
6bd7047e41 | ||
|
|
57f1f5b829 | ||
|
|
9548a0e8fb | ||
|
|
ba672e5b35 | ||
|
|
2cea720f6e | ||
|
|
dbdf9e1a4f | ||
|
|
bff93c4484 | ||
|
|
0342b3eba2 | ||
|
|
d28e7920b3 | ||
|
|
ec7309c735 | ||
|
|
331ca61be9 | ||
|
|
559b965e74 | ||
|
|
9f63613cf8 | ||
|
|
e576650293 | ||
|
|
6299b844f8 | ||
|
|
4385b316c0 | ||
|
|
b1dc6099ff | ||
|
|
15099b3db0 | ||
|
|
8334c6db91 | ||
|
|
1c75e5b2a6 | ||
|
|
1623bba18a | ||
|
|
475d8da342 | ||
|
|
ae09499905 | ||
|
|
c950e26b3e | ||
|
|
f75c062949 | ||
|
|
f22d87b7c7 | ||
|
|
e11a68803e | ||
|
|
45faed057c | ||
|
|
f1b67ade9b | ||
|
|
f9ae7c5454 | ||
|
|
296dee90dd | ||
|
|
967bbbc1a7 | ||
|
|
28a5a1d507 | ||
|
|
5b38ba87df | ||
|
|
db42b60015 | ||
|
|
47ef123601 | ||
|
|
f8c8d59cb5 | ||
|
|
c8779d0d0b | ||
|
|
28160e418c | ||
|
|
ed349f7d6b | ||
|
|
fa569dcef4 | ||
|
|
040d971588 | ||
|
|
e95bfc816e | ||
|
|
44935cef63 | ||
|
|
190050f577 | ||
|
|
bf59c94d24 | ||
|
|
2f50618e62 | ||
|
|
5468767fa0 | ||
|
|
a007d6edb0 | ||
|
|
1c0aa679a6 | ||
|
|
458baeff32 | ||
|
|
4317e58414 | ||
|
|
78a6522190 | ||
|
|
95395322a8 | ||
|
|
1eb1293230 | ||
|
|
c14d4042e0 | ||
|
|
5a451e964d | ||
|
|
b157d73c10 | ||
|
|
985d1990eb | ||
|
|
463096e4be | ||
|
|
892beeab6d | ||
|
|
9ec2f9204b | ||
|
|
c73e6f1fa8 | ||
|
|
9aafbfce13 | ||
|
|
cc6268339b | ||
|
|
834b07e6ad | ||
|
|
8be6aeda3e | ||
|
|
359dcf37e9 | ||
|
|
eb263e747f | ||
|
|
bc576f658e | ||
|
|
cfdeb0edf5 | ||
|
|
6f56a656e4 | ||
|
|
031f453af8 | ||
|
|
002f2a0985 | ||
|
|
d21e27c717 | ||
|
|
30e4822fb7 | ||
|
|
d931ade182 | ||
|
|
ed9a0ea155 | ||
|
|
c3577b34d3 | ||
|
|
e4da8da5d9 | ||
|
|
b455b2c1a6 | ||
|
|
dc4dda1dbc | ||
|
|
098ea50068 | ||
|
|
6e291711ac | ||
|
|
fca6ccd2f1 | ||
|
|
291bb2210c | ||
|
|
4bf717c3e4 | ||
|
|
d15c46836b | ||
|
|
c0fce80b7d | ||
|
|
1b7e3814b0 | ||
|
|
e1c47f5584 | ||
|
|
ffc27b5301 | ||
|
|
c3fa3f26a7 | ||
|
|
943b2a2ed1 | ||
|
|
bf6cfd3bef | ||
|
|
30aefabb2a | ||
|
|
f05b75e04f | ||
|
|
c28f54a78b | ||
|
|
66b03bfb12 | ||
|
|
71e25521cf | ||
|
|
27e6173bb7 | ||
|
|
3a73faf061 | ||
|
|
352ec91a08 | ||
|
|
00549e36ed | ||
|
|
b385ddbab1 | ||
|
|
f599c6d8a9 | ||
|
|
df967ce43f | ||
|
|
6e533c6284 | ||
|
|
2b1b4cd85d | ||
|
|
5280d69500 | ||
|
|
39ed7876c3 | ||
|
|
882280309f | ||
|
|
01a074c146 | ||
|
|
d56625cb8b | ||
|
|
8f10667ee1 | ||
|
|
837cdc8301 | ||
|
|
3a62628938 | ||
|
|
9062fb666a | ||
|
|
b48d483eba | ||
|
|
c327f0f0a7 | ||
|
|
c85d99d949 | ||
|
|
393aad5935 | ||
|
|
8f141cb157 | ||
|
|
5a09a325f2 | ||
|
|
18c0bcec0b | ||
|
|
5fc8a00487 | ||
|
|
b3feb4d7e9 | ||
|
|
2ceb4cffbc | ||
|
|
0d8986cfad | ||
|
|
c71bdce2d0 | ||
|
|
4f6b6b4a6f | ||
|
|
617d950a25 | ||
|
|
340b20f93d | ||
|
|
9f0b0733a6 | ||
|
|
1c87875049 | ||
|
|
5e21a5d284 | ||
|
|
ba51b65d84 | ||
|
|
334fb1fc95 | ||
|
|
0fb439b54d | ||
|
|
e865c3cbd3 | ||
|
|
e4c8406365 | ||
|
|
1f0d9e50c5 | ||
|
|
ae3d98fd6f | ||
|
|
57ec0948cf | ||
|
|
2971a20760 | ||
|
|
b72f34591d | ||
|
|
66dc5501e8 | ||
|
|
b611e7cebf | ||
|
|
01a1b4aa50 | ||
|
|
2d387a98ce | ||
|
|
78a65a7787 | ||
|
|
6d7598115e | ||
|
|
a7264c2b5c | ||
|
|
dc265e7542 | ||
|
|
b858a284c9 | ||
|
|
246c169540 | ||
|
|
97fd2033f1 | ||
|
|
39b9d2ea83 | ||
|
|
eb1024c79b | ||
|
|
86e791980c | ||
|
|
9762313500 | ||
|
|
95bb70f577 | ||
|
|
5e140021fb | ||
|
|
fd26ae18bf | ||
|
|
bb5a78d3f1 | ||
|
|
7112409d27 | ||
|
|
657c29f409 | ||
|
|
94d08aa443 | ||
|
|
8674139de6 | ||
|
|
ebf7231be7 | ||
|
|
9b5556e245 | ||
|
|
2d313ef4c7 | ||
|
|
0963af2ee7 | ||
|
|
a051a57e00 | ||
|
|
0b91310357 | ||
|
|
b8e7e1d15e | ||
|
|
daffae020b | ||
|
|
cad003a39e | ||
|
|
c060827a5d | ||
|
|
7048190929 | ||
|
|
e16647fc87 | ||
|
|
4cc75c5bd6 | ||
|
|
38766c497a | ||
|
|
cd147038cd | ||
|
|
a86862d578 | ||
|
|
04016ebd20 | ||
|
|
f99df55e94 | ||
|
|
abe0bb70ac | ||
|
|
331fbf3251 | ||
|
|
dcb2117b31 | ||
|
|
5eaf682b77 | ||
|
|
f58ff6ac6f | ||
|
|
ff6b8c4eb1 | ||
|
|
5c05a4c752 | ||
|
|
3dcb039c76 | ||
|
|
d44d980003 | ||
|
|
cfa47a6d8e | ||
|
|
db045e0d9e | ||
|
|
fd99e1f6a5 | ||
|
|
b4ec13235d | ||
|
|
5ae025f39a | ||
|
|
76e6f81075 | ||
|
|
136adb2df2 | ||
|
|
f920bc164a | ||
|
|
7aed6f9233 | ||
|
|
11c113bbd5 | ||
|
|
84773fcde4 | ||
|
|
74f483a6f5 | ||
|
|
6f4311d656 | ||
|
|
8a3f29a6bf | ||
|
|
79dcb4b48c | ||
|
|
bdae2af0e2 | ||
|
|
c3ff181198 | ||
|
|
3023d3b8c0 | ||
|
|
4943fc5a57 | ||
|
|
851c30e797 | ||
|
|
68e7f84c23 | ||
|
|
6b434d10ce | ||
|
|
e68826bf99 | ||
|
|
6b37d2009b | ||
|
|
38bd893c81 | ||
|
|
ea4761d3b6 | ||
|
|
e90803a81c | ||
|
|
512c6a59c5 | ||
|
|
d8e75e66d7 | ||
|
|
9b0ad8295e | ||
|
|
3586231e7d | ||
|
|
9d5cf0b331 | ||
|
|
6d4e000c7c | ||
|
|
43d9d2ceb7 | ||
|
|
f9132c5ff0 | ||
|
|
2273bb13b8 | ||
|
|
b782e5bf44 | ||
|
|
4ae35d179e | ||
|
|
d510739ca2 | ||
|
|
1f4cd74a1c | ||
|
|
795e32c681 | ||
|
|
b1c3915fd9 | ||
|
|
d78a7b9d94 | ||
|
|
0cf00ebb5d | ||
|
|
f12310cb86 | ||
|
|
137403f649 | ||
|
|
ab64d9a9d6 | ||
|
|
69e8621062 | ||
|
|
ac838d72de | ||
|
|
b7543f5dc7 | ||
|
|
cd4a546763 | ||
|
|
8f23ba83be | ||
|
|
9b56e83745 | ||
|
|
5442cdb49c | ||
|
|
f643fd7d74 | ||
|
|
45ae4ed362 | ||
|
|
a8eed6bd7e | ||
|
|
3f95dd6916 | ||
|
|
b63294764b | ||
|
|
69502d0c31 | ||
|
|
12f9e3a1dd | ||
|
|
ae577d1e44 | ||
|
|
dd20a9b009 | ||
|
|
df256e601a | ||
|
|
5a9867c5b0 | ||
|
|
10afa4381a | ||
|
|
1c8f474848 | ||
|
|
2787f0a0fc | ||
|
|
2d43eec3c3 | ||
|
|
91b29eee53 | ||
|
|
a04830b8b2 | ||
|
|
5433907c33 | ||
|
|
21cb4909cf | ||
|
|
12cba7909b | ||
|
|
f2ca52d951 | ||
|
|
b2512eb212 | ||
|
|
dc8ca70ab5 | ||
|
|
7ea8f88d47 | ||
|
|
9c8e2321be | ||
|
|
697a7b8a60 | ||
|
|
2b7ce23653 | ||
|
|
33de177fea | ||
|
|
bbde709b3f | ||
|
|
a70d9691da | ||
|
|
af7b295c59 | ||
|
|
9dca6697fb | ||
|
|
0f31fc7cbe | ||
|
|
5220a8d3f8 | ||
|
|
9f43108ba8 | ||
|
|
904a8b1ea9 | ||
|
|
5bee44dcfe | ||
|
|
6568332e3d | ||
|
|
6c50c2bfe6 | ||
|
|
ccaa792343 | ||
|
|
6669cf805f | ||
|
|
0fd4d4a114 | ||
|
|
e8a466a02c | ||
|
|
022c9eb3cd | ||
|
|
6bf2d47321 | ||
|
|
1dc08941f8 | ||
|
|
a0e73eaab0 | ||
|
|
a17cd9bc1c | ||
|
|
4ce8d953d2 | ||
|
|
cff9bcfabc | ||
|
|
4e70e674fd | ||
|
|
ae21bbf0b2 | ||
|
|
3465c34cb6 | ||
|
|
e8eff78799 | ||
|
|
ad756d59c8 | ||
|
|
315bdc2b48 | ||
|
|
637c52d10a | ||
|
|
c85bdcd5ab | ||
|
|
4455ed982d | ||
|
|
1c6a4b8cbf | ||
|
|
84594e66bc | ||
|
|
127f819762 | ||
|
|
e0c89a700f | ||
|
|
be02512dfe | ||
|
|
24b4b05be8 | ||
|
|
d30d71e048 | ||
|
|
426bdc0011 | ||
|
|
d38fa13299 | ||
|
|
5b72aee3ae | ||
|
|
e91987b1a9 | ||
|
|
d544f47746 | ||
|
|
e4f6b1ac27 | ||
|
|
77e48f72ec | ||
|
|
9ec5e6e35e | ||
|
|
424046d238 | ||
|
|
80c4b7357a | ||
|
|
31c2a3be98 | ||
|
|
decbaa9dc7 | ||
|
|
3f0be47c7b | ||
|
|
36f0a78450 | ||
|
|
49428c4585 | ||
|
|
43f1d092f1 | ||
|
|
d86293f9b4 | ||
|
|
d7f1e19d40 | ||
|
|
cc5dd3180a | ||
|
|
c858e4974d | ||
|
|
ff30308a2b | ||
|
|
75e6de8311 | ||
|
|
f67c68da9a | ||
|
|
878299823c | ||
|
|
9cd1e0e546 | ||
|
|
e8209a6a10 | ||
|
|
2e77b8d3c2 | ||
|
|
c397f707a1 | ||
|
|
4b9430d59e | ||
|
|
cd2eec0aa0 | ||
|
|
52fcc5f435 | ||
|
|
63854e36b4 | ||
|
|
a773532d07 | ||
|
|
6c7ea86a12 | ||
|
|
465eb00228 | ||
|
|
01e7d57dba | ||
|
|
7f4bcdfa64 | ||
|
|
eecf32db4d | ||
|
|
4192d09e5c | ||
|
|
b4d89f7554 | ||
|
|
3d45944649 | ||
|
|
bd62ec294e | ||
|
|
1067dd9dd3 | ||
|
|
ec075f8fbe | ||
|
|
f6ae7523b5 | ||
|
|
12cd1c1011 | ||
|
|
4e214e1c7c | ||
|
|
68da5e2bbe | ||
|
|
92b13c4259 | ||
|
|
3d8a7e0ee3 | ||
|
|
c6193ebc0c | ||
|
|
838a00bbc9 | ||
|
|
2abdf7dbbd | ||
|
|
602d16d73f | ||
|
|
b99e44c3ca | ||
|
|
4bcf9e50a0 | ||
|
|
467854ba4b | ||
|
|
57c645bd24 | ||
|
|
2d9ff85753 | ||
|
|
1f2e8d898d | ||
|
|
3e3ea51e69 | ||
|
|
2a33a86c9d | ||
|
|
aa521ecd59 | ||
|
|
abcb5a7a95 | ||
|
|
e621d208e4 | ||
|
|
55ec27f47f | ||
|
|
e90b630c9b | ||
|
|
c6bc1a3f3a | ||
|
|
07eba4e3b1 | ||
|
|
041dc19055 | ||
|
|
989a546796 | ||
|
|
d0ca7045d4 | ||
|
|
a59ed5bc49 | ||
|
|
06191922c3 | ||
|
|
71ad6a8262 | ||
|
|
0d7943031c | ||
|
|
f969274a29 | ||
|
|
225c96ec9f | ||
|
|
245f475fdb | ||
|
|
df4f2a367b | ||
|
|
31f602cd47 | ||
|
|
4689bdb468 | ||
|
|
1054e7a4ee | ||
|
|
003166af13 | ||
|
|
e7e6529df6 | ||
|
|
8d3ed68b68 | ||
|
|
49add7d8ce | ||
|
|
eb228b6e68 | ||
|
|
62dd86bacb | ||
|
|
7b91be6c52 | ||
|
|
11505d6842 | ||
|
|
56a70da28f | ||
|
|
70996a4c7e | ||
|
|
576eda3ec6 | ||
|
|
4cebb7e848 | ||
|
|
f8d427336e | ||
|
|
7bbf1a24d4 | ||
|
|
c6c00e7179 | ||
|
|
3a7df994cb | ||
|
|
387a241efd | ||
|
|
506b911767 | ||
|
|
4009f03087 | ||
|
|
9807a8e1d3 | ||
|
|
af524f0043 | ||
|
|
894f9ab8fa | ||
|
|
7082efa037 | ||
|
|
c34ad25cf9 | ||
|
|
13e60d7b11 | ||
|
|
132cc03e3b | ||
|
|
679d64f0e8 | ||
|
|
30a512c96b | ||
|
|
81d77bf37c | ||
|
|
947e0274c7 | ||
|
|
ac0fd93cb3 | ||
|
|
2f4eea5a0d | ||
|
|
f404d7a5f8 | ||
|
|
392b2af923 | ||
|
|
b82dfa9a21 | ||
|
|
5487b404ed | ||
|
|
0bf2d77a7e | ||
|
|
a161d6e666 | ||
|
|
9ea6ef06ef | ||
|
|
f2b52650d5 | ||
|
|
a35bda2946 | ||
|
|
f82f1df5d6 | ||
|
|
7bf271fb6c | ||
|
|
a9e2f55b61 | ||
|
|
484d0fe4cd | ||
|
|
12d856737a | ||
|
|
8f4509f434 | ||
|
|
431d9d58f1 | ||
|
|
242399817a | ||
|
|
fd757b0089 | ||
|
|
58bf70d61b | ||
|
|
613831b2e1 | ||
|
|
c937230f1a | ||
|
|
c26c68c286 | ||
|
|
7c3684dbb7 | ||
|
|
400910e4d3 | ||
|
|
155073c498 | ||
|
|
48c3db2290 | ||
|
|
206acea41c | ||
|
|
727a7e804c | ||
|
|
37361d9f79 | ||
|
|
f8ab64dff0 | ||
|
|
c717e346fb | ||
|
|
ac115e0a6f | ||
|
|
bb2bbd2d4d | ||
|
|
f6794fe859 | ||
|
|
8e9aa5b560 | ||
|
|
a7f3ef1a6c | ||
|
|
8e2b17cd86 | ||
|
|
6d859daf3d | ||
|
|
b54b5ae0a9 | ||
|
|
b3fa59d94b | ||
|
|
3c86aad16d | ||
|
|
4ce1b680c2 | ||
|
|
048a7c4e42 | ||
|
|
48291dd32d | ||
|
|
0b45b63bd2 | ||
|
|
0c5b528d54 | ||
|
|
1366247f4c | ||
|
|
f7a8a8ae19 | ||
|
|
9736936e54 | ||
|
|
ddb145f15f | ||
|
|
38b811b050 | ||
|
|
1ec1dd368d | ||
|
|
3697ef72c4 | ||
|
|
6e385cabd8 | ||
|
|
37a536baf9 | ||
|
|
5cab25662c | ||
|
|
3478890090 | ||
|
|
8ed10317bd | ||
|
|
dd9a2db137 | ||
|
|
020b4becfd | ||
|
|
b79a5fee14 | ||
|
|
554007b305 | ||
|
|
c82eb4dff3 | ||
|
|
b9ac038de2 | ||
|
|
ceb3d14fe0 | ||
|
|
07ded4278f | ||
|
|
051a77fd79 | ||
|
|
18c8d90a1a | ||
|
|
688afddaf2 | ||
|
|
8f58685b38 | ||
|
|
567aa1102a | ||
|
|
bc34374075 | ||
|
|
e25a655509 | ||
|
|
b9dfeb3aac | ||
|
|
34b9791e46 | ||
|
|
322e6c91be | ||
|
|
8b6c940e76 | ||
|
|
6d6f89e71e | ||
|
|
a39a94ca8e | ||
|
|
19644a8f07 | ||
|
|
7f6ae8b2ab | ||
|
|
11152deeb5 | ||
|
|
f76cde36bb | ||
|
|
e1f7f3cbd4 | ||
|
|
e75562e508 | ||
|
|
5cc94e1105 | ||
|
|
21b7a51d0a | ||
|
|
1479509d93 | ||
|
|
377da9fa66 | ||
|
|
4a1bf95a87 | ||
|
|
e8c18a3883 | ||
|
|
98032d58b8 | ||
|
|
5385cc3aaa | ||
|
|
5b17066e6c | ||
|
|
ea04b500a3 | ||
|
|
b841d5f923 | ||
|
|
81b3ff2bb8 | ||
|
|
79e1aa0498 | ||
|
|
05a4c7fdc1 | ||
|
|
66f4eccc30 | ||
|
|
9087259b1b | ||
|
|
968127eaa3 | ||
|
|
5407b57261 | ||
|
|
aac6cf60ee | ||
|
|
ffff10a7e8 | ||
|
|
7bae2d9192 | ||
|
|
6b031a4623 | ||
|
|
785175e77f | ||
|
|
bfd852aacd | ||
|
|
ec72150893 | ||
|
|
435b7df764 | ||
|
|
8913638b25 | ||
|
|
b259a0ff6a | ||
|
|
c8706e2ad7 | ||
|
|
65081a9a1f | ||
|
|
08b528b5c4 | ||
|
|
0837e400a2 | ||
|
|
efe064284b | ||
|
|
86fe5b47db | ||
|
|
2b939fdf08 | ||
|
|
f81a3ec464 | ||
|
|
375f0ea8b6 | ||
|
|
1e699ec0e5 | ||
|
|
c8edf3151b | ||
|
|
45cf50c2af | ||
|
|
c233094846 | ||
|
|
fa3d401226 | ||
|
|
7cf5210063 | ||
|
|
9a95b9bcda | ||
|
|
c09df2e3f1 | ||
|
|
8f115bfd06 | ||
|
|
91d224eea5 | ||
|
|
fb0f9ec601 | ||
|
|
b8d45ae927 | ||
|
|
e2ef0dc71d | ||
|
|
d46442245b | ||
|
|
435638a5bb | ||
|
|
954b0612d5 | ||
|
|
14db0dfcc7 | ||
|
|
c040d4847b | ||
|
|
dc9f171ee6 | ||
|
|
b4958e7d58 | ||
|
|
a077b70d66 | ||
|
|
535d1e2565 | ||
|
|
55df481e5c | ||
|
|
083be305e1 | ||
|
|
38ecde0cc1 | ||
|
|
3a9ffe189e | ||
|
|
9e2f0b5ed0 | ||
|
|
bf3fb685ad | ||
|
|
14cfb82a8c | ||
|
|
e0782683eb | ||
|
|
60f3598da9 | ||
|
|
e25c0498d4 | ||
|
|
28eb2caacb | ||
|
|
6538a7645d | ||
|
|
1f8a51cffe | ||
|
|
e745df6478 | ||
|
|
6ad8a4db1c | ||
|
|
0cf702a74f | ||
|
|
3c5b9ce0cd | ||
|
|
104700f6d3 | ||
|
|
7af3d239ab | ||
|
|
08cc8b8e80 | ||
|
|
f42bd28ca9 | ||
|
|
741735cc83 | ||
|
|
3939167ba2 | ||
|
|
dafcd5ec98 | ||
|
|
a1e38c3444 | ||
|
|
9d90c24006 | ||
|
|
f288ddc3d5 | ||
|
|
d923784ae4 | ||
|
|
90c63ab6b0 | ||
|
|
2fb4dfeb90 | ||
|
|
665b140a8a | ||
|
|
700201556c | ||
|
|
58dae6d1c6 | ||
|
|
2a91743477 | ||
|
|
a28f19c857 | ||
|
|
c689065f83 | ||
|
|
855d96db66 | ||
|
|
d85284da55 | ||
|
|
02c98fae5f | ||
|
|
1ad06f3293 | ||
|
|
9c15cf18e8 | ||
|
|
3b0b5e403c | ||
|
|
a2bcc97a74 | ||
|
|
743814a234 | ||
|
|
c2d072e3f8 | ||
|
|
22d968fba3 | ||
|
|
31b069041f | ||
|
|
a8eb95a688 | ||
|
|
64d23d4f9b | ||
|
|
5b2d226c35 | ||
|
|
1edca19419 | ||
|
|
24c809b3b5 | ||
|
|
72a1289eba | ||
|
|
c6641dfbf3 | ||
|
|
a85df81b67 | ||
|
|
0612b3795a | ||
|
|
3ee0fa9bc4 | ||
|
|
b77b3763be | ||
|
|
8eeb861963 | ||
|
|
2f53adf2c2 | ||
|
|
dbb5aa9aad | ||
|
|
083a5068c3 | ||
|
|
886c85ddc1 | ||
|
|
958c6ff289 | ||
|
|
ee6cb96d07 | ||
|
|
3219edc603 | ||
|
|
6b94b77a0a | ||
|
|
f8c3b2977a | ||
|
|
f783ca7940 | ||
|
|
96d6ecb108 | ||
|
|
35e19eac96 | ||
|
|
4f8908106b | ||
|
|
f7c07d55ed | ||
|
|
49218cdbfb | ||
|
|
18661eee77 | ||
|
|
66486b08dc | ||
|
|
4aec302fb7 | ||
|
|
eccde3f4f1 | ||
|
|
be494b73d4 | ||
|
|
fb470e4140 | ||
|
|
bf503849ea | ||
|
|
bf6e6a1e68 | ||
|
|
a245d0019e | ||
|
|
9196939384 | ||
|
|
d2d70cc782 | ||
|
|
79f675cdb7 | ||
|
|
a5206028b0 | ||
|
|
d3063e849e | ||
|
|
4cf40ed259 | ||
|
|
2f0ee12584 | ||
|
|
f22d60f011 | ||
|
|
e8f548ab52 | ||
|
|
24687b4156 | ||
|
|
8b23140a08 | ||
|
|
60e7786b04 | ||
|
|
46e44a0036 | ||
|
|
e3dbdc3887 | ||
|
|
a0e2e1ef21 | ||
|
|
1fe565a46f | ||
|
|
3f1e145d2c | ||
|
|
a24e168ec0 | ||
|
|
36f1070b93 | ||
|
|
fc1fc05d16 | ||
|
|
fbfafbfdd4 | ||
|
|
eb3e140008 | ||
|
|
0a0ce1f202 | ||
|
|
20bf3c7f67 | ||
|
|
3ac3169278 | ||
|
|
242f7e1c53 | ||
|
|
18edef6ea4 | ||
|
|
bbeb7b39d7 | ||
|
|
76e56cdac7 | ||
|
|
ad2631202d | ||
|
|
6c8cc79b4d | ||
|
|
a23904ca39 | ||
|
|
3ab5fd5ca4 | ||
|
|
97c27ac11b | ||
|
|
58f4cd77dc | ||
|
|
0eb0c238f3 | ||
|
|
bafe357500 | ||
|
|
0c40223192 | ||
|
|
a8aeb1d03e | ||
|
|
522a2e2594 | ||
|
|
52007fb9a2 | ||
|
|
54a44777b7 | ||
|
|
08c54767f2 | ||
|
|
d654e98650 | ||
|
|
1a9bfb38aa | ||
|
|
bf9d0b93d7 | ||
|
|
1a51c015b4 |
@@ -8,6 +8,8 @@
|
|||||||
/swift/ @github/codeql-swift
|
/swift/ @github/codeql-swift
|
||||||
/misc/codegen/ @github/codeql-swift
|
/misc/codegen/ @github/codeql-swift
|
||||||
/java/kotlin-extractor/ @github/codeql-kotlin
|
/java/kotlin-extractor/ @github/codeql-kotlin
|
||||||
|
/java/ql/test-kotlin1/ @github/codeql-kotlin
|
||||||
|
/java/ql/test-kotlin2/ @github/codeql-kotlin
|
||||||
|
|
||||||
# ML-powered queries
|
# ML-powered queries
|
||||||
/javascript/ql/experimental/adaptivethreatmodeling/ @github/codeql-ml-powered-queries-reviewers
|
/javascript/ql/experimental/adaptivethreatmodeling/ @github/codeql-ml-powered-queries-reviewers
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
provide:
|
provide:
|
||||||
- "*/ql/src/qlpack.yml"
|
- "*/ql/src/qlpack.yml"
|
||||||
- "*/ql/lib/qlpack.yml"
|
- "*/ql/lib/qlpack.yml"
|
||||||
- "*/ql/test/qlpack.yml"
|
- "*/ql/test*/qlpack.yml"
|
||||||
- "*/ql/examples/qlpack.yml"
|
- "*/ql/examples/qlpack.yml"
|
||||||
- "*/ql/consistency-queries/qlpack.yml"
|
- "*/ql/consistency-queries/qlpack.yml"
|
||||||
- "*/ql/automodel/src/qlpack.yml"
|
- "*/ql/automodel/src/qlpack.yml"
|
||||||
@@ -29,6 +29,7 @@ provide:
|
|||||||
- "swift/extractor-pack/codeql-extractor.yml"
|
- "swift/extractor-pack/codeql-extractor.yml"
|
||||||
- "swift/integration-tests/qlpack.yml"
|
- "swift/integration-tests/qlpack.yml"
|
||||||
- "ql/extractor-pack/codeql-extractor.yml"
|
- "ql/extractor-pack/codeql-extractor.yml"
|
||||||
|
- ".github/codeql/extensions/**/codeql-pack.yml"
|
||||||
|
|
||||||
versionPolicies:
|
versionPolicies:
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -145,9 +145,9 @@ namespace Semmle.Autobuild.Cpp.Tests
|
|||||||
|
|
||||||
bool IBuildActions.IsMacOs() => IsMacOs;
|
bool IBuildActions.IsMacOs() => IsMacOs;
|
||||||
|
|
||||||
public bool IsArm { get; set; }
|
public bool IsRunningOnAppleSilicon { get; set; }
|
||||||
|
|
||||||
bool IBuildActions.IsArm() => IsArm;
|
bool IBuildActions.IsRunningOnAppleSilicon() => IsRunningOnAppleSilicon;
|
||||||
|
|
||||||
string IBuildActions.PathCombine(params string[] parts)
|
string IBuildActions.PathCombine(params string[] parts)
|
||||||
{
|
{
|
||||||
|
|||||||
2231
cpp/downgrades/8cba93a44180e0d50a80a660950800d822b981fc/old.dbscheme
Normal file
2231
cpp/downgrades/8cba93a44180e0d50a80a660950800d822b981fc/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
|||||||
|
description: Removed @assignpaddexpr and @assignpsubexpr from @assign_bitwise_expr
|
||||||
|
compatibility: full
|
||||||
@@ -1,3 +1,17 @@
|
|||||||
|
## 0.12.0
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
* The expressions `AssignPointerAddExpr` and `AssignPointerSubExpr` are no longer subtypes of `AssignBitwiseOperation`.
|
||||||
|
|
||||||
|
### Minor Analysis Improvements
|
||||||
|
|
||||||
|
* The "Returning stack-allocated memory" (`cpp/return-stack-allocated-memory`) query now also detects returning stack-allocated memory allocated by calls to `alloca`, `strdupa`, and `strndupa`.
|
||||||
|
* Added models for `strlcpy` and `strlcat`.
|
||||||
|
* Added models for the `sprintf` variants from the `StrSafe.h` header.
|
||||||
|
* Added SQL API models for `ODBC`.
|
||||||
|
* Added taint models for `realloc` and related functions.
|
||||||
|
|
||||||
## 0.11.0
|
## 0.11.0
|
||||||
|
|
||||||
### Breaking Changes
|
### Breaking Changes
|
||||||
|
|||||||
13
cpp/ql/lib/change-notes/released/0.12.0.md
Normal file
13
cpp/ql/lib/change-notes/released/0.12.0.md
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
## 0.12.0
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
* The expressions `AssignPointerAddExpr` and `AssignPointerSubExpr` are no longer subtypes of `AssignBitwiseOperation`.
|
||||||
|
|
||||||
|
### Minor Analysis Improvements
|
||||||
|
|
||||||
|
* The "Returning stack-allocated memory" (`cpp/return-stack-allocated-memory`) query now also detects returning stack-allocated memory allocated by calls to `alloca`, `strdupa`, and `strndupa`.
|
||||||
|
* Added models for `strlcpy` and `strlcat`.
|
||||||
|
* Added models for the `sprintf` variants from the `StrSafe.h` header.
|
||||||
|
* Added SQL API models for `ODBC`.
|
||||||
|
* Added taint models for `realloc` and related functions.
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
---
|
---
|
||||||
lastReleaseVersion: 0.11.0
|
lastReleaseVersion: 0.12.0
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/cpp-all
|
name: codeql/cpp-all
|
||||||
version: 0.11.0
|
version: 0.12.1-dev
|
||||||
groups: cpp
|
groups: cpp
|
||||||
dbscheme: semmlecode.cpp.dbscheme
|
dbscheme: semmlecode.cpp.dbscheme
|
||||||
extractor: cpp
|
extractor: cpp
|
||||||
|
|||||||
@@ -30,11 +30,6 @@ class GuardCondition extends Expr {
|
|||||||
or
|
or
|
||||||
// no binary operators in the IR
|
// no binary operators in the IR
|
||||||
this.(BinaryLogicalOperation).getAnOperand() instanceof GuardCondition
|
this.(BinaryLogicalOperation).getAnOperand() instanceof GuardCondition
|
||||||
or
|
|
||||||
// the IR short-circuits if(!x)
|
|
||||||
// don't produce a guard condition for `y = !x` and other non-short-circuited cases
|
|
||||||
not exists(Instruction inst | this.getFullyConverted() = inst.getAst()) and
|
|
||||||
exists(IRGuardCondition ir | this.(NotExpr).getOperand() = ir.getAst())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -140,39 +135,6 @@ private class GuardConditionFromBinaryLogicalOperator extends GuardCondition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A `!` operator in the AST that guards one or more basic blocks, and does not have a corresponding
|
|
||||||
* IR instruction.
|
|
||||||
*/
|
|
||||||
private class GuardConditionFromShortCircuitNot extends GuardCondition, NotExpr {
|
|
||||||
GuardConditionFromShortCircuitNot() {
|
|
||||||
not exists(Instruction inst | this.getFullyConverted() = inst.getAst()) and
|
|
||||||
exists(IRGuardCondition ir | this.getOperand() = ir.getAst())
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate controls(BasicBlock controlled, boolean testIsTrue) {
|
|
||||||
this.getOperand().(GuardCondition).controls(controlled, testIsTrue.booleanNot())
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate comparesLt(Expr left, Expr right, int k, boolean isLessThan, boolean testIsTrue) {
|
|
||||||
this.getOperand()
|
|
||||||
.(GuardCondition)
|
|
||||||
.comparesLt(left, right, k, isLessThan, testIsTrue.booleanNot())
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate ensuresLt(Expr left, Expr right, int k, BasicBlock block, boolean isLessThan) {
|
|
||||||
this.getOperand().(GuardCondition).ensuresLt(left, right, k, block, isLessThan.booleanNot())
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate comparesEq(Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue) {
|
|
||||||
this.getOperand().(GuardCondition).comparesEq(left, right, k, areEqual, testIsTrue.booleanNot())
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate ensuresEq(Expr left, Expr right, int k, BasicBlock block, boolean areEqual) {
|
|
||||||
this.getOperand().(GuardCondition).ensuresEq(left, right, k, block, areEqual.booleanNot())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Boolean condition in the AST that guards one or more basic blocks and has a corresponding IR
|
* A Boolean condition in the AST that guards one or more basic blocks and has a corresponding IR
|
||||||
* instruction.
|
* instruction.
|
||||||
|
|||||||
@@ -31,6 +31,11 @@ abstract class MustFlowConfiguration extends string {
|
|||||||
*/
|
*/
|
||||||
abstract predicate isSink(Operand sink);
|
abstract predicate isSink(Operand sink);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data flow through `instr` is prohibited.
|
||||||
|
*/
|
||||||
|
predicate isBarrier(Instruction instr) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||||
* into account in the analysis.
|
* into account in the analysis.
|
||||||
@@ -48,18 +53,21 @@ abstract class MustFlowConfiguration extends string {
|
|||||||
*/
|
*/
|
||||||
final predicate hasFlowPath(MustFlowPathNode source, MustFlowPathSink sink) {
|
final predicate hasFlowPath(MustFlowPathNode source, MustFlowPathSink sink) {
|
||||||
this.isSource(source.getInstruction()) and
|
this.isSource(source.getInstruction()) and
|
||||||
source.getASuccessor+() = sink
|
source.getASuccessor*() = sink
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if `node` flows from a source. */
|
/** Holds if `node` flows from a source. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate flowsFromSource(Instruction node, MustFlowConfiguration config) {
|
private predicate flowsFromSource(Instruction node, MustFlowConfiguration config) {
|
||||||
config.isSource(node)
|
not config.isBarrier(node) and
|
||||||
or
|
(
|
||||||
exists(Instruction mid |
|
config.isSource(node)
|
||||||
step(mid, node, config) and
|
or
|
||||||
flowsFromSource(mid, pragma[only_bind_into](config))
|
exists(Instruction mid |
|
||||||
|
step(mid, node, config) and
|
||||||
|
flowsFromSource(mid, pragma[only_bind_into](config))
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -81,6 +81,14 @@ class Node0Impl extends TIRDataFlowNode0 {
|
|||||||
/** Gets the operands corresponding to this node, if any. */
|
/** Gets the operands corresponding to this node, if any. */
|
||||||
Operand asOperand() { result = this.(OperandNode0).getOperand() }
|
Operand asOperand() { result = this.(OperandNode0).getOperand() }
|
||||||
|
|
||||||
|
/** Gets the location of this node. */
|
||||||
|
final Location getLocation() { result = this.getLocationImpl() }
|
||||||
|
|
||||||
|
/** INTERNAL: Do not use. */
|
||||||
|
Location getLocationImpl() {
|
||||||
|
none() // overridden by subclasses
|
||||||
|
}
|
||||||
|
|
||||||
/** INTERNAL: Do not use. */
|
/** INTERNAL: Do not use. */
|
||||||
string toStringImpl() {
|
string toStringImpl() {
|
||||||
none() // overridden by subclasses
|
none() // overridden by subclasses
|
||||||
@@ -131,9 +139,15 @@ abstract class InstructionNode0 extends Node0Impl {
|
|||||||
override DataFlowType getType() { result = getInstructionType(instr, _) }
|
override DataFlowType getType() { result = getInstructionType(instr, _) }
|
||||||
|
|
||||||
override string toStringImpl() {
|
override string toStringImpl() {
|
||||||
// This predicate is overridden in subclasses. This default implementation
|
if instr.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
|
||||||
// does not use `Instruction.toString` because that's expensive to compute.
|
then result = "this"
|
||||||
result = instr.getOpcode().toString()
|
else result = instr.getAst().toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override Location getLocationImpl() {
|
||||||
|
if exists(instr.getAst().getLocation())
|
||||||
|
then result = instr.getAst().getLocation()
|
||||||
|
else result instanceof UnknownDefaultLocation
|
||||||
}
|
}
|
||||||
|
|
||||||
final override predicate isGLValue() { exists(getInstructionType(instr, true)) }
|
final override predicate isGLValue() { exists(getInstructionType(instr, true)) }
|
||||||
@@ -173,7 +187,17 @@ abstract class OperandNode0 extends Node0Impl {
|
|||||||
|
|
||||||
override DataFlowType getType() { result = getOperandType(op, _) }
|
override DataFlowType getType() { result = getOperandType(op, _) }
|
||||||
|
|
||||||
override string toStringImpl() { result = op.toString() }
|
override string toStringImpl() {
|
||||||
|
if op.getDef().(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
|
||||||
|
then result = "this"
|
||||||
|
else result = op.getDef().getAst().toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override Location getLocationImpl() {
|
||||||
|
if exists(op.getDef().getAst().getLocation())
|
||||||
|
then result = op.getDef().getAst().getLocation()
|
||||||
|
else result instanceof UnknownDefaultLocation
|
||||||
|
}
|
||||||
|
|
||||||
final override predicate isGLValue() { exists(getOperandType(op, true)) }
|
final override predicate isGLValue() { exists(getOperandType(op, true)) }
|
||||||
}
|
}
|
||||||
@@ -621,6 +645,24 @@ class GlobalLikeVariable extends Variable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the smallest indirection for the type `t`.
|
||||||
|
*
|
||||||
|
* For most types this is `1`, but for `ArrayType`s (which are allocated on
|
||||||
|
* the stack) this is `0`
|
||||||
|
*/
|
||||||
|
int getMinIndirectionsForType(Type t) {
|
||||||
|
if t.getUnspecifiedType() instanceof Cpp::ArrayType then result = 0 else result = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getMinIndirectionForGlobalUse(Ssa::GlobalUse use) {
|
||||||
|
result = getMinIndirectionsForType(use.getUnspecifiedType())
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getMinIndirectionForGlobalDef(Ssa::GlobalDef def) {
|
||||||
|
result = getMinIndirectionsForType(def.getUnspecifiedType())
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if data can flow from `node1` to `node2` in a way that loses the
|
* Holds if data can flow from `node1` to `node2` in a way that loses the
|
||||||
* calling context. For example, this would happen with flow through a
|
* calling context. For example, this would happen with flow through a
|
||||||
@@ -632,20 +674,20 @@ predicate jumpStep(Node n1, Node n2) {
|
|||||||
v = globalUse.getVariable() and
|
v = globalUse.getVariable() and
|
||||||
n1.(FinalGlobalValue).getGlobalUse() = globalUse
|
n1.(FinalGlobalValue).getGlobalUse() = globalUse
|
||||||
|
|
|
|
||||||
globalUse.getIndirectionIndex() = 1 and
|
globalUse.getIndirection() = getMinIndirectionForGlobalUse(globalUse) and
|
||||||
v = n2.asVariable()
|
v = n2.asVariable()
|
||||||
or
|
or
|
||||||
v = n2.asIndirectVariable(globalUse.getIndirectionIndex())
|
v = n2.asIndirectVariable(globalUse.getIndirection())
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(Ssa::GlobalDef globalDef |
|
exists(Ssa::GlobalDef globalDef |
|
||||||
v = globalDef.getVariable() and
|
v = globalDef.getVariable() and
|
||||||
n2.(InitialGlobalValue).getGlobalDef() = globalDef
|
n2.(InitialGlobalValue).getGlobalDef() = globalDef
|
||||||
|
|
|
|
||||||
globalDef.getIndirectionIndex() = 1 and
|
globalDef.getIndirection() = getMinIndirectionForGlobalDef(globalDef) and
|
||||||
v = n1.asVariable()
|
v = n1.asVariable()
|
||||||
or
|
or
|
||||||
v = n1.asIndirectVariable(globalDef.getIndirectionIndex())
|
v = n1.asIndirectVariable(globalDef.getIndirection())
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,8 @@ cached
|
|||||||
private newtype TIRDataFlowNode =
|
private newtype TIRDataFlowNode =
|
||||||
TNode0(Node0Impl node) { DataFlowImplCommon::forceCachingInSameStage() } or
|
TNode0(Node0Impl node) { DataFlowImplCommon::forceCachingInSameStage() } or
|
||||||
TVariableNode(Variable var, int indirectionIndex) {
|
TVariableNode(Variable var, int indirectionIndex) {
|
||||||
indirectionIndex = [1 .. Ssa::getMaxIndirectionsForType(var.getUnspecifiedType())]
|
indirectionIndex =
|
||||||
|
[getMinIndirectionsForType(var.getUnspecifiedType()) .. Ssa::getMaxIndirectionsForType(var.getUnspecifiedType())]
|
||||||
} or
|
} or
|
||||||
TPostFieldUpdateNode(FieldAddress operand, int indirectionIndex) {
|
TPostFieldUpdateNode(FieldAddress operand, int indirectionIndex) {
|
||||||
indirectionIndex =
|
indirectionIndex =
|
||||||
@@ -44,11 +45,12 @@ private newtype TIRDataFlowNode =
|
|||||||
TIndirectArgumentOutNode(ArgumentOperand operand, int indirectionIndex) {
|
TIndirectArgumentOutNode(ArgumentOperand operand, int indirectionIndex) {
|
||||||
Ssa::isModifiableByCall(operand, indirectionIndex)
|
Ssa::isModifiableByCall(operand, indirectionIndex)
|
||||||
} or
|
} or
|
||||||
TRawIndirectOperand(Operand op, int indirectionIndex) {
|
TRawIndirectOperand0(Node0Impl node, int indirectionIndex) {
|
||||||
Ssa::hasRawIndirectOperand(op, indirectionIndex)
|
Ssa::hasRawIndirectOperand(node.asOperand(), indirectionIndex)
|
||||||
} or
|
} or
|
||||||
TRawIndirectInstruction(Instruction instr, int indirectionIndex) {
|
TRawIndirectInstruction0(Node0Impl node, int indirectionIndex) {
|
||||||
Ssa::hasRawIndirectInstruction(instr, indirectionIndex)
|
not exists(node.asOperand()) and
|
||||||
|
Ssa::hasRawIndirectInstruction(node.asInstruction(), indirectionIndex)
|
||||||
} or
|
} or
|
||||||
TFinalParameterNode(Parameter p, int indirectionIndex) {
|
TFinalParameterNode(Parameter p, int indirectionIndex) {
|
||||||
exists(Ssa::FinalParameterUse use |
|
exists(Ssa::FinalParameterUse use |
|
||||||
@@ -345,7 +347,9 @@ class Node extends TIRDataFlowNode {
|
|||||||
* Gets the variable corresponding to this node, if any. This can be used for
|
* Gets the variable corresponding to this node, if any. This can be used for
|
||||||
* modeling flow in and out of global variables.
|
* modeling flow in and out of global variables.
|
||||||
*/
|
*/
|
||||||
Variable asVariable() { this = TVariableNode(result, 1) }
|
Variable asVariable() {
|
||||||
|
this = TVariableNode(result, getMinIndirectionsForType(result.getUnspecifiedType()))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the `indirectionIndex`'th indirection of this node's underlying variable, if any.
|
* Gets the `indirectionIndex`'th indirection of this node's underlying variable, if any.
|
||||||
@@ -353,7 +357,7 @@ class Node extends TIRDataFlowNode {
|
|||||||
* This can be used for modeling flow in and out of global variables.
|
* This can be used for modeling flow in and out of global variables.
|
||||||
*/
|
*/
|
||||||
Variable asIndirectVariable(int indirectionIndex) {
|
Variable asIndirectVariable(int indirectionIndex) {
|
||||||
indirectionIndex > 1 and
|
indirectionIndex > getMinIndirectionsForType(result.getUnspecifiedType()) and
|
||||||
this = TVariableNode(result, indirectionIndex)
|
this = TVariableNode(result, indirectionIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,6 +435,10 @@ private class Node0 extends Node, TNode0 {
|
|||||||
|
|
||||||
override Declaration getFunction() { result = node.getFunction() }
|
override Declaration getFunction() { result = node.getFunction() }
|
||||||
|
|
||||||
|
override Location getLocationImpl() { result = node.getLocation() }
|
||||||
|
|
||||||
|
override string toStringImpl() { result = node.toString() }
|
||||||
|
|
||||||
override DataFlowType getType() { result = node.getType() }
|
override DataFlowType getType() { result = node.getType() }
|
||||||
|
|
||||||
override predicate isGLValue() { node.isGLValue() }
|
override predicate isGLValue() { node.isGLValue() }
|
||||||
@@ -447,18 +455,6 @@ class InstructionNode extends Node0 {
|
|||||||
|
|
||||||
/** Gets the instruction corresponding to this node. */
|
/** Gets the instruction corresponding to this node. */
|
||||||
Instruction getInstruction() { result = instr }
|
Instruction getInstruction() { result = instr }
|
||||||
|
|
||||||
override Location getLocationImpl() {
|
|
||||||
if exists(instr.getAst().getLocation())
|
|
||||||
then result = instr.getAst().getLocation()
|
|
||||||
else result instanceof UnknownDefaultLocation
|
|
||||||
}
|
|
||||||
|
|
||||||
override string toStringImpl() {
|
|
||||||
if instr.(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
|
|
||||||
then result = "this"
|
|
||||||
else result = instr.getAst().toString()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -472,18 +468,6 @@ class OperandNode extends Node, Node0 {
|
|||||||
|
|
||||||
/** Gets the operand corresponding to this node. */
|
/** Gets the operand corresponding to this node. */
|
||||||
Operand getOperand() { result = op }
|
Operand getOperand() { result = op }
|
||||||
|
|
||||||
override Location getLocationImpl() {
|
|
||||||
if exists(op.getDef().getAst().getLocation())
|
|
||||||
then result = op.getDef().getAst().getLocation()
|
|
||||||
else result instanceof UnknownDefaultLocation
|
|
||||||
}
|
|
||||||
|
|
||||||
override string toStringImpl() {
|
|
||||||
if op.getDef().(InitializeParameterInstruction).getIRVariable() instanceof IRThisVariable
|
|
||||||
then result = "this"
|
|
||||||
else result = op.getDef().getAst().toString()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -918,48 +902,146 @@ Type getTypeImpl(Type t, int indirectionIndex) {
|
|||||||
result instanceof UnknownType
|
result instanceof UnknownType
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private module RawIndirectNodes {
|
||||||
* INTERNAL: Do not use.
|
/**
|
||||||
*
|
* INTERNAL: Do not use.
|
||||||
* A node that represents the indirect value of an operand in the IR
|
*
|
||||||
* after `index` number of loads.
|
* A node that represents the indirect value of an operand in the IR
|
||||||
*/
|
* after `index` number of loads.
|
||||||
class RawIndirectOperand extends Node, TRawIndirectOperand {
|
*/
|
||||||
Operand operand;
|
private class RawIndirectOperand0 extends Node, TRawIndirectOperand0 {
|
||||||
int indirectionIndex;
|
Node0Impl node;
|
||||||
|
int indirectionIndex;
|
||||||
|
|
||||||
RawIndirectOperand() { this = TRawIndirectOperand(operand, indirectionIndex) }
|
RawIndirectOperand0() { this = TRawIndirectOperand0(node, indirectionIndex) }
|
||||||
|
|
||||||
/** Gets the underlying instruction. */
|
/** Gets the underlying instruction. */
|
||||||
Operand getOperand() { result = operand }
|
Operand getOperand() { result = node.asOperand() }
|
||||||
|
|
||||||
/** Gets the underlying indirection index. */
|
/** Gets the underlying indirection index. */
|
||||||
int getIndirectionIndex() { result = indirectionIndex }
|
int getIndirectionIndex() { result = indirectionIndex }
|
||||||
|
|
||||||
override Declaration getFunction() { result = this.getOperand().getDef().getEnclosingFunction() }
|
override Declaration getFunction() {
|
||||||
|
result = this.getOperand().getDef().getEnclosingFunction()
|
||||||
|
}
|
||||||
|
|
||||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||||
|
|
||||||
override DataFlowType getType() {
|
override DataFlowType getType() {
|
||||||
exists(int sub, DataFlowType type, boolean isGLValue |
|
exists(int sub, DataFlowType type, boolean isGLValue |
|
||||||
type = getOperandType(operand, isGLValue) and
|
type = getOperandType(this.getOperand(), isGLValue) and
|
||||||
if isGLValue = true then sub = 1 else sub = 0
|
if isGLValue = true then sub = 1 else sub = 0
|
||||||
|
|
|
|
||||||
result = getTypeImpl(type.getUnspecifiedType(), indirectionIndex - sub)
|
result = getTypeImpl(type.getUnspecifiedType(), indirectionIndex - sub)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
final override Location getLocationImpl() {
|
||||||
|
if exists(this.getOperand().getLocation())
|
||||||
|
then result = this.getOperand().getLocation()
|
||||||
|
else result instanceof UnknownDefaultLocation
|
||||||
|
}
|
||||||
|
|
||||||
|
override string toStringImpl() {
|
||||||
|
result = operandNode(this.getOperand()).toStringImpl() + " indirection"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final override Location getLocationImpl() {
|
/**
|
||||||
if exists(this.getOperand().getLocation())
|
* INTERNAL: Do not use.
|
||||||
then result = this.getOperand().getLocation()
|
*
|
||||||
else result instanceof UnknownDefaultLocation
|
* A node that represents the indirect value of an instruction in the IR
|
||||||
|
* after `index` number of loads.
|
||||||
|
*/
|
||||||
|
private class RawIndirectInstruction0 extends Node, TRawIndirectInstruction0 {
|
||||||
|
Node0Impl node;
|
||||||
|
int indirectionIndex;
|
||||||
|
|
||||||
|
RawIndirectInstruction0() { this = TRawIndirectInstruction0(node, indirectionIndex) }
|
||||||
|
|
||||||
|
/** Gets the underlying instruction. */
|
||||||
|
Instruction getInstruction() { result = node.asInstruction() }
|
||||||
|
|
||||||
|
/** Gets the underlying indirection index. */
|
||||||
|
int getIndirectionIndex() { result = indirectionIndex }
|
||||||
|
|
||||||
|
override Declaration getFunction() { result = this.getInstruction().getEnclosingFunction() }
|
||||||
|
|
||||||
|
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||||
|
|
||||||
|
override DataFlowType getType() {
|
||||||
|
exists(int sub, DataFlowType type, boolean isGLValue |
|
||||||
|
type = getInstructionType(this.getInstruction(), isGLValue) and
|
||||||
|
if isGLValue = true then sub = 1 else sub = 0
|
||||||
|
|
|
||||||
|
result = getTypeImpl(type.getUnspecifiedType(), indirectionIndex - sub)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
final override Location getLocationImpl() {
|
||||||
|
if exists(this.getInstruction().getLocation())
|
||||||
|
then result = this.getInstruction().getLocation()
|
||||||
|
else result instanceof UnknownDefaultLocation
|
||||||
|
}
|
||||||
|
|
||||||
|
override string toStringImpl() {
|
||||||
|
result = instructionNode(this.getInstruction()).toStringImpl() + " indirection"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override string toStringImpl() {
|
/**
|
||||||
result = operandNode(this.getOperand()).toStringImpl() + " indirection"
|
* INTERNAL: Do not use.
|
||||||
|
*
|
||||||
|
* A node that represents the indirect value of an operand in the IR
|
||||||
|
* after a number of loads.
|
||||||
|
*/
|
||||||
|
class RawIndirectOperand extends Node {
|
||||||
|
int indirectionIndex;
|
||||||
|
Operand operand;
|
||||||
|
|
||||||
|
RawIndirectOperand() {
|
||||||
|
exists(Node0Impl node | operand = node.asOperand() |
|
||||||
|
this = TRawIndirectOperand0(node, indirectionIndex)
|
||||||
|
or
|
||||||
|
this = TRawIndirectInstruction0(node, indirectionIndex)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets the operand associated with this node. */
|
||||||
|
Operand getOperand() { result = operand }
|
||||||
|
|
||||||
|
/** Gets the underlying indirection index. */
|
||||||
|
int getIndirectionIndex() { result = indirectionIndex }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* INTERNAL: Do not use.
|
||||||
|
*
|
||||||
|
* A node that represents the indirect value of an instruction in the IR
|
||||||
|
* after a number of loads.
|
||||||
|
*/
|
||||||
|
class RawIndirectInstruction extends Node {
|
||||||
|
int indirectionIndex;
|
||||||
|
Instruction instr;
|
||||||
|
|
||||||
|
RawIndirectInstruction() {
|
||||||
|
exists(Node0Impl node | instr = node.asInstruction() |
|
||||||
|
this = TRawIndirectOperand0(node, indirectionIndex)
|
||||||
|
or
|
||||||
|
this = TRawIndirectInstruction0(node, indirectionIndex)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets the instruction associated with this node. */
|
||||||
|
Instruction getInstruction() { result = instr }
|
||||||
|
|
||||||
|
/** Gets the underlying indirection index. */
|
||||||
|
int getIndirectionIndex() { result = indirectionIndex }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import RawIndirectNodes
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* INTERNAL: do not use.
|
* INTERNAL: do not use.
|
||||||
*
|
*
|
||||||
@@ -1021,48 +1103,6 @@ class UninitializedNode extends Node {
|
|||||||
LocalVariable getLocalVariable() { result = v }
|
LocalVariable getLocalVariable() { result = v }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* INTERNAL: Do not use.
|
|
||||||
*
|
|
||||||
* A node that represents the indirect value of an instruction in the IR
|
|
||||||
* after `index` number of loads.
|
|
||||||
*/
|
|
||||||
class RawIndirectInstruction extends Node, TRawIndirectInstruction {
|
|
||||||
Instruction instr;
|
|
||||||
int indirectionIndex;
|
|
||||||
|
|
||||||
RawIndirectInstruction() { this = TRawIndirectInstruction(instr, indirectionIndex) }
|
|
||||||
|
|
||||||
/** Gets the underlying instruction. */
|
|
||||||
Instruction getInstruction() { result = instr }
|
|
||||||
|
|
||||||
/** Gets the underlying indirection index. */
|
|
||||||
int getIndirectionIndex() { result = indirectionIndex }
|
|
||||||
|
|
||||||
override Declaration getFunction() { result = this.getInstruction().getEnclosingFunction() }
|
|
||||||
|
|
||||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
|
||||||
|
|
||||||
override DataFlowType getType() {
|
|
||||||
exists(int sub, DataFlowType type, boolean isGLValue |
|
|
||||||
type = getInstructionType(instr, isGLValue) and
|
|
||||||
if isGLValue = true then sub = 1 else sub = 0
|
|
||||||
|
|
|
||||||
result = getTypeImpl(type.getUnspecifiedType(), indirectionIndex - sub)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
final override Location getLocationImpl() {
|
|
||||||
if exists(this.getInstruction().getLocation())
|
|
||||||
then result = this.getInstruction().getLocation()
|
|
||||||
else result instanceof UnknownDefaultLocation
|
|
||||||
}
|
|
||||||
|
|
||||||
override string toStringImpl() {
|
|
||||||
result = instructionNode(this.getInstruction()).toStringImpl() + " indirection"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private module GetConvertedResultExpression {
|
private module GetConvertedResultExpression {
|
||||||
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedExpr
|
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedExpr
|
||||||
private import semmle.code.cpp.ir.implementation.raw.internal.InstructionTag
|
private import semmle.code.cpp.ir.implementation.raw.internal.InstructionTag
|
||||||
@@ -1236,31 +1276,90 @@ abstract private class IndirectExprNodeBase extends Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class IndirectOperandIndirectExprNode extends IndirectExprNodeBase instanceof IndirectOperand
|
/** A signature for converting an indirect node to an expression. */
|
||||||
{
|
private signature module IndirectNodeToIndirectExprSig {
|
||||||
IndirectOperandIndirectExprNode() {
|
/** The indirect node class to be converted to an expression */
|
||||||
exists(Expr e, int n, int indirectionIndex |
|
class IndirectNode;
|
||||||
indirectExprNodeShouldBeIndirectOperand(this, e, n, indirectionIndex) and
|
|
||||||
not indirectExprNodeShouldBeIndirectOperand(_, e, n + 1, indirectionIndex)
|
/**
|
||||||
)
|
* Holds if the indirect expression at indirection index `indirectionIndex`
|
||||||
|
* of `node` is `e`. The integer `n` specifies how many conversions has been
|
||||||
|
* applied to `node`.
|
||||||
|
*/
|
||||||
|
predicate indirectNodeHasIndirectExpr(IndirectNode node, Expr e, int n, int indirectionIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A module that implements the logic for deciding whether an indirect node
|
||||||
|
* should be an `IndirectExprNode`.
|
||||||
|
*/
|
||||||
|
private module IndirectNodeToIndirectExpr<IndirectNodeToIndirectExprSig Sig> {
|
||||||
|
import Sig
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This predicate shifts the indirection index by one when `conv` is a
|
||||||
|
* `ReferenceDereferenceExpr`.
|
||||||
|
*
|
||||||
|
* This is necessary because `ReferenceDereferenceExpr` is a conversion
|
||||||
|
* in the AST, but appears as a `LoadInstruction` in the IR.
|
||||||
|
*/
|
||||||
|
bindingset[e, indirectionIndex]
|
||||||
|
private predicate adjustForReference(
|
||||||
|
Expr e, int indirectionIndex, Expr conv, int adjustedIndirectionIndex
|
||||||
|
) {
|
||||||
|
conv.(ReferenceDereferenceExpr).getExpr() = e and
|
||||||
|
adjustedIndirectionIndex = indirectionIndex - 1
|
||||||
|
or
|
||||||
|
not conv instanceof ReferenceDereferenceExpr and
|
||||||
|
conv = e and
|
||||||
|
adjustedIndirectionIndex = indirectionIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
final override Expr getConvertedExpr(int n, int index) {
|
/** Holds if `node` should be an `IndirectExprNode`. */
|
||||||
indirectExprNodeShouldBeIndirectOperand(this, result, n, index)
|
predicate charpred(IndirectNode node) {
|
||||||
|
exists(Expr e, int n, int indirectionIndex |
|
||||||
|
indirectNodeHasIndirectExpr(node, e, n, indirectionIndex) and
|
||||||
|
not exists(Expr conv, int adjustedIndirectionIndex |
|
||||||
|
adjustForReference(e, indirectionIndex, conv, adjustedIndirectionIndex) and
|
||||||
|
indirectNodeHasIndirectExpr(_, conv, n + 1, adjustedIndirectionIndex)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class IndirectInstructionIndirectExprNode extends IndirectExprNodeBase instanceof IndirectInstruction
|
private module IndirectOperandIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
|
||||||
|
class IndirectNode = IndirectOperand;
|
||||||
|
|
||||||
|
predicate indirectNodeHasIndirectExpr = indirectExprNodeShouldBeIndirectOperand/4;
|
||||||
|
}
|
||||||
|
|
||||||
|
module IndirectOperandToIndirectExpr =
|
||||||
|
IndirectNodeToIndirectExpr<IndirectOperandIndirectExprNodeImpl>;
|
||||||
|
|
||||||
|
private class IndirectOperandIndirectExprNode extends IndirectExprNodeBase instanceof IndirectOperand
|
||||||
{
|
{
|
||||||
IndirectInstructionIndirectExprNode() {
|
IndirectOperandIndirectExprNode() { IndirectOperandToIndirectExpr::charpred(this) }
|
||||||
exists(Expr e, int n, int indirectionIndex |
|
|
||||||
indirectExprNodeShouldBeIndirectInstruction(this, e, n, indirectionIndex) and
|
|
||||||
not indirectExprNodeShouldBeIndirectInstruction(_, e, n + 1, indirectionIndex)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
final override Expr getConvertedExpr(int n, int index) {
|
final override Expr getConvertedExpr(int n, int index) {
|
||||||
indirectExprNodeShouldBeIndirectInstruction(this, result, n, index)
|
IndirectOperandToIndirectExpr::indirectNodeHasIndirectExpr(this, result, n, index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private module IndirectInstructionIndirectExprNodeImpl implements IndirectNodeToIndirectExprSig {
|
||||||
|
class IndirectNode = IndirectInstruction;
|
||||||
|
|
||||||
|
predicate indirectNodeHasIndirectExpr = indirectExprNodeShouldBeIndirectInstruction/4;
|
||||||
|
}
|
||||||
|
|
||||||
|
module IndirectInstructionToIndirectExpr =
|
||||||
|
IndirectNodeToIndirectExpr<IndirectInstructionIndirectExprNodeImpl>;
|
||||||
|
|
||||||
|
private class IndirectInstructionIndirectExprNode extends IndirectExprNodeBase instanceof IndirectInstruction
|
||||||
|
{
|
||||||
|
IndirectInstructionIndirectExprNode() { IndirectInstructionToIndirectExpr::charpred(this) }
|
||||||
|
|
||||||
|
final override Expr getConvertedExpr(int n, int index) {
|
||||||
|
IndirectInstructionToIndirectExpr::indirectNodeHasIndirectExpr(this, result, n, index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1600,26 +1699,29 @@ private module Cached {
|
|||||||
predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFrom, nodeTo) }
|
predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFrom, nodeTo) }
|
||||||
|
|
||||||
private predicate indirectionOperandFlow(RawIndirectOperand nodeFrom, Node nodeTo) {
|
private predicate indirectionOperandFlow(RawIndirectOperand nodeFrom, Node nodeTo) {
|
||||||
// Reduce the indirection count by 1 if we're passing through a `LoadInstruction`.
|
nodeFrom != nodeTo and
|
||||||
exists(int ind, LoadInstruction load |
|
(
|
||||||
hasOperandAndIndex(nodeFrom, load.getSourceAddressOperand(), ind) and
|
// Reduce the indirection count by 1 if we're passing through a `LoadInstruction`.
|
||||||
nodeHasInstruction(nodeTo, load, ind - 1)
|
exists(int ind, LoadInstruction load |
|
||||||
)
|
hasOperandAndIndex(nodeFrom, load.getSourceAddressOperand(), ind) and
|
||||||
or
|
nodeHasInstruction(nodeTo, load, ind - 1)
|
||||||
// If an operand flows to an instruction, then the indirection of
|
)
|
||||||
// the operand also flows to the indirection of the instruction.
|
or
|
||||||
exists(Operand operand, Instruction instr, int indirectionIndex |
|
// If an operand flows to an instruction, then the indirection of
|
||||||
simpleInstructionLocalFlowStep(operand, instr) and
|
// the operand also flows to the indirection of the instruction.
|
||||||
hasOperandAndIndex(nodeFrom, operand, pragma[only_bind_into](indirectionIndex)) and
|
exists(Operand operand, Instruction instr, int indirectionIndex |
|
||||||
hasInstructionAndIndex(nodeTo, instr, pragma[only_bind_into](indirectionIndex))
|
simpleInstructionLocalFlowStep(operand, instr) and
|
||||||
)
|
hasOperandAndIndex(nodeFrom, operand, pragma[only_bind_into](indirectionIndex)) and
|
||||||
or
|
hasInstructionAndIndex(nodeTo, instr, pragma[only_bind_into](indirectionIndex))
|
||||||
// If there's indirect flow to an operand, then there's also indirect
|
)
|
||||||
// flow to the operand after applying some pointer arithmetic.
|
or
|
||||||
exists(PointerArithmeticInstruction pointerArith, int indirectionIndex |
|
// If there's indirect flow to an operand, then there's also indirect
|
||||||
hasOperandAndIndex(nodeFrom, pointerArith.getAnOperand(),
|
// flow to the operand after applying some pointer arithmetic.
|
||||||
pragma[only_bind_into](indirectionIndex)) and
|
exists(PointerArithmeticInstruction pointerArith, int indirectionIndex |
|
||||||
hasInstructionAndIndex(nodeTo, pointerArith, pragma[only_bind_into](indirectionIndex))
|
hasOperandAndIndex(nodeFrom, pointerArith.getAnOperand(),
|
||||||
|
pragma[only_bind_into](indirectionIndex)) and
|
||||||
|
hasInstructionAndIndex(nodeTo, pointerArith, pragma[only_bind_into](indirectionIndex))
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1645,6 +1747,7 @@ private module Cached {
|
|||||||
private predicate indirectionInstructionFlow(
|
private predicate indirectionInstructionFlow(
|
||||||
RawIndirectInstruction nodeFrom, IndirectOperand nodeTo
|
RawIndirectInstruction nodeFrom, IndirectOperand nodeTo
|
||||||
) {
|
) {
|
||||||
|
nodeFrom != nodeTo and
|
||||||
// If there's flow from an instruction to an operand, then there's also flow from the
|
// If there's flow from an instruction to an operand, then there's also flow from the
|
||||||
// indirect instruction to the indirect operand.
|
// indirect instruction to the indirect operand.
|
||||||
exists(Operand operand, Instruction instr, int indirectionIndex |
|
exists(Operand operand, Instruction instr, int indirectionIndex |
|
||||||
|
|||||||
@@ -59,6 +59,9 @@ private module SourceVariables {
|
|||||||
then result = base.getType()
|
then result = base.getType()
|
||||||
else result = getTypeImpl(base.getType(), ind - 1)
|
else result = getTypeImpl(base.getType(), ind - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Gets the location of this variable. */
|
||||||
|
Location getLocation() { result = this.getBaseVariable().getLocation() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,22 +116,12 @@ private newtype TDefOrUseImpl =
|
|||||||
TGlobalUse(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
|
TGlobalUse(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
|
||||||
// Represents a final "use" of a global variable to ensure that
|
// Represents a final "use" of a global variable to ensure that
|
||||||
// the assignment to a global variable isn't ruled out as dead.
|
// the assignment to a global variable isn't ruled out as dead.
|
||||||
exists(VariableAddressInstruction vai, int defIndex |
|
isGlobalUse(v, f, _, indirectionIndex)
|
||||||
vai.getEnclosingIRFunction() = f and
|
|
||||||
vai.getAstVariable() = v and
|
|
||||||
isDef(_, _, _, vai, _, defIndex) and
|
|
||||||
indirectionIndex = [0 .. defIndex] + 1
|
|
||||||
)
|
|
||||||
} or
|
} or
|
||||||
TGlobalDefImpl(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
|
TGlobalDefImpl(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
|
||||||
// Represents the initial "definition" of a global variable when entering
|
// Represents the initial "definition" of a global variable when entering
|
||||||
// a function body.
|
// a function body.
|
||||||
exists(VariableAddressInstruction vai |
|
isGlobalDefImpl(v, f, _, indirectionIndex)
|
||||||
vai.getEnclosingIRFunction() = f and
|
|
||||||
vai.getAstVariable() = v and
|
|
||||||
isUse(_, _, vai, _, indirectionIndex) and
|
|
||||||
not isDef(_, _, vai.getAUse(), _, _, _)
|
|
||||||
)
|
|
||||||
} or
|
} or
|
||||||
TIteratorDef(
|
TIteratorDef(
|
||||||
Operand iteratorDerefAddress, BaseSourceVariableInstruction container, int indirectionIndex
|
Operand iteratorDerefAddress, BaseSourceVariableInstruction container, int indirectionIndex
|
||||||
@@ -150,6 +143,27 @@ private newtype TDefOrUseImpl =
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate isGlobalUse(
|
||||||
|
GlobalLikeVariable v, IRFunction f, int indirection, int indirectionIndex
|
||||||
|
) {
|
||||||
|
exists(VariableAddressInstruction vai |
|
||||||
|
vai.getEnclosingIRFunction() = f and
|
||||||
|
vai.getAstVariable() = v and
|
||||||
|
isDef(_, _, _, vai, indirection, indirectionIndex)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate isGlobalDefImpl(
|
||||||
|
GlobalLikeVariable v, IRFunction f, int indirection, int indirectionIndex
|
||||||
|
) {
|
||||||
|
exists(VariableAddressInstruction vai |
|
||||||
|
vai.getEnclosingIRFunction() = f and
|
||||||
|
vai.getAstVariable() = v and
|
||||||
|
isUse(_, _, vai, indirection, indirectionIndex) and
|
||||||
|
not isDef(_, _, _, vai, _, indirectionIndex)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private predicate unspecifiedTypeIsModifiableAt(Type unspecified, int indirectionIndex) {
|
private predicate unspecifiedTypeIsModifiableAt(Type unspecified, int indirectionIndex) {
|
||||||
indirectionIndex = [1 .. getIndirectionForUnspecifiedType(unspecified).getNumberOfIndirections()] and
|
indirectionIndex = [1 .. getIndirectionForUnspecifiedType(unspecified).getNumberOfIndirections()] and
|
||||||
exists(CppType cppType |
|
exists(CppType cppType |
|
||||||
@@ -438,7 +452,7 @@ class GlobalUse extends UseImpl, TGlobalUse {
|
|||||||
|
|
||||||
override FinalGlobalValue getNode() { result.getGlobalUse() = this }
|
override FinalGlobalValue getNode() { result.getGlobalUse() = this }
|
||||||
|
|
||||||
override int getIndirection() { result = ind + 1 }
|
override int getIndirection() { isGlobalUse(global, f, result, ind) }
|
||||||
|
|
||||||
/** Gets the global variable associated with this use. */
|
/** Gets the global variable associated with this use. */
|
||||||
GlobalLikeVariable getVariable() { result = global }
|
GlobalLikeVariable getVariable() { result = global }
|
||||||
@@ -460,7 +474,9 @@ class GlobalUse extends UseImpl, TGlobalUse {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override SourceVariable getSourceVariable() { sourceVariableIsGlobal(result, global, f, ind) }
|
override SourceVariable getSourceVariable() {
|
||||||
|
sourceVariableIsGlobal(result, global, f, this.getIndirection())
|
||||||
|
}
|
||||||
|
|
||||||
final override Cpp::Location getLocation() { result = f.getLocation() }
|
final override Cpp::Location getLocation() { result = f.getLocation() }
|
||||||
|
|
||||||
@@ -501,16 +517,18 @@ class GlobalDefImpl extends DefOrUseImpl, TGlobalDefImpl {
|
|||||||
|
|
||||||
/** Gets the global variable associated with this definition. */
|
/** Gets the global variable associated with this definition. */
|
||||||
override SourceVariable getSourceVariable() {
|
override SourceVariable getSourceVariable() {
|
||||||
sourceVariableIsGlobal(result, global, f, indirectionIndex)
|
sourceVariableIsGlobal(result, global, f, this.getIndirection())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getIndirection() { result = indirectionIndex }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the type of this use after specifiers have been deeply stripped
|
* Gets the type of this use after specifiers have been deeply stripped
|
||||||
* and typedefs have been resolved.
|
* and typedefs have been resolved.
|
||||||
*/
|
*/
|
||||||
Type getUnspecifiedType() { result = global.getUnspecifiedType() }
|
Type getUnspecifiedType() { result = global.getUnspecifiedType() }
|
||||||
|
|
||||||
override string toString() { result = "GlobalDef" }
|
override string toString() { result = "Def of " + this.getSourceVariable() }
|
||||||
|
|
||||||
override Location getLocation() { result = f.getLocation() }
|
override Location getLocation() { result = f.getLocation() }
|
||||||
|
|
||||||
@@ -854,7 +872,7 @@ private predicate sourceVariableIsGlobal(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private module SsaInput implements SsaImplCommon::InputSig {
|
private module SsaInput implements SsaImplCommon::InputSig<Location> {
|
||||||
import InputSigCommon
|
import InputSigCommon
|
||||||
import SourceVariables
|
import SourceVariables
|
||||||
|
|
||||||
@@ -980,7 +998,7 @@ class GlobalDef extends TGlobalDef, SsaDefOrUse {
|
|||||||
final override Location getLocation() { result = global.getLocation() }
|
final override Location getLocation() { result = global.getLocation() }
|
||||||
|
|
||||||
/** Gets a textual representation of this definition. */
|
/** Gets a textual representation of this definition. */
|
||||||
override string toString() { result = "GlobalDef" }
|
override string toString() { result = global.toString() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if this definition has index `index` in block `block`, and
|
* Holds if this definition has index `index` in block `block`, and
|
||||||
@@ -990,6 +1008,9 @@ class GlobalDef extends TGlobalDef, SsaDefOrUse {
|
|||||||
global.hasIndexInBlock(block, index, sv)
|
global.hasIndexInBlock(block, index, sv)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Gets the indirection index of this definition. */
|
||||||
|
int getIndirection() { result = global.getIndirection() }
|
||||||
|
|
||||||
/** Gets the indirection index of this definition. */
|
/** Gets the indirection index of this definition. */
|
||||||
int getIndirectionIndex() { result = global.getIndirectionIndex() }
|
int getIndirectionIndex() { result = global.getIndirectionIndex() }
|
||||||
|
|
||||||
@@ -1074,7 +1095,7 @@ class Def extends DefOrUse {
|
|||||||
predicate isCertain() { defOrUse.isCertain() }
|
predicate isCertain() { defOrUse.isCertain() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private module SsaImpl = SsaImplCommon::Make<SsaInput>;
|
private module SsaImpl = SsaImplCommon::Make<Location, SsaInput>;
|
||||||
|
|
||||||
class PhiNode extends SsaImpl::DefinitionExt {
|
class PhiNode extends SsaImpl::DefinitionExt {
|
||||||
PhiNode() {
|
PhiNode() {
|
||||||
|
|||||||
@@ -377,6 +377,9 @@ abstract private class AbstractBaseSourceVariable extends TBaseSourceVariable {
|
|||||||
/** Gets a textual representation of this element. */
|
/** Gets a textual representation of this element. */
|
||||||
abstract string toString();
|
abstract string toString();
|
||||||
|
|
||||||
|
/** Gets the location of this variable. */
|
||||||
|
abstract Location getLocation();
|
||||||
|
|
||||||
/** Gets the type of this base source variable. */
|
/** Gets the type of this base source variable. */
|
||||||
final DataFlowType getType() { this.getLanguageType().hasUnspecifiedType(result, _) }
|
final DataFlowType getType() { this.getLanguageType().hasUnspecifiedType(result, _) }
|
||||||
|
|
||||||
@@ -395,6 +398,8 @@ class BaseIRVariable extends AbstractBaseSourceVariable, TBaseIRVariable {
|
|||||||
|
|
||||||
override string toString() { result = var.toString() }
|
override string toString() { result = var.toString() }
|
||||||
|
|
||||||
|
override Location getLocation() { result = var.getLocation() }
|
||||||
|
|
||||||
override CppType getLanguageType() { result = var.getLanguageType() }
|
override CppType getLanguageType() { result = var.getLanguageType() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -407,6 +412,8 @@ class BaseCallVariable extends AbstractBaseSourceVariable, TBaseCallVariable {
|
|||||||
|
|
||||||
override string toString() { result = call.toString() }
|
override string toString() { result = call.toString() }
|
||||||
|
|
||||||
|
override Location getLocation() { result = call.getLocation() }
|
||||||
|
|
||||||
override CppType getLanguageType() { result = getResultLanguageType(call) }
|
override CppType getLanguageType() { result = getResultLanguageType(call) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -872,7 +879,7 @@ private module Cached {
|
|||||||
upper = countIndirectionsForCppType(type) and
|
upper = countIndirectionsForCppType(type) and
|
||||||
ind = ind0 + [lower .. upper] and
|
ind = ind0 + [lower .. upper] and
|
||||||
indirectionIndex = ind - (ind0 + lower) and
|
indirectionIndex = ind - (ind0 + lower) and
|
||||||
(if type.hasType(any(Cpp::ArrayType arrayType), true) then lower = 0 else lower = 1)
|
lower = getMinIndirectionsForType(any(Type t | type.hasUnspecifiedType(t, _)))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,6 +72,16 @@ private predicate operandToInstructionTaintStep(Operand opFrom, Instruction inst
|
|||||||
or
|
or
|
||||||
instrTo.(FieldAddressInstruction).getField().getDeclaringType() instanceof Union
|
instrTo.(FieldAddressInstruction).getField().getDeclaringType() instanceof Union
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
// Taint from int to boolean casts. This ensures that we have flow to `!x` in:
|
||||||
|
// ```cpp
|
||||||
|
// x = integer_source();
|
||||||
|
// if(!x) { ... }
|
||||||
|
// ```
|
||||||
|
exists(Operand zero |
|
||||||
|
zero.getDef().(ConstantValueInstruction).getValue() = "0" and
|
||||||
|
instrTo.(CompareNEInstruction).hasOperands(opFrom, zero)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -229,7 +229,7 @@ private class FinalParameterUse extends UseImpl, TFinalParameterUse {
|
|||||||
override predicate isCertain() { any() }
|
override predicate isCertain() { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private module SsaInput implements SsaImplCommon::InputSig {
|
private module SsaInput implements SsaImplCommon::InputSig<Location> {
|
||||||
import InputSigCommon
|
import InputSigCommon
|
||||||
import SourceVariables
|
import SourceVariables
|
||||||
|
|
||||||
@@ -335,7 +335,7 @@ class Def extends DefOrUse {
|
|||||||
predicate isIteratorDef() { defOrUse instanceof IteratorDef }
|
predicate isIteratorDef() { defOrUse instanceof IteratorDef }
|
||||||
}
|
}
|
||||||
|
|
||||||
private module SsaImpl = SsaImplCommon::Make<SsaInput>;
|
private module SsaImpl = SsaImplCommon::Make<Location, SsaInput>;
|
||||||
|
|
||||||
class PhiNode extends SsaImpl::DefinitionExt {
|
class PhiNode extends SsaImpl::DefinitionExt {
|
||||||
PhiNode() {
|
PhiNode() {
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ int getConstantValue(Instruction instr) {
|
|||||||
or
|
or
|
||||||
result = getConstantValue(instr.(CopyInstruction).getSourceValue())
|
result = getConstantValue(instr.(CopyInstruction).getSourceValue())
|
||||||
or
|
or
|
||||||
|
getConstantValue(instr.(LogicalNotInstruction).getUnary()) != 0 and
|
||||||
|
result = 0
|
||||||
|
or
|
||||||
exists(PhiInstruction phi |
|
exists(PhiInstruction phi |
|
||||||
phi = instr and
|
phi = instr and
|
||||||
result = unique(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef()))
|
result = unique(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef()))
|
||||||
@@ -26,28 +29,25 @@ private predicate binaryInstructionOperands(BinaryInstruction instr, int left, i
|
|||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private int getBinaryInstructionValue(BinaryInstruction instr) {
|
private int getBinaryInstructionValue(BinaryInstruction instr) {
|
||||||
exists(int left, int right |
|
exists(int left, int right | binaryInstructionOperands(instr, left, right) |
|
||||||
binaryInstructionOperands(instr, left, right) and
|
instr instanceof AddInstruction and result = add(left, right)
|
||||||
(
|
or
|
||||||
instr instanceof AddInstruction and result = add(left, right)
|
instr instanceof SubInstruction and result = sub(left, right)
|
||||||
or
|
or
|
||||||
instr instanceof SubInstruction and result = sub(left, right)
|
instr instanceof MulInstruction and result = mul(left, right)
|
||||||
or
|
or
|
||||||
instr instanceof MulInstruction and result = mul(left, right)
|
instr instanceof DivInstruction and result = div(left, right)
|
||||||
or
|
or
|
||||||
instr instanceof DivInstruction and result = div(left, right)
|
instr instanceof CompareEQInstruction and result = compareEQ(left, right)
|
||||||
or
|
or
|
||||||
instr instanceof CompareEQInstruction and result = compareEQ(left, right)
|
instr instanceof CompareNEInstruction and result = compareNE(left, right)
|
||||||
or
|
or
|
||||||
instr instanceof CompareNEInstruction and result = compareNE(left, right)
|
instr instanceof CompareLTInstruction and result = compareLT(left, right)
|
||||||
or
|
or
|
||||||
instr instanceof CompareLTInstruction and result = compareLT(left, right)
|
instr instanceof CompareGTInstruction and result = compareGT(left, right)
|
||||||
or
|
or
|
||||||
instr instanceof CompareGTInstruction and result = compareGT(left, right)
|
instr instanceof CompareLEInstruction and result = compareLE(left, right)
|
||||||
or
|
or
|
||||||
instr instanceof CompareLEInstruction and result = compareLE(left, right)
|
instr instanceof CompareGEInstruction and result = compareGE(left, right)
|
||||||
or
|
|
||||||
instr instanceof CompareGEInstruction and result = compareGE(left, right)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ int getConstantValue(Instruction instr) {
|
|||||||
or
|
or
|
||||||
result = getConstantValue(instr.(CopyInstruction).getSourceValue())
|
result = getConstantValue(instr.(CopyInstruction).getSourceValue())
|
||||||
or
|
or
|
||||||
|
getConstantValue(instr.(LogicalNotInstruction).getUnary()) != 0 and
|
||||||
|
result = 0
|
||||||
|
or
|
||||||
exists(PhiInstruction phi |
|
exists(PhiInstruction phi |
|
||||||
phi = instr and
|
phi = instr and
|
||||||
result = unique(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef()))
|
result = unique(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef()))
|
||||||
@@ -26,28 +29,25 @@ private predicate binaryInstructionOperands(BinaryInstruction instr, int left, i
|
|||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private int getBinaryInstructionValue(BinaryInstruction instr) {
|
private int getBinaryInstructionValue(BinaryInstruction instr) {
|
||||||
exists(int left, int right |
|
exists(int left, int right | binaryInstructionOperands(instr, left, right) |
|
||||||
binaryInstructionOperands(instr, left, right) and
|
instr instanceof AddInstruction and result = add(left, right)
|
||||||
(
|
or
|
||||||
instr instanceof AddInstruction and result = add(left, right)
|
instr instanceof SubInstruction and result = sub(left, right)
|
||||||
or
|
or
|
||||||
instr instanceof SubInstruction and result = sub(left, right)
|
instr instanceof MulInstruction and result = mul(left, right)
|
||||||
or
|
or
|
||||||
instr instanceof MulInstruction and result = mul(left, right)
|
instr instanceof DivInstruction and result = div(left, right)
|
||||||
or
|
or
|
||||||
instr instanceof DivInstruction and result = div(left, right)
|
instr instanceof CompareEQInstruction and result = compareEQ(left, right)
|
||||||
or
|
or
|
||||||
instr instanceof CompareEQInstruction and result = compareEQ(left, right)
|
instr instanceof CompareNEInstruction and result = compareNE(left, right)
|
||||||
or
|
or
|
||||||
instr instanceof CompareNEInstruction and result = compareNE(left, right)
|
instr instanceof CompareLTInstruction and result = compareLT(left, right)
|
||||||
or
|
or
|
||||||
instr instanceof CompareLTInstruction and result = compareLT(left, right)
|
instr instanceof CompareGTInstruction and result = compareGT(left, right)
|
||||||
or
|
or
|
||||||
instr instanceof CompareGTInstruction and result = compareGT(left, right)
|
instr instanceof CompareLEInstruction and result = compareLE(left, right)
|
||||||
or
|
or
|
||||||
instr instanceof CompareLEInstruction and result = compareLE(left, right)
|
instr instanceof CompareGEInstruction and result = compareGE(left, right)
|
||||||
or
|
|
||||||
instr instanceof CompareGEInstruction and result = compareGE(left, right)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,24 +77,6 @@ class TranslatedParenthesisCondition extends TranslatedFlexibleCondition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TranslatedNotCondition extends TranslatedFlexibleCondition {
|
|
||||||
override NotExpr expr;
|
|
||||||
|
|
||||||
override Instruction getChildTrueSuccessor(TranslatedCondition child) {
|
|
||||||
child = this.getOperand() and
|
|
||||||
result = this.getConditionContext().getChildFalseSuccessor(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override Instruction getChildFalseSuccessor(TranslatedCondition child) {
|
|
||||||
child = this.getOperand() and
|
|
||||||
result = this.getConditionContext().getChildTrueSuccessor(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override TranslatedCondition getOperand() {
|
|
||||||
result = getTranslatedCondition(expr.getOperand().getFullyConverted())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class TranslatedNativeCondition extends TranslatedCondition, TTranslatedNativeCondition {
|
abstract class TranslatedNativeCondition extends TranslatedCondition, TTranslatedNativeCondition {
|
||||||
TranslatedNativeCondition() { this = TTranslatedNativeCondition(expr) }
|
TranslatedNativeCondition() { this = TTranslatedNativeCondition(expr) }
|
||||||
|
|
||||||
|
|||||||
@@ -190,10 +190,7 @@ private predicate isNativeCondition(Expr expr) {
|
|||||||
* depending on context.
|
* depending on context.
|
||||||
*/
|
*/
|
||||||
private predicate isFlexibleCondition(Expr expr) {
|
private predicate isFlexibleCondition(Expr expr) {
|
||||||
(
|
expr instanceof ParenthesisExpr and
|
||||||
expr instanceof ParenthesisExpr or
|
|
||||||
expr instanceof NotExpr
|
|
||||||
) and
|
|
||||||
usedAsCondition(expr) and
|
usedAsCondition(expr) and
|
||||||
not isIRConstant(expr)
|
not isIRConstant(expr)
|
||||||
}
|
}
|
||||||
@@ -218,11 +215,6 @@ private predicate usedAsCondition(Expr expr) {
|
|||||||
condExpr.getCondition().getFullyConverted() = expr and not condExpr.isTwoOperand()
|
condExpr.getCondition().getFullyConverted() = expr and not condExpr.isTwoOperand()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(NotExpr notExpr |
|
|
||||||
notExpr.getOperand().getFullyConverted() = expr and
|
|
||||||
usedAsCondition(notExpr)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
exists(ParenthesisExpr paren |
|
exists(ParenthesisExpr paren |
|
||||||
paren.getExpr() = expr and
|
paren.getExpr() = expr and
|
||||||
usedAsCondition(paren)
|
usedAsCondition(paren)
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ int getConstantValue(Instruction instr) {
|
|||||||
or
|
or
|
||||||
result = getConstantValue(instr.(CopyInstruction).getSourceValue())
|
result = getConstantValue(instr.(CopyInstruction).getSourceValue())
|
||||||
or
|
or
|
||||||
|
getConstantValue(instr.(LogicalNotInstruction).getUnary()) != 0 and
|
||||||
|
result = 0
|
||||||
|
or
|
||||||
exists(PhiInstruction phi |
|
exists(PhiInstruction phi |
|
||||||
phi = instr and
|
phi = instr and
|
||||||
result = unique(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef()))
|
result = unique(Operand op | op = phi.getAnInputOperand() | getConstantValue(op.getDef()))
|
||||||
@@ -26,28 +29,25 @@ private predicate binaryInstructionOperands(BinaryInstruction instr, int left, i
|
|||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private int getBinaryInstructionValue(BinaryInstruction instr) {
|
private int getBinaryInstructionValue(BinaryInstruction instr) {
|
||||||
exists(int left, int right |
|
exists(int left, int right | binaryInstructionOperands(instr, left, right) |
|
||||||
binaryInstructionOperands(instr, left, right) and
|
instr instanceof AddInstruction and result = add(left, right)
|
||||||
(
|
or
|
||||||
instr instanceof AddInstruction and result = add(left, right)
|
instr instanceof SubInstruction and result = sub(left, right)
|
||||||
or
|
or
|
||||||
instr instanceof SubInstruction and result = sub(left, right)
|
instr instanceof MulInstruction and result = mul(left, right)
|
||||||
or
|
or
|
||||||
instr instanceof MulInstruction and result = mul(left, right)
|
instr instanceof DivInstruction and result = div(left, right)
|
||||||
or
|
or
|
||||||
instr instanceof DivInstruction and result = div(left, right)
|
instr instanceof CompareEQInstruction and result = compareEQ(left, right)
|
||||||
or
|
or
|
||||||
instr instanceof CompareEQInstruction and result = compareEQ(left, right)
|
instr instanceof CompareNEInstruction and result = compareNE(left, right)
|
||||||
or
|
or
|
||||||
instr instanceof CompareNEInstruction and result = compareNE(left, right)
|
instr instanceof CompareLTInstruction and result = compareLT(left, right)
|
||||||
or
|
or
|
||||||
instr instanceof CompareLTInstruction and result = compareLT(left, right)
|
instr instanceof CompareGTInstruction and result = compareGT(left, right)
|
||||||
or
|
or
|
||||||
instr instanceof CompareGTInstruction and result = compareGT(left, right)
|
instr instanceof CompareLEInstruction and result = compareLE(left, right)
|
||||||
or
|
or
|
||||||
instr instanceof CompareLEInstruction and result = compareLE(left, right)
|
instr instanceof CompareGEInstruction and result = compareGE(left, right)
|
||||||
or
|
|
||||||
instr instanceof CompareGEInstruction and result = compareGE(left, right)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ private import implementations.Accept
|
|||||||
private import implementations.Poll
|
private import implementations.Poll
|
||||||
private import implementations.Select
|
private import implementations.Select
|
||||||
private import implementations.MySql
|
private import implementations.MySql
|
||||||
|
private import implementations.ODBC
|
||||||
private import implementations.SqLite3
|
private import implementations.SqLite3
|
||||||
private import implementations.PostgreSql
|
private import implementations.PostgreSql
|
||||||
private import implementations.System
|
private import implementations.System
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import semmle.code.cpp.models.interfaces.Allocation
|
import semmle.code.cpp.models.interfaces.Allocation
|
||||||
|
import semmle.code.cpp.models.interfaces.Taint
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An allocation function (such as `malloc`) that has an argument for the size
|
* An allocation function (such as `malloc`) that has an argument for the size
|
||||||
@@ -121,7 +122,7 @@ private class CallocAllocationFunction extends AllocationFunction {
|
|||||||
* An allocation function (such as `realloc`) that has an argument for the size
|
* An allocation function (such as `realloc`) that has an argument for the size
|
||||||
* in bytes, and an argument for an existing pointer that is to be reallocated.
|
* in bytes, and an argument for an existing pointer that is to be reallocated.
|
||||||
*/
|
*/
|
||||||
private class ReallocAllocationFunction extends AllocationFunction {
|
private class ReallocAllocationFunction extends AllocationFunction, TaintFunction {
|
||||||
int sizeArg;
|
int sizeArg;
|
||||||
int reallocArg;
|
int reallocArg;
|
||||||
|
|
||||||
@@ -151,6 +152,10 @@ private class ReallocAllocationFunction extends AllocationFunction {
|
|||||||
override int getSizeArg() { result = sizeArg }
|
override int getSizeArg() { result = sizeArg }
|
||||||
|
|
||||||
override int getReallocPtrArg() { result = reallocArg }
|
override int getReallocPtrArg() { result = reallocArg }
|
||||||
|
|
||||||
|
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||||
|
input.isParameterDeref(this.getReallocPtrArg()) and output.isReturnValueDeref()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -16,10 +16,7 @@ class Getenv extends LocalFlowSourceFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasLocalFlowSource(FunctionOutput output, string description) {
|
override predicate hasLocalFlowSource(FunctionOutput output, string description) {
|
||||||
(
|
output.isReturnValueDeref() and
|
||||||
output.isReturnValueDeref() or
|
|
||||||
output.isReturnValue()
|
|
||||||
) and
|
|
||||||
description = "an environment variable"
|
description = "an environment variable"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,10 +49,10 @@ private class FgetsFunction extends DataFlowFunction, TaintFunction, ArrayFuncti
|
|||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasRemoteFlowSource(FunctionOutput output, string description) {
|
override predicate hasRemoteFlowSource(FunctionOutput output, string description) {
|
||||||
output.isParameterDeref(0) and
|
(
|
||||||
description = "string read by " + this.getName()
|
output.isParameterDeref(0) or
|
||||||
or
|
output.isReturnValueDeref()
|
||||||
output.isReturnValue() and
|
) and
|
||||||
description = "string read by " + this.getName()
|
description = "string read by " + this.getName()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +101,6 @@ private class GetsFunction extends DataFlowFunction, ArrayFunction, AliasFunctio
|
|||||||
override predicate hasLocalFlowSource(FunctionOutput output, string description) {
|
override predicate hasLocalFlowSource(FunctionOutput output, string description) {
|
||||||
(
|
(
|
||||||
output.isParameterDeref(0) or
|
output.isParameterDeref(0) or
|
||||||
output.isReturnValue() or
|
|
||||||
output.isReturnValueDeref()
|
output.isReturnValueDeref()
|
||||||
) and
|
) and
|
||||||
description = "string read by " + this.getName()
|
description = "string read by " + this.getName()
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ private class Getaddrinfo extends TaintFunction, ArrayFunction, RemoteFlowSource
|
|||||||
override predicate hasArrayWithNullTerminator(int bufParam) { bufParam in [0, 1] }
|
override predicate hasArrayWithNullTerminator(int bufParam) { bufParam in [0, 1] }
|
||||||
|
|
||||||
override predicate hasRemoteFlowSource(FunctionOutput output, string description) {
|
override predicate hasRemoteFlowSource(FunctionOutput output, string description) {
|
||||||
output.isParameterDeref(3) and
|
output.isParameterDeref(3, 2) and
|
||||||
description = "address returned by " + this.getName()
|
description = "address returned by " + this.getName()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,18 +9,17 @@ import semmle.code.cpp.models.interfaces.DataFlow
|
|||||||
import semmle.code.cpp.models.interfaces.Alias
|
import semmle.code.cpp.models.interfaces.Alias
|
||||||
import semmle.code.cpp.models.interfaces.SideEffect
|
import semmle.code.cpp.models.interfaces.SideEffect
|
||||||
|
|
||||||
/**
|
private class MemsetFunctionModel extends ArrayFunction, DataFlowFunction, AliasFunction,
|
||||||
* The standard function `memset` and its assorted variants
|
|
||||||
*/
|
|
||||||
private class MemsetFunction extends ArrayFunction, DataFlowFunction, AliasFunction,
|
|
||||||
SideEffectFunction
|
SideEffectFunction
|
||||||
{
|
{
|
||||||
MemsetFunction() {
|
MemsetFunctionModel() {
|
||||||
this.hasGlobalOrStdOrBslName("memset")
|
this.hasGlobalOrStdOrBslName("memset")
|
||||||
or
|
or
|
||||||
this.hasGlobalOrStdName("wmemset")
|
this.hasGlobalOrStdName("wmemset")
|
||||||
or
|
or
|
||||||
this.hasGlobalName([bzero(), "__builtin_memset", "__builtin_memset_chk"])
|
this.hasGlobalName([
|
||||||
|
bzero(), "__builtin_memset", "__builtin_memset_chk", "RtlZeroMemory", "RtlSecureZeroMemory"
|
||||||
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasArrayOutput(int bufParam) { bufParam = 0 }
|
override predicate hasArrayOutput(int bufParam) { bufParam = 0 }
|
||||||
@@ -60,3 +59,8 @@ private class MemsetFunction extends ArrayFunction, DataFlowFunction, AliasFunct
|
|||||||
}
|
}
|
||||||
|
|
||||||
private string bzero() { result = ["bzero", "explicit_bzero"] }
|
private string bzero() { result = ["bzero", "explicit_bzero"] }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The standard function `memset` and its assorted variants
|
||||||
|
*/
|
||||||
|
class MemsetFunction extends Function instanceof MemsetFunctionModel { }
|
||||||
|
|||||||
28
cpp/ql/lib/semmle/code/cpp/models/implementations/ODBC.qll
Normal file
28
cpp/ql/lib/semmle/code/cpp/models/implementations/ODBC.qll
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* Provides implementation classes modeling the ODBC C/C++ API.
|
||||||
|
* See `semmle.code.cpp.models.Models` for usage information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
private import semmle.code.cpp.models.interfaces.Sql
|
||||||
|
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `SQLExecDirect`, and `SQLPrepare` from the ODBC C/C++ API:
|
||||||
|
* https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlexecdirect-function?view=sql-server-ver16
|
||||||
|
* https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlprepare-function?view=sql-server-ver16
|
||||||
|
*
|
||||||
|
* Note, `SQLExecute` is not included because it operates on a SQLHSTMT type, not a string.
|
||||||
|
* The SQLHSTMT parameter for `SQLExecute` is set through a `SQLPrepare`, which is modeled.
|
||||||
|
* The other source of input to a `SQLExecute` is via a `SQLBindParameter`, which sanitizes user input,
|
||||||
|
* and would be considered a barrier to SQL injection.
|
||||||
|
*/
|
||||||
|
private class ODBCExecutionFunction extends SqlExecutionFunction {
|
||||||
|
ODBCExecutionFunction() { this.hasGlobalName(["SQLExecDirect", "SQLPrepare"]) }
|
||||||
|
|
||||||
|
override predicate hasSqlArgument(FunctionInput input) { input.isParameterDeref(1) }
|
||||||
|
}
|
||||||
|
// NOTE: no need to define a barrier explicitly.
|
||||||
|
// `SQLBindParameter` is the typical means for sanitizing user input.
|
||||||
|
// https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlbindparameter-function?view=sql-server-ver16
|
||||||
|
// First a query is establisehed via `SQLPrepare`, then parameters are bound via `SQLBindParameter`, before
|
||||||
|
// the query is executed via `SQLExecute`. We are not modeling SQLExecute, so we do not need to model SQLBindParameter.
|
||||||
@@ -147,19 +147,32 @@ private class SnprintfImpl extends Snprintf {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The Microsoft `StringCchPrintf` function and variants.
|
* The Microsoft `StringCchPrintf` function and variants.
|
||||||
|
* See: https://learn.microsoft.com/en-us/windows/win32/api/strsafe/
|
||||||
|
* and
|
||||||
|
* https://learn.microsoft.com/en-us/previous-versions/windows/embedded/ms860435(v=msdn.10)
|
||||||
*/
|
*/
|
||||||
private class StringCchPrintf extends FormattingFunction {
|
private class StringCchPrintf extends FormattingFunction {
|
||||||
StringCchPrintf() {
|
StringCchPrintf() {
|
||||||
this instanceof TopLevelFunction and
|
this instanceof TopLevelFunction and
|
||||||
this.hasGlobalName([
|
exists(string baseName |
|
||||||
"StringCchPrintf", "StringCchPrintfEx", "StringCchPrintf_l", "StringCchPrintf_lEx",
|
baseName in [
|
||||||
"StringCbPrintf", "StringCbPrintfEx", "StringCbPrintf_l", "StringCbPrintf_lEx"
|
"StringCchPrintf", //StringCchPrintf(pszDest, cchDest, pszFormat, ...)
|
||||||
]) and
|
"StringCchPrintfEx", //StringCchPrintfEx(pszDest,cchDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, ...)
|
||||||
|
"StringCchPrintf_l", //StringCchPrintf_l(pszDest, cbDest, pszFormat, locale, ...)
|
||||||
|
"StringCchPrintf_lEx", //StringCchPrintf_lEx(pszDest, cchDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, locale, ...)
|
||||||
|
"StringCbPrintf", //StringCbPrintf(pszDest, cbDest, pszFormat, ...)
|
||||||
|
"StringCbPrintfEx", //StringCbPrintfEx(pszDest, cbDest, ppszDestEnd, pcbRemaining, dwFlags, pszFormat, ...)
|
||||||
|
"StringCbPrintf_l", //StringCbPrintf_l(pszDest, cbDest, pszFormat, locale, ...)
|
||||||
|
"StringCbPrintf_lEx" //StringCbPrintf_lEx(pszDest, cbDest, ppszDestEnd, pcbRemaining, dwFlags, pszFormat, locale, ...)
|
||||||
|
]
|
||||||
|
|
|
||||||
|
this.hasGlobalName(baseName + ["", "A", "W"])
|
||||||
|
) and
|
||||||
not exists(this.getDefinition().getFile().getRelativePath())
|
not exists(this.getDefinition().getFile().getRelativePath())
|
||||||
}
|
}
|
||||||
|
|
||||||
override int getFormatParameterIndex() {
|
override int getFormatParameterIndex() {
|
||||||
if this.getName().matches("%Ex") then result = 5 else result = 2
|
if this.getName().matches("%Ex" + ["", "A", "W"]) then result = 5 else result = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
override int getOutputParameterIndex(boolean isStream) { result = 0 and isStream = false }
|
override int getOutputParameterIndex(boolean isStream) { result = 0 and isStream = false }
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ private class Send extends AliasFunction, ArrayFunction, SideEffectFunction, Rem
|
|||||||
override ParameterIndex getParameterSizeIndex(ParameterIndex i) { i = 1 and result = 2 }
|
override ParameterIndex getParameterSizeIndex(ParameterIndex i) { i = 1 and result = 2 }
|
||||||
|
|
||||||
override predicate hasRemoteFlowSink(FunctionInput input, string description) {
|
override predicate hasRemoteFlowSink(FunctionInput input, string description) {
|
||||||
input.isParameterDeref(1) and description = "buffer sent by " + this.getName()
|
input.isParameterDeref(1, 1) and description = "buffer sent by " + this.getName()
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate hasSocketInput(FunctionInput input) { input.isParameter(0) }
|
override predicate hasSocketInput(FunctionInput input) { input.isParameter(0) }
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import semmle.code.cpp.models.interfaces.SideEffect
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The standard function `strcat` and its wide, sized, and Microsoft variants.
|
* The standard function `strcat` and its wide, sized, and Microsoft variants.
|
||||||
|
*
|
||||||
|
* Does not include `strlcat`, which is covered by `StrlcatFunction`
|
||||||
*/
|
*/
|
||||||
class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, SideEffectFunction {
|
class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, SideEffectFunction {
|
||||||
StrcatFunction() {
|
StrcatFunction() {
|
||||||
@@ -90,3 +92,64 @@ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, Sid
|
|||||||
buffer = true
|
buffer = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `strlcat` function.
|
||||||
|
*/
|
||||||
|
class StrlcatFunction extends TaintFunction, ArrayFunction, SideEffectFunction {
|
||||||
|
StrlcatFunction() {
|
||||||
|
this.hasGlobalName("strlcat") // strlcat(dst, src, dst_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the index of the parameter that is the size of the copy (in characters).
|
||||||
|
*/
|
||||||
|
int getParamSize() { result = 2 }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the index of the parameter that is the source of the copy.
|
||||||
|
*/
|
||||||
|
int getParamSrc() { result = 1 }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the index of the parameter that is the destination to be appended to.
|
||||||
|
*/
|
||||||
|
int getParamDest() { result = 0 }
|
||||||
|
|
||||||
|
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||||
|
(
|
||||||
|
input.isParameter(2)
|
||||||
|
or
|
||||||
|
input.isParameterDeref(0)
|
||||||
|
or
|
||||||
|
input.isParameterDeref(1)
|
||||||
|
) and
|
||||||
|
output.isParameterDeref(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate hasArrayInput(int param) {
|
||||||
|
param = 0 or
|
||||||
|
param = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate hasArrayOutput(int param) { param = 0 }
|
||||||
|
|
||||||
|
override predicate hasArrayWithNullTerminator(int param) { param = 1 }
|
||||||
|
|
||||||
|
override predicate hasArrayWithUnknownSize(int param) { param = 0 }
|
||||||
|
|
||||||
|
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||||
|
|
||||||
|
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||||
|
|
||||||
|
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||||
|
i = 0 and
|
||||||
|
buffer = true and
|
||||||
|
mustWrite = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||||
|
(i = 0 or i = 1) and
|
||||||
|
buffer = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
|
|||||||
"wcsxfrm_l", // _strxfrm_l(dest, src, max_amount, locale)
|
"wcsxfrm_l", // _strxfrm_l(dest, src, max_amount, locale)
|
||||||
"_mbsnbcpy", // _mbsnbcpy(dest, src, max_amount)
|
"_mbsnbcpy", // _mbsnbcpy(dest, src, max_amount)
|
||||||
"stpcpy", // stpcpy(dest, src)
|
"stpcpy", // stpcpy(dest, src)
|
||||||
"stpncpy" // stpcpy(dest, src, max_amount)
|
"stpncpy", // stpncpy(dest, src, max_amount)
|
||||||
|
"strlcpy" // strlcpy(dst, src, dst_size)
|
||||||
])
|
])
|
||||||
or
|
or
|
||||||
(
|
(
|
||||||
@@ -53,6 +54,11 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
|
|||||||
*/
|
*/
|
||||||
private predicate isSVariant() { this.getName().matches("%\\_s") }
|
private predicate isSVariant() { this.getName().matches("%\\_s") }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the function returns the total length the string would have had if the size was unlimited.
|
||||||
|
*/
|
||||||
|
private predicate returnsTotalLength() { this.getName() = "strlcpy" }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the index of the parameter that is the maximum size of the copy (in characters).
|
* Gets the index of the parameter that is the maximum size of the copy (in characters).
|
||||||
*/
|
*/
|
||||||
@@ -60,7 +66,7 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
|
|||||||
if this.isSVariant()
|
if this.isSVariant()
|
||||||
then result = 1
|
then result = 1
|
||||||
else (
|
else (
|
||||||
this.getName().matches(["%ncpy%", "%nbcpy%", "%xfrm%"]) and
|
this.getName().matches(["%ncpy%", "%nbcpy%", "%xfrm%", "strlcpy"]) and
|
||||||
result = 2
|
result = 2
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -100,6 +106,7 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
|
|||||||
input.isParameterDeref(this.getParamSrc()) and
|
input.isParameterDeref(this.getParamSrc()) and
|
||||||
output.isReturnValueDeref()
|
output.isReturnValueDeref()
|
||||||
or
|
or
|
||||||
|
not this.returnsTotalLength() and
|
||||||
input.isParameter(this.getParamDest()) and
|
input.isParameter(this.getParamDest()) and
|
||||||
output.isReturnValue()
|
output.isReturnValue()
|
||||||
}
|
}
|
||||||
@@ -110,8 +117,9 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
|
|||||||
exists(this.getParamSize()) and
|
exists(this.getParamSize()) and
|
||||||
input.isParameterDeref(this.getParamSrc()) and
|
input.isParameterDeref(this.getParamSrc()) and
|
||||||
(
|
(
|
||||||
output.isParameterDeref(this.getParamDest()) or
|
output.isParameterDeref(this.getParamDest())
|
||||||
output.isReturnValueDeref()
|
or
|
||||||
|
not this.returnsTotalLength() and output.isReturnValueDeref()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import semmle.code.cpp.Parameter
|
|||||||
|
|
||||||
private newtype TFunctionInput =
|
private newtype TFunctionInput =
|
||||||
TInParameter(ParameterIndex i) or
|
TInParameter(ParameterIndex i) or
|
||||||
TInParameterDeref(ParameterIndex i) or
|
TInParameterDeref(ParameterIndex i, int indirectionIndex) { indirectionIndex = [1, 2] } or
|
||||||
TInQualifierObject() or
|
TInQualifierObject() or
|
||||||
TInQualifierAddress() or
|
TInQualifierAddress() or
|
||||||
TInReturnValueDeref()
|
TInReturnValueDeref()
|
||||||
@@ -245,15 +245,18 @@ class InParameter extends FunctionInput, TInParameter {
|
|||||||
*/
|
*/
|
||||||
class InParameterDeref extends FunctionInput, TInParameterDeref {
|
class InParameterDeref extends FunctionInput, TInParameterDeref {
|
||||||
ParameterIndex index;
|
ParameterIndex index;
|
||||||
|
int indirectionIndex;
|
||||||
|
|
||||||
InParameterDeref() { this = TInParameterDeref(index) }
|
InParameterDeref() { this = TInParameterDeref(index, indirectionIndex) }
|
||||||
|
|
||||||
override string toString() { result = "InParameterDeref " + index.toString() }
|
override string toString() { result = "InParameterDeref " + index.toString() }
|
||||||
|
|
||||||
/** Gets the zero-based index of the parameter. */
|
/** Gets the zero-based index of the parameter. */
|
||||||
ParameterIndex getIndex() { result = index }
|
ParameterIndex getIndex() { result = index }
|
||||||
|
|
||||||
override predicate isParameterDeref(ParameterIndex i) { i = index }
|
override predicate isParameterDeref(ParameterIndex i, int indirection) {
|
||||||
|
i = index and indirectionIndex = indirection
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -321,10 +324,10 @@ class InReturnValueDeref extends FunctionInput, TInReturnValueDeref {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private newtype TFunctionOutput =
|
private newtype TFunctionOutput =
|
||||||
TOutParameterDeref(ParameterIndex i) or
|
TOutParameterDeref(ParameterIndex i, int indirectionIndex) { indirectionIndex = [1, 2] } or
|
||||||
TOutQualifierObject() or
|
TOutQualifierObject() or
|
||||||
TOutReturnValue() or
|
TOutReturnValue() or
|
||||||
TOutReturnValueDeref()
|
TOutReturnValueDeref(int indirections) { indirections = [1, 2] }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An output from a function. This can be:
|
* An output from a function. This can be:
|
||||||
@@ -498,17 +501,16 @@ class FunctionOutput extends TFunctionOutput {
|
|||||||
*/
|
*/
|
||||||
class OutParameterDeref extends FunctionOutput, TOutParameterDeref {
|
class OutParameterDeref extends FunctionOutput, TOutParameterDeref {
|
||||||
ParameterIndex index;
|
ParameterIndex index;
|
||||||
|
int indirectionIndex;
|
||||||
|
|
||||||
OutParameterDeref() { this = TOutParameterDeref(index) }
|
OutParameterDeref() { this = TOutParameterDeref(index, indirectionIndex) }
|
||||||
|
|
||||||
override string toString() { result = "OutParameterDeref " + index.toString() }
|
override string toString() { result = "OutParameterDeref " + index.toString() }
|
||||||
|
|
||||||
ParameterIndex getIndex() { result = index }
|
ParameterIndex getIndex() { result = index }
|
||||||
|
|
||||||
override predicate isParameterDeref(ParameterIndex i) { i = index }
|
|
||||||
|
|
||||||
override predicate isParameterDeref(ParameterIndex i, int ind) {
|
override predicate isParameterDeref(ParameterIndex i, int ind) {
|
||||||
this.isParameterDeref(i) and ind = 1
|
i = index and ind = indirectionIndex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -572,4 +574,8 @@ class OutReturnValueDeref extends FunctionOutput, TOutReturnValueDeref {
|
|||||||
override string toString() { result = "OutReturnValueDeref" }
|
override string toString() { result = "OutReturnValueDeref" }
|
||||||
|
|
||||||
override predicate isReturnValueDeref() { any() }
|
override predicate isReturnValueDeref() { any() }
|
||||||
|
|
||||||
|
override predicate isReturnValueDeref(int indirectionIndex) {
|
||||||
|
this = TOutReturnValueDeref(indirectionIndex)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,9 +17,7 @@ private import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
|||||||
* `upper` is true, and can be traced back to a guard represented by `reason`.
|
* `upper` is true, and can be traced back to a guard represented by `reason`.
|
||||||
*/
|
*/
|
||||||
predicate bounded(Expr e, Bound b, float delta, boolean upper, Reason reason) {
|
predicate bounded(Expr e, Bound b, float delta, boolean upper, Reason reason) {
|
||||||
exists(SemanticExprConfig::Expr semExpr |
|
exists(SemanticExprConfig::Expr semExpr | semExpr.getUnconvertedResultExpression() = e |
|
||||||
semExpr.getUnconverted().getUnconvertedResultExpression() = e
|
|
||||||
|
|
|
||||||
semBounded(semExpr, b, delta, upper, reason)
|
semBounded(semExpr, b, delta, upper, reason)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -30,9 +28,7 @@ predicate bounded(Expr e, Bound b, float delta, boolean upper, Reason reason) {
|
|||||||
* The `Expr` may be a conversion.
|
* The `Expr` may be a conversion.
|
||||||
*/
|
*/
|
||||||
predicate convertedBounded(Expr e, Bound b, float delta, boolean upper, Reason reason) {
|
predicate convertedBounded(Expr e, Bound b, float delta, boolean upper, Reason reason) {
|
||||||
exists(SemanticExprConfig::Expr semExpr |
|
exists(SemanticExprConfig::Expr semExpr | semExpr.getConvertedResultExpression() = e |
|
||||||
semExpr.getConverted().getConvertedResultExpression() = e
|
|
||||||
|
|
|
||||||
semBounded(semExpr, b, delta, upper, reason)
|
semBounded(semExpr, b, delta, upper, reason)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ predicate exprMightOverflowNegatively(Expr expr) {
|
|||||||
lowerBound(expr) < exprMinVal(expr)
|
lowerBound(expr) < exprMinVal(expr)
|
||||||
or
|
or
|
||||||
exists(SemanticExprConfig::Expr semExpr |
|
exists(SemanticExprConfig::Expr semExpr |
|
||||||
semExpr.getUnconverted().getAst() = expr and
|
semExpr.getAst() = expr and
|
||||||
ConstantStage::potentiallyOverflowingExpr(false, semExpr) and
|
ConstantStage::potentiallyOverflowingExpr(false, semExpr) and
|
||||||
not ConstantStage::initialBounded(semExpr, _, _, false, _, _, _)
|
not ConstantStage::initialBounded(semExpr, _, _, false, _, _, _)
|
||||||
)
|
)
|
||||||
@@ -126,7 +126,7 @@ predicate exprMightOverflowPositively(Expr expr) {
|
|||||||
upperBound(expr) > exprMaxVal(expr)
|
upperBound(expr) > exprMaxVal(expr)
|
||||||
or
|
or
|
||||||
exists(SemanticExprConfig::Expr semExpr |
|
exists(SemanticExprConfig::Expr semExpr |
|
||||||
semExpr.getUnconverted().getAst() = expr and
|
semExpr.getAst() = expr and
|
||||||
ConstantStage::potentiallyOverflowingExpr(true, semExpr) and
|
ConstantStage::potentiallyOverflowingExpr(true, semExpr) and
|
||||||
not ConstantStage::initialBounded(semExpr, _, _, true, _, _, _)
|
not ConstantStage::initialBounded(semExpr, _, _, true, _, _, _)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -12,9 +12,6 @@ class SemBasicBlock extends Specific::BasicBlock {
|
|||||||
/** Holds if this block (transitively) dominates `otherblock`. */
|
/** Holds if this block (transitively) dominates `otherblock`. */
|
||||||
final predicate bbDominates(SemBasicBlock otherBlock) { Specific::bbDominates(this, otherBlock) }
|
final predicate bbDominates(SemBasicBlock otherBlock) { Specific::bbDominates(this, otherBlock) }
|
||||||
|
|
||||||
/** Holds if this block has dominance information. */
|
|
||||||
final predicate hasDominanceInformation() { Specific::hasDominanceInformation(this) }
|
|
||||||
|
|
||||||
/** Gets an expression that is evaluated in this basic block. */
|
/** Gets an expression that is evaluated in this basic block. */
|
||||||
final SemExpr getAnExpr() { result.getBasicBlock() = this }
|
final SemExpr getAnExpr() { result.getBasicBlock() = this }
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
private import Semantic
|
private import Semantic
|
||||||
private import SemanticExprSpecific::SemanticExprConfig as Specific
|
private import SemanticExprSpecific::SemanticExprConfig as Specific
|
||||||
|
private import SemanticType
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An language-neutral expression.
|
* An language-neutral expression.
|
||||||
@@ -241,8 +242,21 @@ class SemConvertExpr extends SemUnaryExpr {
|
|||||||
SemConvertExpr() { opcode instanceof Opcode::Convert }
|
SemConvertExpr() { opcode instanceof Opcode::Convert }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private import semmle.code.cpp.ir.IR as IR
|
||||||
|
|
||||||
|
/** A conversion instruction which is guaranteed to not overflow. */
|
||||||
|
private class SafeConversion extends IR::ConvertInstruction {
|
||||||
|
SafeConversion() {
|
||||||
|
exists(SemType tFrom, SemType tTo |
|
||||||
|
tFrom = getSemanticType(super.getUnary().getResultIRType()) and
|
||||||
|
tTo = getSemanticType(super.getResultIRType()) and
|
||||||
|
conversionCannotOverflow(tFrom, tTo)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class SemCopyValueExpr extends SemUnaryExpr {
|
class SemCopyValueExpr extends SemUnaryExpr {
|
||||||
SemCopyValueExpr() { opcode instanceof Opcode::CopyValue }
|
SemCopyValueExpr() { opcode instanceof Opcode::CopyValue or this instanceof SafeConversion }
|
||||||
}
|
}
|
||||||
|
|
||||||
class SemNegateExpr extends SemUnaryExpr {
|
class SemNegateExpr extends SemUnaryExpr {
|
||||||
|
|||||||
@@ -12,87 +12,10 @@ private import semmle.code.cpp.ir.ValueNumbering
|
|||||||
module SemanticExprConfig {
|
module SemanticExprConfig {
|
||||||
class Location = Cpp::Location;
|
class Location = Cpp::Location;
|
||||||
|
|
||||||
/** A `ConvertInstruction` or a `CopyValueInstruction`. */
|
|
||||||
private class Conversion extends IR::UnaryInstruction {
|
|
||||||
Conversion() {
|
|
||||||
this instanceof IR::CopyValueInstruction
|
|
||||||
or
|
|
||||||
this instanceof IR::ConvertInstruction
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if this instruction converts a value of type `tFrom` to a value of type `tTo`. */
|
|
||||||
predicate converts(SemType tFrom, SemType tTo) {
|
|
||||||
tFrom = getSemanticType(this.getUnary().getResultIRType()) and
|
|
||||||
tTo = getSemanticType(this.getResultIRType())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a conversion-like instruction that consumes `op`, and
|
|
||||||
* which is guaranteed to not overflow.
|
|
||||||
*/
|
|
||||||
private IR::Instruction safeConversion(IR::Operand op) {
|
|
||||||
exists(Conversion conv, SemType tFrom, SemType tTo |
|
|
||||||
conv.converts(tFrom, tTo) and
|
|
||||||
conversionCannotOverflow(tFrom, tTo) and
|
|
||||||
conv.getUnaryOperand() = op and
|
|
||||||
result = conv
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if `i1 = i2` or if `i2` is a safe conversion that consumes `i1`. */
|
|
||||||
private predicate idOrSafeConversion(IR::Instruction i1, IR::Instruction i2) {
|
|
||||||
not i1.getResultIRType() instanceof IR::IRVoidType and
|
|
||||||
(
|
|
||||||
i1 = i2
|
|
||||||
or
|
|
||||||
i2 = safeConversion(i1.getAUse()) and
|
|
||||||
i1.getBlock() = i2.getBlock()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
module Equiv = QlBuiltins::EquivalenceRelation<IR::Instruction, idOrSafeConversion/2>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The expressions on which we perform range analysis.
|
* The expressions on which we perform range analysis.
|
||||||
*/
|
*/
|
||||||
class Expr extends Equiv::EquivalenceClass {
|
class Expr = IR::Instruction;
|
||||||
/** Gets the n'th instruction in this equivalence class. */
|
|
||||||
private IR::Instruction getInstruction(int n) {
|
|
||||||
result =
|
|
||||||
rank[n + 1](IR::Instruction instr, int i, IR::IRBlock block |
|
|
||||||
this = Equiv::getEquivalenceClass(instr) and block.getInstruction(i) = instr
|
|
||||||
|
|
|
||||||
instr order by i
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets a textual representation of this element. */
|
|
||||||
string toString() { result = this.getUnconverted().toString() }
|
|
||||||
|
|
||||||
/** Gets the basic block of this expression. */
|
|
||||||
IR::IRBlock getBlock() { result = this.getUnconverted().getBlock() }
|
|
||||||
|
|
||||||
/** Gets the unconverted instruction associated with this expression. */
|
|
||||||
IR::Instruction getUnconverted() { result = this.getInstruction(0) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the final instruction associated with this expression. This
|
|
||||||
* represents the result after applying all the safe conversions.
|
|
||||||
*/
|
|
||||||
IR::Instruction getConverted() {
|
|
||||||
exists(int n |
|
|
||||||
result = this.getInstruction(n) and
|
|
||||||
not exists(this.getInstruction(n + 1))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets the type of the result produced by this instruction. */
|
|
||||||
IR::IRType getResultIRType() { result = this.getConverted().getResultIRType() }
|
|
||||||
|
|
||||||
/** Gets the location of the source code for this expression. */
|
|
||||||
Location getLocation() { result = this.getUnconverted().getLocation() }
|
|
||||||
}
|
|
||||||
|
|
||||||
SemBasicBlock getExprBasicBlock(Expr e) { result = getSemanticBasicBlock(e.getBlock()) }
|
SemBasicBlock getExprBasicBlock(Expr e) { result = getSemanticBasicBlock(e.getBlock()) }
|
||||||
|
|
||||||
@@ -139,12 +62,12 @@ module SemanticExprConfig {
|
|||||||
|
|
||||||
predicate stringLiteral(Expr expr, SemType type, string value) {
|
predicate stringLiteral(Expr expr, SemType type, string value) {
|
||||||
anyConstantExpr(expr, type, value) and
|
anyConstantExpr(expr, type, value) and
|
||||||
expr.getUnconverted() instanceof IR::StringConstantInstruction
|
expr instanceof IR::StringConstantInstruction
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate binaryExpr(Expr expr, Opcode opcode, SemType type, Expr leftOperand, Expr rightOperand) {
|
predicate binaryExpr(Expr expr, Opcode opcode, SemType type, Expr leftOperand, Expr rightOperand) {
|
||||||
exists(IR::BinaryInstruction instr |
|
exists(IR::BinaryInstruction instr |
|
||||||
instr = expr.getUnconverted() and
|
instr = expr and
|
||||||
type = getSemanticType(instr.getResultIRType()) and
|
type = getSemanticType(instr.getResultIRType()) and
|
||||||
leftOperand = getSemanticExpr(instr.getLeft()) and
|
leftOperand = getSemanticExpr(instr.getLeft()) and
|
||||||
rightOperand = getSemanticExpr(instr.getRight()) and
|
rightOperand = getSemanticExpr(instr.getRight()) and
|
||||||
@@ -154,14 +77,14 @@ module SemanticExprConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate unaryExpr(Expr expr, Opcode opcode, SemType type, Expr operand) {
|
predicate unaryExpr(Expr expr, Opcode opcode, SemType type, Expr operand) {
|
||||||
exists(IR::UnaryInstruction instr | instr = expr.getUnconverted() |
|
exists(IR::UnaryInstruction instr | instr = expr |
|
||||||
type = getSemanticType(instr.getResultIRType()) and
|
type = getSemanticType(instr.getResultIRType()) and
|
||||||
operand = getSemanticExpr(instr.getUnary()) and
|
operand = getSemanticExpr(instr.getUnary()) and
|
||||||
// REVIEW: Merge the two operand types.
|
// REVIEW: Merge the two operand types.
|
||||||
opcode.toString() = instr.getOpcode().toString()
|
opcode.toString() = instr.getOpcode().toString()
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(IR::StoreInstruction instr | instr = expr.getUnconverted() |
|
exists(IR::StoreInstruction instr | instr = expr |
|
||||||
type = getSemanticType(instr.getResultIRType()) and
|
type = getSemanticType(instr.getResultIRType()) and
|
||||||
operand = getSemanticExpr(instr.getSourceValue()) and
|
operand = getSemanticExpr(instr.getSourceValue()) and
|
||||||
opcode instanceof Opcode::Store
|
opcode instanceof Opcode::Store
|
||||||
@@ -170,13 +93,13 @@ module SemanticExprConfig {
|
|||||||
|
|
||||||
predicate nullaryExpr(Expr expr, Opcode opcode, SemType type) {
|
predicate nullaryExpr(Expr expr, Opcode opcode, SemType type) {
|
||||||
exists(IR::LoadInstruction load |
|
exists(IR::LoadInstruction load |
|
||||||
load = expr.getUnconverted() and
|
load = expr and
|
||||||
type = getSemanticType(load.getResultIRType()) and
|
type = getSemanticType(load.getResultIRType()) and
|
||||||
opcode instanceof Opcode::Load
|
opcode instanceof Opcode::Load
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(IR::InitializeParameterInstruction init |
|
exists(IR::InitializeParameterInstruction init |
|
||||||
init = expr.getUnconverted() and
|
init = expr and
|
||||||
type = getSemanticType(init.getResultIRType()) and
|
type = getSemanticType(init.getResultIRType()) and
|
||||||
opcode instanceof Opcode::InitializeParameter
|
opcode instanceof Opcode::InitializeParameter
|
||||||
)
|
)
|
||||||
@@ -199,8 +122,6 @@ module SemanticExprConfig {
|
|||||||
dominator.dominates(dominated)
|
dominator.dominates(dominated)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate hasDominanceInformation(BasicBlock block) { any() }
|
|
||||||
|
|
||||||
private predicate id(Cpp::Locatable x, Cpp::Locatable y) { x = y }
|
private predicate id(Cpp::Locatable x, Cpp::Locatable y) { x = y }
|
||||||
|
|
||||||
private predicate idOf(Cpp::Locatable x, int y) = equivalenceRelation(id/2)(x, y)
|
private predicate idOf(Cpp::Locatable x, int y) = equivalenceRelation(id/2)(x, y)
|
||||||
@@ -209,17 +130,7 @@ module SemanticExprConfig {
|
|||||||
|
|
||||||
newtype TSsaVariable =
|
newtype TSsaVariable =
|
||||||
TSsaInstruction(IR::Instruction instr) { instr.hasMemoryResult() } or
|
TSsaInstruction(IR::Instruction instr) { instr.hasMemoryResult() } or
|
||||||
TSsaOperand(IR::Operand op) { op.isDefinitionInexact() } or
|
TSsaOperand(IR::PhiInputOperand op) { op.isDefinitionInexact() }
|
||||||
TSsaPointerArithmeticGuard(ValueNumber instr) {
|
|
||||||
exists(Guard g, IR::Operand use |
|
|
||||||
use = instr.getAUse() and use.getIRType() instanceof IR::IRAddressType
|
|
||||||
|
|
|
||||||
g.comparesLt(use, _, _, _, _) or
|
|
||||||
g.comparesLt(_, use, _, _, _) or
|
|
||||||
g.comparesEq(use, _, _, _, _) or
|
|
||||||
g.comparesEq(_, use, _, _, _)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
class SsaVariable extends TSsaVariable {
|
class SsaVariable extends TSsaVariable {
|
||||||
string toString() { none() }
|
string toString() { none() }
|
||||||
@@ -228,9 +139,7 @@ module SemanticExprConfig {
|
|||||||
|
|
||||||
IR::Instruction asInstruction() { none() }
|
IR::Instruction asInstruction() { none() }
|
||||||
|
|
||||||
ValueNumber asPointerArithGuard() { none() }
|
IR::PhiInputOperand asOperand() { none() }
|
||||||
|
|
||||||
IR::Operand asOperand() { none() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class SsaInstructionVariable extends SsaVariable, TSsaInstruction {
|
class SsaInstructionVariable extends SsaVariable, TSsaInstruction {
|
||||||
@@ -245,20 +154,8 @@ module SemanticExprConfig {
|
|||||||
final override IR::Instruction asInstruction() { result = instr }
|
final override IR::Instruction asInstruction() { result = instr }
|
||||||
}
|
}
|
||||||
|
|
||||||
class SsaPointerArithmeticGuard extends SsaVariable, TSsaPointerArithmeticGuard {
|
|
||||||
ValueNumber vn;
|
|
||||||
|
|
||||||
SsaPointerArithmeticGuard() { this = TSsaPointerArithmeticGuard(vn) }
|
|
||||||
|
|
||||||
final override string toString() { result = vn.toString() }
|
|
||||||
|
|
||||||
final override Location getLocation() { result = vn.getLocation() }
|
|
||||||
|
|
||||||
final override ValueNumber asPointerArithGuard() { result = vn }
|
|
||||||
}
|
|
||||||
|
|
||||||
class SsaOperand extends SsaVariable, TSsaOperand {
|
class SsaOperand extends SsaVariable, TSsaOperand {
|
||||||
IR::Operand op;
|
IR::PhiInputOperand op;
|
||||||
|
|
||||||
SsaOperand() { this = TSsaOperand(op) }
|
SsaOperand() { this = TSsaOperand(op) }
|
||||||
|
|
||||||
@@ -266,7 +163,7 @@ module SemanticExprConfig {
|
|||||||
|
|
||||||
final override Location getLocation() { result = op.getLocation() }
|
final override Location getLocation() { result = op.getLocation() }
|
||||||
|
|
||||||
final override IR::Operand asOperand() { result = op }
|
final override IR::PhiInputOperand asOperand() { result = op }
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate explicitUpdate(SsaVariable v, Expr sourceExpr) {
|
predicate explicitUpdate(SsaVariable v, Expr sourceExpr) {
|
||||||
@@ -289,97 +186,29 @@ module SemanticExprConfig {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr getAUse(SsaVariable v) {
|
Expr getAUse(SsaVariable v) { result.(IR::LoadInstruction).getSourceValue() = v.asInstruction() }
|
||||||
result.getUnconverted().(IR::LoadInstruction).getSourceValue() = v.asInstruction()
|
|
||||||
or
|
|
||||||
result.getUnconverted() = v.asPointerArithGuard().getAnInstruction()
|
|
||||||
}
|
|
||||||
|
|
||||||
SemType getSsaVariableType(SsaVariable v) {
|
SemType getSsaVariableType(SsaVariable v) {
|
||||||
result = getSemanticType(v.asInstruction().getResultIRType())
|
result = getSemanticType(v.asInstruction().getResultIRType())
|
||||||
|
or
|
||||||
|
result = getSemanticType(v.asOperand().getUse().getResultIRType())
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicBlock getSsaVariableBasicBlock(SsaVariable v) {
|
BasicBlock getSsaVariableBasicBlock(SsaVariable v) {
|
||||||
result = v.asInstruction().getBlock()
|
result = v.asInstruction().getBlock()
|
||||||
or
|
or
|
||||||
result = v.asOperand().getUse().getBlock()
|
result = v.asOperand().getAnyDef().getBlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
private newtype TReadPosition =
|
/** Holds if `inp` is an input to the phi node along the edge originating in `bb`. */
|
||||||
TReadPositionBlock(IR::IRBlock block) or
|
predicate phiInputFromBlock(SsaVariable phi, SsaVariable inp, BasicBlock bb) {
|
||||||
TReadPositionPhiInputEdge(IR::IRBlock pred, IR::IRBlock succ) {
|
|
||||||
exists(IR::PhiInputOperand input |
|
|
||||||
pred = input.getPredecessorBlock() and
|
|
||||||
succ = input.getUse().getBlock()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
class SsaReadPosition extends TReadPosition {
|
|
||||||
string toString() { none() }
|
|
||||||
|
|
||||||
Location getLocation() { none() }
|
|
||||||
|
|
||||||
predicate hasRead(SsaVariable v) { none() }
|
|
||||||
}
|
|
||||||
|
|
||||||
private class SsaReadPositionBlock extends SsaReadPosition, TReadPositionBlock {
|
|
||||||
IR::IRBlock block;
|
|
||||||
|
|
||||||
SsaReadPositionBlock() { this = TReadPositionBlock(block) }
|
|
||||||
|
|
||||||
final override string toString() { result = block.toString() }
|
|
||||||
|
|
||||||
final override Location getLocation() { result = block.getLocation() }
|
|
||||||
|
|
||||||
final override predicate hasRead(SsaVariable v) {
|
|
||||||
exists(IR::Operand operand |
|
|
||||||
operand.getDef() = v.asInstruction() or
|
|
||||||
operand.getDef() = v.asPointerArithGuard().getAnInstruction()
|
|
||||||
|
|
|
||||||
not operand instanceof IR::PhiInputOperand and
|
|
||||||
operand.getUse().getBlock() = block
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class SsaReadPositionPhiInputEdge extends SsaReadPosition, TReadPositionPhiInputEdge {
|
|
||||||
IR::IRBlock pred;
|
|
||||||
IR::IRBlock succ;
|
|
||||||
|
|
||||||
SsaReadPositionPhiInputEdge() { this = TReadPositionPhiInputEdge(pred, succ) }
|
|
||||||
|
|
||||||
final override string toString() { result = pred.toString() + "->" + succ.toString() }
|
|
||||||
|
|
||||||
final override Location getLocation() { result = succ.getLocation() }
|
|
||||||
|
|
||||||
final override predicate hasRead(SsaVariable v) {
|
|
||||||
exists(IR::PhiInputOperand operand |
|
|
||||||
operand.getDef() = v.asInstruction() or
|
|
||||||
operand.getDef() = v.asPointerArithGuard().getAnInstruction()
|
|
||||||
|
|
|
||||||
operand.getPredecessorBlock() = pred and
|
|
||||||
operand.getUse().getBlock() = succ
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate hasReadOfSsaVariable(SsaReadPosition pos, SsaVariable v) { pos.hasRead(v) }
|
|
||||||
|
|
||||||
predicate readBlock(SsaReadPosition pos, BasicBlock block) { pos = TReadPositionBlock(block) }
|
|
||||||
|
|
||||||
predicate phiInputEdge(SsaReadPosition pos, BasicBlock origBlock, BasicBlock phiBlock) {
|
|
||||||
pos = TReadPositionPhiInputEdge(origBlock, phiBlock)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate phiInput(SsaReadPosition pos, SsaVariable phi, SsaVariable input) {
|
|
||||||
exists(IR::PhiInputOperand operand |
|
exists(IR::PhiInputOperand operand |
|
||||||
pos = TReadPositionPhiInputEdge(operand.getPredecessorBlock(), operand.getUse().getBlock())
|
bb = operand.getPredecessorBlock() and
|
||||||
|
|
|
||||||
phi.asInstruction() = operand.getUse() and
|
phi.asInstruction() = operand.getUse() and
|
||||||
(
|
(
|
||||||
input.asInstruction() = operand.getDef()
|
inp.asInstruction() = operand.getDef()
|
||||||
or
|
or
|
||||||
input.asOperand() = operand
|
inp.asOperand() = operand
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -433,7 +262,7 @@ module SemanticExprConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the expression associated with `instr`. */
|
/** Gets the expression associated with `instr`. */
|
||||||
SemExpr getSemanticExpr(IR::Instruction instr) { result = Equiv::getEquivalenceClass(instr) }
|
SemExpr getSemanticExpr(IR::Instruction instr) { result = instr }
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate getSemanticExpr = SemanticExprConfig::getSemanticExpr/1;
|
predicate getSemanticExpr = SemanticExprConfig::getSemanticExpr/1;
|
||||||
|
|||||||
@@ -35,32 +35,4 @@ predicate semImplies_v2(SemGuard g1, boolean b1, SemGuard g2, boolean b2) {
|
|||||||
Specific::implies_v2(g1, b1, g2, b2)
|
Specific::implies_v2(g1, b1, g2, b2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `guard` directly controls the position `controlled` with the
|
|
||||||
* value `testIsTrue`.
|
|
||||||
*/
|
|
||||||
pragma[nomagic]
|
|
||||||
predicate semGuardDirectlyControlsSsaRead(
|
|
||||||
SemGuard guard, SemSsaReadPosition controlled, boolean testIsTrue
|
|
||||||
) {
|
|
||||||
guard.directlyControls(controlled.(SemSsaReadPositionBlock).getBlock(), testIsTrue)
|
|
||||||
or
|
|
||||||
exists(SemSsaReadPositionPhiInputEdge controlledEdge | controlledEdge = controlled |
|
|
||||||
guard.directlyControls(controlledEdge.getOrigBlock(), testIsTrue) or
|
|
||||||
guard.hasBranchEdge(controlledEdge.getOrigBlock(), controlledEdge.getPhiBlock(), testIsTrue)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `guard` controls the position `controlled` with the value `testIsTrue`.
|
|
||||||
*/
|
|
||||||
predicate semGuardControlsSsaRead(SemGuard guard, SemSsaReadPosition controlled, boolean testIsTrue) {
|
|
||||||
semGuardDirectlyControlsSsaRead(guard, controlled, testIsTrue)
|
|
||||||
or
|
|
||||||
exists(SemGuard guard0, boolean testIsTrue0 |
|
|
||||||
semImplies_v2(guard0, testIsTrue0, guard, testIsTrue) and
|
|
||||||
semGuardControlsSsaRead(guard0, controlled, testIsTrue0)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
SemGuard semGetComparisonGuard(SemRelationalExpr e) { result = Specific::comparisonGuard(e) }
|
SemGuard semGetComparisonGuard(SemRelationalExpr e) { result = Specific::comparisonGuard(e) }
|
||||||
|
|||||||
@@ -22,75 +22,15 @@ class SemSsaExplicitUpdate extends SemSsaVariable {
|
|||||||
|
|
||||||
SemSsaExplicitUpdate() { Specific::explicitUpdate(this, sourceExpr) }
|
SemSsaExplicitUpdate() { Specific::explicitUpdate(this, sourceExpr) }
|
||||||
|
|
||||||
final SemExpr getSourceExpr() { result = sourceExpr }
|
final SemExpr getDefiningExpr() { result = sourceExpr }
|
||||||
}
|
}
|
||||||
|
|
||||||
class SemSsaPhiNode extends SemSsaVariable {
|
class SemSsaPhiNode extends SemSsaVariable {
|
||||||
SemSsaPhiNode() { Specific::phi(this) }
|
SemSsaPhiNode() { Specific::phi(this) }
|
||||||
|
|
||||||
final SemSsaVariable getAPhiInput() { result = Specific::getAPhiInput(this) }
|
final SemSsaVariable getAPhiInput() { result = Specific::getAPhiInput(this) }
|
||||||
}
|
|
||||||
|
final predicate hasInputFromBlock(SemSsaVariable inp, SemBasicBlock bb) {
|
||||||
class SemSsaReadPosition instanceof Specific::SsaReadPosition {
|
Specific::phiInputFromBlock(this, inp, bb)
|
||||||
final string toString() { result = super.toString() }
|
}
|
||||||
|
|
||||||
final Specific::Location getLocation() { result = super.getLocation() }
|
|
||||||
|
|
||||||
final predicate hasReadOfVar(SemSsaVariable var) { Specific::hasReadOfSsaVariable(this, var) }
|
|
||||||
}
|
|
||||||
|
|
||||||
class SemSsaReadPositionPhiInputEdge extends SemSsaReadPosition {
|
|
||||||
SemBasicBlock origBlock;
|
|
||||||
SemBasicBlock phiBlock;
|
|
||||||
|
|
||||||
SemSsaReadPositionPhiInputEdge() { Specific::phiInputEdge(this, origBlock, phiBlock) }
|
|
||||||
|
|
||||||
predicate phiInput(SemSsaPhiNode phi, SemSsaVariable inp) { Specific::phiInput(this, phi, inp) }
|
|
||||||
|
|
||||||
SemBasicBlock getOrigBlock() { result = origBlock }
|
|
||||||
|
|
||||||
SemBasicBlock getPhiBlock() { result = phiBlock }
|
|
||||||
}
|
|
||||||
|
|
||||||
class SemSsaReadPositionBlock extends SemSsaReadPosition {
|
|
||||||
SemBasicBlock block;
|
|
||||||
|
|
||||||
SemSsaReadPositionBlock() { Specific::readBlock(this, block) }
|
|
||||||
|
|
||||||
SemBasicBlock getBlock() { result = block }
|
|
||||||
|
|
||||||
SemExpr getAnExpr() { result = this.getBlock().getAnExpr() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `inp` is an input to `phi` along a back edge.
|
|
||||||
*/
|
|
||||||
predicate semBackEdge(SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge) {
|
|
||||||
edge.phiInput(phi, inp) and
|
|
||||||
// Conservatively assume that every edge is a back edge if we don't have dominance information.
|
|
||||||
(
|
|
||||||
phi.getBasicBlock().bbDominates(edge.getOrigBlock()) or
|
|
||||||
irreducibleSccEdge(edge.getOrigBlock(), phi.getBasicBlock()) or
|
|
||||||
not edge.getOrigBlock().hasDominanceInformation()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the edge from b1 to b2 is part of a multiple-entry cycle in an irreducible control flow
|
|
||||||
* graph.
|
|
||||||
*
|
|
||||||
* An ireducible control flow graph is one where the usual dominance-based back edge detection does
|
|
||||||
* not work, because there is a cycle with multiple entry points, meaning there are
|
|
||||||
* mutually-reachable basic blocks where neither dominates the other. For such a graph, we first
|
|
||||||
* remove all detectable back-edges using the normal condition that the predecessor block is
|
|
||||||
* dominated by the successor block, then mark all edges in a cycle in the resulting graph as back
|
|
||||||
* edges.
|
|
||||||
*/
|
|
||||||
private predicate irreducibleSccEdge(SemBasicBlock b1, SemBasicBlock b2) {
|
|
||||||
trimmedEdge(b1, b2) and trimmedEdge+(b2, b1)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate trimmedEdge(SemBasicBlock pred, SemBasicBlock succ) {
|
|
||||||
pred.getASuccessor() = succ and
|
|
||||||
not succ.bbDominates(pred)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ private predicate constantIntegerExpr(SemExpr e, int val) {
|
|||||||
// Copy of another constant
|
// Copy of another constant
|
||||||
exists(SemSsaExplicitUpdate v, SemExpr src |
|
exists(SemSsaExplicitUpdate v, SemExpr src |
|
||||||
e = v.getAUse() and
|
e = v.getAUse() and
|
||||||
src = v.getSourceExpr() and
|
src = v.getDefiningExpr() and
|
||||||
constantIntegerExpr(src, val)
|
constantIntegerExpr(src, val)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
|||||||
@@ -1,328 +0,0 @@
|
|||||||
/**
|
|
||||||
* Provides inferences of the form: `e` equals `b + v` modulo `m` where `e` is
|
|
||||||
* an expression, `b` is a `Bound` (typically zero or the value of an SSA
|
|
||||||
* variable), and `v` is an integer in the range `[0 .. m-1]`.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The main recursion has base cases in both `ssaModulus` (for guarded reads) and `semExprModulus`
|
|
||||||
* (for constant values). The most interesting recursive case is `phiModulusRankStep`, which
|
|
||||||
* handles phi inputs.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private import ModulusAnalysisSpecific::Private
|
|
||||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
|
||||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticLocation
|
|
||||||
private import ConstantAnalysis
|
|
||||||
private import RangeUtils
|
|
||||||
private import codeql.rangeanalysis.RangeAnalysis
|
|
||||||
private import RangeAnalysisImpl
|
|
||||||
|
|
||||||
module ModulusAnalysis<DeltaSig D, BoundSig<SemLocation, Sem, D> Bounds, UtilSig<Sem, D> U> {
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate valueFlowStepSsaEqFlowCond(
|
|
||||||
SemSsaReadPosition pos, SemSsaVariable v, SemExpr e, int delta
|
|
||||||
) {
|
|
||||||
exists(SemGuard guard, boolean testIsTrue |
|
|
||||||
guard = U::semEqFlowCond(v, e, D::fromInt(delta), true, testIsTrue) and
|
|
||||||
semGuardDirectlyControlsSsaRead(guard, pos, testIsTrue)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `e + delta` equals `v` at `pos`.
|
|
||||||
*/
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate valueFlowStepSsa(SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, int delta) {
|
|
||||||
U::semSsaUpdateStep(v, e, D::fromInt(delta)) and pos.hasReadOfVar(v)
|
|
||||||
or
|
|
||||||
pos.hasReadOfVar(v) and
|
|
||||||
valueFlowStepSsaEqFlowCond(pos, v, e, delta)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `add` is the addition of `larg` and `rarg`, neither of which are
|
|
||||||
* `ConstantIntegerExpr`s.
|
|
||||||
*/
|
|
||||||
private predicate nonConstAddition(SemExpr add, SemExpr larg, SemExpr rarg) {
|
|
||||||
exists(SemAddExpr a | a = add |
|
|
||||||
larg = a.getLeftOperand() and
|
|
||||||
rarg = a.getRightOperand()
|
|
||||||
) and
|
|
||||||
not larg instanceof SemConstantIntegerExpr and
|
|
||||||
not rarg instanceof SemConstantIntegerExpr
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sub` is the subtraction of `larg` and `rarg`, where `rarg` is not
|
|
||||||
* a `ConstantIntegerExpr`.
|
|
||||||
*/
|
|
||||||
private predicate nonConstSubtraction(SemExpr sub, SemExpr larg, SemExpr rarg) {
|
|
||||||
exists(SemSubExpr s | s = sub |
|
|
||||||
larg = s.getLeftOperand() and
|
|
||||||
rarg = s.getRightOperand()
|
|
||||||
) and
|
|
||||||
not rarg instanceof SemConstantIntegerExpr
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets an expression that is the remainder modulo `mod` of `arg`. */
|
|
||||||
private SemExpr modExpr(SemExpr arg, int mod) {
|
|
||||||
exists(SemRemExpr rem |
|
|
||||||
result = rem and
|
|
||||||
arg = rem.getLeftOperand() and
|
|
||||||
rem.getRightOperand().(SemConstantIntegerExpr).getIntValue() = mod and
|
|
||||||
mod >= 2
|
|
||||||
)
|
|
||||||
or
|
|
||||||
exists(SemConstantIntegerExpr c |
|
|
||||||
mod = 2.pow([1 .. 30]) and
|
|
||||||
c.getIntValue() = mod - 1 and
|
|
||||||
result.(SemBitAndExpr).hasOperands(arg, c)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a guard that tests whether `v` is congruent with `val` modulo `mod` on
|
|
||||||
* its `testIsTrue` branch.
|
|
||||||
*/
|
|
||||||
private SemGuard moduloCheck(SemSsaVariable v, int val, int mod, boolean testIsTrue) {
|
|
||||||
exists(SemExpr rem, SemConstantIntegerExpr c, int r, boolean polarity |
|
|
||||||
result.isEquality(rem, c, polarity) and
|
|
||||||
c.getIntValue() = r and
|
|
||||||
rem = modExpr(v.getAUse(), mod) and
|
|
||||||
(
|
|
||||||
testIsTrue = polarity and val = r
|
|
||||||
or
|
|
||||||
testIsTrue = polarity.booleanNot() and
|
|
||||||
mod = 2 and
|
|
||||||
val = 1 - r and
|
|
||||||
(r = 0 or r = 1)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if a guard ensures that `v` at `pos` is congruent with `val` modulo `mod`.
|
|
||||||
*/
|
|
||||||
private predicate moduloGuardedRead(SemSsaVariable v, SemSsaReadPosition pos, int val, int mod) {
|
|
||||||
exists(SemGuard guard, boolean testIsTrue |
|
|
||||||
pos.hasReadOfVar(v) and
|
|
||||||
guard = moduloCheck(v, val, mod, testIsTrue) and
|
|
||||||
semGuardControlsSsaRead(guard, pos, testIsTrue)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if `factor` is a power of 2 that divides `mask`. */
|
|
||||||
bindingset[mask]
|
|
||||||
private predicate andmaskFactor(int mask, int factor) {
|
|
||||||
mask % factor = 0 and
|
|
||||||
factor = 2.pow([1 .. 30])
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if `e` is evenly divisible by `factor`. */
|
|
||||||
private predicate evenlyDivisibleExpr(SemExpr e, int factor) {
|
|
||||||
exists(SemConstantIntegerExpr c, int k | k = c.getIntValue() |
|
|
||||||
e.(SemMulExpr).getAnOperand() = c and factor = k.abs() and factor >= 2
|
|
||||||
or
|
|
||||||
e.(SemShiftLeftExpr).getRightOperand() = c and factor = 2.pow(k) and k > 0
|
|
||||||
or
|
|
||||||
e.(SemBitAndExpr).getAnOperand() = c and factor = max(int f | andmaskFactor(k, f))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the remainder of `val` modulo `mod`.
|
|
||||||
*
|
|
||||||
* For `mod = 0` the result equals `val` and for `mod > 1` the result is within
|
|
||||||
* the range `[0 .. mod-1]`.
|
|
||||||
*/
|
|
||||||
bindingset[val, mod]
|
|
||||||
private int remainder(int val, int mod) {
|
|
||||||
mod = 0 and result = val
|
|
||||||
or
|
|
||||||
mod > 1 and result = ((val % mod) + mod) % mod
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `inp` is an input to `phi` and equals `phi` modulo `mod` along `edge`.
|
|
||||||
*/
|
|
||||||
private predicate phiSelfModulus(
|
|
||||||
SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int mod
|
|
||||||
) {
|
|
||||||
exists(Bounds::SemSsaBound phibound, int v, int m |
|
|
||||||
edge.phiInput(phi, inp) and
|
|
||||||
phibound.getAVariable() = phi and
|
|
||||||
ssaModulus(inp, edge, phibound, v, m) and
|
|
||||||
mod = m.gcd(v) and
|
|
||||||
mod != 1
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `b + val` modulo `mod` is a candidate congruence class for `phi`.
|
|
||||||
*/
|
|
||||||
private predicate phiModulusInit(SemSsaPhiNode phi, Bounds::SemBound b, int val, int mod) {
|
|
||||||
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
|
|
||||||
edge.phiInput(phi, inp) and
|
|
||||||
ssaModulus(inp, edge, b, val, mod)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if all inputs to `phi` numbered `1` to `rix` are equal to `b + val` modulo `mod`.
|
|
||||||
*/
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate phiModulusRankStep(
|
|
||||||
SemSsaPhiNode phi, Bounds::SemBound b, int val, int mod, int rix
|
|
||||||
) {
|
|
||||||
/*
|
|
||||||
* base case. If any phi input is equal to `b + val` modulo `mod`, that's a potential congruence
|
|
||||||
* class for the phi node.
|
|
||||||
*/
|
|
||||||
|
|
||||||
rix = 0 and
|
|
||||||
phiModulusInit(phi, b, val, mod)
|
|
||||||
or
|
|
||||||
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int v1, int m1 |
|
|
||||||
mod != 1 and
|
|
||||||
val = remainder(v1, mod)
|
|
||||||
|
|
|
||||||
/*
|
|
||||||
* Recursive case. If `inp` = `b + v2` mod `m2`, we combine that with the preceding potential
|
|
||||||
* congruence class `b + v1` mod `m1`. The result will be the congruence class of `v1` modulo
|
|
||||||
* the greatest common denominator of `m1`, `m2`, and `v1 - v2`.
|
|
||||||
*/
|
|
||||||
|
|
||||||
exists(int v2, int m2 |
|
|
||||||
rankedPhiInput(pragma[only_bind_out](phi), inp, edge, rix) and
|
|
||||||
phiModulusRankStep(phi, b, v1, m1, rix - 1) and
|
|
||||||
ssaModulus(inp, edge, b, v2, m2) and
|
|
||||||
mod = m1.gcd(m2).gcd(v1 - v2)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
/*
|
|
||||||
* Recursive case. If `inp` = `phi` mod `m2`, we combine that with the preceding potential
|
|
||||||
* congruence class `b + v1` mod `m1`. The result will be a congruence class modulo the greatest
|
|
||||||
* common denominator of `m1` and `m2`.
|
|
||||||
*/
|
|
||||||
|
|
||||||
exists(int m2 |
|
|
||||||
rankedPhiInput(phi, inp, edge, rix) and
|
|
||||||
phiModulusRankStep(phi, b, v1, m1, rix - 1) and
|
|
||||||
phiSelfModulus(phi, inp, edge, m2) and
|
|
||||||
mod = m1.gcd(m2)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `phi` is equal to `b + val` modulo `mod`.
|
|
||||||
*/
|
|
||||||
private predicate phiModulus(SemSsaPhiNode phi, Bounds::SemBound b, int val, int mod) {
|
|
||||||
exists(int r |
|
|
||||||
maxPhiInputRank(phi, r) and
|
|
||||||
phiModulusRankStep(phi, b, val, mod, r)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `v` at `pos` is equal to `b + val` modulo `mod`.
|
|
||||||
*/
|
|
||||||
private predicate ssaModulus(
|
|
||||||
SemSsaVariable v, SemSsaReadPosition pos, Bounds::SemBound b, int val, int mod
|
|
||||||
) {
|
|
||||||
phiModulus(v, b, val, mod) and pos.hasReadOfVar(v)
|
|
||||||
or
|
|
||||||
b.(Bounds::SemSsaBound).getAVariable() = v and pos.hasReadOfVar(v) and val = 0 and mod = 0
|
|
||||||
or
|
|
||||||
exists(SemExpr e, int val0, int delta |
|
|
||||||
semExprModulus(e, b, val0, mod) and
|
|
||||||
valueFlowStepSsa(v, pos, e, delta) and
|
|
||||||
val = remainder(val0 + delta, mod)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
moduloGuardedRead(v, pos, val, mod) and b instanceof Bounds::SemZeroBound
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `e` is equal to `b + val` modulo `mod`.
|
|
||||||
*
|
|
||||||
* There are two cases for the modulus:
|
|
||||||
* - `mod = 0`: The equality `e = b + val` is an ordinary equality.
|
|
||||||
* - `mod > 1`: `val` lies within the range `[0 .. mod-1]`.
|
|
||||||
*/
|
|
||||||
cached
|
|
||||||
predicate semExprModulus(SemExpr e, Bounds::SemBound b, int val, int mod) {
|
|
||||||
not ignoreExprModulus(e) and
|
|
||||||
(
|
|
||||||
e = b.getExpr(D::fromInt(val)) and mod = 0
|
|
||||||
or
|
|
||||||
evenlyDivisibleExpr(e, mod) and
|
|
||||||
val = 0 and
|
|
||||||
b instanceof Bounds::SemZeroBound
|
|
||||||
or
|
|
||||||
exists(SemSsaVariable v, SemSsaReadPositionBlock bb |
|
|
||||||
ssaModulus(v, bb, b, val, mod) and
|
|
||||||
e = v.getAUse() and
|
|
||||||
bb.getAnExpr() = e
|
|
||||||
)
|
|
||||||
or
|
|
||||||
exists(SemExpr mid, int val0, int delta |
|
|
||||||
semExprModulus(mid, b, val0, mod) and
|
|
||||||
U::semValueFlowStep(e, mid, D::fromInt(delta)) and
|
|
||||||
val = remainder(val0 + delta, mod)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
exists(SemConditionalExpr cond, int v1, int v2, int m1, int m2 |
|
|
||||||
cond = e and
|
|
||||||
condExprBranchModulus(cond, true, b, v1, m1) and
|
|
||||||
condExprBranchModulus(cond, false, b, v2, m2) and
|
|
||||||
mod = m1.gcd(m2).gcd(v1 - v2) and
|
|
||||||
mod != 1 and
|
|
||||||
val = remainder(v1, mod)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
exists(Bounds::SemBound b1, Bounds::SemBound b2, int v1, int v2, int m1, int m2 |
|
|
||||||
addModulus(e, true, b1, v1, m1) and
|
|
||||||
addModulus(e, false, b2, v2, m2) and
|
|
||||||
mod = m1.gcd(m2) and
|
|
||||||
mod != 1 and
|
|
||||||
val = remainder(v1 + v2, mod)
|
|
||||||
|
|
|
||||||
b = b1 and b2 instanceof Bounds::SemZeroBound
|
|
||||||
or
|
|
||||||
b = b2 and b1 instanceof Bounds::SemZeroBound
|
|
||||||
)
|
|
||||||
or
|
|
||||||
exists(int v1, int v2, int m1, int m2 |
|
|
||||||
subModulus(e, true, b, v1, m1) and
|
|
||||||
subModulus(e, false, any(Bounds::SemZeroBound zb), v2, m2) and
|
|
||||||
mod = m1.gcd(m2) and
|
|
||||||
mod != 1 and
|
|
||||||
val = remainder(v1 - v2, mod)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate condExprBranchModulus(
|
|
||||||
SemConditionalExpr cond, boolean branch, Bounds::SemBound b, int val, int mod
|
|
||||||
) {
|
|
||||||
semExprModulus(cond.getBranchExpr(branch), b, val, mod)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate addModulus(SemExpr add, boolean isLeft, Bounds::SemBound b, int val, int mod) {
|
|
||||||
exists(SemExpr larg, SemExpr rarg | nonConstAddition(add, larg, rarg) |
|
|
||||||
semExprModulus(larg, b, val, mod) and isLeft = true
|
|
||||||
or
|
|
||||||
semExprModulus(rarg, b, val, mod) and isLeft = false
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate subModulus(SemExpr sub, boolean isLeft, Bounds::SemBound b, int val, int mod) {
|
|
||||||
exists(SemExpr larg, SemExpr rarg | nonConstSubtraction(sub, larg, rarg) |
|
|
||||||
semExprModulus(larg, b, val, mod) and isLeft = true
|
|
||||||
or
|
|
||||||
semExprModulus(rarg, b, val, mod) and isLeft = false
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
/**
|
|
||||||
* C++-specific implementation of modulus analysis.
|
|
||||||
*/
|
|
||||||
module Private {
|
|
||||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
|
||||||
|
|
||||||
predicate ignoreExprModulus(SemExpr e) { none() }
|
|
||||||
}
|
|
||||||
@@ -8,14 +8,6 @@ private import RangeAnalysisImpl
|
|||||||
private import codeql.rangeanalysis.RangeAnalysis
|
private import codeql.rangeanalysis.RangeAnalysis
|
||||||
|
|
||||||
module CppLangImplConstant implements LangSig<Sem, FloatDelta> {
|
module CppLangImplConstant implements LangSig<Sem, FloatDelta> {
|
||||||
/**
|
|
||||||
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
|
|
||||||
*
|
|
||||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
|
||||||
* removed once we have the new implementation matching the old results exactly.
|
|
||||||
*/
|
|
||||||
predicate ignoreSsaReadCopy(SemExpr e) { none() }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ignore the bound on this expression.
|
* Ignore the bound on this expression.
|
||||||
*
|
*
|
||||||
@@ -24,70 +16,13 @@ module CppLangImplConstant implements LangSig<Sem, FloatDelta> {
|
|||||||
*/
|
*/
|
||||||
predicate ignoreExprBound(SemExpr e) { none() }
|
predicate ignoreExprBound(SemExpr e) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Ignore any inferred zero lower bound on this expression.
|
|
||||||
*
|
|
||||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
|
||||||
* removed once we have the new implementation matching the old results exactly.
|
|
||||||
*/
|
|
||||||
predicate ignoreZeroLowerBound(SemExpr e) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
|
|
||||||
*
|
|
||||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
|
||||||
* removed once we have the new implementation matching the old results exactly.
|
|
||||||
*/
|
|
||||||
predicate ignoreSsaReadArithmeticExpr(SemExpr e) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the specified variable should be excluded from the result of `ssaRead()`.
|
|
||||||
*
|
|
||||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
|
||||||
* removed once we have the new implementation matching the old results exactly.
|
|
||||||
*/
|
|
||||||
predicate ignoreSsaReadAssignment(SemSsaVariable v) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds additional results to `ssaRead()` that are specific to Java.
|
|
||||||
*
|
|
||||||
* This predicate handles propagation of offsets for post-increment and post-decrement expressions
|
|
||||||
* in exactly the same way as the old Java implementation. Once the new implementation matches the
|
|
||||||
* old one, we should remove this predicate and propagate deltas for all similar patterns, whether
|
|
||||||
* or not they come from a post-increment/decrement expression.
|
|
||||||
*/
|
|
||||||
SemExpr specificSsaRead(SemSsaVariable v, float delta) { none() }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`).
|
* Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`).
|
||||||
*/
|
*/
|
||||||
predicate hasConstantBound(SemExpr e, float bound, boolean upper) { none() }
|
predicate hasConstantBound(SemExpr e, float bound, boolean upper) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`).
|
* Holds if `e2 >= e1 + delta` (if `upper = false`) or `e2 <= e1 + delta` (if `upper = true`).
|
||||||
*/
|
*/
|
||||||
predicate hasBound(SemExpr e, SemExpr bound, float delta, boolean upper) { none() }
|
predicate additionalBoundFlowStep(SemExpr e2, SemExpr e1, float delta, boolean upper) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the value of `dest` is known to be `src + delta`.
|
|
||||||
*/
|
|
||||||
predicate additionalValueFlowStep(SemExpr dest, SemExpr src, float delta) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the type that range analysis should use to track the result of the specified expression,
|
|
||||||
* if a type other than the original type of the expression is to be used.
|
|
||||||
*
|
|
||||||
* This predicate is commonly used in languages that support immutable "boxed" types that are
|
|
||||||
* actually references but whose values can be tracked as the type contained in the box.
|
|
||||||
*/
|
|
||||||
SemType getAlternateType(SemExpr e) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the type that range analysis should use to track the result of the specified source
|
|
||||||
* variable, if a type other than the original type of the expression is to be used.
|
|
||||||
*
|
|
||||||
* This predicate is commonly used in languages that support immutable "boxed" types that are
|
|
||||||
* actually references but whose values can be tracked as the type contained in the box.
|
|
||||||
*/
|
|
||||||
SemType getAlternateTypeForSsaVariable(SemSsaVariable var) { none() }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
private import RangeAnalysisConstantSpecific
|
private import RangeAnalysisConstantSpecific
|
||||||
private import RangeAnalysisRelativeSpecific
|
private import RangeAnalysisRelativeSpecific
|
||||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.FloatDelta
|
||||||
private import RangeUtils
|
|
||||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExpr
|
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExpr
|
||||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticCFG
|
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticCFG
|
||||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticGuard
|
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticGuard
|
||||||
@@ -52,20 +51,34 @@ module Sem implements Semantic {
|
|||||||
|
|
||||||
class NegateExpr = SemNegateExpr;
|
class NegateExpr = SemNegateExpr;
|
||||||
|
|
||||||
class AddOneExpr = SemAddOneExpr;
|
class PreIncExpr = SemAddOneExpr;
|
||||||
|
|
||||||
class SubOneExpr = SemSubOneExpr;
|
class PreDecExpr = SemSubOneExpr;
|
||||||
|
|
||||||
|
class PostIncExpr extends SemUnaryExpr {
|
||||||
|
PostIncExpr() { none() }
|
||||||
|
}
|
||||||
|
|
||||||
|
class PostDecExpr extends SemUnaryExpr {
|
||||||
|
PostDecExpr() { none() }
|
||||||
|
}
|
||||||
|
|
||||||
|
class CopyValueExpr extends SemUnaryExpr {
|
||||||
|
CopyValueExpr() { this instanceof SemCopyValueExpr or this instanceof SemStoreExpr }
|
||||||
|
}
|
||||||
|
|
||||||
class ConditionalExpr = SemConditionalExpr;
|
class ConditionalExpr = SemConditionalExpr;
|
||||||
|
|
||||||
class BasicBlock = SemBasicBlock;
|
class BasicBlock = SemBasicBlock;
|
||||||
|
|
||||||
|
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||||
|
|
||||||
|
int getBlockId1(BasicBlock bb) { result = bb.getUniqueId() }
|
||||||
|
|
||||||
class Guard = SemGuard;
|
class Guard = SemGuard;
|
||||||
|
|
||||||
predicate implies_v2 = semImplies_v2/4;
|
predicate implies_v2 = semImplies_v2/4;
|
||||||
|
|
||||||
predicate guardDirectlyControlsSsaRead = semGuardDirectlyControlsSsaRead/3;
|
|
||||||
|
|
||||||
class Type = SemType;
|
class Type = SemType;
|
||||||
|
|
||||||
class IntegerType = SemIntegerType;
|
class IntegerType = SemIntegerType;
|
||||||
@@ -74,19 +87,17 @@ module Sem implements Semantic {
|
|||||||
|
|
||||||
class AddressType = SemAddressType;
|
class AddressType = SemAddressType;
|
||||||
|
|
||||||
|
SemType getExprType(SemExpr e) { result = e.getSemType() }
|
||||||
|
|
||||||
|
SemType getSsaType(SemSsaVariable var) { result = var.getType() }
|
||||||
|
|
||||||
class SsaVariable = SemSsaVariable;
|
class SsaVariable = SemSsaVariable;
|
||||||
|
|
||||||
class SsaPhiNode = SemSsaPhiNode;
|
class SsaPhiNode = SemSsaPhiNode;
|
||||||
|
|
||||||
class SsaExplicitUpdate = SemSsaExplicitUpdate;
|
class SsaExplicitUpdate = SemSsaExplicitUpdate;
|
||||||
|
|
||||||
class SsaReadPosition = SemSsaReadPosition;
|
predicate additionalValueFlowStep(SemExpr dest, SemExpr src, int delta) { none() }
|
||||||
|
|
||||||
class SsaReadPositionPhiInputEdge = SemSsaReadPositionPhiInputEdge;
|
|
||||||
|
|
||||||
class SsaReadPositionBlock = SemSsaReadPositionBlock;
|
|
||||||
|
|
||||||
predicate backEdge = semBackEdge/3;
|
|
||||||
|
|
||||||
predicate conversionCannotOverflow(Type fromType, Type toType) {
|
predicate conversionCannotOverflow(Type fromType, Type toType) {
|
||||||
SemanticType::conversionCannotOverflow(fromType, toType)
|
SemanticType::conversionCannotOverflow(fromType, toType)
|
||||||
@@ -95,7 +106,7 @@ module Sem implements Semantic {
|
|||||||
|
|
||||||
module SignAnalysis implements SignAnalysisSig<Sem> {
|
module SignAnalysis implements SignAnalysisSig<Sem> {
|
||||||
private import SignAnalysisCommon as SA
|
private import SignAnalysisCommon as SA
|
||||||
import SA::SignAnalysis<FloatDelta, Util>
|
import SA::SignAnalysis<FloatDelta>
|
||||||
}
|
}
|
||||||
|
|
||||||
module ConstantBounds implements BoundSig<SemLocation, Sem, FloatDelta> {
|
module ConstantBounds implements BoundSig<SemLocation, Sem, FloatDelta> {
|
||||||
@@ -116,7 +127,7 @@ module ConstantBounds implements BoundSig<SemLocation, Sem, FloatDelta> {
|
|||||||
class SemZeroBound extends SemBound instanceof SemanticBound::SemZeroBound { }
|
class SemZeroBound extends SemBound instanceof SemanticBound::SemZeroBound { }
|
||||||
|
|
||||||
class SemSsaBound extends SemBound instanceof SemanticBound::SemSsaBound {
|
class SemSsaBound extends SemBound instanceof SemanticBound::SemSsaBound {
|
||||||
SemSsaVariable getAVariable() { result = this.(SemanticBound::SemSsaBound).getAVariable() }
|
SemSsaVariable getVariable() { result = this.(SemanticBound::SemSsaBound).getAVariable() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +145,7 @@ module RelativeBounds implements BoundSig<SemLocation, Sem, FloatDelta> {
|
|||||||
class SemZeroBound extends SemBound instanceof SemanticBound::SemZeroBound { }
|
class SemZeroBound extends SemBound instanceof SemanticBound::SemZeroBound { }
|
||||||
|
|
||||||
class SemSsaBound extends SemBound instanceof SemanticBound::SemSsaBound {
|
class SemSsaBound extends SemBound instanceof SemanticBound::SemSsaBound {
|
||||||
SemSsaVariable getAVariable() { result = this.(SemanticBound::SemSsaBound).getAVariable() }
|
SemSsaVariable getVariable() { result = this.(SemanticBound::SemSsaBound).getAVariable() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,26 +161,24 @@ module AllBounds implements BoundSig<SemLocation, Sem, FloatDelta> {
|
|||||||
class SemZeroBound extends SemBound instanceof SemanticBound::SemZeroBound { }
|
class SemZeroBound extends SemBound instanceof SemanticBound::SemZeroBound { }
|
||||||
|
|
||||||
class SemSsaBound extends SemBound instanceof SemanticBound::SemSsaBound {
|
class SemSsaBound extends SemBound instanceof SemanticBound::SemSsaBound {
|
||||||
SemSsaVariable getAVariable() { result = this.(SemanticBound::SemSsaBound).getAVariable() }
|
SemSsaVariable getVariable() { result = this.(SemanticBound::SemSsaBound).getAVariable() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private module ModulusAnalysisInstantiated implements ModulusAnalysisSig<Sem> {
|
private module ModulusAnalysisInstantiated implements ModulusAnalysisSig<Sem> {
|
||||||
class ModBound = AllBounds::SemBound;
|
class ModBound = AllBounds::SemBound;
|
||||||
|
|
||||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.ModulusAnalysis as MA
|
private import codeql.rangeanalysis.ModulusAnalysis as MA
|
||||||
import MA::ModulusAnalysis<FloatDelta, AllBounds, Util>
|
import MA::ModulusAnalysis<SemLocation, Sem, FloatDelta, AllBounds>
|
||||||
}
|
}
|
||||||
|
|
||||||
module Util = RangeUtil<FloatDelta, CppLangImplConstant>;
|
|
||||||
|
|
||||||
module ConstantStage =
|
module ConstantStage =
|
||||||
RangeStage<SemLocation, Sem, FloatDelta, ConstantBounds, FloatOverflow, CppLangImplConstant,
|
RangeStage<SemLocation, Sem, FloatDelta, ConstantBounds, FloatOverflow, CppLangImplConstant,
|
||||||
SignAnalysis, ModulusAnalysisInstantiated, Util>;
|
SignAnalysis, ModulusAnalysisInstantiated>;
|
||||||
|
|
||||||
module RelativeStage =
|
module RelativeStage =
|
||||||
RangeStage<SemLocation, Sem, FloatDelta, RelativeBounds, FloatOverflow, CppLangImplRelative,
|
RangeStage<SemLocation, Sem, FloatDelta, RelativeBounds, FloatOverflow, CppLangImplRelative,
|
||||||
SignAnalysis, ModulusAnalysisInstantiated, Util>;
|
SignAnalysis, ModulusAnalysisInstantiated>;
|
||||||
|
|
||||||
private newtype TSemReason =
|
private newtype TSemReason =
|
||||||
TSemNoReason() or
|
TSemNoReason() or
|
||||||
|
|||||||
@@ -9,14 +9,6 @@ private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
|
|||||||
private import codeql.rangeanalysis.RangeAnalysis
|
private import codeql.rangeanalysis.RangeAnalysis
|
||||||
|
|
||||||
module CppLangImplRelative implements LangSig<Sem, FloatDelta> {
|
module CppLangImplRelative implements LangSig<Sem, FloatDelta> {
|
||||||
/**
|
|
||||||
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
|
|
||||||
*
|
|
||||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
|
||||||
* removed once we have the new implementation matching the old results exactly.
|
|
||||||
*/
|
|
||||||
predicate ignoreSsaReadCopy(SemExpr e) { none() }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ignore the bound on this expression.
|
* Ignore the bound on this expression.
|
||||||
*
|
*
|
||||||
@@ -56,70 +48,13 @@ module CppLangImplRelative implements LangSig<Sem, FloatDelta> {
|
|||||||
t instanceof SemFloatingPointType and lb = -(1.0 / 0.0) and ub = 1.0 / 0.0
|
t instanceof SemFloatingPointType and lb = -(1.0 / 0.0) and ub = 1.0 / 0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Ignore any inferred zero lower bound on this expression.
|
|
||||||
*
|
|
||||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
|
||||||
* removed once we have the new implementation matching the old results exactly.
|
|
||||||
*/
|
|
||||||
predicate ignoreZeroLowerBound(SemExpr e) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
|
|
||||||
*
|
|
||||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
|
||||||
* removed once we have the new implementation matching the old results exactly.
|
|
||||||
*/
|
|
||||||
predicate ignoreSsaReadArithmeticExpr(SemExpr e) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the specified variable should be excluded from the result of `ssaRead()`.
|
|
||||||
*
|
|
||||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
|
||||||
* removed once we have the new implementation matching the old results exactly.
|
|
||||||
*/
|
|
||||||
predicate ignoreSsaReadAssignment(SemSsaVariable v) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds additional results to `ssaRead()` that are specific to Java.
|
|
||||||
*
|
|
||||||
* This predicate handles propagation of offsets for post-increment and post-decrement expressions
|
|
||||||
* in exactly the same way as the old Java implementation. Once the new implementation matches the
|
|
||||||
* old one, we should remove this predicate and propagate deltas for all similar patterns, whether
|
|
||||||
* or not they come from a post-increment/decrement expression.
|
|
||||||
*/
|
|
||||||
SemExpr specificSsaRead(SemSsaVariable v, float delta) { none() }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`).
|
* Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`).
|
||||||
*/
|
*/
|
||||||
predicate hasConstantBound(SemExpr e, float bound, boolean upper) { none() }
|
predicate hasConstantBound(SemExpr e, float bound, boolean upper) { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`).
|
* Holds if `e2 >= e1 + delta` (if `upper = false`) or `e2 <= e1 + delta` (if `upper = true`).
|
||||||
*/
|
*/
|
||||||
predicate hasBound(SemExpr e, SemExpr bound, float delta, boolean upper) { none() }
|
predicate additionalBoundFlowStep(SemExpr e2, SemExpr e1, float delta, boolean upper) { none() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the value of `dest` is known to be `src + delta`.
|
|
||||||
*/
|
|
||||||
predicate additionalValueFlowStep(SemExpr dest, SemExpr src, float delta) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the type that range analysis should use to track the result of the specified expression,
|
|
||||||
* if a type other than the original type of the expression is to be used.
|
|
||||||
*
|
|
||||||
* This predicate is commonly used in languages that support immutable "boxed" types that are
|
|
||||||
* actually references but whose values can be tracked as the type contained in the box.
|
|
||||||
*/
|
|
||||||
SemType getAlternateType(SemExpr e) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the type that range analysis should use to track the result of the specified source
|
|
||||||
* variable, if a type other than the original type of the expression is to be used.
|
|
||||||
*
|
|
||||||
* This predicate is commonly used in languages that support immutable "boxed" types that are
|
|
||||||
* actually references but whose values can be tracked as the type contained in the box.
|
|
||||||
*/
|
|
||||||
SemType getAlternateTypeForSsaVariable(SemSsaVariable var) { none() }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,171 +0,0 @@
|
|||||||
/**
|
|
||||||
* Provides utility predicates for range analysis.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
|
||||||
private import RangeAnalysisRelativeSpecific
|
|
||||||
private import codeql.rangeanalysis.RangeAnalysis
|
|
||||||
private import RangeAnalysisImpl
|
|
||||||
private import ConstantAnalysis
|
|
||||||
|
|
||||||
module RangeUtil<DeltaSig D, LangSig<Sem, D> Lang> implements UtilSig<Sem, D> {
|
|
||||||
/**
|
|
||||||
* Gets an expression that equals `v - d`.
|
|
||||||
*/
|
|
||||||
SemExpr semSsaRead(SemSsaVariable v, D::Delta delta) {
|
|
||||||
// There are various language-specific extension points that can be removed once we no longer
|
|
||||||
// expect to match the original Java implementation's results exactly.
|
|
||||||
result = v.getAUse() and delta = D::fromInt(0)
|
|
||||||
or
|
|
||||||
exists(D::Delta d1, SemConstantIntegerExpr c |
|
|
||||||
result.(SemAddExpr).hasOperands(semSsaRead(v, d1), c) and
|
|
||||||
delta = D::fromFloat(D::toFloat(d1) - c.getIntValue()) and
|
|
||||||
not Lang::ignoreSsaReadArithmeticExpr(result)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
exists(SemSubExpr sub, D::Delta d1, SemConstantIntegerExpr c |
|
|
||||||
result = sub and
|
|
||||||
sub.getLeftOperand() = semSsaRead(v, d1) and
|
|
||||||
sub.getRightOperand() = c and
|
|
||||||
delta = D::fromFloat(D::toFloat(d1) + c.getIntValue()) and
|
|
||||||
not Lang::ignoreSsaReadArithmeticExpr(result)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
result = v.(SemSsaExplicitUpdate).getSourceExpr() and
|
|
||||||
delta = D::fromFloat(0) and
|
|
||||||
not Lang::ignoreSsaReadAssignment(v)
|
|
||||||
or
|
|
||||||
result = Lang::specificSsaRead(v, delta)
|
|
||||||
or
|
|
||||||
result.(SemCopyValueExpr).getOperand() = semSsaRead(v, delta) and
|
|
||||||
not Lang::ignoreSsaReadCopy(result)
|
|
||||||
or
|
|
||||||
result.(SemStoreExpr).getOperand() = semSsaRead(v, delta)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a condition that tests whether `v` equals `e + delta`.
|
|
||||||
*
|
|
||||||
* If the condition evaluates to `testIsTrue`:
|
|
||||||
* - `isEq = true` : `v == e + delta`
|
|
||||||
* - `isEq = false` : `v != e + delta`
|
|
||||||
*/
|
|
||||||
pragma[nomagic]
|
|
||||||
SemGuard semEqFlowCond(
|
|
||||||
SemSsaVariable v, SemExpr e, D::Delta delta, boolean isEq, boolean testIsTrue
|
|
||||||
) {
|
|
||||||
exists(boolean eqpolarity |
|
|
||||||
result.isEquality(semSsaRead(v, delta), e, eqpolarity) and
|
|
||||||
(testIsTrue = true or testIsTrue = false) and
|
|
||||||
eqpolarity.booleanXor(testIsTrue).booleanNot() = isEq
|
|
||||||
)
|
|
||||||
or
|
|
||||||
exists(boolean testIsTrue0 |
|
|
||||||
semImplies_v2(result, testIsTrue, semEqFlowCond(v, e, delta, isEq, testIsTrue0), testIsTrue0)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `v` is an `SsaExplicitUpdate` that equals `e + delta`.
|
|
||||||
*/
|
|
||||||
predicate semSsaUpdateStep(SemSsaExplicitUpdate v, SemExpr e, D::Delta delta) {
|
|
||||||
exists(SemExpr defExpr | defExpr = v.getSourceExpr() |
|
|
||||||
defExpr.(SemCopyValueExpr).getOperand() = e and delta = D::fromFloat(0)
|
|
||||||
or
|
|
||||||
defExpr.(SemStoreExpr).getOperand() = e and delta = D::fromFloat(0)
|
|
||||||
or
|
|
||||||
defExpr.(SemAddOneExpr).getOperand() = e and delta = D::fromFloat(1)
|
|
||||||
or
|
|
||||||
defExpr.(SemSubOneExpr).getOperand() = e and delta = D::fromFloat(-1)
|
|
||||||
or
|
|
||||||
e = defExpr and
|
|
||||||
not (
|
|
||||||
defExpr instanceof SemCopyValueExpr or
|
|
||||||
defExpr instanceof SemStoreExpr or
|
|
||||||
defExpr instanceof SemAddOneExpr or
|
|
||||||
defExpr instanceof SemSubOneExpr
|
|
||||||
) and
|
|
||||||
delta = D::fromFloat(0)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `e1 + delta` equals `e2`.
|
|
||||||
*/
|
|
||||||
predicate semValueFlowStep(SemExpr e2, SemExpr e1, D::Delta delta) {
|
|
||||||
e2.(SemCopyValueExpr).getOperand() = e1 and delta = D::fromFloat(0)
|
|
||||||
or
|
|
||||||
e2.(SemStoreExpr).getOperand() = e1 and delta = D::fromFloat(0)
|
|
||||||
or
|
|
||||||
e2.(SemAddOneExpr).getOperand() = e1 and delta = D::fromFloat(1)
|
|
||||||
or
|
|
||||||
e2.(SemSubOneExpr).getOperand() = e1 and delta = D::fromFloat(-1)
|
|
||||||
or
|
|
||||||
Lang::additionalValueFlowStep(e2, e1, delta)
|
|
||||||
or
|
|
||||||
exists(SemExpr x | e2.(SemAddExpr).hasOperands(e1, x) |
|
|
||||||
D::fromInt(x.(SemConstantIntegerExpr).getIntValue()) = delta
|
|
||||||
)
|
|
||||||
or
|
|
||||||
exists(SemExpr x, SemSubExpr sub |
|
|
||||||
e2 = sub and
|
|
||||||
sub.getLeftOperand() = e1 and
|
|
||||||
sub.getRightOperand() = x
|
|
||||||
|
|
|
||||||
D::fromInt(-x.(SemConstantIntegerExpr).getIntValue()) = delta
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the type used to track the specified expression's range information.
|
|
||||||
*
|
|
||||||
* Usually, this just `e.getSemType()`, but the language can override this to track immutable boxed
|
|
||||||
* primitive types as the underlying primitive type.
|
|
||||||
*/
|
|
||||||
SemType getTrackedType(SemExpr e) {
|
|
||||||
result = Lang::getAlternateType(e)
|
|
||||||
or
|
|
||||||
not exists(Lang::getAlternateType(e)) and result = e.getSemType()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the type used to track the specified source variable's range information.
|
|
||||||
*
|
|
||||||
* Usually, this just `e.getType()`, but the language can override this to track immutable boxed
|
|
||||||
* primitive types as the underlying primitive type.
|
|
||||||
*/
|
|
||||||
SemType getTrackedTypeForSsaVariable(SemSsaVariable var) {
|
|
||||||
result = Lang::getAlternateTypeForSsaVariable(var)
|
|
||||||
or
|
|
||||||
not exists(Lang::getAlternateTypeForSsaVariable(var)) and result = var.getType()
|
|
||||||
}
|
|
||||||
|
|
||||||
import Ranking
|
|
||||||
}
|
|
||||||
|
|
||||||
import Ranking
|
|
||||||
|
|
||||||
module Ranking {
|
|
||||||
/**
|
|
||||||
* Holds if `rix` is the number of input edges to `phi`.
|
|
||||||
*/
|
|
||||||
predicate maxPhiInputRank(SemSsaPhiNode phi, int rix) {
|
|
||||||
rix = max(int r | rankedPhiInput(phi, _, _, r))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `inp` is an input to `phi` along `edge` and this input has index `r`
|
|
||||||
* in an arbitrary 1-based numbering of the input edges to `phi`.
|
|
||||||
*/
|
|
||||||
predicate rankedPhiInput(
|
|
||||||
SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int r
|
|
||||||
) {
|
|
||||||
edge.phiInput(phi, inp) and
|
|
||||||
edge =
|
|
||||||
rank[r](SemSsaReadPositionPhiInputEdge e |
|
|
||||||
e.phiInput(phi, _)
|
|
||||||
|
|
|
||||||
e order by e.getOrigBlock().getUniqueId()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -11,10 +11,11 @@ private import RangeAnalysisImpl
|
|||||||
private import SignAnalysisSpecific as Specific
|
private import SignAnalysisSpecific as Specific
|
||||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.Semantic
|
||||||
private import ConstantAnalysis
|
private import ConstantAnalysis
|
||||||
private import RangeUtils
|
|
||||||
private import Sign
|
private import Sign
|
||||||
|
|
||||||
module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
module SignAnalysis<DeltaSig D> {
|
||||||
|
private import codeql.rangeanalysis.internal.RangeUtils::MakeUtils<Sem, D>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An SSA definition for which the analysis can compute the sign.
|
* An SSA definition for which the analysis can compute the sign.
|
||||||
*
|
*
|
||||||
@@ -37,13 +38,13 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
|
|
||||||
/** An SSA definition whose sign is determined by the sign of that definitions source expression. */
|
/** An SSA definition whose sign is determined by the sign of that definitions source expression. */
|
||||||
private class ExplicitSignDef extends FlowSignDef instanceof SemSsaExplicitUpdate {
|
private class ExplicitSignDef extends FlowSignDef instanceof SemSsaExplicitUpdate {
|
||||||
final override Sign getSign() { result = semExprSign(super.getSourceExpr()) }
|
final override Sign getSign() { result = semExprSign(super.getDefiningExpr()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** An SSA Phi definition, whose sign is the union of the signs of its inputs. */
|
/** An SSA Phi definition, whose sign is the union of the signs of its inputs. */
|
||||||
private class PhiSignDef extends FlowSignDef instanceof SemSsaPhiNode {
|
private class PhiSignDef extends FlowSignDef instanceof SemSsaPhiNode {
|
||||||
final override Sign getSign() {
|
final override Sign getSign() {
|
||||||
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
|
exists(SemSsaVariable inp, SsaReadPositionPhiInputEdge edge |
|
||||||
edge.phiInput(this, inp) and
|
edge.phiInput(this, inp) and
|
||||||
result = semSsaSign(inp, edge)
|
result = semSsaSign(inp, edge)
|
||||||
)
|
)
|
||||||
@@ -146,7 +147,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
not this instanceof ConstantSignExpr and
|
not this instanceof ConstantSignExpr and
|
||||||
(
|
(
|
||||||
// Only track numeric types.
|
// Only track numeric types.
|
||||||
Utils::getTrackedType(this) instanceof SemNumericType
|
Sem::getExprType(this) instanceof SemNumericType
|
||||||
or
|
or
|
||||||
// Unless the language says to track this expression anyway.
|
// Unless the language says to track this expression anyway.
|
||||||
Specific::trackUnknownNonNumericExpr(this)
|
Specific::trackUnknownNonNumericExpr(this)
|
||||||
@@ -168,11 +169,11 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
override Sign getSignRestriction() {
|
override Sign getSignRestriction() {
|
||||||
// Propagate via SSA
|
// Propagate via SSA
|
||||||
// Propagate the sign from the def of `v`, incorporating any inference from guards.
|
// Propagate the sign from the def of `v`, incorporating any inference from guards.
|
||||||
result = semSsaSign(v, any(SemSsaReadPositionBlock bb | bb.getAnExpr() = this))
|
result = semSsaSign(v, any(SsaReadPositionBlock bb | bb.getBlock().getAnExpr() = this))
|
||||||
or
|
or
|
||||||
// No block for this read. Just use the sign of the def.
|
// No block for this read. Just use the sign of the def.
|
||||||
// REVIEW: How can this happen?
|
// REVIEW: How can this happen?
|
||||||
not exists(SemSsaReadPositionBlock bb | bb.getAnExpr() = this) and
|
not exists(SsaReadPositionBlock bb | bb.getBlock().getAnExpr() = this) and
|
||||||
result = semSsaDefSign(v)
|
result = semSsaDefSign(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,7 +202,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
|
|
||||||
/** An expression of an unsigned type. */
|
/** An expression of an unsigned type. */
|
||||||
private class UnsignedExpr extends FlowSignExpr {
|
private class UnsignedExpr extends FlowSignExpr {
|
||||||
UnsignedExpr() { Utils::getTrackedType(this) instanceof SemUnsignedIntegerType }
|
UnsignedExpr() { Sem::getExprType(this) instanceof SemUnsignedIntegerType }
|
||||||
|
|
||||||
override Sign getSignRestriction() {
|
override Sign getSignRestriction() {
|
||||||
result = TPos() or
|
result = TPos() or
|
||||||
@@ -274,7 +275,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
override SemUnboxExpr cast;
|
override SemUnboxExpr cast;
|
||||||
|
|
||||||
UnboxSignExpr() {
|
UnboxSignExpr() {
|
||||||
exists(SemType fromType | fromType = Utils::getTrackedType(cast.getOperand()) |
|
exists(SemType fromType | fromType = Sem::getExprType(cast.getOperand()) |
|
||||||
// Only numeric source types are handled here.
|
// Only numeric source types are handled here.
|
||||||
fromType instanceof SemNumericType
|
fromType instanceof SemNumericType
|
||||||
)
|
)
|
||||||
@@ -288,21 +289,21 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
* to only include bounds for which we might determine a sign.
|
* to only include bounds for which we might determine a sign.
|
||||||
*/
|
*/
|
||||||
private predicate lowerBound(
|
private predicate lowerBound(
|
||||||
SemExpr lowerbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isStrict
|
SemExpr lowerbound, SemSsaVariable v, SsaReadPosition pos, boolean isStrict
|
||||||
) {
|
) {
|
||||||
exists(boolean testIsTrue, SemRelationalExpr comp |
|
exists(boolean testIsTrue, SemRelationalExpr comp |
|
||||||
pos.hasReadOfVar(v) and
|
pos.hasReadOfVar(v) and
|
||||||
semGuardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
|
guardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
|
||||||
not unknownSign(lowerbound)
|
not unknownSign(lowerbound)
|
||||||
|
|
|
|
||||||
testIsTrue = true and
|
testIsTrue = true and
|
||||||
comp.getLesserOperand() = lowerbound and
|
comp.getLesserOperand() = lowerbound and
|
||||||
comp.getGreaterOperand() = Utils::semSsaRead(v, D::fromInt(0)) and
|
comp.getGreaterOperand() = ssaRead(v, D::fromInt(0)) and
|
||||||
(if comp.isStrict() then isStrict = true else isStrict = false)
|
(if comp.isStrict() then isStrict = true else isStrict = false)
|
||||||
or
|
or
|
||||||
testIsTrue = false and
|
testIsTrue = false and
|
||||||
comp.getGreaterOperand() = lowerbound and
|
comp.getGreaterOperand() = lowerbound and
|
||||||
comp.getLesserOperand() = Utils::semSsaRead(v, D::fromInt(0)) and
|
comp.getLesserOperand() = ssaRead(v, D::fromInt(0)) and
|
||||||
(if comp.isStrict() then isStrict = false else isStrict = true)
|
(if comp.isStrict() then isStrict = false else isStrict = true)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -312,21 +313,21 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
* to only include bounds for which we might determine a sign.
|
* to only include bounds for which we might determine a sign.
|
||||||
*/
|
*/
|
||||||
private predicate upperBound(
|
private predicate upperBound(
|
||||||
SemExpr upperbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isStrict
|
SemExpr upperbound, SemSsaVariable v, SsaReadPosition pos, boolean isStrict
|
||||||
) {
|
) {
|
||||||
exists(boolean testIsTrue, SemRelationalExpr comp |
|
exists(boolean testIsTrue, SemRelationalExpr comp |
|
||||||
pos.hasReadOfVar(v) and
|
pos.hasReadOfVar(v) and
|
||||||
semGuardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
|
guardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
|
||||||
not unknownSign(upperbound)
|
not unknownSign(upperbound)
|
||||||
|
|
|
|
||||||
testIsTrue = true and
|
testIsTrue = true and
|
||||||
comp.getGreaterOperand() = upperbound and
|
comp.getGreaterOperand() = upperbound and
|
||||||
comp.getLesserOperand() = Utils::semSsaRead(v, D::fromInt(0)) and
|
comp.getLesserOperand() = ssaRead(v, D::fromInt(0)) and
|
||||||
(if comp.isStrict() then isStrict = true else isStrict = false)
|
(if comp.isStrict() then isStrict = true else isStrict = false)
|
||||||
or
|
or
|
||||||
testIsTrue = false and
|
testIsTrue = false and
|
||||||
comp.getLesserOperand() = upperbound and
|
comp.getLesserOperand() = upperbound and
|
||||||
comp.getGreaterOperand() = Utils::semSsaRead(v, D::fromInt(0)) and
|
comp.getGreaterOperand() = ssaRead(v, D::fromInt(0)) and
|
||||||
(if comp.isStrict() then isStrict = false else isStrict = true)
|
(if comp.isStrict() then isStrict = false else isStrict = true)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -338,11 +339,11 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
* - `isEq = true` : `v = eqbound`
|
* - `isEq = true` : `v = eqbound`
|
||||||
* - `isEq = false` : `v != eqbound`
|
* - `isEq = false` : `v != eqbound`
|
||||||
*/
|
*/
|
||||||
private predicate eqBound(SemExpr eqbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isEq) {
|
private predicate eqBound(SemExpr eqbound, SemSsaVariable v, SsaReadPosition pos, boolean isEq) {
|
||||||
exists(SemGuard guard, boolean testIsTrue, boolean polarity, SemExpr e |
|
exists(SemGuard guard, boolean testIsTrue, boolean polarity, SemExpr e |
|
||||||
pos.hasReadOfVar(pragma[only_bind_into](v)) and
|
pos.hasReadOfVar(pragma[only_bind_into](v)) and
|
||||||
semGuardControlsSsaRead(guard, pragma[only_bind_into](pos), testIsTrue) and
|
guardControlsSsaRead(guard, pragma[only_bind_into](pos), testIsTrue) and
|
||||||
e = Utils::semSsaRead(pragma[only_bind_into](v), D::fromInt(0)) and
|
e = ssaRead(pragma[only_bind_into](v), D::fromInt(0)) and
|
||||||
guard.isEquality(eqbound, e, polarity) and
|
guard.isEquality(eqbound, e, polarity) and
|
||||||
isEq = polarity.booleanXor(testIsTrue).booleanNot() and
|
isEq = polarity.booleanXor(testIsTrue).booleanNot() and
|
||||||
not unknownSign(eqbound)
|
not unknownSign(eqbound)
|
||||||
@@ -353,7 +354,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
* Holds if `bound` is a bound for `v` at `pos` that needs to be positive in
|
* Holds if `bound` is a bound for `v` at `pos` that needs to be positive in
|
||||||
* order for `v` to be positive.
|
* order for `v` to be positive.
|
||||||
*/
|
*/
|
||||||
private predicate posBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
private predicate posBound(SemExpr bound, SemSsaVariable v, SsaReadPosition pos) {
|
||||||
upperBound(bound, v, pos, _) or
|
upperBound(bound, v, pos, _) or
|
||||||
eqBound(bound, v, pos, true)
|
eqBound(bound, v, pos, true)
|
||||||
}
|
}
|
||||||
@@ -362,7 +363,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
* Holds if `bound` is a bound for `v` at `pos` that needs to be negative in
|
* Holds if `bound` is a bound for `v` at `pos` that needs to be negative in
|
||||||
* order for `v` to be negative.
|
* order for `v` to be negative.
|
||||||
*/
|
*/
|
||||||
private predicate negBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
private predicate negBound(SemExpr bound, SemSsaVariable v, SsaReadPosition pos) {
|
||||||
lowerBound(bound, v, pos, _) or
|
lowerBound(bound, v, pos, _) or
|
||||||
eqBound(bound, v, pos, true)
|
eqBound(bound, v, pos, true)
|
||||||
}
|
}
|
||||||
@@ -371,24 +372,24 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
* Holds if `bound` is a bound for `v` at `pos` that can restrict whether `v`
|
* Holds if `bound` is a bound for `v` at `pos` that can restrict whether `v`
|
||||||
* can be zero.
|
* can be zero.
|
||||||
*/
|
*/
|
||||||
private predicate zeroBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
private predicate zeroBound(SemExpr bound, SemSsaVariable v, SsaReadPosition pos) {
|
||||||
lowerBound(bound, v, pos, _) or
|
lowerBound(bound, v, pos, _) or
|
||||||
upperBound(bound, v, pos, _) or
|
upperBound(bound, v, pos, _) or
|
||||||
eqBound(bound, v, pos, _)
|
eqBound(bound, v, pos, _)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if `bound` allows `v` to be positive at `pos`. */
|
/** Holds if `bound` allows `v` to be positive at `pos`. */
|
||||||
private predicate posBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
private predicate posBoundOk(SemExpr bound, SemSsaVariable v, SsaReadPosition pos) {
|
||||||
posBound(bound, v, pos) and TPos() = semExprSign(bound)
|
posBound(bound, v, pos) and TPos() = semExprSign(bound)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if `bound` allows `v` to be negative at `pos`. */
|
/** Holds if `bound` allows `v` to be negative at `pos`. */
|
||||||
private predicate negBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
private predicate negBoundOk(SemExpr bound, SemSsaVariable v, SsaReadPosition pos) {
|
||||||
negBound(bound, v, pos) and TNeg() = semExprSign(bound)
|
negBound(bound, v, pos) and TNeg() = semExprSign(bound)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if `bound` allows `v` to be zero at `pos`. */
|
/** Holds if `bound` allows `v` to be zero at `pos`. */
|
||||||
private predicate zeroBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
private predicate zeroBoundOk(SemExpr bound, SemSsaVariable v, SsaReadPosition pos) {
|
||||||
lowerBound(bound, v, pos, _) and TNeg() = semExprSign(bound)
|
lowerBound(bound, v, pos, _) and TNeg() = semExprSign(bound)
|
||||||
or
|
or
|
||||||
lowerBound(bound, v, pos, false) and TZero() = semExprSign(bound)
|
lowerBound(bound, v, pos, false) and TZero() = semExprSign(bound)
|
||||||
@@ -406,7 +407,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
* Holds if there is a bound that might restrict whether `v` has the sign `s`
|
* Holds if there is a bound that might restrict whether `v` has the sign `s`
|
||||||
* at `pos`.
|
* at `pos`.
|
||||||
*/
|
*/
|
||||||
private predicate hasGuard(SemSsaVariable v, SemSsaReadPosition pos, Sign s) {
|
private predicate hasGuard(SemSsaVariable v, SsaReadPosition pos, Sign s) {
|
||||||
s = TPos() and posBound(_, v, pos)
|
s = TPos() and posBound(_, v, pos)
|
||||||
or
|
or
|
||||||
s = TNeg() and negBound(_, v, pos)
|
s = TNeg() and negBound(_, v, pos)
|
||||||
@@ -419,7 +420,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
* might be ruled out by a guard.
|
* might be ruled out by a guard.
|
||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private Sign guardedSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
|
private Sign guardedSsaSign(SemSsaVariable v, SsaReadPosition pos) {
|
||||||
result = semSsaDefSign(v) and
|
result = semSsaDefSign(v) and
|
||||||
pos.hasReadOfVar(v) and
|
pos.hasReadOfVar(v) and
|
||||||
hasGuard(v, pos, result)
|
hasGuard(v, pos, result)
|
||||||
@@ -430,7 +431,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
* can rule it out.
|
* can rule it out.
|
||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private Sign unguardedSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
|
private Sign unguardedSsaSign(SemSsaVariable v, SsaReadPosition pos) {
|
||||||
result = semSsaDefSign(v) and
|
result = semSsaDefSign(v) and
|
||||||
pos.hasReadOfVar(v) and
|
pos.hasReadOfVar(v) and
|
||||||
not hasGuard(v, pos, result)
|
not hasGuard(v, pos, result)
|
||||||
@@ -441,7 +442,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
* ruled out the sign but does not.
|
* ruled out the sign but does not.
|
||||||
* This does not check that the definition of `v` also allows the sign.
|
* This does not check that the definition of `v` also allows the sign.
|
||||||
*/
|
*/
|
||||||
private Sign guardedSsaSignOk(SemSsaVariable v, SemSsaReadPosition pos) {
|
private Sign guardedSsaSignOk(SemSsaVariable v, SsaReadPosition pos) {
|
||||||
result = TPos() and
|
result = TPos() and
|
||||||
forex(SemExpr bound | posBound(bound, v, pos) | posBoundOk(bound, v, pos))
|
forex(SemExpr bound | posBound(bound, v, pos) | posBoundOk(bound, v, pos))
|
||||||
or
|
or
|
||||||
@@ -453,7 +454,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets a possible sign for `v` at `pos`. */
|
/** Gets a possible sign for `v` at `pos`. */
|
||||||
private Sign semSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
|
private Sign semSsaSign(SemSsaVariable v, SsaReadPosition pos) {
|
||||||
result = unguardedSsaSign(v, pos)
|
result = unguardedSsaSign(v, pos)
|
||||||
or
|
or
|
||||||
result = guardedSsaSign(v, pos) and
|
result = guardedSsaSign(v, pos) and
|
||||||
@@ -469,7 +470,7 @@ module SignAnalysis<DeltaSig D, UtilSig<Sem, D> Utils> {
|
|||||||
Sign semExprSign(SemExpr e) {
|
Sign semExprSign(SemExpr e) {
|
||||||
exists(Sign s | s = e.(SignExpr).getSign() |
|
exists(Sign s | s = e.(SignExpr).getSign() |
|
||||||
if
|
if
|
||||||
Utils::getTrackedType(e) instanceof SemUnsignedIntegerType and
|
Sem::getExprType(e) instanceof SemUnsignedIntegerType and
|
||||||
s = TNeg() and
|
s = TNeg() and
|
||||||
not Specific::ignoreTypeRestrictions(e)
|
not Specific::ignoreTypeRestrictions(e)
|
||||||
then result = TPos()
|
then result = TPos()
|
||||||
|
|||||||
@@ -23,9 +23,7 @@
|
|||||||
* configuration (see `InvalidPointerToDerefConfig`).
|
* configuration (see `InvalidPointerToDerefConfig`).
|
||||||
*
|
*
|
||||||
* The dataflow traversal defines the set of sources as any dataflow node `n` such that there exists a pointer-arithmetic
|
* The dataflow traversal defines the set of sources as any dataflow node `n` such that there exists a pointer-arithmetic
|
||||||
* instruction `pai` found by `AllocationToInvalidPointer.qll` and a `n.asInstruction() >= pai + deltaDerefSourceAndPai`.
|
* instruction `pai` found by `AllocationToInvalidPointer.qll` and a `n.asInstruction() = pai`.
|
||||||
* Here, `deltaDerefSourceAndPai` is the constant difference between the source we track for finding a dereference and the
|
|
||||||
* pointer-arithmetic instruction.
|
|
||||||
*
|
*
|
||||||
* The set of sinks is defined as any dataflow node `n` such that `addr <= n.asInstruction() + deltaDerefSinkAndDerefAddress`
|
* The set of sinks is defined as any dataflow node `n` such that `addr <= n.asInstruction() + deltaDerefSinkAndDerefAddress`
|
||||||
* for some address operand `addr` and constant difference `deltaDerefSinkAndDerefAddress`. Since an address operand is
|
* for some address operand `addr` and constant difference `deltaDerefSinkAndDerefAddress`. Since an address operand is
|
||||||
@@ -37,9 +35,8 @@
|
|||||||
* `deltaDerefSinkAndDerefAddress >= 0`. The load attached to `*p` is the "operation". To ensure that the path makes
|
* `deltaDerefSinkAndDerefAddress >= 0`. The load attached to `*p` is the "operation". To ensure that the path makes
|
||||||
* intuitive sense, we only pick operations that are control-flow reachable from the dereference sink.
|
* intuitive sense, we only pick operations that are control-flow reachable from the dereference sink.
|
||||||
*
|
*
|
||||||
* To compute how many elements the dereference is beyond the end position of the allocation, we sum the two deltas
|
* We use the `deltaDerefSinkAndDerefAddress` to compute how many elements the dereference is beyond the end position of
|
||||||
* `deltaDerefSourceAndPai` and `deltaDerefSinkAndDerefAddress`. This is done in the `operationIsOffBy` predicate
|
* the allocation. This is done in the `operationIsOffBy` predicate (which is the only predicate exposed by this file).
|
||||||
* (which is the only predicate exposed by this file).
|
|
||||||
*
|
*
|
||||||
* Handling false positives:
|
* Handling false positives:
|
||||||
*
|
*
|
||||||
@@ -96,7 +93,7 @@ int invalidPointerToDereferenceFieldFlowBranchLimit() { result = 0 }
|
|||||||
private module InvalidPointerToDerefBarrier {
|
private module InvalidPointerToDerefBarrier {
|
||||||
private module BarrierConfig implements DataFlow::ConfigSig {
|
private module BarrierConfig implements DataFlow::ConfigSig {
|
||||||
additional predicate isSource(DataFlow::Node source, PointerArithmeticInstruction pai) {
|
additional predicate isSource(DataFlow::Node source, PointerArithmeticInstruction pai) {
|
||||||
invalidPointerToDerefSource(_, pai, _, _) and
|
invalidPointerToDerefSource(_, pai, _) and
|
||||||
// source <= pai
|
// source <= pai
|
||||||
bounded2(source.asInstruction(), pai, any(int d | d <= 0))
|
bounded2(source.asInstruction(), pai, any(int d | d <= 0))
|
||||||
}
|
}
|
||||||
@@ -169,11 +166,11 @@ private module InvalidPointerToDerefBarrier {
|
|||||||
*/
|
*/
|
||||||
private module InvalidPointerToDerefConfig implements DataFlow::StateConfigSig {
|
private module InvalidPointerToDerefConfig implements DataFlow::StateConfigSig {
|
||||||
class FlowState extends PointerArithmeticInstruction {
|
class FlowState extends PointerArithmeticInstruction {
|
||||||
FlowState() { invalidPointerToDerefSource(_, this, _, _) }
|
FlowState() { invalidPointerToDerefSource(_, this, _) }
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate isSource(DataFlow::Node source, FlowState pai) {
|
predicate isSource(DataFlow::Node source, FlowState pai) {
|
||||||
invalidPointerToDerefSource(_, pai, source, _)
|
invalidPointerToDerefSource(_, pai, source)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
@@ -198,24 +195,17 @@ private import DataFlow::GlobalWithState<InvalidPointerToDerefConfig>
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `allocSource` is dataflow node that represents an allocation that flows to the
|
* Holds if `allocSource` is dataflow node that represents an allocation that flows to the
|
||||||
* left-hand side of the pointer-arithmetic `pai`, and `derefSource <= pai + derefSourcePaiDelta`.
|
* left-hand side of the pointer-arithmetic instruction represented by `derefSource`.
|
||||||
*
|
|
||||||
* For example, if `pai` is a pointer-arithmetic operation `p + size` in an expression such
|
|
||||||
* as `(p + size) + 1` and `derefSource` is the node representing `(p + size) + 1`. In this
|
|
||||||
* case `derefSourcePaiDelta` is 1.
|
|
||||||
*/
|
*/
|
||||||
private predicate invalidPointerToDerefSource(
|
private predicate invalidPointerToDerefSource(
|
||||||
DataFlow::Node allocSource, PointerArithmeticInstruction pai, DataFlow::Node derefSource,
|
DataFlow::Node allocSource, PointerArithmeticInstruction pai, DataFlow::Node derefSource
|
||||||
int deltaDerefSourceAndPai
|
|
||||||
) {
|
) {
|
||||||
// Note that `deltaDerefSourceAndPai` is not necessarily equal to `rhsSizeDelta`:
|
// Note that `deltaDerefSourceAndPai` is not necessarily equal to `rhsSizeDelta`:
|
||||||
// `rhsSizeDelta` is the constant offset added to the size of the allocation, and
|
// `rhsSizeDelta` is the constant offset added to the size of the allocation, and
|
||||||
// `deltaDerefSourceAndPai` is the constant difference between the pointer-arithmetic instruction
|
// `deltaDerefSourceAndPai` is the constant difference between the pointer-arithmetic instruction
|
||||||
// and the instruction computing the address for which we will search for a dereference.
|
// and the instruction computing the address for which we will search for a dereference.
|
||||||
AllocToInvalidPointer::pointerAddInstructionHasBounds(allocSource, pai, _, _) and
|
AllocToInvalidPointer::pointerAddInstructionHasBounds(allocSource, pai, _, _) and
|
||||||
// derefSource <= pai + deltaDerefSourceAndPai
|
derefSource.asInstruction() = pai
|
||||||
bounded2(derefSource.asInstruction(), pai, deltaDerefSourceAndPai) and
|
|
||||||
deltaDerefSourceAndPai >= 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -258,11 +248,9 @@ private Instruction getASuccessor(Instruction instr) {
|
|||||||
instr.getBlock().getASuccessor+() = result.getBlock()
|
instr.getBlock().getASuccessor+() = result.getBlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate paiForDereferenceSink(
|
private predicate paiForDereferenceSink(PointerArithmeticInstruction pai, DataFlow::Node derefSink) {
|
||||||
PointerArithmeticInstruction pai, DataFlow::Node derefSink, int deltaDerefSourceAndPai
|
|
||||||
) {
|
|
||||||
exists(DataFlow::Node derefSource |
|
exists(DataFlow::Node derefSource |
|
||||||
invalidPointerToDerefSource(_, pai, derefSource, deltaDerefSourceAndPai) and
|
invalidPointerToDerefSource(_, pai, derefSource) and
|
||||||
flow(derefSource, derefSink)
|
flow(derefSource, derefSink)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -274,10 +262,10 @@ private predicate paiForDereferenceSink(
|
|||||||
*/
|
*/
|
||||||
private predicate derefSinkToOperation(
|
private predicate derefSinkToOperation(
|
||||||
DataFlow::Node derefSink, PointerArithmeticInstruction pai, DataFlow::Node operation,
|
DataFlow::Node derefSink, PointerArithmeticInstruction pai, DataFlow::Node operation,
|
||||||
string description, int deltaDerefSourceAndPai, int deltaDerefSinkAndDerefAddress
|
string description, int deltaDerefSinkAndDerefAddress
|
||||||
) {
|
) {
|
||||||
exists(Instruction operationInstr, AddressOperand addr |
|
exists(Instruction operationInstr, AddressOperand addr |
|
||||||
paiForDereferenceSink(pai, pragma[only_bind_into](derefSink), deltaDerefSourceAndPai) and
|
paiForDereferenceSink(pai, pragma[only_bind_into](derefSink)) and
|
||||||
isInvalidPointerDerefSink(derefSink, addr, operationInstr, description,
|
isInvalidPointerDerefSink(derefSink, addr, operationInstr, description,
|
||||||
deltaDerefSinkAndDerefAddress) and
|
deltaDerefSinkAndDerefAddress) and
|
||||||
operationInstr = getASuccessor(derefSink.asInstruction()) and
|
operationInstr = getASuccessor(derefSink.asInstruction()) and
|
||||||
@@ -298,11 +286,7 @@ predicate operationIsOffBy(
|
|||||||
DataFlow::Node allocation, PointerArithmeticInstruction pai, DataFlow::Node derefSource,
|
DataFlow::Node allocation, PointerArithmeticInstruction pai, DataFlow::Node derefSource,
|
||||||
DataFlow::Node derefSink, string description, DataFlow::Node operation, int delta
|
DataFlow::Node derefSink, string description, DataFlow::Node operation, int delta
|
||||||
) {
|
) {
|
||||||
exists(int deltaDerefSourceAndPai, int deltaDerefSinkAndDerefAddress |
|
invalidPointerToDerefSource(allocation, pai, derefSource) and
|
||||||
invalidPointerToDerefSource(allocation, pai, derefSource, deltaDerefSourceAndPai) and
|
flow(derefSource, derefSink) and
|
||||||
flow(derefSource, derefSink) and
|
derefSinkToOperation(derefSink, pai, operation, description, delta)
|
||||||
derefSinkToOperation(derefSink, pai, operation, description, deltaDerefSourceAndPai,
|
|
||||||
deltaDerefSinkAndDerefAddress) and
|
|
||||||
delta = deltaDerefSourceAndPai + deltaDerefSinkAndDerefAddress
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1334,11 +1334,16 @@ funbind(
|
|||||||
| @assignxorexpr
|
| @assignxorexpr
|
||||||
| @assignlshiftexpr
|
| @assignlshiftexpr
|
||||||
| @assignrshiftexpr
|
| @assignrshiftexpr
|
||||||
| @assignpaddexpr
|
;
|
||||||
|
|
||||||
|
@assign_pointer_expr = @assignpaddexpr
|
||||||
| @assignpsubexpr
|
| @assignpsubexpr
|
||||||
;
|
;
|
||||||
|
|
||||||
@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr
|
@assign_op_expr = @assign_arith_expr
|
||||||
|
| @assign_bitwise_expr
|
||||||
|
| @assign_pointer_expr
|
||||||
|
;
|
||||||
|
|
||||||
@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr
|
@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
|||||||
|
description: Removed @assignpaddexpr and @assignpsubexpr from @assign_bitwise_expr
|
||||||
|
compatibility: full
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
## 0.8.3
|
||||||
|
|
||||||
|
### Minor Analysis Improvements
|
||||||
|
|
||||||
|
* The `cpp/uninitialized-local` query has been improved to produce fewer false positives.
|
||||||
|
|
||||||
## 0.8.2
|
## 0.8.2
|
||||||
|
|
||||||
No user-facing changes.
|
No user-facing changes.
|
||||||
|
|||||||
@@ -27,16 +27,26 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
|
|||||||
ReturnStackAllocatedMemoryConfig() { this = "ReturnStackAllocatedMemoryConfig" }
|
ReturnStackAllocatedMemoryConfig() { this = "ReturnStackAllocatedMemoryConfig" }
|
||||||
|
|
||||||
override predicate isSource(Instruction source) {
|
override predicate isSource(Instruction source) {
|
||||||
// Holds if `source` is a node that represents the use of a stack variable
|
exists(Function func |
|
||||||
exists(VariableAddressInstruction var, Function func |
|
|
||||||
var = source and
|
|
||||||
func = source.getEnclosingFunction() and
|
|
||||||
var.getAstVariable() instanceof StackVariable and
|
|
||||||
// Pointer-to-member types aren't properly handled in the dbscheme.
|
|
||||||
not var.getResultType() instanceof PointerToMemberType and
|
|
||||||
// Rule out FPs caused by extraction errors.
|
// Rule out FPs caused by extraction errors.
|
||||||
not any(ErrorExpr e).getEnclosingFunction() = func and
|
not any(ErrorExpr e).getEnclosingFunction() = func and
|
||||||
not intentionallyReturnsStackPointer(func)
|
not intentionallyReturnsStackPointer(func) and
|
||||||
|
func = source.getEnclosingFunction()
|
||||||
|
|
|
||||||
|
// `source` is an instruction that represents the use of a stack variable
|
||||||
|
exists(VariableAddressInstruction var |
|
||||||
|
var = source and
|
||||||
|
var.getAstVariable() instanceof StackVariable and
|
||||||
|
// Pointer-to-member types aren't properly handled in the dbscheme.
|
||||||
|
not var.getResultType() instanceof PointerToMemberType
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// `source` is an instruction that represents the return value of a
|
||||||
|
// function that is known to return stack-allocated memory.
|
||||||
|
exists(Call call |
|
||||||
|
call.getTarget().hasGlobalName(["alloca", "strdupa", "strndupa", "_alloca", "_malloca"]) and
|
||||||
|
source.getUnconvertedResultExpression() = call
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,10 +95,10 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
from
|
from
|
||||||
MustFlowPathNode source, MustFlowPathNode sink, VariableAddressInstruction var,
|
MustFlowPathNode source, MustFlowPathNode sink, Instruction instr,
|
||||||
ReturnStackAllocatedMemoryConfig conf
|
ReturnStackAllocatedMemoryConfig conf
|
||||||
where
|
where
|
||||||
conf.hasFlowPath(pragma[only_bind_into](source), pragma[only_bind_into](sink)) and
|
conf.hasFlowPath(pragma[only_bind_into](source), pragma[only_bind_into](sink)) and
|
||||||
source.getInstruction() = var
|
source.getInstruction() = instr
|
||||||
select sink.getInstruction(), source, sink, "May return stack-allocated memory from $@.",
|
select sink.getInstruction(), source, sink, "May return stack-allocated memory from $@.",
|
||||||
var.getAst(), var.getAst().toString()
|
instr.getAst(), instr.getAst().toString()
|
||||||
|
|||||||
@@ -13,7 +13,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
import semmle.code.cpp.controlflow.StackVariableReachability
|
import semmle.code.cpp.ir.IR
|
||||||
|
import semmle.code.cpp.ir.dataflow.MustFlow
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Auxiliary predicate: Types that don't require initialization
|
* Auxiliary predicate: Types that don't require initialization
|
||||||
@@ -33,31 +34,6 @@ predicate allocatedType(Type t) {
|
|||||||
allocatedType(t.getUnspecifiedType())
|
allocatedType(t.getUnspecifiedType())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A declaration of a local variable that leaves the
|
|
||||||
* variable uninitialized.
|
|
||||||
*/
|
|
||||||
DeclStmt declWithNoInit(LocalVariable v) {
|
|
||||||
result.getADeclaration() = v and
|
|
||||||
not exists(v.getInitializer()) and
|
|
||||||
/* The type of the variable is not stack-allocated. */
|
|
||||||
exists(Type t | t = v.getType() | not allocatedType(t))
|
|
||||||
}
|
|
||||||
|
|
||||||
class UninitialisedLocalReachability extends StackVariableReachability {
|
|
||||||
UninitialisedLocalReachability() { this = "UninitialisedLocal" }
|
|
||||||
|
|
||||||
override predicate isSource(ControlFlowNode node, StackVariable v) { node = declWithNoInit(v) }
|
|
||||||
|
|
||||||
override predicate isSink(ControlFlowNode node, StackVariable v) { useOfVarActual(v, node) }
|
|
||||||
|
|
||||||
override predicate isBarrier(ControlFlowNode node, StackVariable v) {
|
|
||||||
// only report the _first_ possibly uninitialized use
|
|
||||||
useOfVarActual(v, node) or
|
|
||||||
definitionBarrier(v, node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
predicate containsInlineAssembly(Function f) { exists(AsmStmt s | s.getEnclosingFunction() = f) }
|
predicate containsInlineAssembly(Function f) { exists(AsmStmt s | s.getEnclosingFunction() = f) }
|
||||||
|
|
||||||
@@ -82,8 +58,33 @@ VariableAccess commonException() {
|
|||||||
containsInlineAssembly(result.getEnclosingFunction())
|
containsInlineAssembly(result.getEnclosingFunction())
|
||||||
}
|
}
|
||||||
|
|
||||||
from UninitialisedLocalReachability r, LocalVariable v, VariableAccess va
|
predicate isSinkImpl(Instruction sink, VariableAccess va) {
|
||||||
|
exists(LoadInstruction load |
|
||||||
|
va = load.getUnconvertedResultExpression() and
|
||||||
|
not va = commonException() and
|
||||||
|
sink = load.getSourceValue()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
class MustFlow extends MustFlowConfiguration {
|
||||||
|
MustFlow() { this = "MustFlow" }
|
||||||
|
|
||||||
|
override predicate isSource(Instruction source) {
|
||||||
|
source instanceof UninitializedInstruction and
|
||||||
|
exists(Type t | t = source.getResultType() | not allocatedType(t))
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate isSink(Operand sink) { isSinkImpl(sink.getDef(), _) }
|
||||||
|
|
||||||
|
override predicate allowInterproceduralFlow() { none() }
|
||||||
|
|
||||||
|
override predicate isBarrier(Instruction instr) { instr instanceof ChiInstruction }
|
||||||
|
}
|
||||||
|
|
||||||
|
from
|
||||||
|
VariableAccess va, LocalVariable v, MustFlow conf, MustFlowPathNode source, MustFlowPathNode sink
|
||||||
where
|
where
|
||||||
r.reaches(_, v, va) and
|
conf.hasFlowPath(source, sink) and
|
||||||
not va = commonException()
|
isSinkImpl(sink.getInstruction(), va) and
|
||||||
|
v = va.getTarget()
|
||||||
select va, "The variable $@ may not be initialized at this access.", v, v.getName()
|
select va, "The variable $@ may not be initialized at this access.", v, v.getName()
|
||||||
|
|||||||
@@ -14,25 +14,44 @@
|
|||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
import semmle.code.cpp.security.Security
|
import semmle.code.cpp.security.Security
|
||||||
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl
|
import semmle.code.cpp.security.FlowSources
|
||||||
import TaintedWithPath
|
import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||||
|
import semmle.code.cpp.ir.IR
|
||||||
|
import Flow::PathGraph
|
||||||
|
|
||||||
predicate isProcessOperationExplanation(Expr arg, string processOperation) {
|
predicate isProcessOperationExplanation(DataFlow::Node arg, string processOperation) {
|
||||||
exists(int processOperationArg, FunctionCall call |
|
exists(int processOperationArg, FunctionCall call |
|
||||||
isProcessOperationArgument(processOperation, processOperationArg) and
|
isProcessOperationArgument(processOperation, processOperationArg) and
|
||||||
call.getTarget().getName() = processOperation and
|
call.getTarget().getName() = processOperation and
|
||||||
call.getArgument(processOperationArg) = arg
|
call.getArgument(processOperationArg) = [arg.asExpr(), arg.asIndirectExpr()]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
class Configuration extends TaintTrackingConfiguration {
|
predicate isSource(FlowSource source, string sourceType) { sourceType = source.getSourceType() }
|
||||||
override predicate isSink(Element arg) { isProcessOperationExplanation(arg, _) }
|
|
||||||
|
module Config implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node node) { isSource(node, _) }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node node) { isProcessOperationExplanation(node, _) }
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node node) {
|
||||||
|
isSink(node) and node.asExpr().getUnspecifiedType() instanceof ArithmeticType
|
||||||
|
or
|
||||||
|
node.asInstruction().(StoreInstruction).getResultType() instanceof ArithmeticType
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
from string processOperation, Expr arg, Expr source, PathNode sourceNode, PathNode sinkNode
|
module Flow = TaintTracking::Global<Config>;
|
||||||
|
|
||||||
|
from
|
||||||
|
string processOperation, string sourceType, DataFlow::Node source, DataFlow::Node sink,
|
||||||
|
Flow::PathNode sourceNode, Flow::PathNode sinkNode
|
||||||
where
|
where
|
||||||
isProcessOperationExplanation(arg, processOperation) and
|
source = sourceNode.getNode() and
|
||||||
taintedWithPath(source, arg, sourceNode, sinkNode)
|
sink = sinkNode.getNode() and
|
||||||
select arg, sourceNode, sinkNode,
|
isSource(source, sourceType) and
|
||||||
|
isProcessOperationExplanation(sink, processOperation) and
|
||||||
|
Flow::flowPath(sourceNode, sinkNode)
|
||||||
|
select sink, sourceNode, sinkNode,
|
||||||
"The value of this argument may come from $@ and is being passed to " + processOperation + ".",
|
"The value of this argument may come from $@ and is being passed to " + processOperation + ".",
|
||||||
source, source.toString()
|
source, sourceType
|
||||||
|
|||||||
@@ -15,9 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import semmle.code.cpp.security.BufferWrite
|
import semmle.code.cpp.security.BufferWrite
|
||||||
import semmle.code.cpp.security.Security
|
import semmle.code.cpp.security.FlowSources as FS
|
||||||
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl
|
import semmle.code.cpp.dataflow.new.TaintTracking
|
||||||
import TaintedWithPath
|
import semmle.code.cpp.controlflow.IRGuards
|
||||||
|
import Flow::PathGraph
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* --- Summary of CWE-120 alerts ---
|
* --- Summary of CWE-120 alerts ---
|
||||||
@@ -47,38 +48,54 @@ predicate isUnboundedWrite(BufferWrite bw) {
|
|||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* predicate isMaybeUnboundedWrite(BufferWrite bw)
|
|
||||||
* {
|
|
||||||
* not bw.hasExplicitLimit() // has no explicit size limit
|
|
||||||
* and exists(bw.getMaxData()) // and we can deduce an upper bound to the amount copied
|
|
||||||
* and (not exists(getBufferSize(bw.getDest(), _))) // but we can't work out the size of the destination to be sure
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `e` is a source buffer going into an unbounded write `bw` or a
|
* Holds if `e` is a source buffer going into an unbounded write `bw` or a
|
||||||
* qualifier of (a qualifier of ...) such a source.
|
* qualifier of (a qualifier of ...) such a source.
|
||||||
*/
|
*/
|
||||||
predicate unboundedWriteSource(Expr e, BufferWrite bw) {
|
predicate unboundedWriteSource(Expr e, BufferWrite bw, boolean qualifier) {
|
||||||
isUnboundedWrite(bw) and e = bw.getASource()
|
isUnboundedWrite(bw) and e = bw.getASource() and qualifier = false
|
||||||
or
|
or
|
||||||
exists(FieldAccess fa | unboundedWriteSource(fa, bw) and e = fa.getQualifier())
|
exists(FieldAccess fa | unboundedWriteSource(fa, bw, _) and e = fa.getQualifier()) and
|
||||||
|
qualifier = true
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
predicate isSource(FS::FlowSource source, string sourceType) { source.getSourceType() = sourceType }
|
||||||
* --- user input reach ---
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Configuration extends TaintTrackingConfiguration {
|
predicate isSink(DataFlow::Node sink, BufferWrite bw, boolean qualifier) {
|
||||||
override predicate isSink(Element tainted) { unboundedWriteSource(tainted, _) }
|
unboundedWriteSource(sink.asIndirectExpr(), bw, qualifier)
|
||||||
|
or
|
||||||
override predicate taintThroughGlobals() { any() }
|
// `gets` and `scanf` reads from stdin so there's no real input.
|
||||||
|
// The `BufferWrite` library models this as the call itself being
|
||||||
|
// the source. In this case we mark the output argument as being
|
||||||
|
// the sink so that we report a path where source = sink (because
|
||||||
|
// the same output argument is also included in `isSource`).
|
||||||
|
bw.getASource() = bw and
|
||||||
|
unboundedWriteSource(sink.asDefiningArgument(), bw, qualifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
predicate lessThanOrEqual(IRGuardCondition g, Expr e, boolean branch) {
|
||||||
* --- put it together ---
|
exists(Operand left |
|
||||||
*/
|
g.comparesLt(left, _, _, true, branch) or
|
||||||
|
g.comparesEq(left, _, _, true, branch)
|
||||||
|
|
|
||||||
|
left.getDef().getUnconvertedResultExpression() = e
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
module Config implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) { isSource(source, _) }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { isSink(sink, _, _) }
|
||||||
|
|
||||||
|
predicate isBarrierOut(DataFlow::Node node) { isSink(node, _, false) }
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node node) {
|
||||||
|
// Block flow if the node is guarded by any <, <= or = operations.
|
||||||
|
node = DataFlow::BarrierGuard<lessThanOrEqual/3>::getABarrierNode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module Flow = TaintTracking::Global<Config>;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* An unbounded write is, for example `strcpy(..., tainted)`. We're looking
|
* An unbounded write is, for example `strcpy(..., tainted)`. We're looking
|
||||||
@@ -87,17 +104,20 @@ class Configuration extends TaintTrackingConfiguration {
|
|||||||
*
|
*
|
||||||
* In the case of `gets` and `scanf`, where the source buffer is implicit, the
|
* In the case of `gets` and `scanf`, where the source buffer is implicit, the
|
||||||
* `BufferWrite` library reports the source buffer to be the same as the
|
* `BufferWrite` library reports the source buffer to be the same as the
|
||||||
* destination buffer. Since those destination-buffer arguments are also
|
* destination buffer. So to report an alert on a pattern like:
|
||||||
* modeled in the taint-tracking library as being _sources_ of taint, they are
|
* ```
|
||||||
* in practice reported as being tainted because the `security.TaintTracking`
|
* char s[32];
|
||||||
* library does not distinguish between taint going into an argument and out of
|
* gets(s);
|
||||||
* an argument. Thus, we get the desired alerts.
|
* ```
|
||||||
|
* we define the sink as the node corresponding to the output argument of `gets`.
|
||||||
|
* This gives us a path where the source is equal to the sink.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
from BufferWrite bw, Expr inputSource, Expr tainted, PathNode sourceNode, PathNode sinkNode
|
from BufferWrite bw, Flow::PathNode source, Flow::PathNode sink, string sourceType
|
||||||
where
|
where
|
||||||
taintedWithPath(inputSource, tainted, sourceNode, sinkNode) and
|
Flow::flowPath(source, sink) and
|
||||||
unboundedWriteSource(tainted, bw)
|
isSource(source.getNode(), sourceType) and
|
||||||
select bw, sourceNode, sinkNode,
|
isSink(sink.getNode(), bw, _)
|
||||||
"This '" + bw.getBWDesc() + "' with input from $@ may overflow the destination.", inputSource,
|
select bw, source, sink,
|
||||||
inputSource.toString()
|
"This '" + bw.getBWDesc() + "' with input from $@ may overflow the destination.",
|
||||||
|
source.getNode(), sourceType
|
||||||
|
|||||||
@@ -16,22 +16,47 @@
|
|||||||
import cpp
|
import cpp
|
||||||
import semmle.code.cpp.security.Security
|
import semmle.code.cpp.security.Security
|
||||||
import semmle.code.cpp.security.FunctionWithWrappers
|
import semmle.code.cpp.security.FunctionWithWrappers
|
||||||
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl
|
import semmle.code.cpp.security.FlowSources
|
||||||
import TaintedWithPath
|
import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||||
|
import semmle.code.cpp.ir.IR
|
||||||
|
import Flow::PathGraph
|
||||||
|
|
||||||
class Configuration extends TaintTrackingConfiguration {
|
predicate isSource(FlowSource source, string sourceType) { sourceType = source.getSourceType() }
|
||||||
override predicate isSink(Element tainted) {
|
|
||||||
exists(PrintfLikeFunction printf | printf.outermostWrapperFunctionCall(tainted, _))
|
module Config implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node node) { isSource(node, _) }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node node) {
|
||||||
|
exists(PrintfLikeFunction printf |
|
||||||
|
printf.outermostWrapperFunctionCall([node.asExpr(), node.asIndirectExpr()], _)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate isArithmeticNonCharType(ArithmeticType type) {
|
||||||
|
not type instanceof CharType and
|
||||||
|
not type instanceof Char8Type and
|
||||||
|
not type instanceof Char16Type and
|
||||||
|
not type instanceof Char32Type
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node node) {
|
||||||
|
isSink(node) and isArithmeticNonCharType(node.asExpr().getUnspecifiedType())
|
||||||
|
or
|
||||||
|
isArithmeticNonCharType(node.asInstruction().(StoreInstruction).getResultType())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module Flow = TaintTracking::Global<Config>;
|
||||||
|
|
||||||
from
|
from
|
||||||
PrintfLikeFunction printf, Expr arg, PathNode sourceNode, PathNode sinkNode,
|
PrintfLikeFunction printf, string printfFunction, string sourceType, DataFlow::Node source,
|
||||||
string printfFunction, Expr userValue, string cause
|
DataFlow::Node sink, Flow::PathNode sourceNode, Flow::PathNode sinkNode
|
||||||
where
|
where
|
||||||
printf.outermostWrapperFunctionCall(arg, printfFunction) and
|
source = sourceNode.getNode() and
|
||||||
taintedWithPath(userValue, arg, sourceNode, sinkNode) and
|
sink = sinkNode.getNode() and
|
||||||
isUserInput(userValue, cause)
|
isSource(source, sourceType) and
|
||||||
select arg, sourceNode, sinkNode,
|
printf.outermostWrapperFunctionCall([sink.asExpr(), sink.asIndirectExpr()], printfFunction) and
|
||||||
|
Flow::flowPath(sourceNode, sinkNode)
|
||||||
|
select sink, sourceNode, sinkNode,
|
||||||
"The value of this argument may come from $@ and is being used as a formatting argument to " +
|
"The value of this argument may come from $@ and is being used as a formatting argument to " +
|
||||||
printfFunction + ".", userValue, cause
|
printfFunction + ".", source, sourceType
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
char *copy;
|
|
||||||
|
|
||||||
void copyArgv(char **argv) {
|
|
||||||
copy = argv[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
void printWrapper(char *str) {
|
|
||||||
printf(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
copyArgv(argv);
|
|
||||||
|
|
||||||
// This should be avoided
|
|
||||||
printf(copy);
|
|
||||||
|
|
||||||
// This should be avoided too, because it has the same effect
|
|
||||||
printWrapper(copy);
|
|
||||||
|
|
||||||
// This is fine
|
|
||||||
printf("%s", copy);
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
<!DOCTYPE qhelp PUBLIC
|
|
||||||
"-//Semmle//qhelp//EN"
|
|
||||||
"qhelp.dtd">
|
|
||||||
<qhelp>
|
|
||||||
<overview>
|
|
||||||
<p>The program uses input from the user, propagated via a global variable, as a format string for <code>printf</code> style functions.
|
|
||||||
This can lead to buffer overflows or data representation problems. An attacker can exploit this weakness to crash the program,
|
|
||||||
disclose information or even execute arbitrary code.</p>
|
|
||||||
|
|
||||||
<p>This rule only identifies inputs from the user that are transferred through global variables before being used in <code>printf</code> style functions.
|
|
||||||
Analyzing the flow of data through global variables is more prone to errors and so this rule may identify some examples of code where
|
|
||||||
the input is not really from the user. For example, when a global variable is set in two places, one that comes from the user and one that does not.
|
|
||||||
In this case we would mark all usages of the global variable as input from the user, but the input from the user may always came after the call to the
|
|
||||||
<code>printf</code> style functions.</p>
|
|
||||||
|
|
||||||
<p>The results of this rule should be considered alongside the related rule "Uncontrolled format string" which tracks the flow of the
|
|
||||||
values input by a user, excluding global variables, until the values are used as the format argument for a <code>printf</code> like function call.</p>
|
|
||||||
|
|
||||||
</overview>
|
|
||||||
<recommendation>
|
|
||||||
<p>Use constant expressions as the format strings. If you need to print a value from the user, use <code>printf("%s", value_from_user)</code>.</p>
|
|
||||||
|
|
||||||
</recommendation>
|
|
||||||
<example>
|
|
||||||
<sample src="UncontrolledFormatStringThroughGlobalVar.c" />
|
|
||||||
|
|
||||||
</example>
|
|
||||||
<references>
|
|
||||||
|
|
||||||
<li>CERT C Coding
|
|
||||||
Standard: <a href="https://www.securecoding.cert.org/confluence/display/c/FIO30-C.+Exclude+user+input+from+format+strings">FIO30-C. Exclude
|
|
||||||
user input from format strings</a>.</li>
|
|
||||||
|
|
||||||
|
|
||||||
</references>
|
|
||||||
</qhelp>
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
/**
|
|
||||||
* @name Uncontrolled format string (through global variable)
|
|
||||||
* @description Using externally-controlled format strings in
|
|
||||||
* printf-style functions can lead to buffer overflows
|
|
||||||
* or data representation problems.
|
|
||||||
* @kind path-problem
|
|
||||||
* @problem.severity warning
|
|
||||||
* @security-severity 9.3
|
|
||||||
* @precision high
|
|
||||||
* @id cpp/tainted-format-string-through-global
|
|
||||||
* @tags reliability
|
|
||||||
* security
|
|
||||||
* external/cwe/cwe-134
|
|
||||||
*/
|
|
||||||
|
|
||||||
import cpp
|
|
||||||
import semmle.code.cpp.security.FunctionWithWrappers
|
|
||||||
import semmle.code.cpp.security.Security
|
|
||||||
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl
|
|
||||||
import TaintedWithPath
|
|
||||||
|
|
||||||
class Configuration extends TaintTrackingConfiguration {
|
|
||||||
override predicate isSink(Element tainted) {
|
|
||||||
exists(PrintfLikeFunction printf | printf.outermostWrapperFunctionCall(tainted, _))
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate taintThroughGlobals() { any() }
|
|
||||||
}
|
|
||||||
|
|
||||||
from
|
|
||||||
PrintfLikeFunction printf, Expr arg, PathNode sourceNode, PathNode sinkNode,
|
|
||||||
string printfFunction, Expr userValue, string cause
|
|
||||||
where
|
|
||||||
printf.outermostWrapperFunctionCall(arg, printfFunction) and
|
|
||||||
not taintedWithoutGlobals(arg) and
|
|
||||||
taintedWithPath(userValue, arg, sourceNode, sinkNode) and
|
|
||||||
isUserInput(userValue, cause)
|
|
||||||
select arg, sourceNode, sinkNode,
|
|
||||||
"The value of this argument may come from $@ and is being used as a formatting argument to " +
|
|
||||||
printfFunction + ".", userValue, cause
|
|
||||||
@@ -12,79 +12,44 @@
|
|||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
import semmle.code.cpp.commons.NullTermination
|
import semmle.code.cpp.commons.NullTermination
|
||||||
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl
|
import semmle.code.cpp.security.FlowSources as FS
|
||||||
|
import semmle.code.cpp.dataflow.new.TaintTracking
|
||||||
|
import semmle.code.cpp.ir.IR
|
||||||
|
|
||||||
/** A user-controlled expression that may not be null terminated. */
|
predicate isSource(FS::FlowSource source, string sourceType) {
|
||||||
class TaintSource extends VariableAccess {
|
sourceType = source.getSourceType() and
|
||||||
TaintSource() {
|
exists(VariableAccess va, Call call |
|
||||||
exists(SecurityOptions x, string cause |
|
va = source.asDefiningArgument() and
|
||||||
this.getTarget() instanceof SemanticStackVariable and
|
call.getAnArgument() = va and
|
||||||
x.isUserInput(this, cause)
|
va.getTarget() instanceof SemanticStackVariable and
|
||||||
|
|
call.getTarget().hasGlobalName(["read", "fread", "recv", "recvfrom", "recvmsg"])
|
||||||
cause = ["read", "fread", "recv", "recvfrom", "recvmsg"]
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a tainted variable access that must be null
|
|
||||||
* terminated.
|
|
||||||
*/
|
|
||||||
private predicate isSink(VariableAccess sink) {
|
|
||||||
tainted(this, sink) and
|
|
||||||
variableMustBeNullTerminated(sink)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if this source can reach `va`, possibly using intermediate
|
|
||||||
* reassignments.
|
|
||||||
*/
|
|
||||||
private predicate sourceReaches(VariableAccess va) {
|
|
||||||
definitionUsePair(_, this, va)
|
|
||||||
or
|
|
||||||
exists(VariableAccess mid, Expr def |
|
|
||||||
this.sourceReaches(mid) and
|
|
||||||
exprDefinition(_, def, mid) and
|
|
||||||
definitionUsePair(_, def, va)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if the sink `sink` is reachable both from this source and
|
|
||||||
* from `va`, possibly using intermediate reassignments.
|
|
||||||
*/
|
|
||||||
private predicate reachesSink(VariableAccess va, VariableAccess sink) {
|
|
||||||
this.isSink(sink) and
|
|
||||||
va = sink
|
|
||||||
or
|
|
||||||
exists(VariableAccess mid, Expr def |
|
|
||||||
this.reachesSink(mid, sink) and
|
|
||||||
exprDefinition(_, def, va) and
|
|
||||||
definitionUsePair(_, def, mid)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `sink` is a tainted variable access that must be null
|
|
||||||
* terminated, and no access which null terminates its contents can
|
|
||||||
* either reach the sink or be reached from the source. (Ideally,
|
|
||||||
* we should instead look for such accesses only on the path from
|
|
||||||
* this source to `sink` found via `tainted(source, sink)`.)
|
|
||||||
*/
|
|
||||||
predicate reaches(VariableAccess sink) {
|
|
||||||
this.isSink(sink) and
|
|
||||||
not exists(VariableAccess va |
|
|
||||||
va != this and
|
|
||||||
va != sink and
|
|
||||||
mayAddNullTerminator(_, va)
|
|
||||||
|
|
|
||||||
this.sourceReaches(va)
|
|
||||||
or
|
|
||||||
this.reachesSink(va, sink)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
from TaintSource source, VariableAccess sink
|
predicate isSink(DataFlow::Node sink, VariableAccess va) {
|
||||||
where source.reaches(sink)
|
va = [sink.asExpr(), sink.asIndirectExpr()] and
|
||||||
select sink, "String operation depends on a $@ that may not be null terminated.", source,
|
variableMustBeNullTerminated(va)
|
||||||
"user-provided value"
|
}
|
||||||
|
|
||||||
|
private module Config implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) { isSource(source, _) }
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node node) {
|
||||||
|
isSink(node) and node.asExpr().getUnspecifiedType() instanceof ArithmeticType
|
||||||
|
or
|
||||||
|
node.asInstruction().(StoreInstruction).getResultType() instanceof ArithmeticType
|
||||||
|
or
|
||||||
|
mayAddNullTerminator(_, node.asIndirectExpr())
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { isSink(sink, _) }
|
||||||
|
}
|
||||||
|
|
||||||
|
module Flow = TaintTracking::Global<Config>;
|
||||||
|
|
||||||
|
from DataFlow::Node source, DataFlow::Node sink, VariableAccess va, string sourceType
|
||||||
|
where
|
||||||
|
Flow::flow(source, sink) and
|
||||||
|
isSource(source, sourceType) and
|
||||||
|
isSink(sink, va)
|
||||||
|
select va, "String operation depends on $@ that may not be null terminated.", source, sourceType
|
||||||
|
|||||||
@@ -14,10 +14,13 @@
|
|||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
import semmle.code.cpp.security.Overflow
|
import semmle.code.cpp.security.Overflow
|
||||||
import semmle.code.cpp.security.Security
|
import semmle.code.cpp.dataflow.new.TaintTracking
|
||||||
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl
|
import semmle.code.cpp.dataflow.new.DataFlow
|
||||||
import TaintedWithPath
|
import semmle.code.cpp.ir.IR
|
||||||
|
import semmle.code.cpp.controlflow.IRGuards as IRGuards
|
||||||
|
import semmle.code.cpp.security.FlowSources as FS
|
||||||
import Bounded
|
import Bounded
|
||||||
|
import Flow::PathGraph
|
||||||
|
|
||||||
bindingset[op]
|
bindingset[op]
|
||||||
predicate missingGuard(Operation op, Expr e, string effect) {
|
predicate missingGuard(Operation op, Expr e, string effect) {
|
||||||
@@ -28,28 +31,90 @@ predicate missingGuard(Operation op, Expr e, string effect) {
|
|||||||
not e instanceof VariableAccess and effect = "overflow"
|
not e instanceof VariableAccess and effect = "overflow"
|
||||||
}
|
}
|
||||||
|
|
||||||
class Configuration extends TaintTrackingConfiguration {
|
predicate isSource(FS::FlowSource source, string sourceType) { sourceType = source.getSourceType() }
|
||||||
override predicate isSink(Element e) {
|
|
||||||
exists(Operation op |
|
|
||||||
missingGuard(op, e, _) and
|
|
||||||
op.getAnOperand() = e
|
|
||||||
|
|
|
||||||
op instanceof UnaryArithmeticOperation or
|
|
||||||
op instanceof BinaryArithmeticOperation or
|
|
||||||
op instanceof AssignArithmeticOperation
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate isBarrier(Expr e) {
|
predicate isSink(DataFlow::Node sink, Operation op, Expr e) {
|
||||||
super.isBarrier(e) or bounded(e) or e.getUnspecifiedType().(IntegralType).getSize() <= 1
|
e = sink.asExpr() and
|
||||||
|
missingGuard(op, e, _) and
|
||||||
|
op.getAnOperand() = e and
|
||||||
|
(
|
||||||
|
op instanceof UnaryArithmeticOperation or
|
||||||
|
op instanceof BinaryArithmeticOperation or
|
||||||
|
op instanceof AssignArithmeticOperation
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate hasUpperBoundsCheck(Variable var) {
|
||||||
|
exists(RelationalOperation oper, VariableAccess access |
|
||||||
|
oper.getAnOperand() = access and
|
||||||
|
access.getTarget() = var and
|
||||||
|
// Comparing to 0 is not an upper bound check
|
||||||
|
not oper.getAnOperand().getValue() = "0"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate constantInstruction(Instruction instr) {
|
||||||
|
instr instanceof ConstantInstruction or
|
||||||
|
constantInstruction(instr.(UnaryInstruction).getUnary())
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate readsVariable(LoadInstruction load, Variable var) {
|
||||||
|
load.getSourceAddress().(VariableAddressInstruction).getAstVariable() = var
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate nodeIsBarrierEqualityCandidate(DataFlow::Node node, Operand access, Variable checkedVar) {
|
||||||
|
exists(Instruction instr | instr = node.asInstruction() |
|
||||||
|
readsVariable(instr, checkedVar) and
|
||||||
|
any(IRGuards::IRGuardCondition guard).ensuresEq(access, _, _, instr.getBlock(), true)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
module Config implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) { isSource(source, _) }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { isSink(sink, _, _) }
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node node) {
|
||||||
|
exists(StoreInstruction store | store = node.asInstruction() |
|
||||||
|
// Block flow to "likely small expressions"
|
||||||
|
bounded(store.getSourceValue().getUnconvertedResultExpression())
|
||||||
|
or
|
||||||
|
// Block flow to "small types"
|
||||||
|
store.getResultType().getUnspecifiedType().(IntegralType).getSize() <= 1
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// Block flow if there's an upper bound check of the variable anywhere in the program
|
||||||
|
exists(Variable checkedVar, Instruction instr | instr = node.asInstruction() |
|
||||||
|
readsVariable(instr, checkedVar) and
|
||||||
|
hasUpperBoundsCheck(checkedVar)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// Block flow if the node is guarded by an equality check
|
||||||
|
exists(Variable checkedVar, Operand access |
|
||||||
|
nodeIsBarrierEqualityCandidate(node, access, checkedVar) and
|
||||||
|
readsVariable(access.getDef(), checkedVar)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// Block flow to any binary instruction whose operands are both non-constants.
|
||||||
|
exists(BinaryInstruction iTo |
|
||||||
|
iTo = node.asInstruction() and
|
||||||
|
not constantInstruction(iTo.getLeft()) and
|
||||||
|
not constantInstruction(iTo.getRight()) and
|
||||||
|
// propagate taint from either the pointer or the offset, regardless of constantness
|
||||||
|
not iTo instanceof PointerArithmeticInstruction
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
from Expr origin, Expr e, string effect, PathNode sourceNode, PathNode sinkNode, Operation op
|
module Flow = TaintTracking::Global<Config>;
|
||||||
|
|
||||||
|
from
|
||||||
|
Expr e, string effect, Flow::PathNode source, Flow::PathNode sink, Operation op, string sourceType
|
||||||
where
|
where
|
||||||
taintedWithPath(origin, e, sourceNode, sinkNode) and
|
Flow::flowPath(source, sink) and
|
||||||
op.getAnOperand() = e and
|
isSource(source.getNode(), sourceType) and
|
||||||
|
isSink(sink.getNode(), op, e) and
|
||||||
missingGuard(op, e, effect)
|
missingGuard(op, e, effect)
|
||||||
select e, sourceNode, sinkNode,
|
select e, source, sink,
|
||||||
"$@ flows to an operand of an arithmetic expression, potentially causing an " + effect + ".",
|
"$@ flows to an operand of an arithmetic expression, potentially causing an " + effect + ".",
|
||||||
origin, "User-provided value"
|
source, sourceType
|
||||||
|
|||||||
@@ -16,45 +16,30 @@
|
|||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
import semmle.code.cpp.security.Overflow
|
import semmle.code.cpp.security.Overflow
|
||||||
import semmle.code.cpp.security.Security
|
import semmle.code.cpp.dataflow.new.TaintTracking
|
||||||
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl
|
import semmle.code.cpp.ir.IR
|
||||||
|
import semmle.code.cpp.controlflow.IRGuards as IRGuards
|
||||||
|
|
||||||
predicate isMaxValue(Expr mie) {
|
predicate isMaxValue(Expr mie) {
|
||||||
exists(MacroInvocation mi |
|
exists(MacroInvocation mi |
|
||||||
mi.getExpr() = mie and
|
mi.getExpr() = mie and
|
||||||
(
|
mi.getMacroName() = ["CHAR_MAX", "LLONG_MAX", "INT_MAX", "SHRT_MAX", "UINT_MAX"]
|
||||||
mi.getMacroName() = "CHAR_MAX" or
|
|
||||||
mi.getMacroName() = "LLONG_MAX" or
|
|
||||||
mi.getMacroName() = "INT_MAX" or
|
|
||||||
mi.getMacroName() = "SHRT_MAX" or
|
|
||||||
mi.getMacroName() = "UINT_MAX"
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate isMinValue(Expr mie) {
|
predicate isMinValue(Expr mie) {
|
||||||
exists(MacroInvocation mi |
|
exists(MacroInvocation mi |
|
||||||
mi.getExpr() = mie and
|
mi.getExpr() = mie and
|
||||||
(
|
mi.getMacroName() = ["CHAR_MIN", "LLONG_MIN", "INT_MIN", "SHRT_MIN"]
|
||||||
mi.getMacroName() = "CHAR_MIN" or
|
|
||||||
mi.getMacroName() = "LLONG_MIN" or
|
|
||||||
mi.getMacroName() = "INT_MIN" or
|
|
||||||
mi.getMacroName() = "SHRT_MIN"
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
class SecurityOptionsArith extends SecurityOptions {
|
predicate isSource(DataFlow::Node source, string cause) {
|
||||||
override predicate isUserInput(Expr expr, string cause) {
|
exists(Expr expr | expr = source.asExpr() |
|
||||||
isMaxValue(expr) and cause = "max value"
|
isMaxValue(expr) and cause = "max value"
|
||||||
or
|
or
|
||||||
isMinValue(expr) and cause = "min value"
|
isMinValue(expr) and cause = "min value"
|
||||||
}
|
)
|
||||||
}
|
|
||||||
|
|
||||||
predicate taintedVarAccess(Expr origin, VariableAccess va, string cause) {
|
|
||||||
isUserInput(origin, cause) and
|
|
||||||
tainted(origin, va)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate causeEffectCorrespond(string cause, string effect) {
|
predicate causeEffectCorrespond(string cause, string effect) {
|
||||||
@@ -65,16 +50,79 @@ predicate causeEffectCorrespond(string cause, string effect) {
|
|||||||
effect = "underflow"
|
effect = "underflow"
|
||||||
}
|
}
|
||||||
|
|
||||||
from Expr origin, Operation op, VariableAccess va, string cause, string effect
|
predicate isSink(DataFlow::Node sink, VariableAccess va, string effect) {
|
||||||
where
|
exists(Operation op |
|
||||||
taintedVarAccess(origin, va, cause) and
|
sink.asExpr() = va and
|
||||||
op.getAnOperand() = va and
|
op.getAnOperand() = va
|
||||||
(
|
|
|
||||||
missingGuardAgainstUnderflow(op, va) and effect = "underflow"
|
missingGuardAgainstUnderflow(op, va) and effect = "underflow"
|
||||||
or
|
or
|
||||||
missingGuardAgainstOverflow(op, va) and effect = "overflow"
|
missingGuardAgainstOverflow(op, va) and effect = "overflow"
|
||||||
) and
|
)
|
||||||
causeEffectCorrespond(cause, effect)
|
}
|
||||||
|
|
||||||
|
predicate hasUpperBoundsCheck(Variable var) {
|
||||||
|
exists(RelationalOperation oper, VariableAccess access |
|
||||||
|
oper.getAnOperand() = access and
|
||||||
|
access.getTarget() = var and
|
||||||
|
// Comparing to 0 is not an upper bound check
|
||||||
|
not oper.getAnOperand().getValue() = "0"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate constantInstruction(Instruction instr) {
|
||||||
|
instr instanceof ConstantInstruction or
|
||||||
|
constantInstruction(instr.(UnaryInstruction).getUnary())
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate readsVariable(LoadInstruction load, Variable var) {
|
||||||
|
load.getSourceAddress().(VariableAddressInstruction).getAstVariable() = var
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate nodeIsBarrierEqualityCandidate(DataFlow::Node node, Operand access, Variable checkedVar) {
|
||||||
|
exists(Instruction instr | instr = node.asInstruction() |
|
||||||
|
readsVariable(instr, checkedVar) and
|
||||||
|
any(IRGuards::IRGuardCondition guard).ensuresEq(access, _, _, instr.getBlock(), true)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
module Config implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) { isSource(source, _) }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { isSink(sink, _, _) }
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node node) {
|
||||||
|
// Block flow if there's an upper bound check of the variable anywhere in the program
|
||||||
|
exists(Variable checkedVar, Instruction instr | instr = node.asInstruction() |
|
||||||
|
readsVariable(instr, checkedVar) and
|
||||||
|
hasUpperBoundsCheck(checkedVar)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// Block flow if the node is guarded by an equality check
|
||||||
|
exists(Variable checkedVar, Operand access |
|
||||||
|
nodeIsBarrierEqualityCandidate(node, access, checkedVar) and
|
||||||
|
readsVariable(access.getDef(), checkedVar)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// Block flow to any binary instruction whose operands are both non-constants.
|
||||||
|
exists(BinaryInstruction iTo |
|
||||||
|
iTo = node.asInstruction() and
|
||||||
|
not constantInstruction(iTo.getLeft()) and
|
||||||
|
not constantInstruction(iTo.getRight()) and
|
||||||
|
// propagate taint from either the pointer or the offset, regardless of constantness
|
||||||
|
not iTo instanceof PointerArithmeticInstruction
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module Flow = TaintTracking::Global<Config>;
|
||||||
|
|
||||||
|
from DataFlow::Node source, DataFlow::Node sink, VariableAccess va, string cause, string effect
|
||||||
|
where
|
||||||
|
Flow::flow(source, sink) and
|
||||||
|
isSource(source, cause) and
|
||||||
|
causeEffectCorrespond(cause, effect) and
|
||||||
|
isSink(sink, va, effect)
|
||||||
select va,
|
select va,
|
||||||
"$@ flows to an operand of an arithmetic expression, potentially causing an " + effect + ".",
|
"$@ flows to an operand of an arithmetic expression, potentially causing an " + effect + ".",
|
||||||
origin, "Extreme value"
|
source, "Extreme value"
|
||||||
|
|||||||
@@ -15,7 +15,11 @@
|
|||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
|
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
|
||||||
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl
|
import semmle.code.cpp.dataflow.new.DataFlow
|
||||||
|
import semmle.code.cpp.security.FlowSources as FS
|
||||||
|
import semmle.code.cpp.dataflow.new.TaintTracking
|
||||||
|
import semmle.code.cpp.ir.IR
|
||||||
|
import semmle.code.cpp.controlflow.IRGuards as IRGuards
|
||||||
|
|
||||||
/** Holds if `expr` might overflow. */
|
/** Holds if `expr` might overflow. */
|
||||||
predicate outOfBoundsExpr(Expr expr, string kind) {
|
predicate outOfBoundsExpr(Expr expr, string kind) {
|
||||||
@@ -27,13 +31,76 @@ predicate outOfBoundsExpr(Expr expr, string kind) {
|
|||||||
else none()
|
else none()
|
||||||
}
|
}
|
||||||
|
|
||||||
from Expr use, Expr origin, string kind
|
predicate isSource(FS::FlowSource source, string sourceType) { sourceType = source.getSourceType() }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink, string kind) {
|
||||||
|
exists(Expr use |
|
||||||
|
use = sink.asExpr() and
|
||||||
|
not use.getUnspecifiedType() instanceof PointerType and
|
||||||
|
outOfBoundsExpr(use, kind) and
|
||||||
|
not inSystemMacroExpansion(use)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate hasUpperBoundsCheck(Variable var) {
|
||||||
|
exists(RelationalOperation oper, VariableAccess access |
|
||||||
|
oper.getAnOperand() = access and
|
||||||
|
access.getTarget() = var and
|
||||||
|
// Comparing to 0 is not an upper bound check
|
||||||
|
not oper.getAnOperand().getValue() = "0"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate constantInstruction(Instruction instr) {
|
||||||
|
instr instanceof ConstantInstruction or
|
||||||
|
constantInstruction(instr.(UnaryInstruction).getUnary())
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate readsVariable(LoadInstruction load, Variable var) {
|
||||||
|
load.getSourceAddress().(VariableAddressInstruction).getAstVariable() = var
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate nodeIsBarrierEqualityCandidate(DataFlow::Node node, Operand access, Variable checkedVar) {
|
||||||
|
exists(Instruction instr | instr = node.asInstruction() |
|
||||||
|
readsVariable(instr, checkedVar) and
|
||||||
|
any(IRGuards::IRGuardCondition guard).ensuresEq(access, _, _, instr.getBlock(), true)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
module Config implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) { isSource(source, _) }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { isSink(sink, _) }
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node node) {
|
||||||
|
// Block flow if there's an upper bound check of the variable anywhere in the program
|
||||||
|
exists(Variable checkedVar, Instruction instr | instr = node.asInstruction() |
|
||||||
|
readsVariable(instr, checkedVar) and
|
||||||
|
hasUpperBoundsCheck(checkedVar)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// Block flow if the node is guarded by an equality check
|
||||||
|
exists(Variable checkedVar, Operand access |
|
||||||
|
nodeIsBarrierEqualityCandidate(node, access, checkedVar) and
|
||||||
|
readsVariable(access.getDef(), checkedVar)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// Block flow to any binary instruction whose operands are both non-constants.
|
||||||
|
exists(BinaryInstruction iTo |
|
||||||
|
iTo = node.asInstruction() and
|
||||||
|
not constantInstruction(iTo.getLeft()) and
|
||||||
|
not constantInstruction(iTo.getRight()) and
|
||||||
|
// propagate taint from either the pointer or the offset, regardless of constantness
|
||||||
|
not iTo instanceof PointerArithmeticInstruction
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module Flow = TaintTracking::Global<Config>;
|
||||||
|
|
||||||
|
from DataFlow::Node source, DataFlow::Node sink, string kind, string sourceType
|
||||||
where
|
where
|
||||||
not use.getUnspecifiedType() instanceof PointerType and
|
Flow::flow(source, sink) and
|
||||||
outOfBoundsExpr(use, kind) and
|
isSource(source, sourceType) and
|
||||||
tainted(origin, use) and
|
isSink(sink, kind)
|
||||||
origin != use and
|
select sink, "$@ flows an expression which might " + kind + ".", source, sourceType
|
||||||
not inSystemMacroExpansion(use) and
|
|
||||||
// Avoid double-counting: don't include all the conversions of `use`.
|
|
||||||
not use instanceof Conversion
|
|
||||||
select use, "$@ flows an expression which might " + kind + ".", origin, "User-provided value"
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
* @id cpp/invalid-pointer-deref
|
* @id cpp/invalid-pointer-deref
|
||||||
* @tags reliability
|
* @tags reliability
|
||||||
* security
|
* security
|
||||||
* experimental
|
|
||||||
* external/cwe/cwe-119
|
* external/cwe/cwe-119
|
||||||
* external/cwe/cwe-125
|
* external/cwe/cwe-125
|
||||||
* external/cwe/cwe-193
|
* external/cwe/cwe-193
|
||||||
|
|||||||
@@ -12,8 +12,10 @@
|
|||||||
* external/cwe/cwe-290
|
* external/cwe/cwe-290
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl
|
import cpp
|
||||||
import TaintedWithPath
|
import semmle.code.cpp.dataflow.new.TaintTracking
|
||||||
|
import semmle.code.cpp.security.FlowSources as FS
|
||||||
|
import Flow::PathGraph
|
||||||
|
|
||||||
string getATopLevelDomain() {
|
string getATopLevelDomain() {
|
||||||
result =
|
result =
|
||||||
@@ -60,13 +62,26 @@ predicate hardCodedAddressInCondition(Expr subexpression, Expr condition) {
|
|||||||
condition = any(IfStmt ifStmt).getCondition()
|
condition = any(IfStmt ifStmt).getCondition()
|
||||||
}
|
}
|
||||||
|
|
||||||
class Configuration extends TaintTrackingConfiguration {
|
predicate isSource(FS::FlowSource source, string sourceType) { source.getSourceType() = sourceType }
|
||||||
override predicate isSink(Element sink) { hardCodedAddressInCondition(sink, _) }
|
|
||||||
|
predicate isSink(DataFlow::Node sink, Expr condition) {
|
||||||
|
hardCodedAddressInCondition([sink.asExpr(), sink.asIndirectExpr()], condition)
|
||||||
}
|
}
|
||||||
|
|
||||||
from Expr subexpression, Expr source, Expr condition, PathNode sourceNode, PathNode sinkNode
|
module Config implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) { isSource(source, _) }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) { isSink(sink, _) }
|
||||||
|
}
|
||||||
|
|
||||||
|
module Flow = TaintTracking::Global<Config>;
|
||||||
|
|
||||||
|
from
|
||||||
|
Expr subexpression, Expr condition, Flow::PathNode source, Flow::PathNode sink, string sourceType
|
||||||
where
|
where
|
||||||
hardCodedAddressInCondition(subexpression, condition) and
|
hardCodedAddressInCondition(subexpression, condition) and
|
||||||
taintedWithPath(source, subexpression, sourceNode, sinkNode)
|
isSource(source.getNode(), sourceType) and
|
||||||
select condition, sourceNode, sinkNode,
|
Flow::flowPath(source, sink) and
|
||||||
"Untrusted input $@ might be vulnerable to a spoofing attack.", source, source.toString()
|
isSink(sink.getNode(), condition)
|
||||||
|
select condition, source, sink, "Untrusted input $@ might be vulnerable to a spoofing attack.",
|
||||||
|
source, sourceType
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
import cpp
|
import cpp
|
||||||
import semmle.code.cpp.ir.dataflow.TaintTracking
|
import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||||
import semmle.code.cpp.models.interfaces.FlowSource
|
import semmle.code.cpp.models.interfaces.FlowSource
|
||||||
|
import semmle.code.cpp.models.implementations.Memset
|
||||||
import ExposedSystemData::PathGraph
|
import ExposedSystemData::PathGraph
|
||||||
import SystemData
|
import SystemData
|
||||||
|
|
||||||
@@ -28,6 +29,10 @@ module ExposedSystemDataConfig implements DataFlow::ConfigSig {
|
|||||||
fc.getArgument(arg).getAChild*() = sink.asIndirectExpr()
|
fc.getArgument(arg).getAChild*() = sink.asIndirectExpr()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node node) {
|
||||||
|
node.asIndirectArgument() = any(MemsetFunction func).getACallToThisFunction().getAnArgument()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module ExposedSystemData = TaintTracking::Global<ExposedSystemDataConfig>;
|
module ExposedSystemData = TaintTracking::Global<ExposedSystemDataConfig>;
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import cpp
|
|||||||
import semmle.code.cpp.ir.dataflow.TaintTracking
|
import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||||
import semmle.code.cpp.models.interfaces.FlowSource
|
import semmle.code.cpp.models.interfaces.FlowSource
|
||||||
import semmle.code.cpp.security.OutputWrite
|
import semmle.code.cpp.security.OutputWrite
|
||||||
|
import semmle.code.cpp.models.implementations.Memset
|
||||||
import PotentiallyExposedSystemData::PathGraph
|
import PotentiallyExposedSystemData::PathGraph
|
||||||
import SystemData
|
import SystemData
|
||||||
|
|
||||||
@@ -49,6 +50,10 @@ module PotentiallyExposedSystemDataConfig implements DataFlow::ConfigSig {
|
|||||||
else child = sink.asExpr()
|
else child = sink.asExpr()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node node) {
|
||||||
|
node.asIndirectArgument() = any(MemsetFunction func).getACallToThisFunction().getAnArgument()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module PotentiallyExposedSystemData = TaintTracking::Global<PotentiallyExposedSystemDataConfig>;
|
module PotentiallyExposedSystemData = TaintTracking::Global<PotentiallyExposedSystemDataConfig>;
|
||||||
|
|||||||
@@ -12,8 +12,12 @@
|
|||||||
* external/cwe/cwe-807
|
* external/cwe/cwe-807
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import semmle.code.cpp.ir.dataflow.internal.DefaultTaintTrackingImpl
|
import cpp
|
||||||
import TaintedWithPath
|
import semmle.code.cpp.security.Security
|
||||||
|
import semmle.code.cpp.security.FlowSources
|
||||||
|
import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||||
|
import semmle.code.cpp.ir.IR
|
||||||
|
import Flow::PathGraph
|
||||||
|
|
||||||
predicate sensitiveCondition(Expr condition, Expr raise) {
|
predicate sensitiveCondition(Expr condition, Expr raise) {
|
||||||
raisesPrivilege(raise) and
|
raisesPrivilege(raise) and
|
||||||
@@ -23,19 +27,62 @@ predicate sensitiveCondition(Expr condition, Expr raise) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
class Configuration extends TaintTrackingConfiguration {
|
private predicate constantInstruction(Instruction instr) {
|
||||||
override predicate isSink(Element tainted) { sensitiveCondition(tainted, _) }
|
instr instanceof ConstantInstruction
|
||||||
|
or
|
||||||
|
instr instanceof StringConstantInstruction
|
||||||
|
or
|
||||||
|
constantInstruction(instr.(UnaryInstruction).getUnary())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
predicate isSource(FlowSource source, string sourceType) { sourceType = source.getSourceType() }
|
||||||
|
|
||||||
|
module Config implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node node) { isSource(node, _) }
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node node) {
|
||||||
|
sensitiveCondition([node.asExpr(), node.asIndirectExpr()], _)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node node) {
|
||||||
|
// Block flow into binary instructions if both operands are non-constant
|
||||||
|
exists(BinaryInstruction iTo |
|
||||||
|
iTo = node.asInstruction() and
|
||||||
|
not constantInstruction(iTo.getLeft()) and
|
||||||
|
not constantInstruction(iTo.getRight()) and
|
||||||
|
// propagate taint from either the pointer or the offset, regardless of constant-ness
|
||||||
|
not iTo instanceof PointerArithmeticInstruction
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// Block flow through calls to pure functions if two or more operands are non-constant
|
||||||
|
exists(Instruction iFrom1, Instruction iFrom2, CallInstruction iTo |
|
||||||
|
iTo = node.asInstruction() and
|
||||||
|
isPureFunction(iTo.getStaticCallTarget().getName()) and
|
||||||
|
iFrom1 = iTo.getAnArgument() and
|
||||||
|
iFrom2 = iTo.getAnArgument() and
|
||||||
|
not constantInstruction(iFrom1) and
|
||||||
|
not constantInstruction(iFrom2) and
|
||||||
|
iFrom1 != iFrom2
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module Flow = TaintTracking::Global<Config>;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Produce an alert if there is an 'if' statement whose condition `condition`
|
* Produce an alert if there is an 'if' statement whose condition `condition`
|
||||||
* is influenced by tainted data `source`, and the body contains
|
* is influenced by tainted data `source`, and the body contains
|
||||||
* `raise` which escalates privilege.
|
* `raise` which escalates privilege.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
from Expr source, Expr condition, Expr raise, PathNode sourceNode, PathNode sinkNode
|
from
|
||||||
|
Expr raise, string sourceType, DataFlow::Node source, DataFlow::Node sink,
|
||||||
|
Flow::PathNode sourceNode, Flow::PathNode sinkNode
|
||||||
where
|
where
|
||||||
taintedWithPath(source, condition, sourceNode, sinkNode) and
|
source = sourceNode.getNode() and
|
||||||
sensitiveCondition(condition, raise)
|
sink = sinkNode.getNode() and
|
||||||
select condition, sourceNode, sinkNode, "Reliance on untrusted input $@ to raise privilege at $@.",
|
isSource(source, sourceType) and
|
||||||
source, source.toString(), raise, raise.toString()
|
sensitiveCondition([sink.asExpr(), sink.asIndirectExpr()], raise) and
|
||||||
|
Flow::flowPath(sourceNode, sinkNode)
|
||||||
|
select sink, sourceNode, sinkNode, "Reliance on $@ to raise privilege at $@.", source, sourceType,
|
||||||
|
raise, raise.toString()
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
* @description The total number of lines of C/C++ code across all files, including system headers, libraries, and auto-generated files. This is a useful metric of the size of a database. For all files that were seen during the build, this query counts the lines of code, excluding whitespace or comments.
|
* @description The total number of lines of C/C++ code across all files, including system headers, libraries, and auto-generated files. This is a useful metric of the size of a database. For all files that were seen during the build, this query counts the lines of code, excluding whitespace or comments.
|
||||||
* @kind metric
|
* @kind metric
|
||||||
* @tags summary
|
* @tags summary
|
||||||
|
* telemetry
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: breaking
|
||||||
|
---
|
||||||
|
* The `cpp/tainted-format-string-through-global` query has been deleted. This does not lead to a loss of relevant alerts, as the query duplicated a subset of the alerts from `cpp/tainted-format-string`.
|
||||||
5
cpp/ql/src/change-notes/released/0.8.3.md
Normal file
5
cpp/ql/src/change-notes/released/0.8.3.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
## 0.8.3
|
||||||
|
|
||||||
|
### Minor Analysis Improvements
|
||||||
|
|
||||||
|
* The `cpp/uninitialized-local` query has been improved to produce fewer false positives.
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
---
|
---
|
||||||
lastReleaseVersion: 0.8.2
|
lastReleaseVersion: 0.8.3
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/all-asymmetric-algorithms
|
* @id cpp/quantum-readiness/cbom/all-asymmetric-algorithms
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/all-cryptographic-algorithms
|
* @id cpp/quantum-readiness/cbom/all-cryptographic-algorithms
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/all-asymmetric-encryption-algorithms
|
* @id cpp/quantum-readiness/cbom/all-asymmetric-encryption-algorithms
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/authenticated-encryption-algorithms
|
* @id cpp/quantum-readiness/cbom/authenticated-encryption-algorithms
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/block-cipher-mode
|
* @id cpp/quantum-readiness/cbom/block-cipher-mode
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/iv-sources
|
* @id cpp/quantum-readiness/cbom/iv-sources
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/unkown-iv-sources
|
* @id cpp/quantum-readiness/cbom/unkown-iv-sources
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/elliptic-curve-key-length
|
* @id cpp/quantum-readiness/cbom/elliptic-curve-key-length
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/elliptic-curve-algorithms
|
* @id cpp/quantum-readiness/cbom/elliptic-curve-algorithms
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/hash-algorithms
|
* @id cpp/quantum-readiness/cbom/hash-algorithms
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/key-exchange
|
* @id cpp/quantum-readiness/cbom/key-exchange
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/asymmetric-key-generation
|
* @id cpp/quantum-readiness/cbom/asymmetric-key-generation
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/signing-algorithms
|
* @id cpp/quantum-readiness/cbom/signing-algorithms
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/symmetric-encryption-algorithms
|
* @id cpp/quantum-readiness/cbom/symmetric-encryption-algorithms
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/quantum-readiness/cbom/unkwon-asymmetric-key-generation
|
* @id cpp/quantum-readiness/cbom/unkwon-asymmetric-key-generation
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @precision high
|
|
||||||
* @tags cbom
|
* @tags cbom
|
||||||
* cryptography
|
* cryptography
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/cpp-queries
|
name: codeql/cpp-queries
|
||||||
version: 0.8.2
|
version: 0.8.4-dev
|
||||||
groups:
|
groups:
|
||||||
- cpp
|
- cpp
|
||||||
- queries
|
- queries
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ edges
|
|||||||
| test.cpp:69:10:69:10 | arr indirection [post update] [p] | test.cpp:70:5:70:7 | arr indirection [p] |
|
| test.cpp:69:10:69:10 | arr indirection [post update] [p] | test.cpp:70:5:70:7 | arr indirection [p] |
|
||||||
| test.cpp:69:14:69:19 | call to malloc | test.cpp:69:5:69:25 | ... = ... |
|
| test.cpp:69:14:69:19 | call to malloc | test.cpp:69:5:69:25 | ... = ... |
|
||||||
| test.cpp:70:5:70:7 | arr indirection [p] | test.cpp:67:10:67:19 | mk_array_p indirection [p] |
|
| test.cpp:70:5:70:7 | arr indirection [p] | test.cpp:67:10:67:19 | mk_array_p indirection [p] |
|
||||||
| test.cpp:70:5:70:7 | arr indirection [p] | test.cpp:70:5:70:7 | arr indirection [p] |
|
|
||||||
| test.cpp:76:20:76:29 | call to mk_array_p indirection [p] | test.cpp:79:9:79:11 | arr indirection [p] |
|
| test.cpp:76:20:76:29 | call to mk_array_p indirection [p] | test.cpp:79:9:79:11 | arr indirection [p] |
|
||||||
| test.cpp:76:20:76:29 | call to mk_array_p indirection [p] | test.cpp:83:9:83:11 | arr indirection [p] |
|
| test.cpp:76:20:76:29 | call to mk_array_p indirection [p] | test.cpp:83:9:83:11 | arr indirection [p] |
|
||||||
| test.cpp:79:9:79:11 | arr indirection [p] | test.cpp:79:14:79:14 | p |
|
| test.cpp:79:9:79:11 | arr indirection [p] | test.cpp:79:14:79:14 | p |
|
||||||
|
|||||||
@@ -450,6 +450,7 @@ irGuards
|
|||||||
| test.c:126:12:126:26 | Call: call to test3_condition |
|
| test.c:126:12:126:26 | Call: call to test3_condition |
|
||||||
| test.c:131:7:131:7 | Load: b |
|
| test.c:131:7:131:7 | Load: b |
|
||||||
| test.c:137:7:137:7 | Constant: 0 |
|
| test.c:137:7:137:7 | Constant: 0 |
|
||||||
|
| test.c:146:7:146:8 | LogicalNot: ! ... |
|
||||||
| test.c:146:8:146:8 | Load: x |
|
| test.c:146:8:146:8 | Load: x |
|
||||||
| test.c:152:10:152:10 | Load: x |
|
| test.c:152:10:152:10 | Load: x |
|
||||||
| test.c:152:15:152:15 | Load: y |
|
| test.c:152:15:152:15 | Load: y |
|
||||||
@@ -640,6 +641,7 @@ irGuardsControl
|
|||||||
| test.c:126:12:126:26 | Call: call to test3_condition | true | 127 | 127 |
|
| test.c:126:12:126:26 | Call: call to test3_condition | true | 127 | 127 |
|
||||||
| test.c:131:7:131:7 | Load: b | true | 132 | 132 |
|
| test.c:131:7:131:7 | Load: b | true | 132 | 132 |
|
||||||
| test.c:137:7:137:7 | Constant: 0 | false | 142 | 142 |
|
| test.c:137:7:137:7 | Constant: 0 | false | 142 | 142 |
|
||||||
|
| test.c:146:7:146:8 | LogicalNot: ! ... | true | 147 | 147 |
|
||||||
| test.c:146:8:146:8 | Load: x | false | 147 | 147 |
|
| test.c:146:8:146:8 | Load: x | false | 147 | 147 |
|
||||||
| test.c:152:10:152:10 | Load: x | true | 152 | 152 |
|
| test.c:152:10:152:10 | Load: x | true | 152 | 152 |
|
||||||
| test.c:152:15:152:15 | Load: y | true | 152 | 152 |
|
| test.c:152:15:152:15 | Load: y | true | 152 | 152 |
|
||||||
|
|||||||
111
cpp/ql/test/library-tests/dataflow/dataflow-tests/TestBase.qll
Normal file
111
cpp/ql/test/library-tests/dataflow/dataflow-tests/TestBase.qll
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
module AstTest {
|
||||||
|
import semmle.code.cpp.dataflow.DataFlow
|
||||||
|
private import semmle.code.cpp.controlflow.Guards
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A `BarrierGuard` that stops flow to all occurrences of `x` within statement
|
||||||
|
* S in `if (guarded(x)) S`.
|
||||||
|
*/
|
||||||
|
// This is tested in `BarrierGuard.cpp`.
|
||||||
|
predicate testBarrierGuard(GuardCondition g, Expr checked, boolean isTrue) {
|
||||||
|
g.(FunctionCall).getTarget().getName() = "guarded" and
|
||||||
|
checked = g.(FunctionCall).getArgument(0) and
|
||||||
|
isTrue = true
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Common data flow configuration to be used by tests. */
|
||||||
|
module AstTestAllocationConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) {
|
||||||
|
source.asExpr().(FunctionCall).getTarget().getName() = "source"
|
||||||
|
or
|
||||||
|
source.asParameter().getName().matches("source%")
|
||||||
|
or
|
||||||
|
source.asExpr().(FunctionCall).getTarget().getName() = "indirect_source"
|
||||||
|
or
|
||||||
|
source.(DataFlow::DefinitionByReferenceNode).getParameter().getName().matches("ref_source%")
|
||||||
|
or
|
||||||
|
// Track uninitialized variables
|
||||||
|
exists(source.asUninitialized())
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) {
|
||||||
|
exists(FunctionCall call |
|
||||||
|
call.getTarget().getName() = ["sink", "indirect_sink"] and
|
||||||
|
sink.asExpr() = call.getAnArgument()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node barrier) {
|
||||||
|
barrier.asExpr().(VariableAccess).getTarget().hasName("barrier") or
|
||||||
|
barrier = DataFlow::BarrierGuard<testBarrierGuard/3>::getABarrierNode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module AstFlow = DataFlow::Global<AstTestAllocationConfig>;
|
||||||
|
}
|
||||||
|
|
||||||
|
module IRTest {
|
||||||
|
private import cpp
|
||||||
|
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||||
|
private import semmle.code.cpp.ir.IR
|
||||||
|
private import semmle.code.cpp.controlflow.IRGuards
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A `BarrierGuard` that stops flow to all occurrences of `x` within statement
|
||||||
|
* S in `if (guarded(x)) S`.
|
||||||
|
*/
|
||||||
|
// This is tested in `BarrierGuard.cpp`.
|
||||||
|
predicate testBarrierGuard(IRGuardCondition g, Expr checked, boolean isTrue) {
|
||||||
|
exists(Call call |
|
||||||
|
call = g.getUnconvertedResultExpression() and
|
||||||
|
call.getTarget().hasName("guarded") and
|
||||||
|
checked = call.getArgument(0) and
|
||||||
|
isTrue = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Common data flow configuration to be used by tests. */
|
||||||
|
module IRTestAllocationConfig implements DataFlow::ConfigSig {
|
||||||
|
predicate isSource(DataFlow::Node source) {
|
||||||
|
source.asExpr().(FunctionCall).getTarget().getName() = "source"
|
||||||
|
or
|
||||||
|
source.asIndirectExpr(1).(FunctionCall).getTarget().getName() = "indirect_source"
|
||||||
|
or
|
||||||
|
source.asExpr().(StringLiteral).getValue() = "source"
|
||||||
|
or
|
||||||
|
// indirect_source(n) gives the dataflow node representing the indirect node after n dereferences.
|
||||||
|
exists(int n, string s |
|
||||||
|
n = s.regexpCapture("indirect_source\\((\\d)\\)", 1).toInt() and
|
||||||
|
source.asIndirectExpr(n).(StringLiteral).getValue() = s
|
||||||
|
)
|
||||||
|
or
|
||||||
|
source.asParameter().getName().matches("source%")
|
||||||
|
or
|
||||||
|
source.(DataFlow::DefinitionByReferenceNode).getParameter().getName().matches("ref_source%")
|
||||||
|
or
|
||||||
|
exists(source.asUninitialized())
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isSink(DataFlow::Node sink) {
|
||||||
|
exists(FunctionCall call, Expr e | e = call.getAnArgument() |
|
||||||
|
call.getTarget().getName() = "sink" and
|
||||||
|
sink.asExpr() = e
|
||||||
|
or
|
||||||
|
call.getTarget().getName() = "indirect_sink" and
|
||||||
|
sink.asIndirectExpr() = e
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isBarrier(DataFlow::Node barrier) {
|
||||||
|
exists(Expr barrierExpr | barrierExpr in [barrier.asExpr(), barrier.asIndirectExpr()] |
|
||||||
|
barrierExpr.(VariableAccess).getTarget().hasName("barrier")
|
||||||
|
)
|
||||||
|
or
|
||||||
|
barrier = DataFlow::BarrierGuard<testBarrierGuard/3>::getABarrierNode()
|
||||||
|
or
|
||||||
|
barrier = DataFlow::BarrierGuard<testBarrierGuard/3>::getAnIndirectBarrierNode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module IRFlow = DataFlow::Global<IRTestAllocationConfig>;
|
||||||
|
}
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
uniqueEnclosingCallable
|
uniqueEnclosingCallable
|
||||||
|
| test.cpp:864:44:864:58 | {...} | Node should have one enclosing callable but has 0. |
|
||||||
|
| test.cpp:864:47:864:54 | call to source | Node should have one enclosing callable but has 0. |
|
||||||
|
| test.cpp:872:46:872:51 | call to source | Node should have one enclosing callable but has 0. |
|
||||||
|
| test.cpp:872:53:872:56 | 1 | Node should have one enclosing callable but has 0. |
|
||||||
uniqueCallEnclosingCallable
|
uniqueCallEnclosingCallable
|
||||||
|
| test.cpp:864:47:864:54 | call to source | Call should have one enclosing callable but has 0. |
|
||||||
|
| test.cpp:872:46:872:51 | call to source | Call should have one enclosing callable but has 0. |
|
||||||
uniqueType
|
uniqueType
|
||||||
uniqueNodeLocation
|
uniqueNodeLocation
|
||||||
missingLocation
|
missingLocation
|
||||||
@@ -23,6 +29,8 @@ argHasPostUpdate
|
|||||||
| lambdas.cpp:38:2:38:2 | d | ArgumentNode is missing PostUpdateNode. |
|
| lambdas.cpp:38:2:38:2 | d | ArgumentNode is missing PostUpdateNode. |
|
||||||
| lambdas.cpp:45:2:45:2 | e | ArgumentNode is missing PostUpdateNode. |
|
| lambdas.cpp:45:2:45:2 | e | ArgumentNode is missing PostUpdateNode. |
|
||||||
| test.cpp:67:29:67:35 | source1 | ArgumentNode is missing PostUpdateNode. |
|
| test.cpp:67:29:67:35 | source1 | ArgumentNode is missing PostUpdateNode. |
|
||||||
|
| test.cpp:813:19:813:35 | * ... | ArgumentNode is missing PostUpdateNode. |
|
||||||
|
| test.cpp:848:23:848:25 | rpx | ArgumentNode is missing PostUpdateNode. |
|
||||||
postWithInFlow
|
postWithInFlow
|
||||||
| BarrierGuard.cpp:49:6:49:6 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
| BarrierGuard.cpp:49:6:49:6 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
| BarrierGuard.cpp:60:7:60:7 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
| BarrierGuard.cpp:60:7:60:7 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
@@ -41,6 +49,9 @@ postWithInFlow
|
|||||||
| example.c:26:9:26:9 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
| example.c:26:9:26:9 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
| example.c:26:19:26:24 | coords [inner post update] | PostUpdateNode should not be the target of local flow. |
|
| example.c:26:19:26:24 | coords [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
| example.c:28:23:28:25 | pos [inner post update] | PostUpdateNode should not be the target of local flow. |
|
| example.c:28:23:28:25 | pos [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
|
| flowOut.cpp:5:5:5:12 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
|
| flowOut.cpp:5:6:5:12 | toTaint [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
|
| flowOut.cpp:18:17:18:17 | x [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
| globals.cpp:13:5:13:19 | flowTestGlobal1 [post update] | PostUpdateNode should not be the target of local flow. |
|
| globals.cpp:13:5:13:19 | flowTestGlobal1 [post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
| globals.cpp:23:5:23:19 | flowTestGlobal2 [post update] | PostUpdateNode should not be the target of local flow. |
|
| globals.cpp:23:5:23:19 | flowTestGlobal2 [post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
| lambdas.cpp:23:3:23:14 | v [post update] | PostUpdateNode should not be the target of local flow. |
|
| lambdas.cpp:23:3:23:14 | v [post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
@@ -133,6 +144,9 @@ postWithInFlow
|
|||||||
| test.cpp:728:3:728:4 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
|
| test.cpp:728:3:728:4 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
| test.cpp:728:4:728:4 | p [inner post update] | PostUpdateNode should not be the target of local flow. |
|
| test.cpp:728:4:728:4 | p [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
| test.cpp:734:41:734:41 | x [inner post update] | PostUpdateNode should not be the target of local flow. |
|
| test.cpp:734:41:734:41 | x [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
|
| test.cpp:808:5:808:21 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
|
| test.cpp:808:6:808:21 | global_indirect1 [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
|
| test.cpp:832:5:832:17 | global_direct [post update] | PostUpdateNode should not be the target of local flow. |
|
||||||
viableImplInCallContextTooLarge
|
viableImplInCallContextTooLarge
|
||||||
uniqueParameterNodeAtPosition
|
uniqueParameterNodeAtPosition
|
||||||
uniqueParameterNodePosition
|
uniqueParameterNodePosition
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
int source();
|
||||||
|
void sink(int);
|
||||||
|
|
||||||
|
void source_ref(int *toTaint) { // $ ir-def=*toTaint ast-def=toTaint
|
||||||
|
*toTaint = source();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void modify_copy(int* ptr) { // $ ast-def=ptr
|
||||||
|
int deref = *ptr;
|
||||||
|
int* other = &deref;
|
||||||
|
source_ref(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_output() {
|
||||||
|
int x = 0;
|
||||||
|
modify_copy(&x);
|
||||||
|
sink(x); // $ SPURIOUS: ir
|
||||||
|
}
|
||||||
@@ -0,0 +1,306 @@
|
|||||||
|
WARNING: Module DataFlow has been deprecated and may be removed in future (test-source-sink.ql:3,25-42)
|
||||||
|
WARNING: Module DataFlow has been deprecated and may be removed in future (test-source-sink.ql:3,57-74)
|
||||||
|
astFlow
|
||||||
|
| BarrierGuard.cpp:5:19:5:24 | source | BarrierGuard.cpp:9:10:9:15 | source |
|
||||||
|
| BarrierGuard.cpp:13:17:13:22 | source | BarrierGuard.cpp:15:10:15:15 | source |
|
||||||
|
| BarrierGuard.cpp:21:17:21:22 | source | BarrierGuard.cpp:25:10:25:15 | source |
|
||||||
|
| BarrierGuard.cpp:29:16:29:21 | source | BarrierGuard.cpp:31:10:31:15 | source |
|
||||||
|
| BarrierGuard.cpp:29:16:29:21 | source | BarrierGuard.cpp:33:10:33:15 | source |
|
||||||
|
| BarrierGuard.cpp:49:10:49:15 | call to source | BarrierGuard.cpp:51:13:51:13 | x |
|
||||||
|
| BarrierGuard.cpp:49:10:49:15 | call to source | BarrierGuard.cpp:53:13:53:13 | x |
|
||||||
|
| BarrierGuard.cpp:49:10:49:15 | call to source | BarrierGuard.cpp:55:13:55:13 | x |
|
||||||
|
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:62:14:62:14 | x |
|
||||||
|
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:64:14:64:14 | x |
|
||||||
|
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:66:14:66:14 | x |
|
||||||
|
| acrossLinkTargets.cpp:19:27:19:32 | call to source | acrossLinkTargets.cpp:12:8:12:8 | x |
|
||||||
|
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:18:8:18:19 | sourceArray1 |
|
||||||
|
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:22:8:22:20 | & ... |
|
||||||
|
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:23:17:23:29 | & ... |
|
||||||
|
| clang.cpp:29:27:29:32 | call to source | clang.cpp:30:27:30:28 | m1 |
|
||||||
|
| clang.cpp:29:27:29:32 | call to source | clang.cpp:31:27:31:34 | call to getFirst |
|
||||||
|
| clang.cpp:35:32:35:37 | call to source | clang.cpp:38:10:38:11 | m2 |
|
||||||
|
| clang.cpp:44:35:44:40 | call to source | clang.cpp:46:17:46:18 | m2 |
|
||||||
|
| clang.cpp:51:19:51:24 | call to source | clang.cpp:52:8:52:17 | stackArray |
|
||||||
|
| clang.cpp:51:19:51:24 | call to source | clang.cpp:53:17:53:26 | stackArray |
|
||||||
|
| dispatch.cpp:9:37:9:42 | call to source | dispatch.cpp:35:16:35:25 | call to notSource1 |
|
||||||
|
| dispatch.cpp:9:37:9:42 | call to source | dispatch.cpp:43:15:43:24 | call to notSource1 |
|
||||||
|
| dispatch.cpp:10:37:10:42 | call to source | dispatch.cpp:36:16:36:25 | call to notSource2 |
|
||||||
|
| dispatch.cpp:10:37:10:42 | call to source | dispatch.cpp:44:15:44:24 | call to notSource2 |
|
||||||
|
| dispatch.cpp:37:19:37:24 | call to source | dispatch.cpp:11:38:11:38 | x |
|
||||||
|
| dispatch.cpp:45:18:45:23 | call to source | dispatch.cpp:11:38:11:38 | x |
|
||||||
|
| globals.cpp:5:17:5:22 | call to source | globals.cpp:6:10:6:14 | local |
|
||||||
|
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:14:3:14:6 | t |
|
||||||
|
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:18:8:18:8 | call to operator() |
|
||||||
|
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:21:3:21:6 | t |
|
||||||
|
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:29:3:29:6 | t |
|
||||||
|
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:35:8:35:8 | a |
|
||||||
|
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:41:8:41:8 | a |
|
||||||
|
| lambdas.cpp:43:7:43:12 | call to source | lambdas.cpp:46:7:46:7 | w |
|
||||||
|
| ref.cpp:29:11:29:16 | call to source | ref.cpp:62:10:62:11 | x3 |
|
||||||
|
| ref.cpp:53:9:53:10 | x1 | ref.cpp:56:10:56:11 | x1 |
|
||||||
|
| ref.cpp:53:13:53:14 | x2 | ref.cpp:59:10:59:11 | x2 |
|
||||||
|
| ref.cpp:53:17:53:18 | x3 | ref.cpp:62:10:62:11 | x3 |
|
||||||
|
| ref.cpp:53:21:53:22 | x4 | ref.cpp:65:10:65:11 | x4 |
|
||||||
|
| ref.cpp:55:23:55:28 | call to source | ref.cpp:56:10:56:11 | x1 |
|
||||||
|
| ref.cpp:94:15:94:20 | call to source | ref.cpp:129:13:129:15 | val |
|
||||||
|
| ref.cpp:109:15:109:20 | call to source | ref.cpp:132:13:132:15 | val |
|
||||||
|
| ref.cpp:122:23:122:28 | call to source | ref.cpp:123:13:123:15 | val |
|
||||||
|
| ref.cpp:125:19:125:24 | call to source | ref.cpp:126:13:126:15 | val |
|
||||||
|
| self-Iterator.cpp:19:23:19:28 | call to source | self-Iterator.cpp:20:10:20:10 | x |
|
||||||
|
| test.cpp:6:12:6:17 | call to source | test.cpp:7:8:7:9 | t1 |
|
||||||
|
| test.cpp:6:12:6:17 | call to source | test.cpp:9:8:9:9 | t1 |
|
||||||
|
| test.cpp:6:12:6:17 | call to source | test.cpp:10:8:10:9 | t2 |
|
||||||
|
| test.cpp:6:12:6:17 | call to source | test.cpp:15:8:15:9 | t2 |
|
||||||
|
| test.cpp:6:12:6:17 | call to source | test.cpp:26:8:26:9 | t1 |
|
||||||
|
| test.cpp:35:10:35:15 | call to source | test.cpp:30:8:30:8 | t |
|
||||||
|
| test.cpp:36:13:36:18 | call to source | test.cpp:31:8:31:8 | c |
|
||||||
|
| test.cpp:50:14:50:19 | call to source | test.cpp:58:10:58:10 | t |
|
||||||
|
| test.cpp:66:30:66:36 | source1 | test.cpp:71:8:71:9 | x4 |
|
||||||
|
| test.cpp:75:7:75:8 | u1 | test.cpp:76:8:76:9 | u1 |
|
||||||
|
| test.cpp:83:7:83:8 | u2 | test.cpp:84:8:84:18 | ... ? ... : ... |
|
||||||
|
| test.cpp:83:7:83:8 | u2 | test.cpp:86:8:86:9 | i1 |
|
||||||
|
| test.cpp:89:28:89:34 | source1 | test.cpp:90:8:90:14 | source1 |
|
||||||
|
| test.cpp:100:13:100:18 | call to source | test.cpp:103:10:103:12 | ref |
|
||||||
|
| test.cpp:138:27:138:32 | call to source | test.cpp:140:8:140:8 | y |
|
||||||
|
| test.cpp:151:33:151:38 | call to source | test.cpp:144:8:144:8 | s |
|
||||||
|
| test.cpp:151:33:151:38 | call to source | test.cpp:152:8:152:8 | y |
|
||||||
|
| test.cpp:164:34:164:39 | call to source | test.cpp:157:8:157:8 | x |
|
||||||
|
| test.cpp:164:34:164:39 | call to source | test.cpp:165:8:165:8 | y |
|
||||||
|
| test.cpp:171:11:171:16 | call to source | test.cpp:178:8:178:8 | y |
|
||||||
|
| test.cpp:245:14:245:19 | call to source | test.cpp:260:12:260:12 | x |
|
||||||
|
| test.cpp:265:22:265:27 | call to source | test.cpp:266:12:266:12 | x |
|
||||||
|
| test.cpp:305:17:305:22 | call to source | test.cpp:289:14:289:14 | x |
|
||||||
|
| test.cpp:314:4:314:9 | call to source | test.cpp:318:7:318:7 | x |
|
||||||
|
| test.cpp:347:17:347:22 | call to source | test.cpp:349:10:349:18 | globalVar |
|
||||||
|
| test.cpp:359:13:359:18 | call to source | test.cpp:365:10:365:14 | field |
|
||||||
|
| test.cpp:373:13:373:18 | call to source | test.cpp:369:10:369:14 | field |
|
||||||
|
| test.cpp:373:13:373:18 | call to source | test.cpp:375:10:375:14 | field |
|
||||||
|
| test.cpp:382:48:382:54 | source1 | test.cpp:385:8:385:10 | tmp |
|
||||||
|
| test.cpp:388:53:388:59 | source1 | test.cpp:392:8:392:10 | tmp |
|
||||||
|
| test.cpp:388:53:388:59 | source1 | test.cpp:394:10:394:12 | tmp |
|
||||||
|
| test.cpp:399:7:399:9 | tmp | test.cpp:401:8:401:10 | tmp |
|
||||||
|
| test.cpp:405:7:405:9 | tmp | test.cpp:408:8:408:10 | tmp |
|
||||||
|
| test.cpp:416:7:416:11 | local | test.cpp:418:8:418:12 | local |
|
||||||
|
| test.cpp:417:16:417:20 | ref arg local | test.cpp:418:8:418:12 | local |
|
||||||
|
| test.cpp:422:7:422:11 | local | test.cpp:424:8:424:12 | local |
|
||||||
|
| test.cpp:423:20:423:25 | ref arg & ... | test.cpp:424:8:424:12 | local |
|
||||||
|
| test.cpp:433:7:433:11 | local | test.cpp:435:8:435:12 | local |
|
||||||
|
| test.cpp:433:7:433:11 | local | test.cpp:436:8:436:13 | * ... |
|
||||||
|
| test.cpp:434:20:434:24 | ref arg local | test.cpp:435:8:435:12 | local |
|
||||||
|
| test.cpp:434:20:434:24 | ref arg local | test.cpp:436:8:436:13 | * ... |
|
||||||
|
| test.cpp:440:7:440:11 | local | test.cpp:442:8:442:12 | local |
|
||||||
|
| test.cpp:441:18:441:23 | ref arg & ... | test.cpp:442:8:442:12 | local |
|
||||||
|
| test.cpp:448:7:448:11 | local | test.cpp:450:8:450:12 | local |
|
||||||
|
| test.cpp:448:7:448:11 | local | test.cpp:451:8:451:13 | * ... |
|
||||||
|
| test.cpp:449:18:449:22 | ref arg local | test.cpp:450:8:450:12 | local |
|
||||||
|
| test.cpp:449:18:449:22 | ref arg local | test.cpp:451:8:451:13 | * ... |
|
||||||
|
| test.cpp:456:26:456:32 | source1 | test.cpp:457:9:457:22 | (statement expression) |
|
||||||
|
| test.cpp:456:26:456:32 | source1 | test.cpp:468:8:468:12 | local |
|
||||||
|
| test.cpp:472:8:472:13 | call to source | test.cpp:478:8:478:8 | x |
|
||||||
|
| test.cpp:506:8:506:13 | call to source | test.cpp:513:8:513:8 | x |
|
||||||
|
| test.cpp:517:7:517:16 | stackArray | test.cpp:521:8:521:20 | access to array |
|
||||||
|
| test.cpp:519:19:519:24 | call to source | test.cpp:521:8:521:20 | access to array |
|
||||||
|
| test.cpp:551:9:551:9 | y | test.cpp:541:10:541:10 | y |
|
||||||
|
| test.cpp:583:11:583:16 | call to source | test.cpp:590:8:590:8 | x |
|
||||||
|
| test.cpp:628:20:628:25 | ref arg buffer | test.cpp:629:17:629:22 | buffer |
|
||||||
|
| test.cpp:633:18:633:23 | call to source | test.cpp:634:8:634:8 | x |
|
||||||
|
| test.cpp:702:38:702:43 | source | test.cpp:695:8:695:10 | buf |
|
||||||
|
| test.cpp:726:11:726:16 | call to source | test.cpp:735:8:735:8 | x |
|
||||||
|
| test.cpp:733:7:733:7 | x | test.cpp:735:8:735:8 | x |
|
||||||
|
| test.cpp:749:27:749:32 | call to source | test.cpp:740:10:740:10 | x |
|
||||||
|
| test.cpp:751:27:751:32 | call to source | test.cpp:740:10:740:10 | x |
|
||||||
|
| test.cpp:753:32:753:37 | call to source | test.cpp:740:10:740:10 | x |
|
||||||
|
| test.cpp:755:32:755:37 | call to source | test.cpp:740:10:740:10 | x |
|
||||||
|
| test.cpp:769:27:769:32 | call to source | test.cpp:760:10:760:10 | x |
|
||||||
|
| test.cpp:771:27:771:32 | call to source | test.cpp:760:10:760:10 | x |
|
||||||
|
| test.cpp:773:32:773:37 | call to source | test.cpp:760:10:760:10 | x |
|
||||||
|
| test.cpp:775:32:775:37 | call to source | test.cpp:760:10:760:10 | x |
|
||||||
|
| test.cpp:788:31:788:36 | call to source | test.cpp:782:12:782:12 | x |
|
||||||
|
| test.cpp:790:31:790:36 | call to source | test.cpp:782:12:782:12 | x |
|
||||||
|
| test.cpp:797:22:797:28 | ref arg content | test.cpp:798:19:798:25 | content |
|
||||||
|
| test.cpp:842:11:842:16 | call to source | test.cpp:844:8:844:8 | y |
|
||||||
|
| test.cpp:846:13:846:27 | call to indirect_source | test.cpp:848:23:848:25 | rpx |
|
||||||
|
| test.cpp:860:54:860:59 | call to source | test.cpp:861:10:861:37 | static_local_pointer_dynamic |
|
||||||
|
| true_upon_entry.cpp:17:11:17:16 | call to source | true_upon_entry.cpp:21:8:21:8 | x |
|
||||||
|
| true_upon_entry.cpp:27:9:27:14 | call to source | true_upon_entry.cpp:29:8:29:8 | x |
|
||||||
|
| true_upon_entry.cpp:33:11:33:16 | call to source | true_upon_entry.cpp:39:8:39:8 | x |
|
||||||
|
| true_upon_entry.cpp:43:11:43:16 | call to source | true_upon_entry.cpp:49:8:49:8 | x |
|
||||||
|
| true_upon_entry.cpp:54:11:54:16 | call to source | true_upon_entry.cpp:57:8:57:8 | x |
|
||||||
|
| true_upon_entry.cpp:70:11:70:16 | call to source | true_upon_entry.cpp:78:8:78:8 | x |
|
||||||
|
| true_upon_entry.cpp:83:11:83:16 | call to source | true_upon_entry.cpp:86:8:86:8 | x |
|
||||||
|
irFlow
|
||||||
|
| BarrierGuard.cpp:5:19:5:24 | source | BarrierGuard.cpp:9:10:9:15 | source |
|
||||||
|
| BarrierGuard.cpp:13:17:13:22 | source | BarrierGuard.cpp:15:10:15:15 | source |
|
||||||
|
| BarrierGuard.cpp:21:17:21:22 | source | BarrierGuard.cpp:25:10:25:15 | source |
|
||||||
|
| BarrierGuard.cpp:29:16:29:21 | source | BarrierGuard.cpp:31:10:31:15 | source |
|
||||||
|
| BarrierGuard.cpp:29:16:29:21 | source | BarrierGuard.cpp:33:10:33:15 | source |
|
||||||
|
| BarrierGuard.cpp:49:10:49:15 | call to source | BarrierGuard.cpp:53:13:53:13 | x |
|
||||||
|
| BarrierGuard.cpp:49:10:49:15 | call to source | BarrierGuard.cpp:55:13:55:13 | x |
|
||||||
|
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:64:14:64:14 | x |
|
||||||
|
| BarrierGuard.cpp:60:11:60:16 | call to source | BarrierGuard.cpp:66:14:66:14 | x |
|
||||||
|
| acrossLinkTargets.cpp:19:27:19:32 | call to source | acrossLinkTargets.cpp:12:8:12:8 | x |
|
||||||
|
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:18:8:18:19 | sourceArray1 |
|
||||||
|
| clang.cpp:12:9:12:20 | sourceArray1 | clang.cpp:23:17:23:29 | & ... indirection |
|
||||||
|
| clang.cpp:29:27:29:32 | call to source | clang.cpp:30:27:30:28 | m1 |
|
||||||
|
| clang.cpp:29:27:29:32 | call to source | clang.cpp:31:27:31:34 | call to getFirst |
|
||||||
|
| clang.cpp:35:32:35:37 | call to source | clang.cpp:38:10:38:11 | m2 |
|
||||||
|
| clang.cpp:40:42:40:47 | call to source | clang.cpp:42:18:42:19 | m2 |
|
||||||
|
| clang.cpp:44:35:44:40 | call to source | clang.cpp:46:17:46:18 | m2 |
|
||||||
|
| clang.cpp:50:7:50:16 | definition of stackArray | clang.cpp:52:8:52:17 | stackArray |
|
||||||
|
| clang.cpp:50:25:50:30 | call to source | clang.cpp:53:17:53:26 | stackArray indirection |
|
||||||
|
| clang.cpp:50:35:50:40 | call to source | clang.cpp:53:17:53:26 | stackArray indirection |
|
||||||
|
| clang.cpp:51:19:51:24 | call to source | clang.cpp:53:17:53:26 | stackArray indirection |
|
||||||
|
| dispatch.cpp:9:37:9:42 | call to source | dispatch.cpp:35:16:35:25 | call to notSource1 |
|
||||||
|
| dispatch.cpp:9:37:9:42 | call to source | dispatch.cpp:43:15:43:24 | call to notSource1 |
|
||||||
|
| dispatch.cpp:10:37:10:42 | call to source | dispatch.cpp:36:16:36:25 | call to notSource2 |
|
||||||
|
| dispatch.cpp:10:37:10:42 | call to source | dispatch.cpp:44:15:44:24 | call to notSource2 |
|
||||||
|
| dispatch.cpp:16:37:16:42 | call to source | dispatch.cpp:32:16:32:24 | call to isSource2 |
|
||||||
|
| dispatch.cpp:16:37:16:42 | call to source | dispatch.cpp:40:15:40:23 | call to isSource2 |
|
||||||
|
| dispatch.cpp:22:37:22:42 | call to source | dispatch.cpp:31:16:31:24 | call to isSource1 |
|
||||||
|
| dispatch.cpp:22:37:22:42 | call to source | dispatch.cpp:39:15:39:23 | call to isSource1 |
|
||||||
|
| dispatch.cpp:22:37:22:42 | call to source | dispatch.cpp:55:22:55:30 | call to isSource1 |
|
||||||
|
| dispatch.cpp:22:37:22:42 | call to source | dispatch.cpp:58:28:58:36 | call to isSource1 |
|
||||||
|
| dispatch.cpp:33:18:33:23 | call to source | dispatch.cpp:23:38:23:38 | x |
|
||||||
|
| dispatch.cpp:37:19:37:24 | call to source | dispatch.cpp:11:38:11:38 | x |
|
||||||
|
| dispatch.cpp:41:17:41:22 | call to source | dispatch.cpp:23:38:23:38 | x |
|
||||||
|
| dispatch.cpp:45:18:45:23 | call to source | dispatch.cpp:11:38:11:38 | x |
|
||||||
|
| dispatch.cpp:69:15:69:20 | call to source | dispatch.cpp:23:38:23:38 | x |
|
||||||
|
| dispatch.cpp:73:14:73:19 | call to source | dispatch.cpp:23:38:23:38 | x |
|
||||||
|
| dispatch.cpp:81:13:81:18 | call to source | dispatch.cpp:23:38:23:38 | x |
|
||||||
|
| dispatch.cpp:107:17:107:22 | call to source | dispatch.cpp:96:8:96:8 | x |
|
||||||
|
| dispatch.cpp:140:8:140:13 | call to source | dispatch.cpp:96:8:96:8 | x |
|
||||||
|
| dispatch.cpp:144:8:144:13 | call to source | dispatch.cpp:96:8:96:8 | x |
|
||||||
|
| flowOut.cpp:5:16:5:21 | call to source | flowOut.cpp:19:9:19:9 | x |
|
||||||
|
| globals.cpp:5:17:5:22 | call to source | globals.cpp:6:10:6:14 | local |
|
||||||
|
| globals.cpp:13:23:13:28 | call to source | globals.cpp:12:10:12:24 | flowTestGlobal1 |
|
||||||
|
| globals.cpp:23:23:23:28 | call to source | globals.cpp:19:10:19:24 | flowTestGlobal2 |
|
||||||
|
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:14:8:14:8 | t |
|
||||||
|
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:18:8:18:8 | call to operator() |
|
||||||
|
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:21:8:21:8 | t |
|
||||||
|
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:29:8:29:8 | t |
|
||||||
|
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:35:8:35:8 | a |
|
||||||
|
| lambdas.cpp:8:10:8:15 | call to source | lambdas.cpp:41:8:41:8 | a |
|
||||||
|
| lambdas.cpp:43:7:43:12 | call to source | lambdas.cpp:46:7:46:7 | w |
|
||||||
|
| ref.cpp:29:11:29:16 | call to source | ref.cpp:62:10:62:11 | x3 |
|
||||||
|
| ref.cpp:53:9:53:10 | definition of x1 | ref.cpp:56:10:56:11 | x1 |
|
||||||
|
| ref.cpp:53:13:53:14 | definition of x2 | ref.cpp:59:10:59:11 | x2 |
|
||||||
|
| ref.cpp:53:17:53:18 | definition of x3 | ref.cpp:62:10:62:11 | x3 |
|
||||||
|
| ref.cpp:53:21:53:22 | definition of x4 | ref.cpp:65:10:65:11 | x4 |
|
||||||
|
| ref.cpp:55:23:55:28 | call to source | ref.cpp:56:10:56:11 | x1 |
|
||||||
|
| ref.cpp:94:15:94:20 | call to source | ref.cpp:129:13:129:15 | val |
|
||||||
|
| ref.cpp:109:15:109:20 | call to source | ref.cpp:132:13:132:15 | val |
|
||||||
|
| ref.cpp:122:23:122:28 | call to source | ref.cpp:123:13:123:15 | val |
|
||||||
|
| ref.cpp:125:19:125:24 | call to source | ref.cpp:126:13:126:15 | val |
|
||||||
|
| self-Iterator.cpp:19:23:19:30 | call to source | self-Iterator.cpp:20:10:20:10 | x |
|
||||||
|
| test.cpp:6:12:6:17 | call to source | test.cpp:7:8:7:9 | t1 |
|
||||||
|
| test.cpp:6:12:6:17 | call to source | test.cpp:9:8:9:9 | t1 |
|
||||||
|
| test.cpp:6:12:6:17 | call to source | test.cpp:10:8:10:9 | t2 |
|
||||||
|
| test.cpp:6:12:6:17 | call to source | test.cpp:15:8:15:9 | t2 |
|
||||||
|
| test.cpp:6:12:6:17 | call to source | test.cpp:26:8:26:9 | t1 |
|
||||||
|
| test.cpp:35:10:35:15 | call to source | test.cpp:30:8:30:8 | t |
|
||||||
|
| test.cpp:36:13:36:18 | call to source | test.cpp:31:8:31:8 | c |
|
||||||
|
| test.cpp:50:14:50:19 | call to source | test.cpp:58:10:58:10 | t |
|
||||||
|
| test.cpp:66:30:66:36 | source1 | test.cpp:71:8:71:9 | x4 |
|
||||||
|
| test.cpp:75:7:75:8 | definition of u1 | test.cpp:76:8:76:9 | u1 |
|
||||||
|
| test.cpp:83:7:83:8 | definition of u2 | test.cpp:84:8:84:18 | ... ? ... : ... |
|
||||||
|
| test.cpp:83:7:83:8 | definition of u2 | test.cpp:86:8:86:9 | i1 |
|
||||||
|
| test.cpp:89:28:89:34 | source1 indirection | test.cpp:90:8:90:14 | source1 |
|
||||||
|
| test.cpp:100:13:100:18 | call to source | test.cpp:103:10:103:12 | ref |
|
||||||
|
| test.cpp:138:27:138:32 | call to source | test.cpp:140:8:140:8 | y |
|
||||||
|
| test.cpp:151:33:151:38 | call to source | test.cpp:144:8:144:8 | s |
|
||||||
|
| test.cpp:151:33:151:38 | call to source | test.cpp:152:8:152:8 | y |
|
||||||
|
| test.cpp:164:34:164:39 | call to source | test.cpp:157:8:157:8 | x |
|
||||||
|
| test.cpp:164:34:164:39 | call to source | test.cpp:165:8:165:8 | y |
|
||||||
|
| test.cpp:171:11:171:16 | call to source | test.cpp:178:8:178:8 | y |
|
||||||
|
| test.cpp:245:14:245:19 | call to source | test.cpp:260:12:260:12 | x |
|
||||||
|
| test.cpp:265:22:265:27 | call to source | test.cpp:266:12:266:12 | x |
|
||||||
|
| test.cpp:305:17:305:22 | call to source | test.cpp:289:14:289:14 | x |
|
||||||
|
| test.cpp:314:4:314:9 | call to source | test.cpp:318:7:318:7 | x |
|
||||||
|
| test.cpp:333:17:333:22 | call to source | test.cpp:337:10:337:18 | globalVar |
|
||||||
|
| test.cpp:333:17:333:22 | call to source | test.cpp:339:10:339:18 | globalVar |
|
||||||
|
| test.cpp:333:17:333:22 | call to source | test.cpp:343:10:343:18 | globalVar |
|
||||||
|
| test.cpp:333:17:333:22 | call to source | test.cpp:349:10:349:18 | globalVar |
|
||||||
|
| test.cpp:347:17:347:22 | call to source | test.cpp:337:10:337:18 | globalVar |
|
||||||
|
| test.cpp:347:17:347:22 | call to source | test.cpp:339:10:339:18 | globalVar |
|
||||||
|
| test.cpp:347:17:347:22 | call to source | test.cpp:343:10:343:18 | globalVar |
|
||||||
|
| test.cpp:347:17:347:22 | call to source | test.cpp:349:10:349:18 | globalVar |
|
||||||
|
| test.cpp:359:13:359:18 | call to source | test.cpp:365:10:365:14 | field |
|
||||||
|
| test.cpp:373:13:373:18 | call to source | test.cpp:369:10:369:14 | field |
|
||||||
|
| test.cpp:373:13:373:18 | call to source | test.cpp:375:10:375:14 | field |
|
||||||
|
| test.cpp:382:48:382:54 | source1 | test.cpp:385:8:385:10 | tmp |
|
||||||
|
| test.cpp:388:53:388:59 | source1 | test.cpp:392:8:392:10 | tmp |
|
||||||
|
| test.cpp:388:53:388:59 | source1 | test.cpp:394:10:394:12 | tmp |
|
||||||
|
| test.cpp:399:7:399:9 | definition of tmp | test.cpp:401:8:401:10 | tmp |
|
||||||
|
| test.cpp:405:7:405:9 | definition of tmp | test.cpp:408:8:408:10 | tmp |
|
||||||
|
| test.cpp:416:7:416:11 | definition of local | test.cpp:418:8:418:12 | local |
|
||||||
|
| test.cpp:417:16:417:20 | intRefSource output argument | test.cpp:418:8:418:12 | local |
|
||||||
|
| test.cpp:422:7:422:11 | definition of local | test.cpp:424:8:424:12 | local |
|
||||||
|
| test.cpp:423:20:423:25 | intPointerSource output argument | test.cpp:424:8:424:12 | local |
|
||||||
|
| test.cpp:433:7:433:11 | definition of local | test.cpp:435:8:435:12 | local |
|
||||||
|
| test.cpp:434:20:434:24 | intPointerSource output argument | test.cpp:436:8:436:13 | * ... |
|
||||||
|
| test.cpp:440:7:440:11 | definition of local | test.cpp:442:8:442:12 | local |
|
||||||
|
| test.cpp:441:18:441:23 | intArraySource output argument | test.cpp:442:8:442:12 | local |
|
||||||
|
| test.cpp:448:7:448:11 | definition of local | test.cpp:450:8:450:12 | local |
|
||||||
|
| test.cpp:449:18:449:22 | intArraySource output argument | test.cpp:451:8:451:13 | * ... |
|
||||||
|
| test.cpp:456:26:456:32 | source1 | test.cpp:457:9:457:22 | (statement expression) |
|
||||||
|
| test.cpp:456:26:456:32 | source1 | test.cpp:468:8:468:12 | local |
|
||||||
|
| test.cpp:472:8:472:13 | call to source | test.cpp:478:8:478:8 | x |
|
||||||
|
| test.cpp:506:8:506:13 | call to source | test.cpp:513:8:513:8 | x |
|
||||||
|
| test.cpp:519:19:519:24 | call to source | test.cpp:521:8:521:20 | access to array |
|
||||||
|
| test.cpp:531:29:531:34 | call to source | test.cpp:532:8:532:9 | * ... |
|
||||||
|
| test.cpp:547:9:547:9 | definition of x | test.cpp:536:10:536:11 | * ... |
|
||||||
|
| test.cpp:551:9:551:9 | definition of y | test.cpp:541:10:541:10 | y |
|
||||||
|
| test.cpp:562:17:562:31 | call to indirect_source indirection | test.cpp:566:10:566:19 | * ... |
|
||||||
|
| test.cpp:562:17:562:31 | call to indirect_source indirection | test.cpp:568:10:568:19 | * ... |
|
||||||
|
| test.cpp:562:17:562:31 | call to indirect_source indirection | test.cpp:572:10:572:19 | * ... |
|
||||||
|
| test.cpp:562:17:562:31 | call to indirect_source indirection | test.cpp:578:10:578:19 | * ... |
|
||||||
|
| test.cpp:576:17:576:31 | call to indirect_source indirection | test.cpp:566:10:566:19 | * ... |
|
||||||
|
| test.cpp:576:17:576:31 | call to indirect_source indirection | test.cpp:568:10:568:19 | * ... |
|
||||||
|
| test.cpp:576:17:576:31 | call to indirect_source indirection | test.cpp:572:10:572:19 | * ... |
|
||||||
|
| test.cpp:576:17:576:31 | call to indirect_source indirection | test.cpp:578:10:578:19 | * ... |
|
||||||
|
| test.cpp:594:12:594:26 | call to indirect_source indirection | test.cpp:597:8:597:13 | * ... |
|
||||||
|
| test.cpp:601:20:601:20 | intPointerSource output argument | test.cpp:603:8:603:9 | * ... |
|
||||||
|
| test.cpp:607:20:607:20 | intPointerSource output argument | test.cpp:609:8:609:9 | * ... |
|
||||||
|
| test.cpp:614:20:614:20 | intPointerSource output argument | test.cpp:616:8:616:17 | * ... |
|
||||||
|
| test.cpp:628:20:628:25 | intPointerSource output argument | test.cpp:629:17:629:22 | buffer indirection |
|
||||||
|
| test.cpp:633:18:633:23 | call to source | test.cpp:634:8:634:8 | x |
|
||||||
|
| test.cpp:646:7:646:12 | call to source | test.cpp:645:8:645:8 | x |
|
||||||
|
| test.cpp:660:7:660:12 | call to source | test.cpp:658:8:658:8 | x |
|
||||||
|
| test.cpp:664:18:664:23 | call to source | test.cpp:666:8:666:16 | * ... |
|
||||||
|
| test.cpp:681:7:681:12 | call to source | test.cpp:679:8:679:16 | * ... |
|
||||||
|
| test.cpp:733:7:733:7 | definition of x | test.cpp:735:8:735:8 | x |
|
||||||
|
| test.cpp:751:27:751:32 | call to source | test.cpp:740:10:740:10 | x |
|
||||||
|
| test.cpp:753:32:753:37 | call to source | test.cpp:740:10:740:10 | x |
|
||||||
|
| test.cpp:755:32:755:37 | call to source | test.cpp:740:10:740:10 | x |
|
||||||
|
| test.cpp:771:27:771:32 | call to source | test.cpp:760:10:760:10 | x |
|
||||||
|
| test.cpp:773:32:773:37 | call to source | test.cpp:760:10:760:10 | x |
|
||||||
|
| test.cpp:775:32:775:37 | call to source | test.cpp:760:10:760:10 | x |
|
||||||
|
| test.cpp:788:31:788:36 | call to source | test.cpp:782:12:782:12 | x |
|
||||||
|
| test.cpp:790:31:790:36 | call to source | test.cpp:782:12:782:12 | x |
|
||||||
|
| test.cpp:797:22:797:28 | intPointerSource output argument | test.cpp:798:19:798:25 | content indirection |
|
||||||
|
| test.cpp:808:25:808:39 | call to indirect_source indirection | test.cpp:813:19:813:35 | * ... indirection |
|
||||||
|
| test.cpp:818:26:818:31 | call to source | test.cpp:823:10:823:27 | * ... |
|
||||||
|
| test.cpp:832:21:832:26 | call to source | test.cpp:836:10:836:22 | global_direct |
|
||||||
|
| test.cpp:842:11:842:16 | call to source | test.cpp:844:8:844:8 | y |
|
||||||
|
| test.cpp:846:13:846:27 | call to indirect_source indirection | test.cpp:848:17:848:25 | rpx indirection |
|
||||||
|
| test.cpp:853:55:853:62 | call to source | test.cpp:854:10:854:36 | * ... |
|
||||||
|
| test.cpp:860:54:860:59 | call to source | test.cpp:861:10:861:37 | static_local_pointer_dynamic |
|
||||||
|
| test.cpp:872:46:872:51 | call to source | test.cpp:875:10:875:31 | global_pointer_dynamic |
|
||||||
|
| test.cpp:880:64:880:83 | indirect_source(1) indirection | test.cpp:883:10:883:45 | static_local_array_static_indirect_1 |
|
||||||
|
| test.cpp:881:64:881:83 | indirect_source(2) indirection | test.cpp:886:19:886:54 | static_local_array_static_indirect_2 indirection |
|
||||||
|
| test.cpp:890:54:890:61 | source | test.cpp:893:10:893:36 | static_local_pointer_static |
|
||||||
|
| test.cpp:891:65:891:84 | indirect_source(1) indirection | test.cpp:895:19:895:56 | static_local_pointer_static_indirect_1 indirection |
|
||||||
|
| test.cpp:901:56:901:75 | indirect_source(1) indirection | test.cpp:907:10:907:39 | global_array_static_indirect_1 |
|
||||||
|
| test.cpp:902:56:902:75 | indirect_source(2) indirection | test.cpp:911:19:911:48 | global_array_static_indirect_2 indirection |
|
||||||
|
| test.cpp:914:46:914:53 | source | test.cpp:919:10:919:30 | global_pointer_static |
|
||||||
|
| test.cpp:915:57:915:76 | indirect_source(1) indirection | test.cpp:921:19:921:50 | global_pointer_static_indirect_1 indirection |
|
||||||
|
| true_upon_entry.cpp:9:11:9:16 | call to source | true_upon_entry.cpp:13:8:13:8 | x |
|
||||||
|
| true_upon_entry.cpp:17:11:17:16 | call to source | true_upon_entry.cpp:21:8:21:8 | x |
|
||||||
|
| true_upon_entry.cpp:27:9:27:14 | call to source | true_upon_entry.cpp:29:8:29:8 | x |
|
||||||
|
| true_upon_entry.cpp:33:11:33:16 | call to source | true_upon_entry.cpp:39:8:39:8 | x |
|
||||||
|
| true_upon_entry.cpp:43:11:43:16 | call to source | true_upon_entry.cpp:49:8:49:8 | x |
|
||||||
|
| true_upon_entry.cpp:54:11:54:16 | call to source | true_upon_entry.cpp:57:8:57:8 | x |
|
||||||
|
| true_upon_entry.cpp:62:11:62:16 | call to source | true_upon_entry.cpp:66:8:66:8 | x |
|
||||||
|
| true_upon_entry.cpp:70:11:70:16 | call to source | true_upon_entry.cpp:78:8:78:8 | x |
|
||||||
|
| true_upon_entry.cpp:83:11:83:16 | call to source | true_upon_entry.cpp:86:8:86:8 | x |
|
||||||
|
| true_upon_entry.cpp:98:11:98:16 | call to source | true_upon_entry.cpp:105:8:105:8 | x |
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import TestBase
|
||||||
|
|
||||||
|
query predicate astFlow(AstTest::DataFlow::Node source, AstTest::DataFlow::Node sink) {
|
||||||
|
AstTest::AstFlow::flow(source, sink)
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate irFlow(IRTest::DataFlow::Node source, IRTest::DataFlow::Node sink) {
|
||||||
|
IRTest::IRFlow::flow(source, sink)
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user