mirror of
https://github.com/github/codeql.git
synced 2026-05-17 04:37:07 +02:00
Compare commits
1222 Commits
codeql-cli
...
codeql-cli
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a971ba161 | ||
|
|
280890c556 | ||
|
|
f348b6cbf7 | ||
|
|
3d8c402b6f | ||
|
|
0db6379602 | ||
|
|
cf1f290b61 | ||
|
|
0f44cd3f62 | ||
|
|
92910f961a | ||
|
|
7cb67a50be | ||
|
|
a832730a11 | ||
|
|
ab88b9b136 | ||
|
|
8fc3b00fb9 | ||
|
|
e7f788ae35 | ||
|
|
4e6d7fcb29 | ||
|
|
d8a2c08f12 | ||
|
|
59bb142e8b | ||
|
|
ec59492866 | ||
|
|
fa07f16bcc | ||
|
|
b3326babba | ||
|
|
c33568b602 | ||
|
|
437df5c2a5 | ||
|
|
a6e3b913d0 | ||
|
|
686f47af98 | ||
|
|
b6f1024114 | ||
|
|
ea6092ad3f | ||
|
|
28c333a327 | ||
|
|
ecb1428198 | ||
|
|
c4d37ebec7 | ||
|
|
17cd9624fb | ||
|
|
2f3ebfb81f | ||
|
|
c2fa721966 | ||
|
|
6fdff977e5 | ||
|
|
2aa3e1f7a2 | ||
|
|
210ea5be79 | ||
|
|
7ae52425ce | ||
|
|
318a376a78 | ||
|
|
15989ce213 | ||
|
|
771992ca9f | ||
|
|
a1a6fe45f1 | ||
|
|
88cd77e459 | ||
|
|
b91ad04e6a | ||
|
|
b6255571d8 | ||
|
|
68dfca49f5 | ||
|
|
e4ce003e87 | ||
|
|
0eddaa0664 | ||
|
|
9f00a0060d | ||
|
|
cf3b3d75d0 | ||
|
|
8a7e378b40 | ||
|
|
f0f535b0e4 | ||
|
|
257436a49d | ||
|
|
47974914a5 | ||
|
|
ed36aaa570 | ||
|
|
69679dec1d | ||
|
|
69f02293f5 | ||
|
|
65a6fa7bc3 | ||
|
|
6103749188 | ||
|
|
f0fe3a3388 | ||
|
|
b14c58445a | ||
|
|
b001c24dfc | ||
|
|
06f73e76b8 | ||
|
|
e066c52ac6 | ||
|
|
73674e72e6 | ||
|
|
658326d7f2 | ||
|
|
8b4e060934 | ||
|
|
30f8d6e4ff | ||
|
|
993bfee096 | ||
|
|
07a5c20309 | ||
|
|
a0dc20caef | ||
|
|
f0327732ef | ||
|
|
0037ad406d | ||
|
|
ff242dc6cf | ||
|
|
38f4f4c724 | ||
|
|
79bd81fa12 | ||
|
|
932c07a0f4 | ||
|
|
e73fc94354 | ||
|
|
8470e91c16 | ||
|
|
4afdb0927e | ||
|
|
0361b5c342 | ||
|
|
bb1cf4f51f | ||
|
|
e3ffbbe3b7 | ||
|
|
442026cc9d | ||
|
|
2629e09b67 | ||
|
|
a308bdb75d | ||
|
|
4c5c6c6968 | ||
|
|
5e8185ac4f | ||
|
|
704cd8aee3 | ||
|
|
fc38476e42 | ||
|
|
f89174a6f3 | ||
|
|
0f7ad98a23 | ||
|
|
eb8c785c6b | ||
|
|
3f640a99d3 | ||
|
|
383e27c2bd | ||
|
|
80e03c3c51 | ||
|
|
27522a2781 | ||
|
|
9d7314febb | ||
|
|
35ff4d69b7 | ||
|
|
8b6c293b5c | ||
|
|
33f87c0c46 | ||
|
|
ccd90f25ba | ||
|
|
c2aff1ea97 | ||
|
|
3be219c79d | ||
|
|
ed7f3305d9 | ||
|
|
dc0832c3d8 | ||
|
|
a25d9c7397 | ||
|
|
2933a3be9c | ||
|
|
675e920667 | ||
|
|
1faad979ad | ||
|
|
ec9f533325 | ||
|
|
1665badc83 | ||
|
|
1959e1929e | ||
|
|
9279bebf07 | ||
|
|
f9bc97b2a1 | ||
|
|
b001f47c17 | ||
|
|
9c0bdbb20a | ||
|
|
e3b9b0a9bd | ||
|
|
f4764378c9 | ||
|
|
5504799d44 | ||
|
|
d88b310b0e | ||
|
|
3a9610795b | ||
|
|
7a7ab457a9 | ||
|
|
9ee7599aeb | ||
|
|
699d3a0a0a | ||
|
|
07800ea7ef | ||
|
|
5548304432 | ||
|
|
2d2afb17ad | ||
|
|
ec9d88b364 | ||
|
|
86e9f15929 | ||
|
|
ced000ae46 | ||
|
|
652dd88c36 | ||
|
|
c7859ecebf | ||
|
|
501bb3eb56 | ||
|
|
ad213579a1 | ||
|
|
e1bdc7f5a7 | ||
|
|
3eb5b2669b | ||
|
|
3b2b7d7d1c | ||
|
|
ba310417a8 | ||
|
|
7ad63fc3e6 | ||
|
|
db559f75b6 | ||
|
|
ce0cb12c29 | ||
|
|
06f86dd22f | ||
|
|
0acb29d3dd | ||
|
|
f7d8c210e5 | ||
|
|
d6af999c2d | ||
|
|
467256d465 | ||
|
|
2d264052b3 | ||
|
|
25fc5f3803 | ||
|
|
c3d8efc43d | ||
|
|
ae013ba01a | ||
|
|
51c43a7440 | ||
|
|
86708c9ff8 | ||
|
|
0b56bf98f3 | ||
|
|
fb7b89f309 | ||
|
|
7a446231b6 | ||
|
|
e77c3dfda1 | ||
|
|
78770bcd1b | ||
|
|
1e7eae58f4 | ||
|
|
ebafe65ac2 | ||
|
|
43b61dd2aa | ||
|
|
fee38b3781 | ||
|
|
1e12c11adc | ||
|
|
7395223410 | ||
|
|
157d0b7f37 | ||
|
|
7d61d9282c | ||
|
|
fcb2b5730f | ||
|
|
6f23e8dcf3 | ||
|
|
a85f8a2fbd | ||
|
|
f0de9f9276 | ||
|
|
3450e509fe | ||
|
|
2c591f5420 | ||
|
|
4b3cc5bd0e | ||
|
|
fb1dfd4217 | ||
|
|
beba032ba5 | ||
|
|
3cdc8d5eca | ||
|
|
b16dc20bbd | ||
|
|
4c0f31d77b | ||
|
|
b4a42de7f4 | ||
|
|
c1d03acd45 | ||
|
|
27e9cb5384 | ||
|
|
79dec723b0 | ||
|
|
c8d301ed43 | ||
|
|
d5f8adbfee | ||
|
|
0c525972a2 | ||
|
|
4b0427c732 | ||
|
|
35ec9db23a | ||
|
|
094c98db5e | ||
|
|
3425efe421 | ||
|
|
005ffd4f64 | ||
|
|
4e02e34fd5 | ||
|
|
eaf4f5eeab | ||
|
|
f0817dc07c | ||
|
|
046018fa25 | ||
|
|
6f79480b40 | ||
|
|
86ab941acd | ||
|
|
5f74ead99b | ||
|
|
5e8ac5ef0d | ||
|
|
05500568c9 | ||
|
|
c5343fb829 | ||
|
|
97f9340a0a | ||
|
|
ddbca5aee9 | ||
|
|
a782952969 | ||
|
|
3395dc9e71 | ||
|
|
aeabee3e34 | ||
|
|
51077ce2e7 | ||
|
|
69b581cc4d | ||
|
|
c9aaba677d | ||
|
|
0fcfb47423 | ||
|
|
f83df76928 | ||
|
|
d5a0df3f87 | ||
|
|
8646643f0e | ||
|
|
446c992181 | ||
|
|
897bfb5517 | ||
|
|
fbcb4498fe | ||
|
|
6dd52e45e4 | ||
|
|
345e1840f2 | ||
|
|
0dfdee775b | ||
|
|
c98110306b | ||
|
|
6b6e773ce1 | ||
|
|
e6873cfb2e | ||
|
|
8bc9e497eb | ||
|
|
d08713f66c | ||
|
|
75aa439132 | ||
|
|
757fdf567d | ||
|
|
bfaafcf88c | ||
|
|
3d5d270dfb | ||
|
|
089999dd3c | ||
|
|
4a5c9f0ec4 | ||
|
|
3c6459e65a | ||
|
|
f28f42bcba | ||
|
|
c514d36d90 | ||
|
|
5248c8e3a2 | ||
|
|
f0bc55e8d7 | ||
|
|
36e32f43ef | ||
|
|
5b5d8fe04d | ||
|
|
ae51668147 | ||
|
|
fa3b65fc4e | ||
|
|
63d07a933a | ||
|
|
600c84505f | ||
|
|
30dc2289a3 | ||
|
|
1bcac50db1 | ||
|
|
29c204bc61 | ||
|
|
1df81dbfb6 | ||
|
|
2fe74a8554 | ||
|
|
49f3959405 | ||
|
|
3a285f500e | ||
|
|
a5a999f7d6 | ||
|
|
f851f2120f | ||
|
|
8b51f9865d | ||
|
|
974868cf9c | ||
|
|
0b60bfecd1 | ||
|
|
d82f66cc63 | ||
|
|
d97f6572c2 | ||
|
|
6f5a045437 | ||
|
|
00efebe8b0 | ||
|
|
1689e60445 | ||
|
|
cdf067703b | ||
|
|
ae96111848 | ||
|
|
4de0d10dce | ||
|
|
267ee3dce9 | ||
|
|
32958e9625 | ||
|
|
d066faf212 | ||
|
|
5ef37c4501 | ||
|
|
8536e7eb02 | ||
|
|
fa472f5e18 | ||
|
|
d240951da0 | ||
|
|
ffd811a55d | ||
|
|
84f3b7322e | ||
|
|
2109bba928 | ||
|
|
9ce8018093 | ||
|
|
c0a69f197d | ||
|
|
cc6d87c276 | ||
|
|
448da89519 | ||
|
|
2310bd94a4 | ||
|
|
55de3511b0 | ||
|
|
875d1d3be4 | ||
|
|
081b8759d4 | ||
|
|
de40dfdc17 | ||
|
|
2b0ff17884 | ||
|
|
41506fbfef | ||
|
|
718d46ed2f | ||
|
|
e5261f8bfc | ||
|
|
2d3d46e0e2 | ||
|
|
c1e242ecda | ||
|
|
ef21ee53a5 | ||
|
|
e451f2b343 | ||
|
|
b64cb4da09 | ||
|
|
16e19a6b04 | ||
|
|
a38b6abdbe | ||
|
|
58088b62df | ||
|
|
a1b3ea53f6 | ||
|
|
019da8c287 | ||
|
|
eea9df894a | ||
|
|
0263cc1609 | ||
|
|
46577b585e | ||
|
|
26444cb0cd | ||
|
|
67331fb810 | ||
|
|
59922e5c46 | ||
|
|
d9ff4ef567 | ||
|
|
c576a116f5 | ||
|
|
40282daeb5 | ||
|
|
b63bd2ad14 | ||
|
|
5fe3d17a26 | ||
|
|
42be9e98c8 | ||
|
|
2a2b371244 | ||
|
|
7388c6db24 | ||
|
|
139e09d5d3 | ||
|
|
bef4fe627d | ||
|
|
62c2fe6b17 | ||
|
|
d88b25c243 | ||
|
|
24df54804a | ||
|
|
b8187ed294 | ||
|
|
5f7f37f6c8 | ||
|
|
e5911c90d4 | ||
|
|
78cd3d8332 | ||
|
|
e222b49258 | ||
|
|
a5d671a1ca | ||
|
|
d704fd9682 | ||
|
|
b2d20f1fed | ||
|
|
1f37662e3b | ||
|
|
b4db86491d | ||
|
|
c88ed68766 | ||
|
|
46cf779062 | ||
|
|
bf66a787ab | ||
|
|
ffde68aaec | ||
|
|
def662d641 | ||
|
|
00d447ba4b | ||
|
|
01ff7e1f26 | ||
|
|
f0d1740ff8 | ||
|
|
c14ba0e4bd | ||
|
|
4489749ce4 | ||
|
|
14977a7917 | ||
|
|
572c773345 | ||
|
|
32b3924548 | ||
|
|
0f1b5327ef | ||
|
|
a7410e4a16 | ||
|
|
2377546240 | ||
|
|
4e013af530 | ||
|
|
d50898e114 | ||
|
|
e47d4ccb79 | ||
|
|
87c5627024 | ||
|
|
79740ed72b | ||
|
|
f08f17511e | ||
|
|
d42e424289 | ||
|
|
7e82986e7c | ||
|
|
a6e2fbb241 | ||
|
|
59572e5633 | ||
|
|
e88bf31270 | ||
|
|
aea13b46ce | ||
|
|
a4e357e46d | ||
|
|
ec9de41fea | ||
|
|
968c279fd7 | ||
|
|
a31d90897d | ||
|
|
6f23819f60 | ||
|
|
e4deb7d304 | ||
|
|
841f317cbd | ||
|
|
3721e346c6 | ||
|
|
fce183c7cb | ||
|
|
4eb6afa880 | ||
|
|
133a0914b5 | ||
|
|
6cb6aeffbb | ||
|
|
aec06c8100 | ||
|
|
4225774a3a | ||
|
|
95e504a5ff | ||
|
|
0f7598786c | ||
|
|
fe00dbc96c | ||
|
|
28702046aa | ||
|
|
bfae86e9e8 | ||
|
|
59db802fa4 | ||
|
|
ccec347b0a | ||
|
|
74596ef000 | ||
|
|
6273bb60a3 | ||
|
|
f5394c9ee9 | ||
|
|
4169cfac9f | ||
|
|
62046fa3a8 | ||
|
|
6596705811 | ||
|
|
f891423810 | ||
|
|
1ee87670c6 | ||
|
|
ee11307751 | ||
|
|
08bb794f76 | ||
|
|
9794309d2e | ||
|
|
6a49647a28 | ||
|
|
41373538d6 | ||
|
|
742922c719 | ||
|
|
9744c06933 | ||
|
|
12261e6d08 | ||
|
|
0525e9c6ee | ||
|
|
b87d832fcb | ||
|
|
49335e5b63 | ||
|
|
e66cd05f96 | ||
|
|
972d9ca2b8 | ||
|
|
fa898b8489 | ||
|
|
aae19ab9f5 | ||
|
|
927c65e8ed | ||
|
|
5a5fdb2f6b | ||
|
|
d3cdffef61 | ||
|
|
be945f14f6 | ||
|
|
4d023f14a6 | ||
|
|
c299d8ddc1 | ||
|
|
2c85511af1 | ||
|
|
4d75832c9a | ||
|
|
c8994003c1 | ||
|
|
a645e01b4b | ||
|
|
d52826879b | ||
|
|
ee9f134828 | ||
|
|
af43178602 | ||
|
|
1551cf0093 | ||
|
|
4dcf67940c | ||
|
|
354fcbe7fe | ||
|
|
39411b0780 | ||
|
|
e313fdb392 | ||
|
|
2486c8423b | ||
|
|
b95189d132 | ||
|
|
c23938d119 | ||
|
|
14763f3bb5 | ||
|
|
8e68e0dfba | ||
|
|
3f26250967 | ||
|
|
2b7b1c624d | ||
|
|
7bf61d1d7e | ||
|
|
683ca2d578 | ||
|
|
9167057dfd | ||
|
|
c75db669ed | ||
|
|
1a697fe993 | ||
|
|
3ccdce291a | ||
|
|
62adb31ca6 | ||
|
|
9d866192a6 | ||
|
|
e051815d96 | ||
|
|
8325c4c69c | ||
|
|
cbe54717f6 | ||
|
|
776c01aa8d | ||
|
|
90272ddbfa | ||
|
|
2ed2a76866 | ||
|
|
2fd4b57d74 | ||
|
|
9f6a5d9e13 | ||
|
|
61eb5cd55c | ||
|
|
0c3e8ced4b | ||
|
|
2543f3ecfb | ||
|
|
c8438c38f2 | ||
|
|
69c18f9cd2 | ||
|
|
b944d47f58 | ||
|
|
d5dc95f1e6 | ||
|
|
377301a55a | ||
|
|
97c9207595 | ||
|
|
251036c6b4 | ||
|
|
f9f57e9122 | ||
|
|
20672acb74 | ||
|
|
06a4f907ef | ||
|
|
6280ed2a6b | ||
|
|
c172b946a1 | ||
|
|
4aea4c0323 | ||
|
|
c04428dedc | ||
|
|
9724516c84 | ||
|
|
af06763c42 | ||
|
|
4fb29c4473 | ||
|
|
61eda0df9d | ||
|
|
05b0a3f41c | ||
|
|
fe575df325 | ||
|
|
4e62dc81d2 | ||
|
|
123dcc75d1 | ||
|
|
9bd00c9e1e | ||
|
|
2a6ad00a2f | ||
|
|
72e7b6c872 | ||
|
|
01c6dbaa27 | ||
|
|
8901b1fd14 | ||
|
|
59e22f6cd9 | ||
|
|
e4cd29efc6 | ||
|
|
d75da82528 | ||
|
|
f953249692 | ||
|
|
de47838c36 | ||
|
|
d560c1ea0f | ||
|
|
f8e8b362ab | ||
|
|
9110df6e80 | ||
|
|
c6814fcf47 | ||
|
|
701e3d7e53 | ||
|
|
3ece3ec50f | ||
|
|
1ce15ae2fd | ||
|
|
d0c2b4a60f | ||
|
|
bae0ea5599 | ||
|
|
fa6d61809e | ||
|
|
d04dc9afe0 | ||
|
|
f986484813 | ||
|
|
674a5bb9b4 | ||
|
|
2db07bdbf3 | ||
|
|
40eef25133 | ||
|
|
3d6a889d24 | ||
|
|
591b1b4f07 | ||
|
|
81f3609c4b | ||
|
|
dfc51922ba | ||
|
|
ef2b225144 | ||
|
|
1cb5f35c56 | ||
|
|
cd0af0fc57 | ||
|
|
050dcb1370 | ||
|
|
f796efe470 | ||
|
|
9741ddb926 | ||
|
|
31f68d2da8 | ||
|
|
2c8f3a58b3 | ||
|
|
44b6309e07 | ||
|
|
e259b25428 | ||
|
|
0704946324 | ||
|
|
bdff0fdcc5 | ||
|
|
0d71072f94 | ||
|
|
6d8a83fc1f | ||
|
|
0d469536ae | ||
|
|
ef0370b64e | ||
|
|
a8236e1545 | ||
|
|
ffeb86c1f5 | ||
|
|
5455a365d1 | ||
|
|
5073f4f7dd | ||
|
|
9662950405 | ||
|
|
8f52b2cd95 | ||
|
|
a781522ca0 | ||
|
|
bfd2e4350b | ||
|
|
afc0d0a078 | ||
|
|
5c8f21d596 | ||
|
|
94f290411f | ||
|
|
1347f55d89 | ||
|
|
42ee501b96 | ||
|
|
f932e515a7 | ||
|
|
68a972d578 | ||
|
|
6b37cb0718 | ||
|
|
da5250d3a7 | ||
|
|
8edf19adc0 | ||
|
|
ff788c93c0 | ||
|
|
9cb01d4573 | ||
|
|
d39609254c | ||
|
|
e68ef87662 | ||
|
|
82da8b95a7 | ||
|
|
f10d007496 | ||
|
|
c989e01197 | ||
|
|
41c3d1b833 | ||
|
|
4dc1a10f71 | ||
|
|
d66e407c3e | ||
|
|
e226da4f04 | ||
|
|
46b92f372b | ||
|
|
1cb58922a2 | ||
|
|
2396c3c798 | ||
|
|
1530037eae | ||
|
|
9dff666cb3 | ||
|
|
68512eea14 | ||
|
|
ef3bbeacd6 | ||
|
|
90e87a1752 | ||
|
|
c7f9095739 | ||
|
|
1127b08635 | ||
|
|
d997eee6e6 | ||
|
|
58689c90fb | ||
|
|
0a7772d8a7 | ||
|
|
d23d138e7d | ||
|
|
bab89c46b6 | ||
|
|
0a382bf0cf | ||
|
|
c70d39539e | ||
|
|
f307f272d5 | ||
|
|
6960c5232b | ||
|
|
c8749ff82e | ||
|
|
209fa1a10a | ||
|
|
0593eaad52 | ||
|
|
cc752113af | ||
|
|
7689db7d42 | ||
|
|
1b97804f45 | ||
|
|
96c142bf0a | ||
|
|
6538a06f29 | ||
|
|
b5e7716579 | ||
|
|
46ddddc8cf | ||
|
|
85b02b1399 | ||
|
|
494f0b709e | ||
|
|
14cf47b906 | ||
|
|
e3559d8f93 | ||
|
|
142d7ae005 | ||
|
|
e1329dff72 | ||
|
|
b6aea3cde1 | ||
|
|
d189526283 | ||
|
|
707acdef08 | ||
|
|
450137d2cf | ||
|
|
0ba5a74f6a | ||
|
|
a05266c236 | ||
|
|
ff9093f2de | ||
|
|
358a1b3a20 | ||
|
|
6d1c00742f | ||
|
|
221c18934c | ||
|
|
8eb3b31ee2 | ||
|
|
72e05c952e | ||
|
|
c0263bef5a | ||
|
|
6b68cf6bdc | ||
|
|
06a3bf8808 | ||
|
|
822f8b06f0 | ||
|
|
a944922c97 | ||
|
|
b34b589005 | ||
|
|
c051d33cc7 | ||
|
|
ebeb187fd9 | ||
|
|
52020f7e5b | ||
|
|
feb31d2006 | ||
|
|
91edf82c8a | ||
|
|
b640bdccdc | ||
|
|
52f8f04e9d | ||
|
|
1c1ba7734f | ||
|
|
91f5f086fb | ||
|
|
d2f5734ac5 | ||
|
|
9d6260b334 | ||
|
|
30abc958a8 | ||
|
|
eea3e82cca | ||
|
|
27314aac16 | ||
|
|
1aa63c3f2e | ||
|
|
9d75782c44 | ||
|
|
087b0dac1d | ||
|
|
9fb657c4c4 | ||
|
|
4d3377b116 | ||
|
|
3e7a60c1a6 | ||
|
|
c693f03462 | ||
|
|
245f43dd58 | ||
|
|
a6cb511ed7 | ||
|
|
f3069c8fbb | ||
|
|
78b66abad3 | ||
|
|
93c9910e6f | ||
|
|
f7d681516a | ||
|
|
225d2915e5 | ||
|
|
e4b9335ce0 | ||
|
|
099c282277 | ||
|
|
7a48fe1102 | ||
|
|
c5da43e691 | ||
|
|
34ad211900 | ||
|
|
032ae9e1e7 | ||
|
|
8e7e7c0188 | ||
|
|
9478139390 | ||
|
|
5a1adc51c1 | ||
|
|
a35be08d18 | ||
|
|
8f714c631f | ||
|
|
5a39610ba7 | ||
|
|
5854e88f63 | ||
|
|
d77d7c533b | ||
|
|
ecefa3e383 | ||
|
|
3f5b4a81cf | ||
|
|
44e33c7be7 | ||
|
|
d8cc92068a | ||
|
|
4a34dc125b | ||
|
|
b3bffb6826 | ||
|
|
7ec3162583 | ||
|
|
a5efe9fa09 | ||
|
|
90b25a6696 | ||
|
|
5e484e4006 | ||
|
|
b1bea31720 | ||
|
|
28cff2ea20 | ||
|
|
1de91b4cd5 | ||
|
|
ff60d9647f | ||
|
|
ec134927d8 | ||
|
|
9f79a39deb | ||
|
|
854a277ab5 | ||
|
|
b7542ee575 | ||
|
|
eaf2949857 | ||
|
|
741a3289a1 | ||
|
|
4cbc3349f6 | ||
|
|
acbca9c108 | ||
|
|
3edeb82d5b | ||
|
|
89f958105a | ||
|
|
1456012b54 | ||
|
|
4920039a00 | ||
|
|
a98fac0d7d | ||
|
|
6026f65f8b | ||
|
|
43df4a9393 | ||
|
|
c3f2faff76 | ||
|
|
a9f6b2110e | ||
|
|
4c8da54b64 | ||
|
|
67dac96e80 | ||
|
|
e467cc033e | ||
|
|
1ed5af1d6a | ||
|
|
db53be39fe | ||
|
|
37ceb0118a | ||
|
|
86c63dbedf | ||
|
|
e461691c85 | ||
|
|
5e6c9fb661 | ||
|
|
5a5c5d1012 | ||
|
|
29bda5a805 | ||
|
|
f598a0b607 | ||
|
|
db27fd934a | ||
|
|
c1bd892a13 | ||
|
|
4f80ae2190 | ||
|
|
092de640fe | ||
|
|
44271813a5 | ||
|
|
93f70b3ad9 | ||
|
|
b28d79960b | ||
|
|
be87eb50d4 | ||
|
|
a73d675e6e | ||
|
|
226e4eb8a5 | ||
|
|
df5569fda9 | ||
|
|
32fbe52f0f | ||
|
|
6a7bdaf284 | ||
|
|
033dd9f8a6 | ||
|
|
9ad6c8c5eb | ||
|
|
2df09f6194 | ||
|
|
6f7b2a2d20 | ||
|
|
ff8bb2b1f8 | ||
|
|
d2573310c6 | ||
|
|
b5b9c4d931 | ||
|
|
bb86a07a93 | ||
|
|
5912a17ab4 | ||
|
|
49cc8f8ff8 | ||
|
|
54ac18092d | ||
|
|
a5fe3f4d9c | ||
|
|
368bcb684a | ||
|
|
09f5e19c71 | ||
|
|
8038796207 | ||
|
|
23320b6e5e | ||
|
|
3defc8b5de | ||
|
|
437c679266 | ||
|
|
af562f15f3 | ||
|
|
e8718f9d2f | ||
|
|
7b03f3268f | ||
|
|
81ab2025a1 | ||
|
|
06a9599906 | ||
|
|
cda4339056 | ||
|
|
11f5663afc | ||
|
|
a0954f15c0 | ||
|
|
45e92cec6a | ||
|
|
2ad70cbee2 | ||
|
|
db9cd1f612 | ||
|
|
b1608d815b | ||
|
|
b4fa23d731 | ||
|
|
c256c87a7e | ||
|
|
281212a22c | ||
|
|
999fb07931 | ||
|
|
55935fc123 | ||
|
|
272e523323 | ||
|
|
8262330e4d | ||
|
|
b00e312569 | ||
|
|
f931dab14a | ||
|
|
ffc61ae1bb | ||
|
|
6d468c1bae | ||
|
|
4790656b79 | ||
|
|
2a5144d9d9 | ||
|
|
a64eafca2b | ||
|
|
38aac1f444 | ||
|
|
f83b70dbc2 | ||
|
|
d6d2a213e7 | ||
|
|
f3e5b55cc4 | ||
|
|
183b3fe6b0 | ||
|
|
1ca0de9067 | ||
|
|
68a21663d9 | ||
|
|
a63e70d173 | ||
|
|
24261b29d5 | ||
|
|
620582fc09 | ||
|
|
661a4126ac | ||
|
|
baf51334e4 | ||
|
|
2796597d1a | ||
|
|
ad4bca9975 | ||
|
|
0990a370c7 | ||
|
|
9713551448 | ||
|
|
4fa45bb81c | ||
|
|
62944ee473 | ||
|
|
3bd330423d | ||
|
|
9a66e66d66 | ||
|
|
4d943f8d94 | ||
|
|
7bb7d83b26 | ||
|
|
aef0a03ab6 | ||
|
|
9a729144e8 | ||
|
|
3a9ff64780 | ||
|
|
3badd61a56 | ||
|
|
0bf1ed1d96 | ||
|
|
ca4bd0c606 | ||
|
|
c9832df3c0 | ||
|
|
8fa575d79b | ||
|
|
94078e851c | ||
|
|
c1853e04f5 | ||
|
|
a717c30c02 | ||
|
|
cb0589dfb7 | ||
|
|
1abe0d0f6d | ||
|
|
fc17b905f0 | ||
|
|
e6c1ff573a | ||
|
|
afb6e412f0 | ||
|
|
0a2ed8302a | ||
|
|
1e4aadfbfd | ||
|
|
8bc883274f | ||
|
|
a9bf17ef49 | ||
|
|
ca42eac589 | ||
|
|
433137ada6 | ||
|
|
98319be3a7 | ||
|
|
7b8301ac7a | ||
|
|
1c8e0c453c | ||
|
|
45ba0c3319 | ||
|
|
7029de5989 | ||
|
|
8a3a3fa263 | ||
|
|
d5ccb2e396 | ||
|
|
784a07353e | ||
|
|
3641dfebff | ||
|
|
bf69c76829 | ||
|
|
d109b1e20d | ||
|
|
6b52cd4957 | ||
|
|
cfdd48711b | ||
|
|
abeca3d9f9 | ||
|
|
729069e3d9 | ||
|
|
c3169d258f | ||
|
|
5a00b5ec96 | ||
|
|
f33927457f | ||
|
|
a8a4a201bd | ||
|
|
5f70c44270 | ||
|
|
9dd43d8e6f | ||
|
|
dc32806f3f | ||
|
|
238c6ccb2e | ||
|
|
f67026f2ad | ||
|
|
4c3220ea9d | ||
|
|
4b2075bfb1 | ||
|
|
aa0749e4ba | ||
|
|
8a5a9418c7 | ||
|
|
e6c7e1a0bc | ||
|
|
f09010e79c | ||
|
|
12fe998a4e | ||
|
|
39f0288e09 | ||
|
|
e2356d9820 | ||
|
|
fc6b17ad64 | ||
|
|
dbe0fceea6 | ||
|
|
083b9b77c9 | ||
|
|
f90df85722 | ||
|
|
535b4ea986 | ||
|
|
873fd6646b | ||
|
|
034f2d4221 | ||
|
|
2da1de7b13 | ||
|
|
070d67816d | ||
|
|
8d93c3a852 | ||
|
|
e885f1f8c4 | ||
|
|
983bdb92a1 | ||
|
|
123214cb2b | ||
|
|
bf4a202cbd | ||
|
|
9504e0f119 | ||
|
|
8894fba17a | ||
|
|
950d70ffed | ||
|
|
8647f69720 | ||
|
|
0793c589f7 | ||
|
|
a73170df49 | ||
|
|
91dd99d7a6 | ||
|
|
06cc74f3aa | ||
|
|
adaeb01906 | ||
|
|
64ebfc6297 | ||
|
|
eb0bcdd9b2 | ||
|
|
777cc357ee | ||
|
|
f293b77bce | ||
|
|
4e916dedb1 | ||
|
|
510bfb911a | ||
|
|
3d88f08264 | ||
|
|
983acf23bc | ||
|
|
68e3be187a | ||
|
|
d539ce0a01 | ||
|
|
575fbd2578 | ||
|
|
f5ec2315d7 | ||
|
|
db6cd1877c | ||
|
|
0d0b69eee0 | ||
|
|
ca06589386 | ||
|
|
cafb1181a0 | ||
|
|
e469534b84 | ||
|
|
124567caa4 | ||
|
|
b3744ef230 | ||
|
|
061c187a8e | ||
|
|
ef833de123 | ||
|
|
06a2a40f50 | ||
|
|
7bfa4c1947 | ||
|
|
37d78249e7 | ||
|
|
2bfd65f145 | ||
|
|
b2f57b4b48 | ||
|
|
938f46b888 | ||
|
|
dc64a08467 | ||
|
|
12d6875cc4 | ||
|
|
e39e7656da | ||
|
|
0fb27fb6fc | ||
|
|
195c20cfd5 | ||
|
|
eefbb676e9 | ||
|
|
2dc63ef8d1 | ||
|
|
8f6d4be256 | ||
|
|
391816c9e7 | ||
|
|
b70a4c839c | ||
|
|
7f34dd1e0a | ||
|
|
cd82ada239 | ||
|
|
18cde3bd78 | ||
|
|
1c336985e0 | ||
|
|
29e9c05f26 | ||
|
|
da5abc8321 | ||
|
|
5da3fb5e05 | ||
|
|
a951718f2e | ||
|
|
8eba4a3e51 | ||
|
|
cd9b364e5a | ||
|
|
3efbee0d81 | ||
|
|
99ed3c2ac1 | ||
|
|
2ec64a9ca8 | ||
|
|
3fc598dbe9 | ||
|
|
5b38d51f62 | ||
|
|
3bd4a203bb | ||
|
|
7fc95b8eff | ||
|
|
dd1d5ecab4 | ||
|
|
bf506f8a9e | ||
|
|
71e1d63953 | ||
|
|
d8e2d355df | ||
|
|
8f7c690529 | ||
|
|
1d1c476674 | ||
|
|
9c98296ad2 | ||
|
|
1cb9f6370f | ||
|
|
059a1389c6 | ||
|
|
4e9a528df9 | ||
|
|
025aa77e79 | ||
|
|
8c106964ec | ||
|
|
3868b386f3 | ||
|
|
0165696a1e | ||
|
|
8ba48e801a | ||
|
|
dd3cc33298 | ||
|
|
c824aa4e45 | ||
|
|
a3b5d2a28d | ||
|
|
4fbf76008e | ||
|
|
b7a5252cb0 | ||
|
|
8dcef8223f | ||
|
|
5d657ba99a | ||
|
|
faf77d5526 | ||
|
|
b3b04b4e5b | ||
|
|
18d9310a61 | ||
|
|
772344dfa4 | ||
|
|
de5ec1fc01 | ||
|
|
efcd4e297e | ||
|
|
79980a98a2 | ||
|
|
11249e7182 | ||
|
|
db8a5306cf | ||
|
|
eed8b3e87b | ||
|
|
1de2943a9b | ||
|
|
9263977329 | ||
|
|
8a9f0bf433 | ||
|
|
c9af53f050 | ||
|
|
61df4d2f04 | ||
|
|
00d91dc6ba | ||
|
|
040f948e65 | ||
|
|
0839742daa | ||
|
|
354394d4c2 | ||
|
|
3f37fe6add | ||
|
|
f6627cc092 | ||
|
|
04f173d14e | ||
|
|
7a2b170da2 | ||
|
|
813f08ef57 | ||
|
|
5a41b2c5fb | ||
|
|
d689ab0916 | ||
|
|
6b497da15f | ||
|
|
ab9a6faaf3 | ||
|
|
77a8ba934c | ||
|
|
744a1a9b72 | ||
|
|
5cf05ec863 | ||
|
|
4a1497f367 | ||
|
|
1a2b4a30bb | ||
|
|
24914efcb8 | ||
|
|
13c25a494f | ||
|
|
bf47574796 | ||
|
|
5c97a5f667 | ||
|
|
a2a065c04e | ||
|
|
f5bfdbf5ef | ||
|
|
0459422a6c | ||
|
|
35bf990f23 | ||
|
|
9794269550 | ||
|
|
e5761d6524 | ||
|
|
f41d2a896c | ||
|
|
64513fb6c2 | ||
|
|
8012f3b2f7 | ||
|
|
8152ec7472 | ||
|
|
0b6714e06f | ||
|
|
c6fb50095b | ||
|
|
5ecde387af | ||
|
|
d5d0cf5d90 | ||
|
|
29df3cb5b3 | ||
|
|
311799c798 | ||
|
|
de9370ae95 | ||
|
|
5bdef38dd9 | ||
|
|
90641a5152 | ||
|
|
87d9218369 | ||
|
|
d71be8aeaf | ||
|
|
45b782554c | ||
|
|
412ad177c2 | ||
|
|
5e0ce7efc4 | ||
|
|
ed42c3cd6f | ||
|
|
16b142d332 | ||
|
|
a452eadb33 | ||
|
|
fd8cda36e5 | ||
|
|
48bf06f1aa | ||
|
|
0413e0e090 | ||
|
|
3417605b6d | ||
|
|
3f789bad60 | ||
|
|
2c7fbda2ec | ||
|
|
32acff76c2 | ||
|
|
b64ef84393 | ||
|
|
3e2ebf436c | ||
|
|
f6b9195a61 | ||
|
|
ab991af2a5 | ||
|
|
f650e3f72b | ||
|
|
01afa360d7 | ||
|
|
1e448d547d | ||
|
|
fde7d7b969 | ||
|
|
4193b7e591 | ||
|
|
57efb84b98 | ||
|
|
39b5dbfaf7 | ||
|
|
f18338259f | ||
|
|
0344381120 | ||
|
|
74384625f6 | ||
|
|
8979bac4d8 | ||
|
|
ccf56a21c2 | ||
|
|
7928d751d1 | ||
|
|
01ec7c22df | ||
|
|
dd4bce8e30 | ||
|
|
7a5838f1a2 | ||
|
|
e87d2fe922 | ||
|
|
0aab2aef3b | ||
|
|
dae2aeb7d3 | ||
|
|
81593ece5a | ||
|
|
86afd54a9b | ||
|
|
60d1dc8af8 | ||
|
|
6b3625e24e | ||
|
|
c1da2c1d2f | ||
|
|
a8b976b389 | ||
|
|
d41eae6fc3 | ||
|
|
48edb77300 | ||
|
|
6359388cea | ||
|
|
d4bfab4735 | ||
|
|
39ad4d4a89 | ||
|
|
2c5f007687 | ||
|
|
f87e680185 | ||
|
|
496e76c1c5 | ||
|
|
16660ab1df | ||
|
|
8df2e4952c | ||
|
|
a774aacfa8 | ||
|
|
9cfd06c761 | ||
|
|
68929d1f73 | ||
|
|
eec2aa82a6 | ||
|
|
962c73da16 | ||
|
|
80bd361607 | ||
|
|
b83147fa44 | ||
|
|
8241d0b7ef | ||
|
|
07a25a233d | ||
|
|
bb78536804 | ||
|
|
64432215a9 | ||
|
|
8526510783 | ||
|
|
d5d04f2f4c | ||
|
|
8818f63ca7 | ||
|
|
80af5b7725 | ||
|
|
4f0d725acd | ||
|
|
d52210d565 | ||
|
|
3c70583aa2 | ||
|
|
0288499801 | ||
|
|
ae3aba061b | ||
|
|
7ca57e114f | ||
|
|
bc61a58000 | ||
|
|
7387c565e4 | ||
|
|
7fc1e13672 | ||
|
|
0421ceff93 | ||
|
|
a30e7d2cfd | ||
|
|
5a3328b07a | ||
|
|
2aff2a7385 | ||
|
|
d896fdf9fa | ||
|
|
173cd13ded | ||
|
|
c003f265b0 | ||
|
|
002e1eb730 | ||
|
|
1fe14e26b1 | ||
|
|
e2a6358048 | ||
|
|
de5fc4e609 | ||
|
|
5347770608 | ||
|
|
0e6b2f0f53 | ||
|
|
8ccdc2518f | ||
|
|
a747ffca07 | ||
|
|
9c82966022 | ||
|
|
79919d3c58 | ||
|
|
5d898727c0 | ||
|
|
1343e4c9aa | ||
|
|
7abece46c7 | ||
|
|
4de43e1bfa | ||
|
|
f64743e91d | ||
|
|
4893785c68 | ||
|
|
5d58cf6208 | ||
|
|
fe1103d997 | ||
|
|
b954845318 | ||
|
|
6ef9dba2fb | ||
|
|
89f0705585 | ||
|
|
72b52cc814 | ||
|
|
d1e1037586 | ||
|
|
92e814b75e | ||
|
|
db525f5cee | ||
|
|
03ec184ee0 | ||
|
|
c4d72e5b4f | ||
|
|
cf8b2d55c5 | ||
|
|
8db7ece8d4 | ||
|
|
2c4bf13d05 | ||
|
|
c54dc49891 | ||
|
|
b185c67d4f | ||
|
|
e7c43b3fcc | ||
|
|
09c03d9a5f | ||
|
|
399d47d2cb | ||
|
|
5e1c67f5f1 | ||
|
|
0a32f9fed6 | ||
|
|
8d1113cdaf | ||
|
|
c5c4f08bea | ||
|
|
0b84329e8c | ||
|
|
1c8cf3cd2c | ||
|
|
ffa55b4bf8 | ||
|
|
ef8532982c | ||
|
|
72679c82a9 | ||
|
|
4953e7e7fa | ||
|
|
ea16f72c6f | ||
|
|
3260966e3b | ||
|
|
808af28618 | ||
|
|
7e5f2e2a48 | ||
|
|
e05f835683 | ||
|
|
5639ada3ed | ||
|
|
70494d339d | ||
|
|
a108b9c37d | ||
|
|
e2b37f97b0 | ||
|
|
7df59ffe6c | ||
|
|
d289fb414e | ||
|
|
73fc6bcdb1 | ||
|
|
b4d8c4889a | ||
|
|
c985c9adb3 | ||
|
|
1744a98017 | ||
|
|
ceda46e317 | ||
|
|
a1b0703690 | ||
|
|
a6833945c1 | ||
|
|
fc6fba8d06 | ||
|
|
d1d082982a | ||
|
|
d31711bd89 | ||
|
|
f1324a413a | ||
|
|
b360c8adb8 | ||
|
|
5a1877547f | ||
|
|
6ecd8b7ee8 | ||
|
|
b81d41ba7b | ||
|
|
fa8c457015 | ||
|
|
60aa711005 | ||
|
|
65fdb8ccce | ||
|
|
60b9d19d72 | ||
|
|
f22778960b | ||
|
|
6538d22d3f | ||
|
|
0901b3d0a6 | ||
|
|
8458bde51e | ||
|
|
9e25279cb8 | ||
|
|
162245fb9a | ||
|
|
059ef42f41 | ||
|
|
878867205e | ||
|
|
91db2b6c9c | ||
|
|
d0f735ac28 | ||
|
|
c404f00a9b | ||
|
|
79c0ed6074 | ||
|
|
5ced5c010c | ||
|
|
7704801e47 | ||
|
|
a0201e9c4f | ||
|
|
6b8080a5b3 | ||
|
|
d11f58f768 | ||
|
|
b71ba7c30f | ||
|
|
472cca9221 | ||
|
|
1728e5dfd5 | ||
|
|
1ecd72727d | ||
|
|
a07639f4f6 | ||
|
|
26f1b36736 | ||
|
|
252c9e9416 | ||
|
|
3a98edb60b | ||
|
|
d142f830da | ||
|
|
8a3cec4977 | ||
|
|
de96d3951d | ||
|
|
f4691b1919 | ||
|
|
81ef255a87 | ||
|
|
da9e1e61a4 | ||
|
|
51f3f15e42 | ||
|
|
d79a253c20 | ||
|
|
7380e29774 | ||
|
|
d994959720 | ||
|
|
81ec6861f9 | ||
|
|
f217de9623 | ||
|
|
6a46fb54c5 | ||
|
|
f017821062 | ||
|
|
d4203d9286 | ||
|
|
412472e9a4 | ||
|
|
240b4cd696 | ||
|
|
ceea475c45 | ||
|
|
7ee5655f31 | ||
|
|
975811ae59 | ||
|
|
43a140e62c | ||
|
|
7136763c37 | ||
|
|
465d64a810 | ||
|
|
29322f5ff0 | ||
|
|
f5d465f08a | ||
|
|
5a69bbf6b0 | ||
|
|
e4ffdb848e | ||
|
|
ee05ec0386 | ||
|
|
61a11c6512 | ||
|
|
71dfdfaa92 | ||
|
|
c2f96a1352 | ||
|
|
5d98ec33ab | ||
|
|
d77513579f | ||
|
|
2226f5126b | ||
|
|
4e365e242c | ||
|
|
20c087ce39 | ||
|
|
c299b5657a | ||
|
|
1860af075d | ||
|
|
1f13e462b1 | ||
|
|
06dea2d27f | ||
|
|
0d4cd3e103 | ||
|
|
65dfd4c860 | ||
|
|
68e21a594a | ||
|
|
bda794fde7 | ||
|
|
83037b1195 | ||
|
|
8300aeb0a0 | ||
|
|
3a885eaf9f | ||
|
|
533c5218dd | ||
|
|
8f15b0b6c1 | ||
|
|
bdee99ae88 | ||
|
|
02b0b402d6 | ||
|
|
484923e706 | ||
|
|
be03e582c6 | ||
|
|
9fffd7846a | ||
|
|
c9daf914cb | ||
|
|
3eb5778543 | ||
|
|
e23cbeda24 | ||
|
|
4b68dd2315 | ||
|
|
9946e07f36 | ||
|
|
0d0dc5158c | ||
|
|
97eb7b7b72 | ||
|
|
01fb29e8dc | ||
|
|
e1d42fad2c | ||
|
|
8e0f52cebc | ||
|
|
59fb479895 | ||
|
|
e34cc42441 | ||
|
|
7fcf39277d | ||
|
|
863fa364e2 | ||
|
|
bb8063c0f4 | ||
|
|
2ab10262fc | ||
|
|
83cffea1a1 | ||
|
|
3e9c3e6987 | ||
|
|
c1b9310ec2 | ||
|
|
9877294b1c | ||
|
|
193693565c | ||
|
|
664890ab33 | ||
|
|
45499b03d2 | ||
|
|
21b5571bff | ||
|
|
7354db873a |
1
.bazelrc
1
.bazelrc
@@ -24,5 +24,6 @@ common --registry=file:///%workspace%/misc/bazel/registry
|
||||
common --registry=https://bcr.bazel.build
|
||||
|
||||
common --@rules_dotnet//dotnet/settings:strict_deps=false
|
||||
common --experimental_isolated_extension_usages
|
||||
|
||||
try-import %workspace%/local.bazelrc
|
||||
|
||||
@@ -8,3 +8,4 @@ common --registry=https://bcr.bazel.build
|
||||
# its implementation packages without providing any code itself.
|
||||
# We either can depend on internal implementation details, or turn of strict deps.
|
||||
common --@rules_dotnet//dotnet/settings:strict_deps=false
|
||||
common --experimental_isolated_extension_usages
|
||||
|
||||
5
.github/workflows/compile-queries.yml
vendored
5
.github/workflows/compile-queries.yml
vendored
@@ -29,8 +29,6 @@ jobs:
|
||||
key: all-queries
|
||||
- name: check formatting
|
||||
run: find shared */ql -type f \( -name "*.qll" -o -name "*.ql" \) -print0 | xargs -0 -n 3000 -P 10 codeql query format -q --check-only
|
||||
- name: Omit DatabaseQualityDiagnostics.ql from compile checking # Remove me once CodeQL 2.18.0 is released!
|
||||
run: mv java/ql/src/Telemetry/DatabaseQualityDiagnostics.ql{,.hidden}
|
||||
- name: compile queries - check-only
|
||||
# run with --check-only if running in a PR (github.sha != main)
|
||||
if : ${{ github.event_name == 'pull_request' }}
|
||||
@@ -41,6 +39,3 @@ jobs:
|
||||
if : ${{ github.event_name != 'pull_request' }}
|
||||
shell: bash
|
||||
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" --compilation-cache-size=500
|
||||
- name: Restore DatabaseQualityDiagnostics.ql after compile checking # Remove me once CodeQL 2.18.0 is released
|
||||
run: mv java/ql/src/Telemetry/DatabaseQualityDiagnostics.ql{.hidden,}
|
||||
|
||||
|
||||
36
MODULE.bazel
36
MODULE.bazel
@@ -1,6 +1,7 @@
|
||||
module(
|
||||
name = "codeql",
|
||||
name = "ql",
|
||||
version = "0.0",
|
||||
repo_name = "codeql",
|
||||
)
|
||||
|
||||
# this points to our internal repository when `codeql` is checked out as a submodule thereof
|
||||
@@ -14,7 +15,7 @@ local_path_override(
|
||||
# see https://registry.bazel.build/ for a list of available packages
|
||||
|
||||
bazel_dep(name = "platforms", version = "0.0.10")
|
||||
bazel_dep(name = "rules_go", version = "0.48.0")
|
||||
bazel_dep(name = "rules_go", version = "0.49.0")
|
||||
bazel_dep(name = "rules_pkg", version = "0.10.1")
|
||||
bazel_dep(name = "rules_nodejs", version = "6.2.0-codeql.1")
|
||||
bazel_dep(name = "rules_python", version = "0.32.2")
|
||||
@@ -23,18 +24,20 @@ bazel_dep(name = "abseil-cpp", version = "20240116.0", repo_name = "absl")
|
||||
bazel_dep(name = "nlohmann_json", version = "3.11.3", repo_name = "json")
|
||||
bazel_dep(name = "fmt", version = "10.0.0")
|
||||
bazel_dep(name = "rules_kotlin", version = "1.9.4-codeql.1")
|
||||
bazel_dep(name = "gazelle", version = "0.37.0")
|
||||
bazel_dep(name = "gazelle", version = "0.38.0")
|
||||
bazel_dep(name = "rules_dotnet", version = "0.15.1")
|
||||
bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
|
||||
bazel_dep(name = "rules_rust", version = "0.46.0")
|
||||
bazel_dep(name = "rules_rust", version = "0.49.1")
|
||||
|
||||
bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True)
|
||||
|
||||
crate = use_extension(
|
||||
# crate_py but shortened due to Windows file path considerations
|
||||
cp = use_extension(
|
||||
"@rules_rust//crate_universe:extension.bzl",
|
||||
"crate",
|
||||
isolate = True,
|
||||
)
|
||||
crate.from_cargo(
|
||||
cp.from_cargo(
|
||||
name = "py_deps",
|
||||
cargo_lockfile = "//python/extractor/tsg-python:Cargo.lock",
|
||||
manifests = [
|
||||
@@ -42,15 +45,23 @@ crate.from_cargo(
|
||||
"//python/extractor/tsg-python/tsp:Cargo.toml",
|
||||
],
|
||||
)
|
||||
crate.from_cargo(
|
||||
name = "ruby_deps",
|
||||
use_repo(cp, "py_deps")
|
||||
|
||||
# crate_ruby, but shortened due to windows file paths
|
||||
r = use_extension(
|
||||
"@rules_rust//crate_universe:extension.bzl",
|
||||
"crate",
|
||||
isolate = True,
|
||||
)
|
||||
r.from_cargo(
|
||||
name = "rd",
|
||||
cargo_lockfile = "//ruby/extractor:Cargo.lock",
|
||||
manifests = [
|
||||
"//ruby/extractor:Cargo.toml",
|
||||
"//ruby/extractor/codeql-extractor-fake-crate:Cargo.toml",
|
||||
],
|
||||
)
|
||||
use_repo(crate, "py_deps", "ruby_deps")
|
||||
use_repo(r, ruby_deps = "rd")
|
||||
|
||||
dotnet = use_extension("@rules_dotnet//dotnet:extensions.bzl", "dotnet")
|
||||
dotnet.toolchain(dotnet_version = "8.0.101")
|
||||
@@ -112,6 +123,7 @@ use_repo(
|
||||
"kotlin-compiler-1.9.0-Beta",
|
||||
"kotlin-compiler-1.9.20-Beta",
|
||||
"kotlin-compiler-2.0.0-RC1",
|
||||
"kotlin-compiler-2.0.20-Beta2",
|
||||
"kotlin-compiler-embeddable-1.5.0",
|
||||
"kotlin-compiler-embeddable-1.5.10",
|
||||
"kotlin-compiler-embeddable-1.5.20",
|
||||
@@ -124,6 +136,7 @@ use_repo(
|
||||
"kotlin-compiler-embeddable-1.9.0-Beta",
|
||||
"kotlin-compiler-embeddable-1.9.20-Beta",
|
||||
"kotlin-compiler-embeddable-2.0.0-RC1",
|
||||
"kotlin-compiler-embeddable-2.0.20-Beta2",
|
||||
"kotlin-stdlib-1.5.0",
|
||||
"kotlin-stdlib-1.5.10",
|
||||
"kotlin-stdlib-1.5.20",
|
||||
@@ -136,11 +149,16 @@ use_repo(
|
||||
"kotlin-stdlib-1.9.0-Beta",
|
||||
"kotlin-stdlib-1.9.20-Beta",
|
||||
"kotlin-stdlib-2.0.0-RC1",
|
||||
"kotlin-stdlib-2.0.20-Beta2",
|
||||
)
|
||||
|
||||
go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")
|
||||
go_sdk.download(version = "1.22.2")
|
||||
|
||||
go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps")
|
||||
go_deps.from_file(go_mod = "//go/extractor:go.mod")
|
||||
use_repo(go_deps, "org_golang_x_mod", "org_golang_x_tools")
|
||||
|
||||
lfs_files = use_repo_rule("//misc/bazel:lfs.bzl", "lfs_files")
|
||||
|
||||
lfs_files(
|
||||
|
||||
2296
cpp/downgrades/25e365d1e8147df0f759b604f96eb4bffea48271/old.dbscheme
Normal file
2296
cpp/downgrades/25e365d1e8147df0f759b604f96eb4bffea48271/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,4 @@
|
||||
description: Revert support for using-enum declarations.
|
||||
compatibility: partial
|
||||
usings.rel: run usings.qlo
|
||||
using_container.rel: run using_container.qlo
|
||||
@@ -0,0 +1,14 @@
|
||||
class UsingEntry extends @using {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Element extends @element {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from UsingEntry u, Element parent, int kind
|
||||
where
|
||||
usings(u, _, _, kind) and
|
||||
using_container(parent, u) and
|
||||
kind != 3
|
||||
select parent, u
|
||||
@@ -0,0 +1,17 @@
|
||||
class UsingEntry extends @using {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Element extends @element {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Location extends @location_default {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from UsingEntry u, Element target, Location loc, int kind
|
||||
where
|
||||
usings(u, target, loc, kind) and
|
||||
kind != 3
|
||||
select u, target, loc
|
||||
@@ -0,0 +1,17 @@
|
||||
class Expr extends @expr {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Location extends @location_expr {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
predicate isExprWithNewBuiltin(Expr expr) {
|
||||
exists(int kind | exprs(expr, kind, _) | 364 <= kind and kind <= 384)
|
||||
}
|
||||
|
||||
from Expr expr, int kind, int kind_new, Location location
|
||||
where
|
||||
exprs(expr, kind, location) and
|
||||
if isExprWithNewBuiltin(expr) then kind_new = 1 else kind_new = kind
|
||||
select expr, kind_new, location
|
||||
2289
cpp/downgrades/3d35dd6b50edfc540c14c6757e0c7b3c5b7b04dd/old.dbscheme
Normal file
2289
cpp/downgrades/3d35dd6b50edfc540c14c6757e0c7b3c5b7b04dd/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,3 @@
|
||||
description: Add new builtin operations
|
||||
compatibility: partial
|
||||
exprs.rel: run exprs.qlo
|
||||
2310
cpp/downgrades/68930f3b81bbe3fdbb91c850deca1fec8072d62a/old.dbscheme
Normal file
2310
cpp/downgrades/68930f3b81bbe3fdbb91c850deca1fec8072d62a/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,3 @@
|
||||
description: description: Support explicit(bool) specifiers
|
||||
compatibility: full
|
||||
explicit_specifier_exprs.rel: delete
|
||||
2300
cpp/downgrades/9629fc87dab7dbed0771bf5ce22bce4d7f943b52/old.dbscheme
Normal file
2300
cpp/downgrades/9629fc87dab7dbed0771bf5ce22bce4d7f943b52/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: Support destroying deletes
|
||||
compatibility: full
|
||||
2305
cpp/downgrades/e197626a6ebccd052d5c891975fccf8aebcc9803/old.dbscheme
Normal file
2305
cpp/downgrades/e197626a6ebccd052d5c891975fccf8aebcc9803/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,3 @@
|
||||
description: Add relation between deduction guides and class templates
|
||||
compatibility: full
|
||||
deduction_guide_for_class.rel: delete
|
||||
@@ -1,3 +1,30 @@
|
||||
## 1.4.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.4.0
|
||||
|
||||
### New Features
|
||||
|
||||
* A `getTemplateClass` predicate was added to the `DeductionGuide` class to get the class template for which the deduction guide is a guide.
|
||||
* An `isExplicit` predicate was added to the `Function` class that determines whether the function was declared as explicit.
|
||||
* A `getExplicitExpr` predicate was added to the `Function` class that yields the constant boolean expression (if any) that conditionally determines whether the function is explicit.
|
||||
* A `isDestroyingDeleteDeallocation` predicate was added to the `NewOrNewArrayExpr` and `DeleteOrDeleteArrayExpr` classes to indicate whether the deallocation function is a destroying delete.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The controlling expression of a `constexpr if` is now always recognized as an unevaluated expression.
|
||||
* Improved performance of alias analysis of large function bodies. In rare cases, alerts that depend on alias analysis of large function bodies may be affected.
|
||||
* A `UsingEnumDeclarationEntry` class has been added for C++ `using enum` declarations. As part of this, synthesized `UsingDeclarationEntry`s are no longer emitted for individual enumerators of the referenced enumeration.
|
||||
|
||||
## 1.3.0
|
||||
|
||||
### New Features
|
||||
|
||||
* Models-as-data alert provenance information has been extended to the C/C++ language. Any qltests that include the edges relation in their output (for example, `.qlref`s that reference path-problem queries) will need to be have their expected output updated accordingly.
|
||||
* Added subclasses of `BuiltInOperations` for `__builtin_has_attribute`, `__builtin_is_corresponding_member`, `__builtin_is_pointer_interconvertible_with_class`, `__is_assignable_no_precondition_check`, `__is_bounded_array`, `__is_convertible`, `__is_corresponding_member`, `__is_nothrow_convertible`, `__is_pointer_interconvertible_with_class`, `__is_referenceable`, `__is_same_as`, `__is_trivially_copy_assignable`, `__is_unbounded_array`, `__is_valid_winrt_type`, `_is_win_class`, `__is_win_interface`, `__reference_binds_to_temporary`, `__reference_constructs_from_temporary`, and `__reference_converts_from_temporary`.
|
||||
* The class `NewArrayExpr` adds a predicate `getArraySize()` to allow a more convenient way to access the static size of the array when the extent is missing.
|
||||
|
||||
## 1.2.0
|
||||
|
||||
### New Features
|
||||
|
||||
7
cpp/ql/lib/change-notes/released/1.3.0.md
Normal file
7
cpp/ql/lib/change-notes/released/1.3.0.md
Normal file
@@ -0,0 +1,7 @@
|
||||
## 1.3.0
|
||||
|
||||
### New Features
|
||||
|
||||
* Models-as-data alert provenance information has been extended to the C/C++ language. Any qltests that include the edges relation in their output (for example, `.qlref`s that reference path-problem queries) will need to be have their expected output updated accordingly.
|
||||
* Added subclasses of `BuiltInOperations` for `__builtin_has_attribute`, `__builtin_is_corresponding_member`, `__builtin_is_pointer_interconvertible_with_class`, `__is_assignable_no_precondition_check`, `__is_bounded_array`, `__is_convertible`, `__is_corresponding_member`, `__is_nothrow_convertible`, `__is_pointer_interconvertible_with_class`, `__is_referenceable`, `__is_same_as`, `__is_trivially_copy_assignable`, `__is_unbounded_array`, `__is_valid_winrt_type`, `_is_win_class`, `__is_win_interface`, `__reference_binds_to_temporary`, `__reference_constructs_from_temporary`, and `__reference_converts_from_temporary`.
|
||||
* The class `NewArrayExpr` adds a predicate `getArraySize()` to allow a more convenient way to access the static size of the array when the extent is missing.
|
||||
14
cpp/ql/lib/change-notes/released/1.4.0.md
Normal file
14
cpp/ql/lib/change-notes/released/1.4.0.md
Normal file
@@ -0,0 +1,14 @@
|
||||
## 1.4.0
|
||||
|
||||
### New Features
|
||||
|
||||
* A `getTemplateClass` predicate was added to the `DeductionGuide` class to get the class template for which the deduction guide is a guide.
|
||||
* An `isExplicit` predicate was added to the `Function` class that determines whether the function was declared as explicit.
|
||||
* A `getExplicitExpr` predicate was added to the `Function` class that yields the constant boolean expression (if any) that conditionally determines whether the function is explicit.
|
||||
* A `isDestroyingDeleteDeallocation` predicate was added to the `NewOrNewArrayExpr` and `DeleteOrDeleteArrayExpr` classes to indicate whether the deallocation function is a destroying delete.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The controlling expression of a `constexpr if` is now always recognized as an unevaluated expression.
|
||||
* Improved performance of alias analysis of large function bodies. In rare cases, alerts that depend on alias analysis of large function bodies may be affected.
|
||||
* A `UsingEnumDeclarationEntry` class has been added for C++ `using enum` declarations. As part of this, synthesized `UsingDeclarationEntry`s are no longer emitted for individual enumerators of the referenced enumeration.
|
||||
3
cpp/ql/lib/change-notes/released/1.4.1.md
Normal file
3
cpp/ql/lib/change-notes/released/1.4.1.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.4.1
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.2.0
|
||||
lastReleaseVersion: 1.4.1
|
||||
|
||||
14
cpp/ql/lib/ext/std.format.model.yml
Normal file
14
cpp/ql/lib/ext/std.format.model.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: summaryModel
|
||||
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
|
||||
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
|
||||
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*1]", "ReturnValue", "taint", "manual"]
|
||||
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*2]", "ReturnValue", "taint", "manual"]
|
||||
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*3]", "ReturnValue", "taint", "manual"]
|
||||
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*4]", "ReturnValue", "taint", "manual"]
|
||||
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*5]", "ReturnValue", "taint", "manual"]
|
||||
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*6]", "ReturnValue", "taint", "manual"]
|
||||
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*7]", "ReturnValue", "taint", "manual"]
|
||||
- ["std", "", False, "format<Args>", "(format_string,Args &&)", "", "Argument[*8]", "ReturnValue", "taint", "manual"]
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 1.2.0
|
||||
version: 1.4.1
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -158,6 +158,26 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
|
||||
*/
|
||||
predicate isConsteval() { this.hasSpecifier("is_consteval") }
|
||||
|
||||
/**
|
||||
* Holds if this function is declared to be `explicit`.
|
||||
*/
|
||||
predicate isExplicit() { this.hasSpecifier("explicit") }
|
||||
|
||||
/**
|
||||
* Gets the constant expression that determines whether the function is explicit.
|
||||
*
|
||||
* For example, for the following code the result is the expression `sizeof(T) == 1`:
|
||||
* ```
|
||||
* template<typename T> struct C {
|
||||
* explicit(sizeof(T) == 1)
|
||||
* C(const T);
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
Expr getExplicitExpr() {
|
||||
explicit_specifier_exprs(underlyingElement(this), unresolveElement(result))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this function is declared with `__attribute__((naked))` or
|
||||
* `__declspec(naked)`.
|
||||
@@ -898,4 +918,11 @@ class UserDefinedLiteral extends Function {
|
||||
*/
|
||||
class DeductionGuide extends Function {
|
||||
DeductionGuide() { functions(underlyingElement(this), _, 8) }
|
||||
|
||||
/**
|
||||
* Gets the class template for which this is a deduction guide.
|
||||
*/
|
||||
TemplateClass getTemplateClass() {
|
||||
deduction_guide_for_class(underlyingElement(this), unresolveElement(result))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ class NamespaceDeclarationEntry extends Locatable, @namespace_decl {
|
||||
* A C++ `using` directive or `using` declaration.
|
||||
*/
|
||||
class UsingEntry extends Locatable, @using {
|
||||
override Location getLocation() { usings(underlyingElement(this), _, result) }
|
||||
override Location getLocation() { usings(underlyingElement(this), _, result, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -166,15 +166,13 @@ class UsingEntry extends Locatable, @using {
|
||||
* ```
|
||||
*/
|
||||
class UsingDeclarationEntry extends UsingEntry {
|
||||
UsingDeclarationEntry() {
|
||||
not exists(Namespace n | usings(underlyingElement(this), unresolveElement(n), _))
|
||||
}
|
||||
UsingDeclarationEntry() { usings(underlyingElement(this), _, _, 1) }
|
||||
|
||||
/**
|
||||
* Gets the declaration that is referenced by this using declaration. For
|
||||
* example, `std::string` in `using std::string`.
|
||||
*/
|
||||
Declaration getDeclaration() { usings(underlyingElement(this), unresolveElement(result), _) }
|
||||
Declaration getDeclaration() { usings(underlyingElement(this), unresolveElement(result), _, _) }
|
||||
|
||||
override string toString() { result = "using " + this.getDeclaration().getDescription() }
|
||||
}
|
||||
@@ -186,19 +184,36 @@ class UsingDeclarationEntry extends UsingEntry {
|
||||
* ```
|
||||
*/
|
||||
class UsingDirectiveEntry extends UsingEntry {
|
||||
UsingDirectiveEntry() {
|
||||
exists(Namespace n | usings(underlyingElement(this), unresolveElement(n), _))
|
||||
}
|
||||
UsingDirectiveEntry() { usings(underlyingElement(this), _, _, 2) }
|
||||
|
||||
/**
|
||||
* Gets the namespace that is referenced by this using directive. For
|
||||
* example, `std` in `using namespace std`.
|
||||
*/
|
||||
Namespace getNamespace() { usings(underlyingElement(this), unresolveElement(result), _) }
|
||||
Namespace getNamespace() { usings(underlyingElement(this), unresolveElement(result), _, _) }
|
||||
|
||||
override string toString() { result = "using namespace " + this.getNamespace().getFriendlyName() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `using enum` declaration. For example:
|
||||
* ```
|
||||
* enum class Foo { a, b };
|
||||
* using enum Foo;
|
||||
* ```
|
||||
*/
|
||||
class UsingEnumDeclarationEntry extends UsingEntry {
|
||||
UsingEnumDeclarationEntry() { usings(underlyingElement(this), _, _, 3) }
|
||||
|
||||
/**
|
||||
* Gets the enumeration that is referenced by this using directive. For
|
||||
* example, `Foo` in `using enum Foo`.
|
||||
*/
|
||||
Enum getEnum() { usings(underlyingElement(this), unresolveElement(result), _, _) }
|
||||
|
||||
override string toString() { result = "using enum " + this.getEnum().getQualifiedName() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `g` is an instance of `GlobalNamespace`. This predicate
|
||||
* is used suppress a warning in `GlobalNamespace.getADeclaration()`
|
||||
|
||||
@@ -146,7 +146,7 @@ predicate summaryModel(string row) { any(SummaryModelCsv s).row(row) }
|
||||
/** Holds if a source model exists for the given parameters. */
|
||||
predicate sourceModel(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string output, string kind, string provenance
|
||||
string output, string kind, string provenance, string model
|
||||
) {
|
||||
exists(string row |
|
||||
sourceModel(row) and
|
||||
@@ -160,16 +160,20 @@ predicate sourceModel(
|
||||
row.splitAt(";", 6) = output and
|
||||
row.splitAt(";", 7) = kind
|
||||
) and
|
||||
provenance = "manual"
|
||||
provenance = "manual" and
|
||||
model = ""
|
||||
or
|
||||
Extensions::sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance,
|
||||
_)
|
||||
exists(QlBuiltins::ExtensionId madId |
|
||||
Extensions::sourceModel(namespace, type, subtypes, name, signature, ext, output, kind,
|
||||
provenance, madId) and
|
||||
model = "MaD:" + madId.toString()
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if a sink model exists for the given parameters. */
|
||||
predicate sinkModel(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string kind, string provenance
|
||||
string input, string kind, string provenance, string model
|
||||
) {
|
||||
exists(string row |
|
||||
sinkModel(row) and
|
||||
@@ -183,9 +187,14 @@ predicate sinkModel(
|
||||
row.splitAt(";", 6) = input and
|
||||
row.splitAt(";", 7) = kind
|
||||
) and
|
||||
provenance = "manual"
|
||||
provenance = "manual" and
|
||||
model = ""
|
||||
or
|
||||
Extensions::sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, provenance, _)
|
||||
exists(QlBuiltins::ExtensionId madId |
|
||||
Extensions::sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, provenance,
|
||||
madId) and
|
||||
model = "MaD:" + madId.toString()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -195,7 +204,7 @@ predicate sinkModel(
|
||||
*/
|
||||
private predicate summaryModel0(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string output, string kind, string provenance
|
||||
string input, string output, string kind, string provenance, string model
|
||||
) {
|
||||
exists(string row |
|
||||
summaryModel(row) and
|
||||
@@ -210,10 +219,14 @@ private predicate summaryModel0(
|
||||
row.splitAt(";", 7) = output and
|
||||
row.splitAt(";", 8) = kind
|
||||
) and
|
||||
provenance = "manual"
|
||||
provenance = "manual" and
|
||||
model = ""
|
||||
or
|
||||
Extensions::summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind,
|
||||
provenance, _)
|
||||
exists(QlBuiltins::ExtensionId madId |
|
||||
Extensions::summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind,
|
||||
provenance, madId) and
|
||||
model = "MaD:" + madId.toString()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -234,19 +247,20 @@ private predicate expandInputAndOutput(
|
||||
*/
|
||||
predicate summaryModel(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
string input, string output, string kind, string provenance
|
||||
string input, string output, string kind, string provenance, string model
|
||||
) {
|
||||
exists(string input0, string output0 |
|
||||
summaryModel0(namespace, type, subtypes, name, signature, ext, input0, output0, kind, provenance) and
|
||||
summaryModel0(namespace, type, subtypes, name, signature, ext, input0, output0, kind,
|
||||
provenance, model) and
|
||||
expandInputAndOutput(input0, input, output0, output,
|
||||
[0 .. Private::getMaxElementContentIndirectionIndex() - 1])
|
||||
)
|
||||
}
|
||||
|
||||
private predicate relevantNamespace(string namespace) {
|
||||
sourceModel(namespace, _, _, _, _, _, _, _, _) or
|
||||
sinkModel(namespace, _, _, _, _, _, _, _, _) or
|
||||
summaryModel(namespace, _, _, _, _, _, _, _, _, _)
|
||||
sourceModel(namespace, _, _, _, _, _, _, _, _, _) or
|
||||
sinkModel(namespace, _, _, _, _, _, _, _, _, _) or
|
||||
summaryModel(namespace, _, _, _, _, _, _, _, _, _, _)
|
||||
}
|
||||
|
||||
private predicate namespaceLink(string shortns, string longns) {
|
||||
@@ -276,17 +290,17 @@ predicate modelCoverage(string namespace, int namespaces, string kind, string pa
|
||||
part = "source" and
|
||||
n =
|
||||
strictcount(string subns, string type, boolean subtypes, string name, string signature,
|
||||
string ext, string output, string provenance |
|
||||
string ext, string output, string provenance, string model |
|
||||
canonicalNamespaceLink(namespace, subns) and
|
||||
sourceModel(subns, type, subtypes, name, signature, ext, output, kind, provenance)
|
||||
sourceModel(subns, type, subtypes, name, signature, ext, output, kind, provenance, model)
|
||||
)
|
||||
or
|
||||
part = "sink" and
|
||||
n =
|
||||
strictcount(string subns, string type, boolean subtypes, string name, string signature,
|
||||
string ext, string input, string provenance |
|
||||
string ext, string input, string provenance, string model |
|
||||
canonicalNamespaceLink(namespace, subns) and
|
||||
sinkModel(subns, type, subtypes, name, signature, ext, input, kind, provenance)
|
||||
sinkModel(subns, type, subtypes, name, signature, ext, input, kind, provenance, model)
|
||||
)
|
||||
or
|
||||
part = "summary" and
|
||||
@@ -294,7 +308,7 @@ predicate modelCoverage(string namespace, int namespaces, string kind, string pa
|
||||
strictcount(string subns, string type, boolean subtypes, string name, string signature,
|
||||
string ext, string input, string output, string provenance |
|
||||
canonicalNamespaceLink(namespace, subns) and
|
||||
summaryModel(subns, type, subtypes, name, signature, ext, input, output, kind, provenance)
|
||||
summaryModel(subns, type, subtypes, name, signature, ext, input, output, kind, provenance, _)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -303,9 +317,9 @@ predicate modelCoverage(string namespace, int namespaces, string kind, string pa
|
||||
module CsvValidation {
|
||||
private string getInvalidModelInput() {
|
||||
exists(string pred, AccessPath input, string part |
|
||||
sinkModel(_, _, _, _, _, _, input, _, _) and pred = "sink"
|
||||
sinkModel(_, _, _, _, _, _, input, _, _, _) and pred = "sink"
|
||||
or
|
||||
summaryModel(_, _, _, _, _, _, input, _, _, _) and pred = "summary"
|
||||
summaryModel(_, _, _, _, _, _, input, _, _, _, _) and pred = "summary"
|
||||
|
|
||||
(
|
||||
invalidSpecComponent(input, part) and
|
||||
@@ -322,9 +336,9 @@ module CsvValidation {
|
||||
|
||||
private string getInvalidModelOutput() {
|
||||
exists(string pred, string output, string part |
|
||||
sourceModel(_, _, _, _, _, _, output, _, _) and pred = "source"
|
||||
sourceModel(_, _, _, _, _, _, output, _, _, _) and pred = "source"
|
||||
or
|
||||
summaryModel(_, _, _, _, _, _, _, output, _, _) and pred = "summary"
|
||||
summaryModel(_, _, _, _, _, _, _, output, _, _, _) and pred = "summary"
|
||||
|
|
||||
invalidSpecComponent(output, part) and
|
||||
not part = "" and
|
||||
@@ -334,11 +348,11 @@ module CsvValidation {
|
||||
}
|
||||
|
||||
private module KindValConfig implements SharedModelVal::KindValidationConfigSig {
|
||||
predicate summaryKind(string kind) { summaryModel(_, _, _, _, _, _, _, _, kind, _) }
|
||||
predicate summaryKind(string kind) { summaryModel(_, _, _, _, _, _, _, _, kind, _, _) }
|
||||
|
||||
predicate sinkKind(string kind) { sinkModel(_, _, _, _, _, _, _, kind, _) }
|
||||
predicate sinkKind(string kind) { sinkModel(_, _, _, _, _, _, _, kind, _, _) }
|
||||
|
||||
predicate sourceKind(string kind) { sourceModel(_, _, _, _, _, _, _, kind, _) }
|
||||
predicate sourceKind(string kind) { sourceModel(_, _, _, _, _, _, _, kind, _, _) }
|
||||
}
|
||||
|
||||
private module KindVal = SharedModelVal::KindValidation<KindValConfig>;
|
||||
@@ -379,11 +393,11 @@ module CsvValidation {
|
||||
|
||||
private string getInvalidModelSignature() {
|
||||
exists(string pred, string namespace, string type, string name, string signature, string ext |
|
||||
sourceModel(namespace, type, _, name, signature, ext, _, _, _) and pred = "source"
|
||||
sourceModel(namespace, type, _, name, signature, ext, _, _, _, _) and pred = "source"
|
||||
or
|
||||
sinkModel(namespace, type, _, name, signature, ext, _, _, _) and pred = "sink"
|
||||
sinkModel(namespace, type, _, name, signature, ext, _, _, _, _) and pred = "sink"
|
||||
or
|
||||
summaryModel(namespace, type, _, name, signature, ext, _, _, _, _) and pred = "summary"
|
||||
summaryModel(namespace, type, _, name, signature, ext, _, _, _, _, _) and pred = "summary"
|
||||
|
|
||||
not namespace.regexpMatch("[a-zA-Z0-9_\\.:]*") and
|
||||
result = "Dubious namespace \"" + namespace + "\" in " + pred + " model."
|
||||
@@ -415,18 +429,23 @@ module CsvValidation {
|
||||
private predicate elementSpec(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
||||
) {
|
||||
sourceModel(namespace, type, subtypes, name, signature, ext, _, _, _) or
|
||||
sinkModel(namespace, type, subtypes, name, signature, ext, _, _, _) or
|
||||
summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _, _)
|
||||
sourceModel(namespace, type, subtypes, name, signature, ext, _, _, _, _) or
|
||||
sinkModel(namespace, type, subtypes, name, signature, ext, _, _, _, _) or
|
||||
summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _, _, _)
|
||||
}
|
||||
|
||||
/** Gets the fully templated version of `f`. */
|
||||
private Function getFullyTemplatedMemberFunction(Function f) {
|
||||
private Function getFullyTemplatedFunction(Function f) {
|
||||
not f.isFromUninstantiatedTemplate(_) and
|
||||
exists(Class c, Class templateClass, int i |
|
||||
c.isConstructedFrom(templateClass) and
|
||||
f = c.getAMember(i) and
|
||||
result = templateClass.getCanonicalMember(i)
|
||||
(
|
||||
exists(Class c, Class templateClass, int i |
|
||||
c.isConstructedFrom(templateClass) and
|
||||
f = c.getAMember(i) and
|
||||
result = templateClass.getCanonicalMember(i)
|
||||
)
|
||||
or
|
||||
not exists(f.getDeclaringType()) and
|
||||
f.isConstructedFrom(result)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -450,14 +469,14 @@ string getParameterTypeWithoutTemplateArguments(Function f, int n) {
|
||||
*/
|
||||
private string getTypeNameWithoutFunctionTemplates(Function f, int n, int remaining) {
|
||||
exists(Function templateFunction |
|
||||
templateFunction = getFullyTemplatedMemberFunction(f) and
|
||||
templateFunction = getFullyTemplatedFunction(f) and
|
||||
remaining = templateFunction.getNumberOfTemplateArguments() and
|
||||
result = getParameterTypeWithoutTemplateArguments(templateFunction, n)
|
||||
)
|
||||
or
|
||||
exists(string mid, TemplateParameter tp, Function templateFunction |
|
||||
mid = getTypeNameWithoutFunctionTemplates(f, n, remaining + 1) and
|
||||
templateFunction = getFullyTemplatedMemberFunction(f) and
|
||||
templateFunction = getFullyTemplatedFunction(f) and
|
||||
tp = templateFunction.getTemplateArgument(remaining) and
|
||||
result = mid.replaceAll(tp.getName(), "func:" + remaining.toString())
|
||||
)
|
||||
@@ -468,12 +487,18 @@ private string getTypeNameWithoutFunctionTemplates(Function f, int n, int remain
|
||||
* with `class:N` (where `N` is the index of the template).
|
||||
*/
|
||||
private string getTypeNameWithoutClassTemplates(Function f, int n, int remaining) {
|
||||
// If there is a declaring type then we start by expanding the function templates
|
||||
exists(Class template |
|
||||
f.getDeclaringType().isConstructedFrom(template) and
|
||||
remaining = template.getNumberOfTemplateArguments() and
|
||||
result = getTypeNameWithoutFunctionTemplates(f, n, 0)
|
||||
)
|
||||
or
|
||||
// If there is no declaring type we're done after expanding the function templates
|
||||
not exists(f.getDeclaringType()) and
|
||||
remaining = 0 and
|
||||
result = getTypeNameWithoutFunctionTemplates(f, n, 0)
|
||||
or
|
||||
exists(string mid, TemplateParameter tp, Class template |
|
||||
mid = getTypeNameWithoutClassTemplates(f, n, remaining + 1) and
|
||||
f.getDeclaringType().isConstructedFrom(template) and
|
||||
@@ -556,38 +581,6 @@ private string getSignatureWithoutFunctionTemplateNames(
|
||||
)
|
||||
}
|
||||
|
||||
private string paramsStringPart(Function c, int i) {
|
||||
not c.isFromUninstantiatedTemplate(_) and
|
||||
(
|
||||
i = -1 and result = "(" and exists(c)
|
||||
or
|
||||
exists(int n, string p | getParameterTypeName(c, n) = p |
|
||||
i = 2 * n and result = p
|
||||
or
|
||||
i = 2 * n - 1 and result = "," and n != 0
|
||||
)
|
||||
or
|
||||
i = 2 * c.getNumberOfParameters() and result = ")"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a parenthesized string containing all parameter types of this callable, separated by a comma.
|
||||
*
|
||||
* Returns the empty string if the callable has no parameters.
|
||||
* Parameter types are represented by their type erasure.
|
||||
*/
|
||||
cached
|
||||
private string paramsString(Function c) {
|
||||
result = concat(int i | | paramsStringPart(c, i) order by i)
|
||||
}
|
||||
|
||||
bindingset[func]
|
||||
private predicate matchesSignature(Function func, string signature) {
|
||||
signature = "" or
|
||||
paramsString(func) = signature
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `elementSpec(_, type, _, name, signature, _)` holds and
|
||||
* - `typeArgs` represents the named template parameters supplied to `type`, and
|
||||
@@ -736,17 +729,17 @@ private predicate elementSpecWithArguments0(
|
||||
|
||||
/**
|
||||
* Holds if `elementSpec(namespace, type, subtypes, name, signature, _)` and
|
||||
* `method`'s signature matches `signature`.
|
||||
* `func`'s signature matches `signature`.
|
||||
*
|
||||
* `signature` may contain template parameter names that are bound by `type` and `name`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate elementSpecMatchesSignature(
|
||||
Function method, string namespace, string type, boolean subtypes, string name, string signature
|
||||
Function func, string namespace, string type, boolean subtypes, string name, string signature
|
||||
) {
|
||||
elementSpec(namespace, pragma[only_bind_into](type), subtypes, pragma[only_bind_into](name),
|
||||
pragma[only_bind_into](signature), _) and
|
||||
signatureMatches(method, signature, type, name, 0)
|
||||
signatureMatches(func, signature, type, name, 0)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -762,13 +755,22 @@ private predicate hasClassAndName(Class classWithMethod, Function method, string
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[name]
|
||||
pragma[inline_late]
|
||||
private predicate funcHasQualifiedName(Function func, string namespace, string name) {
|
||||
exists(string nameWithoutArgs |
|
||||
parseAngles(name, nameWithoutArgs, _, "") and
|
||||
func.hasQualifiedName(namespace, nameWithoutArgs)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `namedClass` is in namespace `namespace` and has
|
||||
* name `type` (excluding any template parameters).
|
||||
*/
|
||||
bindingset[type, namespace]
|
||||
pragma[inline_late]
|
||||
private predicate hasQualifiedName(Class namedClass, string namespace, string type) {
|
||||
private predicate classHasQualifiedName(Class namedClass, string namespace, string type) {
|
||||
exists(string typeWithoutArgs |
|
||||
parseAngles(type, typeWithoutArgs, _, "") and
|
||||
namedClass.hasQualifiedName(namespace, typeWithoutArgs)
|
||||
@@ -790,15 +792,16 @@ private Element interpretElement0(
|
||||
string namespace, string type, boolean subtypes, string name, string signature
|
||||
) {
|
||||
(
|
||||
elementSpec(namespace, type, subtypes, name, signature, _) and
|
||||
// Non-member functions
|
||||
exists(Function func |
|
||||
func.hasQualifiedName(namespace, name) and
|
||||
type = "" and
|
||||
matchesSignature(func, signature) and
|
||||
subtypes = false and
|
||||
not exists(func.getDeclaringType()) and
|
||||
result = func
|
||||
elementSpec(namespace, type, subtypes, name, signature, _) and
|
||||
subtypes = false and
|
||||
type = "" and
|
||||
(
|
||||
elementSpecMatchesSignature(result, namespace, type, subtypes, name, signature)
|
||||
or
|
||||
signature = "" and
|
||||
elementSpec(namespace, type, subtypes, name, "", _) and
|
||||
funcHasQualifiedName(result, namespace, name)
|
||||
)
|
||||
or
|
||||
// Member functions
|
||||
@@ -811,7 +814,7 @@ private Element interpretElement0(
|
||||
elementSpec(namespace, type, subtypes, name, "", _) and
|
||||
hasClassAndName(classWithMethod, result, name)
|
||||
) and
|
||||
hasQualifiedName(namedClass, namespace, type) and
|
||||
classHasQualifiedName(namedClass, namespace, type) and
|
||||
(
|
||||
// member declared in the named type or a subtype of it
|
||||
subtypes = true and
|
||||
@@ -867,9 +870,9 @@ private module Cached {
|
||||
* model.
|
||||
*/
|
||||
cached
|
||||
predicate sourceNode(DataFlow::Node node, string kind) {
|
||||
predicate sourceNode(DataFlow::Node node, string kind, string model) {
|
||||
exists(SourceSinkInterpretationInput::InterpretNode n |
|
||||
isSourceNode(n, kind, _) and n.asNode() = node // TODO
|
||||
isSourceNode(n, kind, model) and n.asNode() = node
|
||||
)
|
||||
}
|
||||
|
||||
@@ -878,40 +881,57 @@ private module Cached {
|
||||
* model.
|
||||
*/
|
||||
cached
|
||||
predicate sinkNode(DataFlow::Node node, string kind) {
|
||||
predicate sinkNode(DataFlow::Node node, string kind, string model) {
|
||||
exists(SourceSinkInterpretationInput::InterpretNode n |
|
||||
isSinkNode(n, kind, _) and n.asNode() = node // TODO
|
||||
isSinkNode(n, kind, model) and n.asNode() = node
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import Cached
|
||||
|
||||
/**
|
||||
* Holds if `node` is specified as a source with the given kind in a MaD flow
|
||||
* model.
|
||||
*/
|
||||
predicate sourceNode(DataFlow::Node node, string kind) { sourceNode(node, kind, _) }
|
||||
|
||||
/**
|
||||
* Holds if `node` is specified as a sink with the given kind in a MaD flow
|
||||
* model.
|
||||
*/
|
||||
predicate sinkNode(DataFlow::Node node, string kind) { sinkNode(node, kind, _) }
|
||||
|
||||
private predicate interpretSummary(
|
||||
Function f, string input, string output, string kind, string provenance
|
||||
Function f, string input, string output, string kind, string provenance, string model
|
||||
) {
|
||||
exists(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
||||
|
|
||||
summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, provenance) and
|
||||
summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, provenance,
|
||||
model) and
|
||||
f = interpretElement(namespace, type, subtypes, name, signature, ext)
|
||||
)
|
||||
}
|
||||
|
||||
// adapter class for converting Mad summaries to `SummarizedCallable`s
|
||||
private class SummarizedCallableAdapter extends SummarizedCallable {
|
||||
SummarizedCallableAdapter() { interpretSummary(this, _, _, _, _) }
|
||||
SummarizedCallableAdapter() { interpretSummary(this, _, _, _, _, _) }
|
||||
|
||||
private predicate relevantSummaryElementManual(string input, string output, string kind) {
|
||||
private predicate relevantSummaryElementManual(
|
||||
string input, string output, string kind, string model
|
||||
) {
|
||||
exists(Provenance provenance |
|
||||
interpretSummary(this, input, output, kind, provenance) and
|
||||
interpretSummary(this, input, output, kind, provenance, model) and
|
||||
provenance.isManual()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate relevantSummaryElementGenerated(string input, string output, string kind) {
|
||||
private predicate relevantSummaryElementGenerated(
|
||||
string input, string output, string kind, string model
|
||||
) {
|
||||
exists(Provenance provenance |
|
||||
interpretSummary(this, input, output, kind, provenance) and
|
||||
interpretSummary(this, input, output, kind, provenance, model) and
|
||||
provenance.isGenerated()
|
||||
)
|
||||
}
|
||||
@@ -920,35 +940,16 @@ private class SummarizedCallableAdapter extends SummarizedCallable {
|
||||
string input, string output, boolean preservesValue, string model
|
||||
) {
|
||||
exists(string kind |
|
||||
this.relevantSummaryElementManual(input, output, kind)
|
||||
this.relevantSummaryElementManual(input, output, kind, model)
|
||||
or
|
||||
not this.relevantSummaryElementManual(_, _, _) and
|
||||
this.relevantSummaryElementGenerated(input, output, kind)
|
||||
not this.relevantSummaryElementManual(_, _, _, _) and
|
||||
this.relevantSummaryElementGenerated(input, output, kind, model)
|
||||
|
|
||||
if kind = "value" then preservesValue = true else preservesValue = false
|
||||
) and
|
||||
model = "" // TODO
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasProvenance(Provenance provenance) {
|
||||
interpretSummary(this, _, _, _, provenance)
|
||||
interpretSummary(this, _, _, _, provenance, _)
|
||||
}
|
||||
}
|
||||
|
||||
// adapter class for converting Mad neutrals to `NeutralCallable`s
|
||||
private class NeutralCallableAdapter extends NeutralCallable {
|
||||
string kind;
|
||||
string provenance_;
|
||||
|
||||
NeutralCallableAdapter() {
|
||||
// Neutral models have not been implemented for CPP.
|
||||
none() and
|
||||
exists(this) and
|
||||
exists(kind) and
|
||||
exists(provenance_)
|
||||
}
|
||||
|
||||
override string getKind() { result = kind }
|
||||
|
||||
override predicate hasProvenance(Provenance provenance) { provenance = provenance_ }
|
||||
}
|
||||
|
||||
@@ -290,14 +290,6 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate sourceGrouping(Node source, string sourceGroup) {
|
||||
any(Configuration config).sourceGrouping(source, sourceGroup)
|
||||
}
|
||||
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) {
|
||||
any(Configuration config).sinkGrouping(sink, sinkGroup)
|
||||
}
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
}
|
||||
|
||||
|
||||
@@ -290,14 +290,6 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate sourceGrouping(Node source, string sourceGroup) {
|
||||
any(Configuration config).sourceGrouping(source, sourceGroup)
|
||||
}
|
||||
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) {
|
||||
any(Configuration config).sinkGrouping(sink, sinkGroup)
|
||||
}
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
}
|
||||
|
||||
|
||||
@@ -290,14 +290,6 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate sourceGrouping(Node source, string sourceGroup) {
|
||||
any(Configuration config).sourceGrouping(source, sourceGroup)
|
||||
}
|
||||
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) {
|
||||
any(Configuration config).sinkGrouping(sink, sinkGroup)
|
||||
}
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
}
|
||||
|
||||
|
||||
@@ -290,14 +290,6 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate sourceGrouping(Node source, string sourceGroup) {
|
||||
any(Configuration config).sourceGrouping(source, sourceGroup)
|
||||
}
|
||||
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) {
|
||||
any(Configuration config).sinkGrouping(sink, sinkGroup)
|
||||
}
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
}
|
||||
|
||||
|
||||
@@ -290,14 +290,6 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate sourceGrouping(Node source, string sourceGroup) {
|
||||
any(Configuration config).sourceGrouping(source, sourceGroup)
|
||||
}
|
||||
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) {
|
||||
any(Configuration config).sinkGrouping(sink, sinkGroup)
|
||||
}
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
}
|
||||
|
||||
|
||||
@@ -215,19 +215,16 @@ predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() }
|
||||
predicate localMustFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/** Gets the type of `n` used for type pruning. */
|
||||
Type getNodeType(Node n) {
|
||||
DataFlowType getNodeType(Node n) {
|
||||
exists(n) and
|
||||
result instanceof VoidType // stub implementation
|
||||
}
|
||||
|
||||
/** Gets a string representation of a type returned by `getNodeType`. */
|
||||
string ppReprType(Type t) { none() } // stub implementation
|
||||
|
||||
/**
|
||||
* Holds if `t1` and `t2` are compatible, that is, whether data can flow from
|
||||
* a node of type `t1` to a node of type `t2`.
|
||||
*/
|
||||
predicate compatibleTypes(Type t1, Type t2) {
|
||||
predicate compatibleTypes(DataFlowType t1, DataFlowType t2) {
|
||||
t1 instanceof VoidType and t2 instanceof VoidType // stub implementation
|
||||
}
|
||||
|
||||
@@ -239,21 +236,15 @@ class CastNode extends Node {
|
||||
CastNode() { none() } // stub implementation
|
||||
}
|
||||
|
||||
class DataFlowCallable extends Function {
|
||||
/** Gets a best-effort total ordering. */
|
||||
int totalorder() {
|
||||
this =
|
||||
rank[result](DataFlowCallable c, string file, int startline, int startcolumn |
|
||||
c.getLocation().hasLocationInfo(file, startline, startcolumn, _, _)
|
||||
|
|
||||
c order by file, startline, startcolumn
|
||||
)
|
||||
}
|
||||
}
|
||||
class DataFlowCallable extends Function { }
|
||||
|
||||
class DataFlowExpr = Expr;
|
||||
|
||||
class DataFlowType = Type;
|
||||
final private class TypeFinal = Type;
|
||||
|
||||
class DataFlowType extends TypeFinal {
|
||||
string toString() { result = "" }
|
||||
}
|
||||
|
||||
/** A function call relevant for data flow. */
|
||||
class DataFlowCall extends Expr instanceof Call {
|
||||
@@ -269,24 +260,12 @@ class DataFlowCall extends Expr instanceof Call {
|
||||
|
||||
/** Gets the enclosing callable of this call. */
|
||||
DataFlowCallable getEnclosingCallable() { result = this.getEnclosingFunction() }
|
||||
|
||||
/** Gets a best-effort total ordering. */
|
||||
int totalorder() {
|
||||
this =
|
||||
rank[result](DataFlowCall c, int startline, int startcolumn |
|
||||
c.getLocation().hasLocationInfo(_, startline, startcolumn, _, _)
|
||||
|
|
||||
c order by startline, startcolumn
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class NodeRegion instanceof Unit {
|
||||
string toString() { result = "NodeRegion" }
|
||||
|
||||
predicate contains(Node n) { none() }
|
||||
|
||||
int totalOrder() { result = 1 }
|
||||
}
|
||||
|
||||
predicate isUnreachableInCall(NodeRegion nr, DataFlowCall call) { none() } // stub implementation
|
||||
|
||||
@@ -112,9 +112,8 @@ module SourceSinkInterpretationInput implements
|
||||
exists(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
||||
|
|
||||
sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance) and
|
||||
e = interpretElement(namespace, type, subtypes, name, signature, ext) and
|
||||
model = "" // TODO
|
||||
sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance, model) and
|
||||
e = interpretElement(namespace, type, subtypes, name, signature, ext)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -128,9 +127,8 @@ module SourceSinkInterpretationInput implements
|
||||
exists(
|
||||
string package, string type, boolean subtypes, string name, string signature, string ext
|
||||
|
|
||||
sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance) and
|
||||
e = interpretElement(package, type, subtypes, name, signature, ext) and
|
||||
model = "" // TODO
|
||||
sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance, model) and
|
||||
e = interpretElement(package, type, subtypes, name, signature, ext)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -383,6 +383,37 @@ class BuiltInOperationIsConvertibleTo extends BuiltInOperation, @isconvtoexpr {
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsConvertibleTo" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__is_convertible` built-in operation (used by some implementations
|
||||
* of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the first type can be converted to the second type.
|
||||
* ```
|
||||
* bool v = __is_convertible(MyType, OtherType);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsConvertible extends BuiltInOperation, @isconvertible {
|
||||
override string toString() { result = "__is_convertible" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsConvertible" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__is_nothrow_convertible` built-in operation (used by some implementations
|
||||
* of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if the first type can be converted to the second type and the
|
||||
* conversion operator has an empty exception specification.
|
||||
* ```
|
||||
* bool v = __is_nothrow_convertible(MyType, OtherType);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsNothrowConvertible extends BuiltInOperation, @isnothrowconvertible {
|
||||
override string toString() { result = "__is_nothrow_convertible" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsNothrowConvertible" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__is_empty` built-in operation (used by some implementations of the
|
||||
* `<type_traits>` header).
|
||||
@@ -647,8 +678,7 @@ class BuiltInOperationIsTriviallyAssignable extends BuiltInOperation, @istrivial
|
||||
* The `__is_nothrow_assignable` built-in operation (used by some
|
||||
* implementations of the `<type_traits>` header).
|
||||
*
|
||||
* Returns true if there exists a `C::operator =(const D& d) nothrow`
|
||||
* assignment operator (i.e, with an empty exception specification).
|
||||
* Returns true if there exists an assignment operator with an empty exception specification.
|
||||
* ```
|
||||
* bool v = __is_nothrow_assignable(MyType1, MyType2);
|
||||
* ```
|
||||
@@ -663,8 +693,7 @@ class BuiltInOperationIsNothrowAssignable extends BuiltInOperation, @isnothrowas
|
||||
* The `__is_assignable` built-in operation (used by some implementations
|
||||
* of the `<type_traits>` header).
|
||||
*
|
||||
* Returns true if there exists a `C::operator =(const D& d)` assignment
|
||||
* operator.
|
||||
* Returns true if there exists an assignment operator.
|
||||
* ```
|
||||
* bool v = __is_assignable(MyType1, MyType2);
|
||||
* ```
|
||||
@@ -675,6 +704,25 @@ class BuiltInOperationIsAssignable extends BuiltInOperation, @isassignable {
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsAssignable" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__is_assignable_no_precondition_check` built-in operation (used by some
|
||||
* implementations of the `<type_traits>` header).
|
||||
*
|
||||
* Returns true if there exists an assignment operator.
|
||||
* ```
|
||||
* bool v = __is_assignable_no_precondition_check(MyType1, MyType2);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsAssignableNoPreconditionCheck extends BuiltInOperation,
|
||||
@isassignablenopreconditioncheck
|
||||
{
|
||||
override string toString() { result = "__is_assignable_no_precondition_check" }
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
result = "BuiltInOperationIsAssignableNoPreconditionCheck"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__is_standard_layout` built-in operation (used by some implementations
|
||||
* of the `<type_traits>` header).
|
||||
@@ -708,6 +756,20 @@ class BuiltInOperationIsTriviallyCopyable extends BuiltInOperation, @istrivially
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyCopyable" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__is_trivially_copy_assignable` built-in operation (used by some
|
||||
* implementations of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if instances of this type can be copied using a trivial
|
||||
* copy operator.
|
||||
*/
|
||||
class BuiltInOperationIsTriviallyCopyAssignable extends BuiltInOperation, @istriviallycopyassignable
|
||||
{
|
||||
override string toString() { result = "__is_trivially_copy_assignable" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyCopyAssignable" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__is_literal_type` built-in operation (used by some implementations of
|
||||
* the `<type_traits>` header).
|
||||
@@ -1062,6 +1124,24 @@ class BuiltInOperationIsSame extends BuiltInOperation, @issame {
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsSame" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__is_same_as` built-in operation (used by some implementations of the
|
||||
* `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if two types are the same.
|
||||
* ```
|
||||
* template<typename _Tp, typename _Up>
|
||||
* struct is_same
|
||||
* : public integral_constant<bool, __is_same_as(_Tp, _Up)>
|
||||
* { };
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsSameAs extends BuiltInOperation, @issameas {
|
||||
override string toString() { result = "__is_same_as" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsSameAs" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__is_function` built-in operation (used by some implementations of the
|
||||
* `<type_traits>` header).
|
||||
@@ -1120,6 +1200,87 @@ class BuiltInOperationIsPointerInterconvertibleBaseOf extends BuiltInOperation,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__is_pointer_interconvertible_with_class` built-in operation (used
|
||||
* by some implementations of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if a member pointer is pointer-interconvertible with a
|
||||
* class type.
|
||||
* ```
|
||||
* template<typename _Tp, typename _Up>
|
||||
* constexpr bool is_pointer_interconvertible_with_class(_Up _Tp::*mp) noexcept
|
||||
* = __is_pointer_interconvertible_with_class(_Tp, mp);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsPointerInterconvertibleWithClass extends BuiltInOperation,
|
||||
@ispointerinterconvertiblewithclass
|
||||
{
|
||||
override string toString() { result = "__is_pointer_interconvertible_with_class" }
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
result = "BuiltInOperationIsPointerInterconvertibleWithClass"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__builtin_is_pointer_interconvertible_with_class` built-in operation (used
|
||||
* by some implementations of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if a member pointer is pointer-interconvertible with a class type.
|
||||
* ```
|
||||
* template<typename _Tp, typename _Up>
|
||||
* constexpr bool is_pointer_interconvertible_with_class(_Up _Tp::*mp) noexcept
|
||||
* = __builtin_is_pointer_interconvertible_with_class(mp);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationBuiltInIsPointerInterconvertible extends BuiltInOperation,
|
||||
@builtinispointerinterconvertiblewithclass
|
||||
{
|
||||
override string toString() { result = "__builtin_is_pointer_interconvertible_with_class" }
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
result = "BuiltInOperationBuiltInIsPointerInterconvertible"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__is_corresponding_member` built-in operation (used
|
||||
* by some implementations of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if two member pointers refer to corresponding
|
||||
* members in the initial sequences of two class types.
|
||||
* ```
|
||||
* template<typename _Tp1, typename _Tp2, typename _Up1, typename _Up2>
|
||||
* constexpr bool is_corresponding_member(_Up1 _Tp1::*mp1, _Up2 _Tp2::*mp2 ) noexcept
|
||||
* = __is_corresponding_member(_Tp1, _Tp2, mp1, mp2);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsCorrespondingMember extends BuiltInOperation, @iscorrespondingmember {
|
||||
override string toString() { result = "__is_corresponding_member" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsCorrespondingMember" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__builtin_is_corresponding_member` built-in operation (used
|
||||
* by some implementations of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if two member pointers refer to corresponding
|
||||
* members in the initial sequences of two class types.
|
||||
* ```
|
||||
* template<typename _Tp1, typename _Tp2, typename _Up1, typename _Up2>
|
||||
* constexpr bool is_corresponding_member(_Up1 _Tp1::*mp1, _Up2 _Tp2::*mp2 ) noexcept
|
||||
* = __builtin_is_corresponding_member(mp1, mp2);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationBuiltInIsCorrespondingMember extends BuiltInOperation,
|
||||
@builtiniscorrespondingmember
|
||||
{
|
||||
override string toString() { result = "__builtin_is_corresponding_member" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInIsCorrespondingMember" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__is_array` built-in operation (used by some implementations of the
|
||||
* `<type_traits>` header).
|
||||
@@ -1138,6 +1299,42 @@ class BuiltInOperationIsArray extends BuiltInOperation, @isarray {
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsArray" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__is_bounded_array` built-in operation (used by some implementations
|
||||
* of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if a type is a bounded array type.
|
||||
* ```
|
||||
* template<typename _Tp>
|
||||
* struct is_bounded_array
|
||||
* : public integral_constant<bool, __is_bounded_array(_Tp)>
|
||||
* { };
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsBoundedArray extends BuiltInOperation, @isboundedarray {
|
||||
override string toString() { result = "__is_bounded_array" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsBoundedArray" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__is_unbounded_array` built-in operation (used by some implementations
|
||||
* of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if a type is an unbounded array type.
|
||||
* ```
|
||||
* template<typename _Tp>
|
||||
* struct is_bounded_array
|
||||
* : public integral_constant<bool, __is_unbounded_array(_Tp)>
|
||||
* { };
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsUnboundedArray extends BuiltInOperation, @isunboundedarray {
|
||||
override string toString() { result = "__is_unbounded_array" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsUnboundedArray" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__array_rank` built-in operation (used by some implementations of the
|
||||
* `<type_traits>` header).
|
||||
@@ -1554,10 +1751,10 @@ class BuiltInBitCast extends BuiltInOperation, @builtinbitcast {
|
||||
*
|
||||
* Returns `true` if a type is a trivial type.
|
||||
* ```
|
||||
* template<typename _Tp>
|
||||
* struct is_trivial
|
||||
* : public integral_constant<bool, __is_trivial(_Tp)>
|
||||
* {};
|
||||
* template<typename _Tp>
|
||||
* struct is_trivial
|
||||
* : public integral_constant<bool, __is_trivial(_Tp)>
|
||||
* {};
|
||||
* ```
|
||||
*/
|
||||
class BuiltInIsTrivial extends BuiltInOperation, @istrivialexpr {
|
||||
@@ -1565,3 +1762,126 @@ class BuiltInIsTrivial extends BuiltInOperation, @istrivialexpr {
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInIsTrivial" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__reference_constructs_from_temporary` built-in operation
|
||||
* (used by some implementations of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if a reference type `_Tp` is bound to an expression of
|
||||
* type `_Up` in direct-initialization, and a temporary object is bound.
|
||||
* ```
|
||||
* template<typename _Tp, typename _Up>
|
||||
* struct reference_constructs_from_temporary
|
||||
* : public integral_constant<bool, __reference_constructs_from_temporary(_Tp, _Up)>
|
||||
* {};
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationReferenceConstructsFromTemporary extends BuiltInOperation,
|
||||
@referenceconstructsfromtemporary
|
||||
{
|
||||
override string toString() { result = "__reference_constructs_from_temporary" }
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
result = "BuiltInOperationReferenceConstructsFromTemporary"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__reference_converts_from_temporary` built-in operation
|
||||
* (used by some implementations of the `<type_traits>` header).
|
||||
*
|
||||
* Returns `true` if a reference type `_Tp` is bound to an expression of
|
||||
* type `_Up` in copy-initialization, and a temporary object is bound.
|
||||
* ```
|
||||
* template<typename _Tp, typename _Up>
|
||||
* struct reference_converts_from_temporary
|
||||
* : public integral_constant<bool, __reference_converts_from_temporary(_Tp, _Up)>
|
||||
* {};
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationReferenceCovertsFromTemporary extends BuiltInOperation,
|
||||
@referenceconvertsfromtemporary
|
||||
{
|
||||
override string toString() { result = "__reference_converts_from_temporary" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationReferenceCovertsFromTemporary" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__reference_binds_to_temporary` built-in operation (used by some
|
||||
* implementations of the `<tuple>` header).
|
||||
*
|
||||
* Returns `true` if a reference of type `Type1` is bound to an expression of
|
||||
* type `Type1`, and a temporary object is bound.
|
||||
* ```
|
||||
* __reference_binds_to_temporary(Type1, Type2)
|
||||
*/
|
||||
class BuiltInOperationReferenceBindsToTemporary extends BuiltInOperation, @referencebindstotemporary
|
||||
{
|
||||
override string toString() { result = "__reference_binds_to_temporary" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationReferenceBindsToTemporary" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__builtin_has_attribute` built-in operation.
|
||||
*
|
||||
* Returns `true` if a type or expression has been declared with the
|
||||
* specified attribute.
|
||||
* ```
|
||||
* __attribute__ ((aligned(8))) int v;
|
||||
* bool has_attribute = __builtin_has_attribute(v, aligned);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationHasAttribute extends BuiltInOperation, @builtinhasattribute {
|
||||
override string toString() { result = "__builtin_has_attribute" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasAttribute" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C++ `__is_referenceable` built-in operation.
|
||||
*
|
||||
* Returns `true` if a type can be referenced.
|
||||
* ```
|
||||
* bool is_referenceable = __is_referenceable(int);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsReferenceable extends BuiltInOperation, @isreferenceable {
|
||||
override string toString() { result = "__is_referenceable" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsReferenceable" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__is_valid_winrt_type` built-in operation. This is a Microsoft extension.
|
||||
*
|
||||
* Returns `true` if the type is a valid WinRT type.
|
||||
*/
|
||||
class BuiltInOperationIsValidWinRtType extends BuiltInOperation, @isvalidwinrttype {
|
||||
override string toString() { result = "__is_valid_winrt_type" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsValidWinRtType" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__is_win_class` built-in operation. This is a Microsoft extension.
|
||||
*
|
||||
* Returns `true` if the class is a ref class.
|
||||
*/
|
||||
class BuiltInOperationIsWinClass extends BuiltInOperation, @iswinclass {
|
||||
override string toString() { result = "__is_win_class" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsWinClass" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `__is_win_class` built-in operation. This is a Microsoft extension.
|
||||
*
|
||||
* Returns `true` if the class is an interface class.
|
||||
*/
|
||||
class BuiltInOperationIsWinInterface extends BuiltInOperation, @iswininterface {
|
||||
override string toString() { result = "__is_win_interface" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsWinInterface" }
|
||||
}
|
||||
|
||||
@@ -307,6 +307,10 @@ class Expr extends StmtParent, @expr {
|
||||
)
|
||||
or
|
||||
exists(Decltype d | d.getExpr() = this.getParentWithConversions*())
|
||||
or
|
||||
exists(ConstexprIfStmt constIf |
|
||||
constIf.getControllingExpr() = this.getParentWithConversions*()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -855,6 +859,16 @@ class NewOrNewArrayExpr extends Expr, @any_new_expr {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the deallocation function is a destroying delete.
|
||||
*/
|
||||
predicate isDestroyingDeleteDeallocation() {
|
||||
exists(int form |
|
||||
expr_deallocator(underlyingElement(this), _, form) and
|
||||
form.bitAnd(4) != 0 // Bit two is the "destroying delete" bit
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type that is being allocated.
|
||||
*
|
||||
@@ -949,6 +963,16 @@ class NewArrayExpr extends NewOrNewArrayExpr, @new_array_expr {
|
||||
* gives nothing, as the 10 is considered part of the type.
|
||||
*/
|
||||
Expr getExtent() { result = this.getChild(2) }
|
||||
|
||||
/**
|
||||
* Gets the number of elements in the array, if available.
|
||||
*
|
||||
* For example, `new int[]{1,2,3}` has an array size of 3.
|
||||
*/
|
||||
int getArraySize() {
|
||||
result = this.getAllocatedType().(ArrayType).getArraySize() or
|
||||
result = this.getInitializer().(ArrayAggregateLiteral).getArraySize()
|
||||
}
|
||||
}
|
||||
|
||||
private class TDeleteOrDeleteArrayExpr = @delete_expr or @delete_array_expr;
|
||||
@@ -1015,6 +1039,16 @@ class DeleteOrDeleteArrayExpr extends Expr, TDeleteOrDeleteArrayExpr {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the deallocation function is a destroying delete.
|
||||
*/
|
||||
predicate isDestroyingDeleteDeallocation() {
|
||||
exists(int form |
|
||||
expr_deallocator(underlyingElement(this), _, form) and
|
||||
form.bitAnd(4) != 0 // Bit two is the "destroying delete" bit
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the object or array being deleted.
|
||||
*/
|
||||
|
||||
@@ -290,14 +290,6 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate sourceGrouping(Node source, string sourceGroup) {
|
||||
any(Configuration config).sourceGrouping(source, sourceGroup)
|
||||
}
|
||||
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) {
|
||||
any(Configuration config).sinkGrouping(sink, sinkGroup)
|
||||
}
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
}
|
||||
|
||||
|
||||
@@ -290,14 +290,6 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate sourceGrouping(Node source, string sourceGroup) {
|
||||
any(Configuration config).sourceGrouping(source, sourceGroup)
|
||||
}
|
||||
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) {
|
||||
any(Configuration config).sinkGrouping(sink, sinkGroup)
|
||||
}
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
}
|
||||
|
||||
|
||||
@@ -290,14 +290,6 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate sourceGrouping(Node source, string sourceGroup) {
|
||||
any(Configuration config).sourceGrouping(source, sourceGroup)
|
||||
}
|
||||
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) {
|
||||
any(Configuration config).sinkGrouping(sink, sinkGroup)
|
||||
}
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
}
|
||||
|
||||
|
||||
@@ -290,14 +290,6 @@ deprecated private module Config implements FullStateConfigSig {
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate sourceGrouping(Node source, string sourceGroup) {
|
||||
any(Configuration config).sourceGrouping(source, sourceGroup)
|
||||
}
|
||||
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) {
|
||||
any(Configuration config).sinkGrouping(sink, sinkGroup)
|
||||
}
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ private import Node0ToString
|
||||
private import ModelUtil
|
||||
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs as IO
|
||||
private import semmle.code.cpp.models.interfaces.DataFlow as DF
|
||||
private import semmle.code.cpp.dataflow.ExternalFlow as External
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
@@ -993,9 +994,6 @@ DataFlowType getNodeType(Node n) {
|
||||
result instanceof VoidType // stub implementation
|
||||
}
|
||||
|
||||
/** Gets a string representation of a type returned by `getNodeType`. */
|
||||
string ppReprType(DataFlowType t) { none() } // stub implementation
|
||||
|
||||
/**
|
||||
* Holds if `t1` and `t2` are compatible, that is, whether data can flow from
|
||||
* a node of type `t1` to a node of type `t2`.
|
||||
@@ -1060,16 +1058,6 @@ class DataFlowCallable extends TDataFlowCallable {
|
||||
result = this.asSummarizedCallable() or // SummarizedCallable = Function (in CPP)
|
||||
result = this.asSourceCallable()
|
||||
}
|
||||
|
||||
/** Gets a best-effort total ordering. */
|
||||
int totalorder() {
|
||||
this =
|
||||
rank[result](DataFlowCallable c, string file, int startline, int startcolumn |
|
||||
c.getLocation().hasLocationInfo(file, startline, startcolumn, _, _)
|
||||
|
|
||||
c order by file, startline, startcolumn
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1106,7 +1094,11 @@ class SummarizedCallable extends DataFlowCallable, TSummarizedCallable {
|
||||
|
||||
class DataFlowExpr = Expr;
|
||||
|
||||
class DataFlowType = Type;
|
||||
final private class TypeFinal = Type;
|
||||
|
||||
class DataFlowType extends TypeFinal {
|
||||
string toString() { result = "" }
|
||||
}
|
||||
|
||||
cached
|
||||
private newtype TDataFlowCall =
|
||||
@@ -1167,16 +1159,6 @@ class DataFlowCall extends TDataFlowCall {
|
||||
* Gets the location of this call.
|
||||
*/
|
||||
Location getLocation() { none() }
|
||||
|
||||
/** Gets a best-effort total ordering. */
|
||||
int totalorder() {
|
||||
this =
|
||||
rank[result](DataFlowCall c, int startline, int startcolumn |
|
||||
c.getLocation().hasLocationInfo(_, startline, startcolumn, _, _)
|
||||
|
|
||||
c order by startline, startcolumn
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1269,15 +1251,6 @@ module IsUnreachableInCall {
|
||||
string toString() { result = "NodeRegion" }
|
||||
|
||||
predicate contains(Node n) { this = n.getBasicBlock() }
|
||||
|
||||
int totalOrder() {
|
||||
this =
|
||||
rank[result](IRBlock b, int startline, int startcolumn |
|
||||
b.getLocation().hasLocationInfo(_, startline, startcolumn, _, _)
|
||||
|
|
||||
b order by startline, startcolumn
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
predicate isUnreachableInCall(NodeRegion block, DataFlowCall call) {
|
||||
@@ -1362,9 +1335,9 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
|
||||
/** Extra data-flow steps needed for lambda flow analysis. */
|
||||
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }
|
||||
|
||||
predicate knownSourceModel(Node source, string model) { none() }
|
||||
predicate knownSourceModel(Node source, string model) { External::sourceNode(source, _, model) }
|
||||
|
||||
predicate knownSinkModel(Node sink, string model) { none() }
|
||||
predicate knownSinkModel(Node sink, string model) { External::sinkNode(sink, _, model) }
|
||||
|
||||
/**
|
||||
* Holds if flow is allowed to pass from parameter `p` and back to itself as a
|
||||
|
||||
@@ -104,7 +104,7 @@ predicate hasRawIndirectInstruction(Instruction instr, int indirectionIndex) {
|
||||
|
||||
cached
|
||||
private newtype TDefImpl =
|
||||
TDefAddressImpl(BaseIRVariable v) or
|
||||
TDefAddressImpl(BaseSourceVariable v) or
|
||||
TDirectDefImpl(Operand address, int indirectionIndex) {
|
||||
isDef(_, _, address, _, _, indirectionIndex)
|
||||
} or
|
||||
@@ -325,9 +325,9 @@ private Instruction getInitializationTargetAddress(IRVariable v) {
|
||||
)
|
||||
}
|
||||
|
||||
/** An initial definition of an `IRVariable`'s address. */
|
||||
private class DefAddressImpl extends DefImpl, TDefAddressImpl {
|
||||
BaseIRVariable v;
|
||||
/** An initial definition of an SSA variable address. */
|
||||
abstract private class DefAddressImpl extends DefImpl, TDefAddressImpl {
|
||||
BaseSourceVariable v;
|
||||
|
||||
DefAddressImpl() {
|
||||
this = TDefAddressImpl(v) and
|
||||
@@ -342,6 +342,19 @@ private class DefAddressImpl extends DefImpl, TDefAddressImpl {
|
||||
|
||||
final override Node0Impl getValue() { none() }
|
||||
|
||||
override Cpp::Location getLocation() { result = v.getLocation() }
|
||||
|
||||
final override SourceVariable getSourceVariable() {
|
||||
result.getBaseVariable() = v and
|
||||
result.getIndirection() = 0
|
||||
}
|
||||
|
||||
final override BaseSourceVariable getBaseSourceVariable() { result = v }
|
||||
}
|
||||
|
||||
private class DefVariableAddressImpl extends DefAddressImpl {
|
||||
override BaseIRVariable v;
|
||||
|
||||
final override predicate hasIndexInBlock(IRBlock block, int index) {
|
||||
exists(IRVariable var | var = v.getIRVariable() |
|
||||
block.getInstruction(index) = getInitializationTargetAddress(var)
|
||||
@@ -353,15 +366,14 @@ private class DefAddressImpl extends DefImpl, TDefAddressImpl {
|
||||
index = 0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override Cpp::Location getLocation() { result = v.getIRVariable().getLocation() }
|
||||
private class DefCallAddressImpl extends DefAddressImpl {
|
||||
override BaseCallVariable v;
|
||||
|
||||
final override SourceVariable getSourceVariable() {
|
||||
result.getBaseVariable() = v and
|
||||
result.getIndirection() = 0
|
||||
final override predicate hasIndexInBlock(IRBlock block, int index) {
|
||||
block.getInstruction(index) = v.getCallInstruction()
|
||||
}
|
||||
|
||||
final override BaseSourceVariable getBaseSourceVariable() { result = v }
|
||||
}
|
||||
|
||||
private class DirectDef extends DefImpl, TDirectDefImpl {
|
||||
|
||||
@@ -40,7 +40,8 @@ predicate ignoreInstruction(Instruction instr) {
|
||||
instr instanceof AliasedDefinitionInstruction or
|
||||
instr instanceof AliasedUseInstruction or
|
||||
instr instanceof InitializeNonLocalInstruction or
|
||||
instr instanceof ReturnIndirectionInstruction
|
||||
instr instanceof ReturnIndirectionInstruction or
|
||||
instr instanceof UninitializedGroupInstruction
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,8 @@ private newtype TMemoryAccessKind =
|
||||
TPhiMemoryAccess() or
|
||||
TUnmodeledMemoryAccess() or
|
||||
TChiTotalMemoryAccess() or
|
||||
TChiPartialMemoryAccess()
|
||||
TChiPartialMemoryAccess() or
|
||||
TGroupedMemoryAccess()
|
||||
|
||||
/**
|
||||
* Describes the set of memory locations memory accessed by a memory operand or
|
||||
@@ -99,3 +100,11 @@ class ChiTotalMemoryAccess extends MemoryAccessKind, TChiTotalMemoryAccess {
|
||||
class ChiPartialMemoryAccess extends MemoryAccessKind, TChiPartialMemoryAccess {
|
||||
override string toString() { result = "chi(partial)" }
|
||||
}
|
||||
|
||||
/**
|
||||
* The result of an `UninitializedGroup` instruction, which initializes a set of
|
||||
* allocations that are each assigned the same virtual variable.
|
||||
*/
|
||||
class GroupedMemoryAccess extends MemoryAccessKind, TGroupedMemoryAccess {
|
||||
override string toString() { result = "group" }
|
||||
}
|
||||
|
||||
@@ -89,6 +89,7 @@ private newtype TOpcode =
|
||||
TSizedBufferMayWriteSideEffect() or
|
||||
TInitializeDynamicAllocation() or
|
||||
TChi() or
|
||||
TUninitializedGroup() or
|
||||
TInlineAsm() or
|
||||
TUnreached() or
|
||||
TNewObj()
|
||||
@@ -1237,6 +1238,17 @@ module Opcode {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `Opcode` for a `UninitializedGroup`.
|
||||
*
|
||||
* See the `UninitializedGroupInstruction` documentation for more details.
|
||||
*/
|
||||
class UninitializedGroup extends Opcode, TUninitializedGroup {
|
||||
final override string toString() { result = "UninitializedGroup" }
|
||||
|
||||
override GroupedMemoryAccess getWriteMemoryAccess() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The `Opcode` for an `InlineAsmInstruction`.
|
||||
*
|
||||
|
||||
@@ -2142,6 +2142,47 @@ class ChiInstruction extends Instruction {
|
||||
final predicate isPartialUpdate() { Construction::chiOnlyPartiallyUpdatesLocation(this) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that initializes a set of allocations that are each assigned
|
||||
* the same "virtual variable".
|
||||
*
|
||||
* As an example, consider the following snippet:
|
||||
* ```
|
||||
* int a;
|
||||
* int b;
|
||||
* int* p;
|
||||
* if(b) {
|
||||
* p = &a;
|
||||
* } else {
|
||||
* p = &b;
|
||||
* }
|
||||
* *p = 5;
|
||||
* int x = a;
|
||||
* ```
|
||||
*
|
||||
* Since both the address of `a` and `b` reach `p` at `*p = 5` the IR alias
|
||||
* analysis will create a region that contains both `a` and `b`. The region
|
||||
* containing both `a` and `b` are initialized by an `UninitializedGroup`
|
||||
* instruction in the entry block of the enclosing function.
|
||||
*/
|
||||
class UninitializedGroupInstruction extends Instruction {
|
||||
UninitializedGroupInstruction() { this.getOpcode() instanceof Opcode::UninitializedGroup }
|
||||
|
||||
/**
|
||||
* Gets an `IRVariable` whose memory is initialized by this instruction, if any.
|
||||
* Note: Allocations that are not represented as `IRVariable`s (such as
|
||||
* dynamic allocations) are not returned by this predicate even if this
|
||||
* instruction initializes such memory.
|
||||
*/
|
||||
final IRVariable getAnIRVariable() {
|
||||
result = Construction::getAnUninitializedGroupVariable(this)
|
||||
}
|
||||
|
||||
final override string getImmediateString() {
|
||||
result = strictconcat(this.getAnIRVariable().toString(), ",")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing unreachable code.
|
||||
*
|
||||
|
||||
@@ -106,8 +106,7 @@ private predicate operandEscapesDomain(Operand operand) {
|
||||
not isArgumentForParameter(_, operand, _) and
|
||||
not isOnlyEscapesViaReturnArgument(operand) and
|
||||
not operand.getUse() instanceof ReturnValueInstruction and
|
||||
not operand.getUse() instanceof ReturnIndirectionInstruction and
|
||||
not operand instanceof PhiInputOperand
|
||||
not operand.getUse() instanceof ReturnIndirectionInstruction
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -191,6 +190,11 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset, Instr
|
||||
// A copy propagates the source value.
|
||||
operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0
|
||||
)
|
||||
or
|
||||
operand = instr.(PhiInstruction).getAnInputOperand() and
|
||||
// Using `unknown` ensures termination since we cannot keep incrementing a bit offset
|
||||
// through the back edge of a loop (or through recursion).
|
||||
bitOffset = Ints::unknown()
|
||||
}
|
||||
|
||||
private predicate operandEscapesNonReturn(Operand operand) {
|
||||
@@ -212,9 +216,6 @@ private predicate operandEscapesNonReturn(Operand operand) {
|
||||
or
|
||||
isOnlyEscapesViaReturnArgument(operand) and resultEscapesNonReturn(operand.getUse())
|
||||
or
|
||||
operand instanceof PhiInputOperand and
|
||||
resultEscapesNonReturn(operand.getUse())
|
||||
or
|
||||
operandEscapesDomain(operand)
|
||||
}
|
||||
|
||||
@@ -236,9 +237,6 @@ private predicate operandMayReachReturn(Operand operand) {
|
||||
operand.getUse() instanceof ReturnValueInstruction
|
||||
or
|
||||
isOnlyEscapesViaReturnArgument(operand) and resultMayReachReturn(operand.getUse())
|
||||
or
|
||||
operand instanceof PhiInputOperand and
|
||||
resultMayReachReturn(operand.getUse())
|
||||
}
|
||||
|
||||
private predicate operandReturned(Operand operand, IntValue bitOffset) {
|
||||
@@ -340,6 +338,56 @@ private predicate resultEscapesNonReturn(Instruction instr) {
|
||||
not instr.isResultModeled()
|
||||
}
|
||||
|
||||
/** Holds if `operand` may (transitively) flow to an `AddressOperand`. */
|
||||
private predicate consumedAsAddressOperand(Operand operand) {
|
||||
operand instanceof AddressOperand
|
||||
or
|
||||
exists(Operand address |
|
||||
consumedAsAddressOperand(address) and
|
||||
operandIsPropagated(operand, _, address.getDef())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `operand` may originate from a base instruction of an allocation,
|
||||
* and that operand may transitively flow to an `AddressOperand`.
|
||||
*/
|
||||
private predicate propagatedFromAllocationBase(Operand operand, Configuration::Allocation allocation) {
|
||||
consumedAsAddressOperand(operand) and
|
||||
(
|
||||
not exists(Configuration::getOldAllocation(allocation)) and
|
||||
operand.getDef() = allocation.getABaseInstruction()
|
||||
or
|
||||
exists(Operand address |
|
||||
operandIsPropagated(address, _, operand.getDef()) and
|
||||
propagatedFromAllocationBase(address, allocation)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate propagatedFromNonAllocationBase(Operand operand) {
|
||||
exists(Instruction def |
|
||||
def = operand.getDef() and
|
||||
not operandIsPropagated(_, _, def) and
|
||||
not def = any(Configuration::Allocation allocation).getABaseInstruction()
|
||||
)
|
||||
or
|
||||
exists(Operand address |
|
||||
operandIsPropagated(address, _, operand.getDef()) and
|
||||
propagatedFromNonAllocationBase(address)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if we cannot see all producers of an operand for which allocation also flows into.
|
||||
*/
|
||||
private predicate operandConsumesEscaped(Configuration::Allocation allocation) {
|
||||
exists(AddressOperand address |
|
||||
propagatedFromAllocationBase(address, allocation) and
|
||||
propagatedFromNonAllocationBase(address)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the address of `allocation` escapes outside the domain of the analysis. This can occur
|
||||
* either because the allocation's address is taken within the function and escapes, or because the
|
||||
@@ -348,12 +396,14 @@ private predicate resultEscapesNonReturn(Instruction instr) {
|
||||
predicate allocationEscapes(Configuration::Allocation allocation) {
|
||||
allocation.alwaysEscapes()
|
||||
or
|
||||
exists(IREscapeAnalysisConfiguration config |
|
||||
config.useSoundEscapeAnalysis() and resultEscapesNonReturn(allocation.getABaseInstruction())
|
||||
exists(IREscapeAnalysisConfiguration config | config.useSoundEscapeAnalysis() |
|
||||
resultEscapesNonReturn(allocation.getABaseInstruction())
|
||||
or
|
||||
operandConsumesEscaped(allocation)
|
||||
)
|
||||
or
|
||||
Configuration::phaseNeedsSoundEscapeAnalysis() and
|
||||
resultEscapesNonReturn(allocation.getABaseInstruction())
|
||||
(resultEscapesNonReturn(allocation.getABaseInstruction()) or operandConsumesEscaped(allocation))
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -101,6 +101,8 @@ class IndirectParameterAllocation extends Allocation, TIndirectParameterAllocati
|
||||
final override predicate isAlwaysAllocatedOnStack() { none() }
|
||||
|
||||
final override predicate alwaysEscapes() { none() }
|
||||
|
||||
final IRAutomaticVariable getIRVariable() { result = var }
|
||||
}
|
||||
|
||||
class DynamicAllocation extends Allocation, TDynamicAllocation {
|
||||
@@ -144,3 +146,8 @@ class DynamicAllocation extends Allocation, TDynamicAllocation {
|
||||
}
|
||||
|
||||
predicate phaseNeedsSoundEscapeAnalysis() { none() }
|
||||
|
||||
UnaliasedSsa::Allocation getOldAllocation(VariableAllocation allocation) {
|
||||
UnaliasedSsa::canReuseSsaForVariable(allocation.getIRVariable()) and
|
||||
result = allocation.getIRVariable()
|
||||
}
|
||||
|
||||
@@ -7,7 +7,8 @@ private import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConst
|
||||
private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
|
||||
private import semmle.code.cpp.ir.internal.IntegerInterval as Interval
|
||||
private import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||
private import AliasConfiguration
|
||||
import AliasConfiguration
|
||||
private import codeql.util.Boolean
|
||||
|
||||
private class IntValue = Ints::IntValue;
|
||||
|
||||
@@ -16,49 +17,196 @@ private predicate isIndirectOrBufferMemoryAccess(MemoryAccessKind kind) {
|
||||
kind instanceof BufferMemoryAccess
|
||||
}
|
||||
|
||||
private predicate hasResultMemoryAccess(
|
||||
Instruction instr, Allocation var, IRType type, Language::LanguageType languageType,
|
||||
IntValue startBitOffset, IntValue endBitOffset, boolean isMayAccess
|
||||
private predicate hasMemoryAccess(
|
||||
AddressOperand addrOperand, Allocation var, IntValue startBitOffset, boolean grouped
|
||||
) {
|
||||
exists(AddressOperand addrOperand |
|
||||
addrOperand = instr.getResultAddressOperand() and
|
||||
addressOperandAllocationAndOffset(addrOperand, var, startBitOffset) and
|
||||
languageType = instr.getResultLanguageType() and
|
||||
type = languageType.getIRType() and
|
||||
isIndirectOrBufferMemoryAccess(instr.getResultMemoryAccess()) and
|
||||
(if instr.hasResultMayMemoryAccess() then isMayAccess = true else isMayAccess = false) and
|
||||
if exists(type.getByteSize())
|
||||
then endBitOffset = Ints::add(startBitOffset, Ints::mul(type.getByteSize(), 8))
|
||||
else endBitOffset = Ints::unknown()
|
||||
)
|
||||
addressOperandAllocationAndOffset(addrOperand, var, startBitOffset) and
|
||||
if strictcount(Allocation alloc | addressOperandAllocationAndOffset(addrOperand, alloc, _)) > 1
|
||||
then grouped = true
|
||||
else grouped = false
|
||||
}
|
||||
|
||||
private predicate hasResultMemoryAccess(
|
||||
AddressOperand address, Instruction instr, Allocation var, IRType type,
|
||||
Language::LanguageType languageType, IntValue startBitOffset, IntValue endBitOffset,
|
||||
boolean isMayAccess, boolean grouped
|
||||
) {
|
||||
address = instr.getResultAddressOperand() and
|
||||
hasMemoryAccess(address, var, startBitOffset, grouped) and
|
||||
languageType = instr.getResultLanguageType() and
|
||||
type = languageType.getIRType() and
|
||||
isIndirectOrBufferMemoryAccess(instr.getResultMemoryAccess()) and
|
||||
(if instr.hasResultMayMemoryAccess() then isMayAccess = true else isMayAccess = false) and
|
||||
if exists(type.getByteSize())
|
||||
then endBitOffset = Ints::add(startBitOffset, Ints::mul(type.getByteSize(), 8))
|
||||
else endBitOffset = Ints::unknown()
|
||||
}
|
||||
|
||||
private predicate hasOperandMemoryAccess(
|
||||
MemoryOperand operand, Allocation var, IRType type, Language::LanguageType languageType,
|
||||
IntValue startBitOffset, IntValue endBitOffset, boolean isMayAccess
|
||||
AddressOperand address, MemoryOperand operand, Allocation var, IRType type,
|
||||
Language::LanguageType languageType, IntValue startBitOffset, IntValue endBitOffset,
|
||||
boolean isMayAccess, boolean grouped
|
||||
) {
|
||||
exists(AddressOperand addrOperand |
|
||||
addrOperand = operand.getAddressOperand() and
|
||||
addressOperandAllocationAndOffset(addrOperand, var, startBitOffset) and
|
||||
languageType = operand.getLanguageType() and
|
||||
type = languageType.getIRType() and
|
||||
isIndirectOrBufferMemoryAccess(operand.getMemoryAccess()) and
|
||||
(if operand.hasMayReadMemoryAccess() then isMayAccess = true else isMayAccess = false) and
|
||||
if exists(type.getByteSize())
|
||||
then endBitOffset = Ints::add(startBitOffset, Ints::mul(type.getByteSize(), 8))
|
||||
else endBitOffset = Ints::unknown()
|
||||
address = operand.getAddressOperand() and
|
||||
hasMemoryAccess(address, var, startBitOffset, grouped) and
|
||||
languageType = operand.getLanguageType() and
|
||||
type = languageType.getIRType() and
|
||||
isIndirectOrBufferMemoryAccess(operand.getMemoryAccess()) and
|
||||
(if operand.hasMayReadMemoryAccess() then isMayAccess = true else isMayAccess = false) and
|
||||
if exists(type.getByteSize())
|
||||
then endBitOffset = Ints::add(startBitOffset, Ints::mul(type.getByteSize(), 8))
|
||||
else endBitOffset = Ints::unknown()
|
||||
}
|
||||
|
||||
private Allocation getAnAllocation(AddressOperand address) {
|
||||
hasResultMemoryAccess(address, _, result, _, _, _, _, _, true) or
|
||||
hasOperandMemoryAccess(address, _, result, _, _, _, _, _, true)
|
||||
}
|
||||
|
||||
private module AllocationSet0 =
|
||||
QlBuiltins::InternSets<AddressOperand, Allocation, getAnAllocation/1>;
|
||||
|
||||
/**
|
||||
* A set of allocations containing at least 2 elements.
|
||||
*/
|
||||
private class NonSingletonSets extends AllocationSet0::Set {
|
||||
NonSingletonSets() { strictcount(Allocation var | this.contains(var)) > 1 }
|
||||
|
||||
/** Gets an allocation from this set. */
|
||||
Allocation getAnAllocation() { this.contains(result) }
|
||||
|
||||
/** Gets the string representation of this set. */
|
||||
string toString() { result = "{" + strictconcat(this.getAnAllocation().toString(), ", ") + "}" }
|
||||
}
|
||||
|
||||
/** Holds the instersection of `s1` and `s2` is non-empty. */
|
||||
private predicate hasOverlappingElement(NonSingletonSets s1, NonSingletonSets s2) {
|
||||
exists(Allocation var |
|
||||
s1.contains(var) and
|
||||
s2.contains(var)
|
||||
)
|
||||
}
|
||||
|
||||
private module AllocationSet =
|
||||
QlBuiltins::EquivalenceRelation<NonSingletonSets, hasOverlappingElement/2>;
|
||||
|
||||
/**
|
||||
* Holds if `var` is created by the AST element `e`. Furthermore, the value `d`
|
||||
* represents which branch of the `Allocation` type `var` is from.
|
||||
*/
|
||||
private predicate allocationAst(Allocation var, @element e, int d) {
|
||||
var.(VariableAllocation).getIRVariable().getAst() = e and d = 0
|
||||
or
|
||||
var.(IndirectParameterAllocation).getIRVariable().getAst() = e and d = 1
|
||||
or
|
||||
var.(DynamicAllocation).getABaseInstruction().getAst() = e and d = 2
|
||||
}
|
||||
|
||||
/** Holds if `x = y` and `x` is an AST element that creates an `Allocation`. */
|
||||
private predicate id(@element x, @element y) {
|
||||
allocationAst(_, x, _) and
|
||||
x = y
|
||||
}
|
||||
|
||||
private predicate idOf(@element x, int y) = equivalenceRelation(id/2)(x, y)
|
||||
|
||||
/** Gets a unique integer representation of `var`. */
|
||||
private int getUniqueAllocationId(Allocation var) {
|
||||
exists(int r, @element e, int d |
|
||||
allocationAst(var, e, d) and
|
||||
idOf(e, r) and
|
||||
result = 3 * r + d
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* An equivalence class of a set of allocations.
|
||||
*
|
||||
* Any `VariableGroup` will be completely disjunct from any other
|
||||
* `VariableGroup`.
|
||||
*/
|
||||
class VariableGroup extends AllocationSet::EquivalenceClass {
|
||||
/** Gets the location of this set. */
|
||||
final Location getLocation() { result = this.getIRFunction().getLocation() }
|
||||
|
||||
/** Gets the enclosing `IRFunction` of this set. */
|
||||
final IRFunction getIRFunction() {
|
||||
result = unique( | | this.getAnAllocation().getEnclosingIRFunction())
|
||||
}
|
||||
|
||||
/** Gets the type of elements contained in this set. */
|
||||
final Language::LanguageType getType() {
|
||||
strictcount(Language::LanguageType langType |
|
||||
exists(Allocation var | var = this.getAnAllocation() |
|
||||
hasResultMemoryAccess(_, _, var, _, langType, _, _, _, true) or
|
||||
hasOperandMemoryAccess(_, _, var, _, langType, _, _, _, true)
|
||||
)
|
||||
) = 1 and
|
||||
exists(Allocation var | var = this.getAnAllocation() |
|
||||
hasResultMemoryAccess(_, _, var, _, result, _, _, _, true) or
|
||||
hasOperandMemoryAccess(_, _, var, _, result, _, _, _, true)
|
||||
)
|
||||
or
|
||||
strictcount(Language::LanguageType langType |
|
||||
exists(Allocation var | var = this.getAnAllocation() |
|
||||
hasResultMemoryAccess(_, _, var, _, langType, _, _, _, true) or
|
||||
hasOperandMemoryAccess(_, _, var, _, langType, _, _, _, true)
|
||||
)
|
||||
) > 1 and
|
||||
result = any(IRUnknownType type).getCanonicalLanguageType()
|
||||
}
|
||||
|
||||
/** Gets an allocation of this set. */
|
||||
final Allocation getAnAllocation() {
|
||||
exists(AllocationSet0::Set set |
|
||||
this = AllocationSet::getEquivalenceClass(set) and
|
||||
set.contains(result)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a unique string representing this set. */
|
||||
final private string getUniqueId() {
|
||||
result = strictconcat(getUniqueAllocationId(this.getAnAllocation()).toString(), ",")
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the order that this set should be initialized in.
|
||||
*
|
||||
* Note: This is _not_ the order in which the _members_ of the set should be
|
||||
* initialized. Rather, it represents the order in which the set should be
|
||||
* initialized in relation to other sets. That is, if
|
||||
* ```
|
||||
* getInitializationOrder() = 2
|
||||
* ```
|
||||
* then this set will be initialized as the second (third) set in the
|
||||
* enclosing function. In order words, the third `UninitializedGroup`
|
||||
* instruction in the entry block of the enclosing function will initialize
|
||||
* this set of allocations.
|
||||
*/
|
||||
final int getInitializationOrder() {
|
||||
exists(IRFunction func |
|
||||
func = this.getIRFunction() and
|
||||
this =
|
||||
rank[result + 1](VariableGroup vg, string uniq |
|
||||
vg.getIRFunction() = func and uniq = vg.getUniqueId()
|
||||
|
|
||||
vg order by uniq
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
string toString() { result = "{" + strictconcat(this.getAnAllocation().toString(), ", ") + "}" }
|
||||
}
|
||||
|
||||
private newtype TMemoryLocation =
|
||||
TVariableMemoryLocation(
|
||||
Allocation var, IRType type, Language::LanguageType languageType, IntValue startBitOffset,
|
||||
IntValue endBitOffset, boolean isMayAccess
|
||||
) {
|
||||
(
|
||||
hasResultMemoryAccess(_, var, type, _, startBitOffset, endBitOffset, isMayAccess)
|
||||
hasResultMemoryAccess(_, _, var, type, _, startBitOffset, endBitOffset, isMayAccess, false)
|
||||
or
|
||||
hasOperandMemoryAccess(_, var, type, _, startBitOffset, endBitOffset, isMayAccess)
|
||||
hasOperandMemoryAccess(_, _, var, type, _, startBitOffset, endBitOffset, isMayAccess, false)
|
||||
or
|
||||
// For a stack variable, always create a memory location for the entire variable.
|
||||
var.isAlwaysAllocatedOnStack() and
|
||||
@@ -69,31 +217,25 @@ private newtype TMemoryLocation =
|
||||
) and
|
||||
languageType = type.getCanonicalLanguageType()
|
||||
} or
|
||||
TEntireAllocationMemoryLocation(Allocation var, boolean isMayAccess) {
|
||||
(
|
||||
var instanceof IndirectParameterAllocation or
|
||||
var instanceof DynamicAllocation
|
||||
) and
|
||||
(isMayAccess = false or isMayAccess = true)
|
||||
TEntireAllocationMemoryLocation(Allocation var, Boolean isMayAccess) {
|
||||
var instanceof IndirectParameterAllocation or
|
||||
var instanceof DynamicAllocation
|
||||
} or
|
||||
TUnknownMemoryLocation(IRFunction irFunc, boolean isMayAccess) {
|
||||
isMayAccess = false or isMayAccess = true
|
||||
} or
|
||||
TAllNonLocalMemory(IRFunction irFunc, boolean isMayAccess) {
|
||||
isMayAccess = false or isMayAccess = true
|
||||
} or
|
||||
TAllAliasedMemory(IRFunction irFunc, boolean isMayAccess) {
|
||||
isMayAccess = false or isMayAccess = true
|
||||
}
|
||||
TGroupedMemoryLocation(VariableGroup vg, Boolean isMayAccess, Boolean isAll) or
|
||||
TUnknownMemoryLocation(IRFunction irFunc, Boolean isMayAccess) or
|
||||
TAllNonLocalMemory(IRFunction irFunc, Boolean isMayAccess) or
|
||||
TAllAliasedMemory(IRFunction irFunc, Boolean isMayAccess)
|
||||
|
||||
/**
|
||||
* Represents the memory location accessed by a memory operand or memory result. In this implementation, the location is
|
||||
* A memory location accessed by a memory operand or memory result. In this implementation, the location is
|
||||
* one of the following:
|
||||
* - `VariableMemoryLocation` - A location within a known `IRVariable`, at an offset that is either a constant or is
|
||||
* unknown.
|
||||
* - `UnknownMemoryLocation` - A location not known to be within a specific `IRVariable`.
|
||||
*
|
||||
* Some of these memory locations will be filtered out for performance reasons before being passed to SSA construction.
|
||||
*/
|
||||
abstract class MemoryLocation extends TMemoryLocation {
|
||||
abstract private class MemoryLocation0 extends TMemoryLocation {
|
||||
final string toString() {
|
||||
if this.isMayAccess()
|
||||
then result = "?" + this.toStringInternal()
|
||||
@@ -116,7 +258,14 @@ abstract class MemoryLocation extends TMemoryLocation {
|
||||
|
||||
abstract predicate isMayAccess();
|
||||
|
||||
Allocation getAllocation() { none() }
|
||||
/**
|
||||
* Gets an allocation associated with this `MemoryLocation`.
|
||||
*
|
||||
* This returns zero or one results in all cases except when `this` is an
|
||||
* instance of `GroupedMemoryLocation`. When `this` is an instance of
|
||||
* `GroupedMemoryLocation` this predicate always returns two or more results.
|
||||
*/
|
||||
Allocation getAnAllocation() { none() }
|
||||
|
||||
/**
|
||||
* Holds if the location cannot be overwritten except by definition of a `MemoryLocation` for
|
||||
@@ -147,30 +296,35 @@ abstract class MemoryLocation extends TMemoryLocation {
|
||||
* represented by a `MemoryLocation` that totally overlaps all other
|
||||
* `MemoryLocations` in the set.
|
||||
*/
|
||||
abstract class VirtualVariable extends MemoryLocation { }
|
||||
abstract class VirtualVariable extends MemoryLocation0 { }
|
||||
|
||||
abstract class AllocationMemoryLocation extends MemoryLocation {
|
||||
abstract class AllocationMemoryLocation extends MemoryLocation0 {
|
||||
Allocation var;
|
||||
boolean isMayAccess;
|
||||
|
||||
AllocationMemoryLocation() {
|
||||
this instanceof TMemoryLocation and
|
||||
isMayAccess = false
|
||||
or
|
||||
isMayAccess = true // Just ensures that `isMayAccess` is bound.
|
||||
}
|
||||
bindingset[isMayAccess]
|
||||
AllocationMemoryLocation() { any() }
|
||||
|
||||
final override VirtualVariable getVirtualVariable() {
|
||||
if allocationEscapes(var)
|
||||
then result = TAllAliasedMemory(var.getEnclosingIRFunction(), false)
|
||||
else result.(AllocationMemoryLocation).getAllocation() = var
|
||||
else (
|
||||
// It may be that the grouped memory location contains an escaping
|
||||
// allocation. In that case, the virtual variable is still the memory
|
||||
// location that represents all aliased memory. Thus, we need to
|
||||
// call `getVirtualVariable` on the grouped memory location.
|
||||
result = getGroupedMemoryLocation(var, false, false).getVirtualVariable()
|
||||
or
|
||||
not exists(getGroupedMemoryLocation(var, false, false)) and
|
||||
result.(AllocationMemoryLocation).getAnAllocation() = var
|
||||
)
|
||||
}
|
||||
|
||||
final override IRFunction getIRFunction() { result = var.getEnclosingIRFunction() }
|
||||
|
||||
final override Location getLocation() { result = var.getLocation() }
|
||||
|
||||
final override Allocation getAllocation() { result = var }
|
||||
final override Allocation getAnAllocation() { result = var }
|
||||
|
||||
final override predicate isMayAccess() { isMayAccess = true }
|
||||
|
||||
@@ -211,13 +365,13 @@ class VariableMemoryLocation extends TVariableMemoryLocation, AllocationMemoryLo
|
||||
final override Language::LanguageType getType() {
|
||||
if
|
||||
strictcount(Language::LanguageType accessType |
|
||||
hasResultMemoryAccess(_, var, type, accessType, startBitOffset, endBitOffset, _) or
|
||||
hasOperandMemoryAccess(_, var, type, accessType, startBitOffset, endBitOffset, _)
|
||||
hasResultMemoryAccess(_, _, var, type, accessType, startBitOffset, endBitOffset, _, false) or
|
||||
hasOperandMemoryAccess(_, _, var, type, accessType, startBitOffset, endBitOffset, _, false)
|
||||
) = 1
|
||||
then
|
||||
// All of the accesses have the same `LanguageType`, so just use that.
|
||||
hasResultMemoryAccess(_, var, type, result, startBitOffset, endBitOffset, _) or
|
||||
hasOperandMemoryAccess(_, var, type, result, startBitOffset, endBitOffset, _)
|
||||
hasResultMemoryAccess(_, _, var, type, result, startBitOffset, endBitOffset, _, false) or
|
||||
hasOperandMemoryAccess(_, _, var, type, result, startBitOffset, endBitOffset, _, false)
|
||||
else
|
||||
// There is no single type for all accesses, so just use the canonical one for this `IRType`.
|
||||
result = type.getCanonicalLanguageType()
|
||||
@@ -247,6 +401,89 @@ class VariableMemoryLocation extends TVariableMemoryLocation, AllocationMemoryLo
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A group of allocations represented as a single memory location.
|
||||
*
|
||||
* If `isAll()` holds then this memory location represents all the enclosing
|
||||
* allocations, and if `isSome()` holds then this memory location represents
|
||||
* one or more of the enclosing allocations.
|
||||
*
|
||||
* For example, consider the following snippet:
|
||||
* ```
|
||||
* int* p;
|
||||
* int a, b;
|
||||
* if(b) {
|
||||
* p = &a;
|
||||
* } else {
|
||||
* p = &b;
|
||||
* }
|
||||
* *p = 42;
|
||||
* ```
|
||||
*
|
||||
* The write memory location associated with the write to `*p` writes to a
|
||||
* grouped memory location representing the _some_ allocation in the set
|
||||
* `{a, b}`, and the subsequent `Chi` instruction merges the new value of
|
||||
* `{a, b}` into a memory location that represents _all_ of the allocations
|
||||
* in the set.
|
||||
*/
|
||||
class GroupedMemoryLocation extends TGroupedMemoryLocation, MemoryLocation0 {
|
||||
VariableGroup vg;
|
||||
boolean isMayAccess;
|
||||
boolean isAll;
|
||||
|
||||
GroupedMemoryLocation() { this = TGroupedMemoryLocation(vg, isMayAccess, isAll) }
|
||||
|
||||
final override Location getLocation() { result = vg.getLocation() }
|
||||
|
||||
final override IRFunction getIRFunction() { result = vg.getIRFunction() }
|
||||
|
||||
final override predicate isMayAccess() { isMayAccess = true }
|
||||
|
||||
final override string getUniqueId() {
|
||||
if this.isAll()
|
||||
then result = "All{" + strictconcat(vg.getAnAllocation().getUniqueId(), ", ") + "}"
|
||||
else result = "Some{" + strictconcat(vg.getAnAllocation().getUniqueId(), ", ") + "}"
|
||||
}
|
||||
|
||||
final override string toStringInternal() { result = this.getUniqueId() }
|
||||
|
||||
final override Language::LanguageType getType() { result = vg.getType() }
|
||||
|
||||
final override VirtualVariable getVirtualVariable() {
|
||||
if allocationEscapes(this.getAnAllocation())
|
||||
then result = TAllAliasedMemory(vg.getIRFunction(), false)
|
||||
else result = TGroupedMemoryLocation(vg, false, true)
|
||||
}
|
||||
|
||||
/** Gets an allocation of this memory location. */
|
||||
override Allocation getAnAllocation() { result = vg.getAnAllocation() }
|
||||
|
||||
/** Gets the set of allocations associated with this memory location. */
|
||||
VariableGroup getGroup() { result = vg }
|
||||
|
||||
/** Holds if this memory location represents all the enclosing allocations. */
|
||||
predicate isAll() { isAll = true }
|
||||
|
||||
/** Holds if this memory location represents one or more of the enclosing allocations. */
|
||||
predicate isSome() { isAll = false }
|
||||
}
|
||||
|
||||
private GroupedMemoryLocation getGroupedMemoryLocation(
|
||||
Allocation alloc, boolean isMayAccess, boolean isAll
|
||||
) {
|
||||
result.getAnAllocation() = alloc and
|
||||
(
|
||||
isMayAccess = true and result.isMayAccess()
|
||||
or
|
||||
isMayAccess = false and not result.isMayAccess()
|
||||
) and
|
||||
(
|
||||
isAll = true and result.isAll()
|
||||
or
|
||||
isAll = false and result.isSome()
|
||||
)
|
||||
}
|
||||
|
||||
class EntireAllocationMemoryLocation extends TEntireAllocationMemoryLocation,
|
||||
AllocationMemoryLocation
|
||||
{
|
||||
@@ -282,10 +519,18 @@ class VariableVirtualVariable extends VariableMemoryLocation, VirtualVariable {
|
||||
}
|
||||
}
|
||||
|
||||
class GroupedVirtualVariable extends GroupedMemoryLocation, VirtualVariable {
|
||||
GroupedVirtualVariable() {
|
||||
forex(Allocation var | var = this.getAnAllocation() | not allocationEscapes(var)) and
|
||||
not this.isMayAccess() and
|
||||
this.isAll()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An access to memory that is not known to be confined to a specific `IRVariable`.
|
||||
*/
|
||||
class UnknownMemoryLocation extends TUnknownMemoryLocation, MemoryLocation {
|
||||
class UnknownMemoryLocation extends TUnknownMemoryLocation, MemoryLocation0 {
|
||||
IRFunction irFunc;
|
||||
boolean isMayAccess;
|
||||
|
||||
@@ -312,7 +557,7 @@ class UnknownMemoryLocation extends TUnknownMemoryLocation, MemoryLocation {
|
||||
* An access to memory that is not known to be confined to a specific `IRVariable`, but is known to
|
||||
* not access memory on the current function's stack frame.
|
||||
*/
|
||||
class AllNonLocalMemory extends TAllNonLocalMemory, MemoryLocation {
|
||||
class AllNonLocalMemory extends TAllNonLocalMemory, MemoryLocation0 {
|
||||
IRFunction irFunc;
|
||||
boolean isMayAccess;
|
||||
|
||||
@@ -346,7 +591,7 @@ class AllNonLocalMemory extends TAllNonLocalMemory, MemoryLocation {
|
||||
/**
|
||||
* An access to all aliased memory.
|
||||
*/
|
||||
class AllAliasedMemory extends TAllAliasedMemory, MemoryLocation {
|
||||
class AllAliasedMemory extends TAllAliasedMemory, MemoryLocation0 {
|
||||
IRFunction irFunc;
|
||||
boolean isMayAccess;
|
||||
|
||||
@@ -377,7 +622,7 @@ class AliasedVirtualVariable extends AllAliasedMemory, VirtualVariable {
|
||||
/**
|
||||
* Gets the overlap relationship between the definition location `def` and the use location `use`.
|
||||
*/
|
||||
Overlap getOverlap(MemoryLocation def, MemoryLocation use) {
|
||||
Overlap getOverlap(MemoryLocation0 def, MemoryLocation0 use) {
|
||||
exists(Overlap overlap |
|
||||
// Compute the overlap based only on the extent.
|
||||
overlap = getExtentOverlap(def, use) and
|
||||
@@ -405,7 +650,7 @@ Overlap getOverlap(MemoryLocation def, MemoryLocation use) {
|
||||
* based only on the set of memory locations accessed. Handling of "may" accesses and read-only
|
||||
* locations occurs in `getOverlap()`.
|
||||
*/
|
||||
private Overlap getExtentOverlap(MemoryLocation def, MemoryLocation use) {
|
||||
private Overlap getExtentOverlap(MemoryLocation0 def, MemoryLocation0 use) {
|
||||
// The def and the use must have the same virtual variable, or no overlap is possible.
|
||||
(
|
||||
// AllAliasedMemory must totally overlap any location within the same virtual variable.
|
||||
@@ -446,7 +691,7 @@ private Overlap getExtentOverlap(MemoryLocation def, MemoryLocation use) {
|
||||
result instanceof MustExactlyOverlap
|
||||
or
|
||||
not use instanceof EntireAllocationMemoryLocation and
|
||||
if def.getAllocation() = use.getAllocation()
|
||||
if def.getAnAllocation() = use.getAnAllocation()
|
||||
then
|
||||
// EntireAllocationMemoryLocation totally overlaps any location within
|
||||
// the same allocation.
|
||||
@@ -454,11 +699,48 @@ private Overlap getExtentOverlap(MemoryLocation def, MemoryLocation use) {
|
||||
else (
|
||||
// There is no overlap with a location that's known to belong to a
|
||||
// different allocation, but all other locations may partially overlap.
|
||||
not exists(use.getAllocation()) and
|
||||
not exists(use.getAnAllocation()) and
|
||||
result instanceof MayPartiallyOverlap
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(GroupedMemoryLocation group |
|
||||
group = def and
|
||||
def.getVirtualVariable() = use.getVirtualVariable()
|
||||
|
|
||||
(
|
||||
use instanceof UnknownMemoryLocation or
|
||||
use instanceof AllAliasedMemory
|
||||
) and
|
||||
result instanceof MayPartiallyOverlap
|
||||
or
|
||||
group.isAll() and
|
||||
(
|
||||
group.getAnAllocation() =
|
||||
[
|
||||
use.(EntireAllocationMemoryLocation).getAnAllocation(),
|
||||
use.(VariableMemoryLocation).getAnAllocation()
|
||||
]
|
||||
or
|
||||
use.(GroupedMemoryLocation).isSome()
|
||||
) and
|
||||
result instanceof MustTotallyOverlap
|
||||
or
|
||||
group.isAll() and
|
||||
use.(GroupedMemoryLocation).isAll() and
|
||||
result instanceof MustExactlyOverlap
|
||||
or
|
||||
group.isSome() and
|
||||
(
|
||||
use instanceof EntireAllocationMemoryLocation
|
||||
or
|
||||
use instanceof VariableMemoryLocation
|
||||
or
|
||||
use instanceof GroupedMemoryLocation
|
||||
) and
|
||||
result instanceof MayPartiallyOverlap
|
||||
)
|
||||
or
|
||||
exists(VariableMemoryLocation defVariableLocation |
|
||||
defVariableLocation = def and
|
||||
(
|
||||
@@ -468,7 +750,8 @@ private Overlap getExtentOverlap(MemoryLocation def, MemoryLocation use) {
|
||||
(
|
||||
use instanceof UnknownMemoryLocation or
|
||||
use instanceof AllAliasedMemory or
|
||||
use instanceof EntireAllocationMemoryLocation
|
||||
use instanceof EntireAllocationMemoryLocation or
|
||||
use instanceof GroupedMemoryLocation
|
||||
) and
|
||||
result instanceof MayPartiallyOverlap
|
||||
or
|
||||
@@ -534,7 +817,7 @@ private predicate isCoveredOffset(Allocation var, int offsetRank, VariableMemory
|
||||
exists(int startRank, int endRank, VirtualVariable vvar |
|
||||
vml.getStartBitOffset() = rank[startRank](IntValue offset_ | isRelevantOffset(vvar, offset_)) and
|
||||
vml.getEndBitOffset() = rank[endRank](IntValue offset_ | isRelevantOffset(vvar, offset_)) and
|
||||
var = vml.getAllocation() and
|
||||
var = vml.getAnAllocation() and
|
||||
vvar = vml.getVirtualVariable() and
|
||||
isRelatableMemoryLocation(vml) and
|
||||
offsetRank in [startRank .. endRank]
|
||||
@@ -542,7 +825,7 @@ private predicate isCoveredOffset(Allocation var, int offsetRank, VariableMemory
|
||||
}
|
||||
|
||||
private predicate hasUnknownOffset(Allocation var, VariableMemoryLocation vml) {
|
||||
vml.getAllocation() = var and
|
||||
vml.getAnAllocation() = var and
|
||||
(
|
||||
vml.getStartBitOffset() = Ints::unknown() or
|
||||
vml.getEndBitOffset() = Ints::unknown()
|
||||
@@ -557,9 +840,9 @@ private predicate overlappingIRVariableMemoryLocations(
|
||||
isCoveredOffset(var, offsetRank, use)
|
||||
)
|
||||
or
|
||||
hasUnknownOffset(use.getAllocation(), def)
|
||||
hasUnknownOffset(use.getAnAllocation(), def)
|
||||
or
|
||||
hasUnknownOffset(def.getAllocation(), use)
|
||||
hasUnknownOffset(def.getAnAllocation(), use)
|
||||
}
|
||||
|
||||
private Overlap getVariableMemoryLocationOverlap(
|
||||
@@ -580,6 +863,40 @@ predicate canReuseSsaForOldResult(Instruction instr) { OldSsa::canReuseSsaForMem
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
/** Gets the number of overlapping uses of `def`. */
|
||||
private int numberOfOverlappingUses(MemoryLocation0 def) {
|
||||
result = strictcount(MemoryLocation0 use | exists(getOverlap(def, use)))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `def` is a busy definition. That is, it has a large number of
|
||||
* overlapping uses.
|
||||
*/
|
||||
private predicate isBusyDef(MemoryLocation0 def) { numberOfOverlappingUses(def) > 1024 }
|
||||
|
||||
/** Holds if `use` is a use that overlaps with a busy definition. */
|
||||
private predicate useOverlapWithBusyDef(MemoryLocation0 use) {
|
||||
exists(MemoryLocation0 def |
|
||||
exists(getOverlap(def, use)) and
|
||||
isBusyDef(def)
|
||||
)
|
||||
}
|
||||
|
||||
final private class FinalMemoryLocation = MemoryLocation0;
|
||||
|
||||
/**
|
||||
* A memory location accessed by a memory operand or memory result. In this implementation, the location is
|
||||
* one of the following:
|
||||
* - `VariableMemoryLocation` - A location within a known `IRVariable`, at an offset that is either a constant or is
|
||||
* unknown.
|
||||
* - `UnknownMemoryLocation` - A location not known to be within a specific `IRVariable`.
|
||||
*
|
||||
* Compared to `MemoryLocation0`, this class does not contain memory locations that represent uses of busy definitions.
|
||||
*/
|
||||
class MemoryLocation extends FinalMemoryLocation {
|
||||
MemoryLocation() { not useOverlapWithBusyDef(this) }
|
||||
}
|
||||
|
||||
MemoryLocation getResultMemoryLocation(Instruction instr) {
|
||||
not canReuseSsaForOldResult(instr) and
|
||||
exists(MemoryAccessKind kind, boolean isMayAccess |
|
||||
@@ -588,13 +905,24 @@ MemoryLocation getResultMemoryLocation(Instruction instr) {
|
||||
(
|
||||
(
|
||||
isIndirectOrBufferMemoryAccess(kind) and
|
||||
if hasResultMemoryAccess(instr, _, _, _, _, _, _)
|
||||
if hasResultMemoryAccess(_, instr, _, _, _, _, _, _, _)
|
||||
then
|
||||
exists(Allocation var, IRType type, IntValue startBitOffset, IntValue endBitOffset |
|
||||
hasResultMemoryAccess(instr, var, type, _, startBitOffset, endBitOffset, isMayAccess) and
|
||||
result =
|
||||
TVariableMemoryLocation(var, type, _, startBitOffset, endBitOffset,
|
||||
unbindBool(isMayAccess))
|
||||
exists(
|
||||
Allocation var, IRType type, IntValue startBitOffset, IntValue endBitOffset,
|
||||
boolean grouped
|
||||
|
|
||||
hasResultMemoryAccess(_, instr, var, type, _, startBitOffset, endBitOffset, isMayAccess,
|
||||
grouped)
|
||||
|
|
||||
// If the instruction is only associated with one allocation we assign it a `VariableMemoryLocation`
|
||||
if grouped = false
|
||||
then
|
||||
result =
|
||||
TVariableMemoryLocation(var, type, _, startBitOffset, endBitOffset,
|
||||
unbindBool(isMayAccess))
|
||||
else
|
||||
// And otherwise we assign it a memory location that groups all the relevant memory locations into one.
|
||||
result = getGroupedMemoryLocation(var, unbindBool(isMayAccess), false)
|
||||
)
|
||||
else result = TUnknownMemoryLocation(instr.getEnclosingIRFunction(), isMayAccess)
|
||||
)
|
||||
@@ -613,20 +941,31 @@ MemoryLocation getResultMemoryLocation(Instruction instr) {
|
||||
)
|
||||
}
|
||||
|
||||
MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
|
||||
private MemoryLocation0 getOperandMemoryLocation0(MemoryOperand operand, boolean isMayAccess) {
|
||||
not canReuseSsaForOldResult(operand.getAnyDef()) and
|
||||
exists(MemoryAccessKind kind, boolean isMayAccess |
|
||||
exists(MemoryAccessKind kind |
|
||||
kind = operand.getMemoryAccess() and
|
||||
(if operand.hasMayReadMemoryAccess() then isMayAccess = true else isMayAccess = false) and
|
||||
(
|
||||
(
|
||||
isIndirectOrBufferMemoryAccess(kind) and
|
||||
if hasOperandMemoryAccess(operand, _, _, _, _, _, _)
|
||||
if hasOperandMemoryAccess(_, operand, _, _, _, _, _, _, _)
|
||||
then
|
||||
exists(Allocation var, IRType type, IntValue startBitOffset, IntValue endBitOffset |
|
||||
hasOperandMemoryAccess(operand, var, type, _, startBitOffset, endBitOffset, isMayAccess) and
|
||||
result =
|
||||
TVariableMemoryLocation(var, type, _, startBitOffset, endBitOffset, isMayAccess)
|
||||
exists(
|
||||
Allocation var, IRType type, IntValue startBitOffset, IntValue endBitOffset,
|
||||
boolean grouped
|
||||
|
|
||||
hasOperandMemoryAccess(_, operand, var, type, _, startBitOffset, endBitOffset,
|
||||
isMayAccess, grouped)
|
||||
|
|
||||
// If the operand is only associated with one memory location we assign it a `VariableMemoryLocation`
|
||||
if grouped = false
|
||||
then
|
||||
result =
|
||||
TVariableMemoryLocation(var, type, _, startBitOffset, endBitOffset, isMayAccess)
|
||||
else
|
||||
// And otherwise we assign it a memory location that groups all relevant memory locations into one.
|
||||
result = getGroupedMemoryLocation(var, isMayAccess, false)
|
||||
)
|
||||
else result = TUnknownMemoryLocation(operand.getEnclosingIRFunction(), isMayAccess)
|
||||
)
|
||||
@@ -645,6 +984,19 @@ MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
|
||||
)
|
||||
}
|
||||
|
||||
MemoryLocation getOperandMemoryLocation(MemoryOperand operand) {
|
||||
exists(MemoryLocation0 use0, boolean isMayAccess |
|
||||
use0 = getOperandMemoryLocation0(operand, isMayAccess)
|
||||
|
|
||||
result = use0
|
||||
or
|
||||
// If `use0` overlaps with a busy definition we turn it into a use
|
||||
// of `UnknownMemoryLocation`.
|
||||
not use0 instanceof MemoryLocation and
|
||||
result = TUnknownMemoryLocation(operand.getEnclosingIRFunction(), isMayAccess)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the start bit offset of a `MemoryLocation`, if any. */
|
||||
int getStartBitOffset(VariableMemoryLocation location) {
|
||||
result = location.getStartBitOffset() and Ints::hasValue(result)
|
||||
|
||||
@@ -15,6 +15,51 @@ private class OldInstruction = Reachability::ReachableInstruction;
|
||||
|
||||
import Cached
|
||||
|
||||
/**
|
||||
* Holds if `instruction` is the first instruction that may be followed by
|
||||
* an `UninitializedGroup` instruction, and the enclosing function of
|
||||
* `instruction` is `func`.
|
||||
*/
|
||||
private predicate isFirstInstructionBeforeUninitializedGroup(
|
||||
Instruction instruction, IRFunction func
|
||||
) {
|
||||
instruction = getChi(any(OldIR::InitializeNonLocalInstruction init)) and
|
||||
func = instruction.getEnclosingIRFunction()
|
||||
}
|
||||
|
||||
/** Gets the `i`'th `UninitializedGroup` instruction in `func`. */
|
||||
private UninitializedGroupInstruction getInitGroupInstruction(int i, IRFunction func) {
|
||||
exists(Alias::VariableGroup vg |
|
||||
vg.getIRFunction() = func and
|
||||
vg.getInitializationOrder() = i and
|
||||
result = uninitializedGroup(vg)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instruction` is the last instruction in the chain of `UninitializedGroup`
|
||||
* instructions in `func`. The chain of instructions may be empty in which case
|
||||
* `instruction` satisfies
|
||||
* ```
|
||||
* isFirstInstructionBeforeUninitializedGroup(instruction, func)
|
||||
* ```
|
||||
*/
|
||||
predicate isLastInstructionForUninitializedGroups(Instruction instruction, IRFunction func) {
|
||||
exists(int i |
|
||||
instruction = getInitGroupInstruction(i, func) and
|
||||
not exists(getChi(instruction)) and
|
||||
not exists(getInitGroupInstruction(i + 1, func))
|
||||
)
|
||||
or
|
||||
exists(int i |
|
||||
instruction = getChi(getInitGroupInstruction(i, func)) and
|
||||
not exists(getInitGroupInstruction(i + 1, func))
|
||||
)
|
||||
or
|
||||
isFirstInstructionBeforeUninitializedGroup(instruction, func) and
|
||||
not exists(getInitGroupInstruction(0, func))
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
cached
|
||||
@@ -32,6 +77,11 @@ private module Cached {
|
||||
hasChiNode(_, primaryInstruction)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate hasChiNodeAfterUninitializedGroup(UninitializedGroupInstruction initGroup) {
|
||||
hasChiNodeAfterUninitializedGroup(_, initGroup)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate hasUnreachedInstructionCached(IRFunction irFunc) {
|
||||
exists(OldIR::Instruction oldInstruction |
|
||||
@@ -45,7 +95,8 @@ private module Cached {
|
||||
}
|
||||
|
||||
class TStageInstruction =
|
||||
TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction;
|
||||
TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction or
|
||||
TUninitializedGroupInstruction;
|
||||
|
||||
/**
|
||||
* If `oldInstruction` is a `Phi` instruction that has exactly one reachable predecessor block,
|
||||
@@ -78,6 +129,8 @@ private module Cached {
|
||||
or
|
||||
instr instanceof TChiInstruction
|
||||
or
|
||||
instr instanceof TUninitializedGroupInstruction
|
||||
or
|
||||
instr instanceof TUnreachedInstruction
|
||||
}
|
||||
|
||||
@@ -123,7 +176,8 @@ private module Cached {
|
||||
predicate hasModeledMemoryResult(Instruction instruction) {
|
||||
canModelResultForOldInstruction(getOldInstruction(instruction)) or
|
||||
instruction instanceof PhiInstruction or // Phis always have modeled results
|
||||
instruction instanceof ChiInstruction // Chis always have modeled results
|
||||
instruction instanceof ChiInstruction or // Chis always have modeled results
|
||||
instruction instanceof UninitializedGroupInstruction // Group initializers always have modeled results
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -134,16 +188,23 @@ private module Cached {
|
||||
or
|
||||
// Chi instructions track virtual variables, and therefore a chi instruction is
|
||||
// conflated if it's associated with the aliased virtual variable.
|
||||
exists(OldInstruction oldInstruction | instruction = getChi(oldInstruction) |
|
||||
Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof
|
||||
exists(Instruction input | instruction = getChi(input) |
|
||||
Alias::getResultMemoryLocation(input).getVirtualVariable() instanceof
|
||||
Alias::AliasedVirtualVariable
|
||||
or
|
||||
// A chi following an `UninitializedGroupInstruction` only happens when the virtual
|
||||
// variable of the grouped memory location is `{AllAliasedMemory}`.
|
||||
exists(Alias::GroupedMemoryLocation gml |
|
||||
input = uninitializedGroup(gml.getGroup()) and
|
||||
gml.getVirtualVariable() instanceof Alias::AliasedVirtualVariable
|
||||
)
|
||||
)
|
||||
or
|
||||
// Phi instructions track locations, and therefore a phi instruction is
|
||||
// conflated if it's associated with a conflated location.
|
||||
exists(Alias::MemoryLocation location |
|
||||
instruction = getPhi(_, location) and
|
||||
not exists(location.getAllocation())
|
||||
not exists(location.getAnAllocation())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -205,7 +266,11 @@ private module Cached {
|
||||
hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result)
|
||||
)
|
||||
or
|
||||
instruction = getChi(getOldInstruction(result)) and
|
||||
(
|
||||
instruction = getChi(getOldInstruction(result))
|
||||
or
|
||||
instruction = getChi(result.(UninitializedGroupInstruction))
|
||||
) and
|
||||
tag instanceof ChiPartialOperandTag and
|
||||
overlap instanceof MustExactlyOverlap
|
||||
or
|
||||
@@ -263,6 +328,14 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
IRVariable getAnUninitializedGroupVariable(UninitializedGroupInstruction init) {
|
||||
exists(Alias::VariableGroup vg |
|
||||
init = uninitializedGroup(vg) and
|
||||
result = vg.getAnAllocation().getABaseInstruction().(VariableInstruction).getIRVariable()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
|
||||
* through a phi instruction and therefore should be impossible.
|
||||
@@ -316,6 +389,19 @@ private module Cached {
|
||||
result = getNewPhiOperandDefinitionFromOldSsa(instr, newPredecessorBlock, overlap)
|
||||
}
|
||||
|
||||
private ChiInstruction getChiAfterUninitializedGroup(int i, IRFunction func) {
|
||||
result =
|
||||
rank[i + 1](VariableGroup vg, UninitializedGroupInstruction initGroup, ChiInstruction chi,
|
||||
int r |
|
||||
initGroup.getEnclosingIRFunction() = func and
|
||||
chi = getChi(initGroup) and
|
||||
initGroup = uninitializedGroup(vg) and
|
||||
r = vg.getInitializationOrder()
|
||||
|
|
||||
chi order by r
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) {
|
||||
exists(
|
||||
@@ -329,6 +415,19 @@ private module Cached {
|
||||
definitionReachesUse(vvar, defBlock, defRank, useBlock, useRank) and
|
||||
result = getDefinitionOrChiInstruction(defBlock, defOffset, vvar, _)
|
||||
)
|
||||
or
|
||||
exists(UninitializedGroupInstruction initGroup, IRFunction func |
|
||||
chiInstr = getChi(initGroup) and
|
||||
func = initGroup.getEnclosingIRFunction()
|
||||
|
|
||||
chiInstr = getChiAfterUninitializedGroup(0, func) and
|
||||
isFirstInstructionBeforeUninitializedGroup(result, func)
|
||||
or
|
||||
exists(int i |
|
||||
chiInstr = getChiAfterUninitializedGroup(i + 1, func) and
|
||||
result = getChiAfterUninitializedGroup(i, func)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -344,14 +443,40 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
* This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
|
||||
* that node is its successor in the new successor relation, and the Chi node's successors are
|
||||
* the new instructions generated from the successors of the old instruction
|
||||
*/
|
||||
private UninitializedGroupInstruction firstInstructionToUninitializedGroup(
|
||||
Instruction instruction, EdgeKind kind
|
||||
) {
|
||||
exists(IRFunction func |
|
||||
isFirstInstructionBeforeUninitializedGroup(instruction, func) and
|
||||
result = getInitGroupInstruction(0, func) and
|
||||
kind instanceof GotoEdge
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
private Instruction getNextUninitializedGroupInstruction(Instruction instruction, EdgeKind kind) {
|
||||
exists(int i, IRFunction func |
|
||||
func = instruction.getEnclosingIRFunction() and
|
||||
instruction = getInitGroupInstruction(i, func) and
|
||||
kind instanceof GotoEdge
|
||||
|
|
||||
if hasChiNodeAfterUninitializedGroup(_, instruction)
|
||||
then result = getChi(instruction)
|
||||
else result = getInitGroupInstruction(i + 1, func)
|
||||
)
|
||||
or
|
||||
exists(int i, IRFunction func, UninitializedGroupInstruction initGroup |
|
||||
func = instruction.getEnclosingIRFunction() and
|
||||
instruction = getChi(initGroup) and
|
||||
initGroup = getInitGroupInstruction(i, func) and
|
||||
kind instanceof GotoEdge
|
||||
|
|
||||
result = getInitGroupInstruction(i + 1, func)
|
||||
)
|
||||
}
|
||||
|
||||
private Instruction getInstructionSuccessorAfterUninitializedGroup0(
|
||||
Instruction instruction, EdgeKind kind
|
||||
) {
|
||||
if hasChiNode(_, getOldInstruction(instruction))
|
||||
then
|
||||
result = getChi(getOldInstruction(instruction)) and
|
||||
@@ -371,6 +496,107 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
private Instruction getInstructionSuccessorAfterUninitializedGroup(
|
||||
Instruction instruction, EdgeKind kind
|
||||
) {
|
||||
exists(IRFunction func, Instruction firstBeforeUninitializedGroup |
|
||||
isLastInstructionForUninitializedGroups(instruction, func) and
|
||||
isFirstInstructionBeforeUninitializedGroup(firstBeforeUninitializedGroup, func) and
|
||||
result = getInstructionSuccessorAfterUninitializedGroup0(firstBeforeUninitializedGroup, kind)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
|
||||
* that node is its successor in the new successor relation, and the Chi node's successors are
|
||||
* the new instructions generated from the successors of the old instruction.
|
||||
*
|
||||
* Furthermore, the entry block is augmented with `UninitializedGroup` instructions and `Chi`
|
||||
* instructions. For example, consider this example:
|
||||
* ```cpp
|
||||
* int x, y;
|
||||
* int* p;
|
||||
* if(b) {
|
||||
* p = &x;
|
||||
* escape(&x);
|
||||
* } else {
|
||||
* p = &y;
|
||||
* }
|
||||
* *p = 42;
|
||||
*
|
||||
* int z, w;
|
||||
* int* q;
|
||||
* if(b) {
|
||||
* q = &z;
|
||||
* } else {
|
||||
* q = &w;
|
||||
* }
|
||||
* *q = 43;
|
||||
* ```
|
||||
*
|
||||
* the unaliased IR for the entry block of this snippet is:
|
||||
* ```
|
||||
* v1(void) = EnterFunction :
|
||||
* m1(unknown) = AliasedDefinition :
|
||||
* m2(unknown) = InitializeNonLocal :
|
||||
* r1(glval<bool>) = VariableAddress[b] :
|
||||
* m3(bool) = InitializeParameter[b] : &:r1
|
||||
* r2(glval<int>) = VariableAddress[x] :
|
||||
* m4(int) = Uninitialized[x] : &:r2
|
||||
* r3(glval<int>) = VariableAddress[y] :
|
||||
* m5(int) = Uninitialized[y] : &:r3
|
||||
* r4(glval<int *>) = VariableAddress[p] :
|
||||
* m6(int *) = Uninitialized[p] : &:r4
|
||||
* r5(glval<bool>) = VariableAddress[b] :
|
||||
* r6(bool) = Load[b] : &:r5, m3
|
||||
* v2(void) = ConditionalBranch : r6
|
||||
* ```
|
||||
* and we need to transform this to aliased IR by inserting an `UninitializedGroup`
|
||||
* instruction for every `VariableGroup` memory location in the function. Furthermore,
|
||||
* if the `VariableGroup` memory location contains an allocation that escapes we need
|
||||
* to insert a `Chi` that writes the memory produced by `UninitializedGroup` into
|
||||
* `{AllAliasedMemory}`. For the above snippet we then end up with:
|
||||
* ```
|
||||
* v1(void) = EnterFunction :
|
||||
* m2(unknown) = AliasedDefinition :
|
||||
* m3(unknown) = InitializeNonLocal :
|
||||
* m4(unknown) = Chi : total:m2, partial:m3
|
||||
* m5(int) = UninitializedGroup[x,y] :
|
||||
* m6(unknown) = Chi : total:m4, partial:m5
|
||||
* m7(int) = UninitializedGroup[w,z] :
|
||||
* r1(glval<bool>) = VariableAddress[b] :
|
||||
* m8(bool) = InitializeParameter[b] : &:r1
|
||||
* r2(glval<int>) = VariableAddress[x] :
|
||||
* m10(int) = Uninitialized[x] : &:r2
|
||||
* m11(unknown) = Chi : total:m6, partial:m10
|
||||
* r3(glval<int>) = VariableAddress[y] :
|
||||
* m12(int) = Uninitialized[y] : &:r3
|
||||
* m13(unknown) = Chi : total:m11, partial:m12
|
||||
* r4(glval<int *>) = VariableAddress[p] :
|
||||
* m14(int *) = Uninitialized[p] : &:r4
|
||||
* r5(glval<bool>) = VariableAddress[b] :
|
||||
* r6(bool) = Load[b] : &:r5, m8
|
||||
* v2(void) = ConditionalBranch : r6
|
||||
* ```
|
||||
*
|
||||
* Here, the group `{x, y}` contains an allocation that escapes (`x`), so there
|
||||
* is a `Chi` after the `UninitializedGroup` that initializes the memory for the
|
||||
* `VariableGroup` containing `x`. None of the allocations in `{w, z}` escape so
|
||||
* there is no `Chi` following that the `UninitializedGroup` that initializes the
|
||||
* memory of `{w, z}`.
|
||||
*/
|
||||
cached
|
||||
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
result = firstInstructionToUninitializedGroup(instruction, kind)
|
||||
or
|
||||
result = getNextUninitializedGroupInstruction(instruction, kind)
|
||||
or
|
||||
result = getInstructionSuccessorAfterUninitializedGroup(instruction, kind)
|
||||
or
|
||||
not isFirstInstructionBeforeUninitializedGroup(instruction, _) and
|
||||
result = getInstructionSuccessorAfterUninitializedGroup0(instruction, kind)
|
||||
}
|
||||
|
||||
cached
|
||||
Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
exists(OldInstruction oldInstruction |
|
||||
@@ -406,6 +632,16 @@ private module Cached {
|
||||
exists(IRFunctionBase irFunc |
|
||||
instr = unreachedInstruction(irFunc) and result = irFunc.getFunction()
|
||||
)
|
||||
or
|
||||
exists(Alias::VariableGroup vg |
|
||||
instr = uninitializedGroup(vg) and
|
||||
result = vg.getIRFunction().getFunction()
|
||||
)
|
||||
or
|
||||
exists(UninitializedGroupInstruction initGroup |
|
||||
instr = chiInstruction(initGroup) and
|
||||
result = getInstructionAst(initGroup)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -418,9 +654,16 @@ private module Cached {
|
||||
)
|
||||
or
|
||||
exists(Instruction primaryInstr, Alias::VirtualVariable vvar |
|
||||
instr = chiInstruction(primaryInstr) and
|
||||
hasChiNode(vvar, primaryInstr) and
|
||||
result = vvar.getType()
|
||||
instr = chiInstruction(primaryInstr) and result = vvar.getType()
|
||||
|
|
||||
hasChiNode(vvar, primaryInstr)
|
||||
or
|
||||
hasChiNodeAfterUninitializedGroup(vvar, primaryInstr)
|
||||
)
|
||||
or
|
||||
exists(Alias::VariableGroup vg |
|
||||
instr = uninitializedGroup(vg) and
|
||||
result = vg.getType()
|
||||
)
|
||||
or
|
||||
instr = reusedPhiInstruction(_) and
|
||||
@@ -448,6 +691,8 @@ private module Cached {
|
||||
or
|
||||
instr = chiInstruction(_) and opcode instanceof Opcode::Chi
|
||||
or
|
||||
instr = uninitializedGroup(_) and opcode instanceof Opcode::UninitializedGroup
|
||||
or
|
||||
instr = unreachedInstruction(_) and opcode instanceof Opcode::Unreached
|
||||
}
|
||||
|
||||
@@ -460,10 +705,15 @@ private module Cached {
|
||||
result = blockStartInstr.getEnclosingIRFunction()
|
||||
)
|
||||
or
|
||||
exists(OldInstruction primaryInstr |
|
||||
exists(Instruction primaryInstr |
|
||||
instr = chiInstruction(primaryInstr) and result = primaryInstr.getEnclosingIRFunction()
|
||||
)
|
||||
or
|
||||
exists(Alias::VariableGroup vg |
|
||||
instr = uninitializedGroup(vg) and
|
||||
result = vg.getIRFunction()
|
||||
)
|
||||
or
|
||||
instr = unreachedInstruction(result)
|
||||
}
|
||||
|
||||
@@ -478,6 +728,8 @@ private module Cached {
|
||||
instruction = getChi(oldInstruction) and
|
||||
result = getNewInstruction(oldInstruction)
|
||||
)
|
||||
or
|
||||
instruction = getChi(result.(UninitializedGroupInstruction))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -485,7 +737,7 @@ private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(
|
||||
|
||||
private OldInstruction getOldInstruction(Instruction instr) { instr = result }
|
||||
|
||||
private ChiInstruction getChi(OldInstruction primaryInstr) { result = chiInstruction(primaryInstr) }
|
||||
private ChiInstruction getChi(Instruction primaryInstr) { result = chiInstruction(primaryInstr) }
|
||||
|
||||
private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) {
|
||||
result = phiInstruction(defBlock.getFirstInstruction(), defLocation)
|
||||
@@ -506,6 +758,16 @@ private predicate hasChiNode(Alias::VirtualVariable vvar, OldInstruction def) {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate hasChiNodeAfterUninitializedGroup(
|
||||
Alias::AliasedVirtualVariable vvar, UninitializedGroupInstruction initGroup
|
||||
) {
|
||||
exists(Alias::GroupedMemoryLocation defLocation |
|
||||
initGroup = uninitializedGroup(defLocation.getGroup()) and
|
||||
defLocation.getVirtualVariable() = vvar and
|
||||
Alias::getOverlap(defLocation, vvar) instanceof MayPartiallyOverlap
|
||||
)
|
||||
}
|
||||
|
||||
private import PhiInsertion
|
||||
|
||||
/**
|
||||
@@ -668,19 +930,37 @@ private import DefUse
|
||||
* potentially very sparse.
|
||||
*/
|
||||
module DefUse {
|
||||
bindingset[index, block]
|
||||
pragma[inline_late]
|
||||
private int getNonChiOffset(int index, OldBlock block) {
|
||||
exists(OldIR::IRFunction func, Instruction i, OldBlock entryBlock |
|
||||
func = block.getEnclosingIRFunction() and
|
||||
i = block.getInstruction(index) and
|
||||
entryBlock = func.getEntryBlock()
|
||||
|
|
||||
if
|
||||
block = entryBlock and
|
||||
not i instanceof InitializeNonLocalInstruction and
|
||||
not i instanceof AliasedDefinitionInstruction
|
||||
then result = 2 * (index + count(VariableGroup vg | vg.getIRFunction() = func))
|
||||
else result = 2 * index
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[index, block]
|
||||
pragma[inline_late]
|
||||
private int getChiOffset(int index, OldBlock block) { result = getNonChiOffset(index, block) + 1 }
|
||||
|
||||
/**
|
||||
* Gets the `Instruction` for the definition at offset `defOffset` in block `defBlock`.
|
||||
*/
|
||||
Instruction getDefinitionOrChiInstruction(
|
||||
private Instruction getDefinitionOrChiInstruction0(
|
||||
OldBlock defBlock, int defOffset, Alias::MemoryLocation defLocation,
|
||||
Alias::MemoryLocation actualDefLocation
|
||||
) {
|
||||
exists(OldInstruction oldInstr, int oldOffset |
|
||||
oldInstr = defBlock.getInstruction(oldOffset) and
|
||||
oldOffset >= 0
|
||||
|
|
||||
exists(OldInstruction oldInstr, int oldOffset | oldInstr = defBlock.getInstruction(oldOffset) |
|
||||
// An odd offset corresponds to the `Chi` instruction.
|
||||
defOffset = oldOffset * 2 + 1 and
|
||||
defOffset = getChiOffset(oldOffset, defBlock) and
|
||||
result = getChi(oldInstr) and
|
||||
(
|
||||
defLocation = Alias::getResultMemoryLocation(oldInstr) or
|
||||
@@ -689,7 +969,7 @@ module DefUse {
|
||||
actualDefLocation = defLocation.getVirtualVariable()
|
||||
or
|
||||
// An even offset corresponds to the original instruction.
|
||||
defOffset = oldOffset * 2 and
|
||||
defOffset = getNonChiOffset(oldOffset, defBlock) and
|
||||
result = getNewInstruction(oldInstr) and
|
||||
(
|
||||
defLocation = Alias::getResultMemoryLocation(oldInstr) or
|
||||
@@ -702,6 +982,54 @@ module DefUse {
|
||||
hasDefinition(_, defLocation, defBlock, defOffset) and
|
||||
result = getPhi(defBlock, defLocation) and
|
||||
actualDefLocation = defLocation
|
||||
or
|
||||
exists(
|
||||
Alias::VariableGroup vg, int index, UninitializedGroupInstruction initGroup,
|
||||
Alias::GroupedMemoryLocation gml
|
||||
|
|
||||
// Add 3 to account for the function prologue:
|
||||
// v1(void) = EnterFunction
|
||||
// m1(unknown) = AliasedDefinition
|
||||
// m2(unknown) = InitializeNonLocal
|
||||
index = 3 + vg.getInitializationOrder() and
|
||||
not gml.isMayAccess() and
|
||||
gml.isSome() and
|
||||
gml.getGroup() = vg and
|
||||
vg.getIRFunction().getEntryBlock() = defBlock and
|
||||
initGroup = uninitializedGroup(vg) and
|
||||
(defLocation = gml or defLocation = gml.getVirtualVariable())
|
||||
|
|
||||
result = initGroup and
|
||||
defOffset = 2 * index and
|
||||
actualDefLocation = defLocation
|
||||
or
|
||||
result = getChi(initGroup) and
|
||||
defOffset = 2 * index + 1 and
|
||||
actualDefLocation = defLocation.getVirtualVariable()
|
||||
)
|
||||
}
|
||||
|
||||
private ChiInstruction remapGetDefinitionOrChiInstruction(Instruction oldResult) {
|
||||
exists(IRFunction func |
|
||||
isFirstInstructionBeforeUninitializedGroup(oldResult, func) and
|
||||
isLastInstructionForUninitializedGroups(result, func)
|
||||
)
|
||||
}
|
||||
|
||||
Instruction getDefinitionOrChiInstruction(
|
||||
OldBlock defBlock, int defOffset, Alias::MemoryLocation defLocation,
|
||||
Alias::MemoryLocation actualDefLocation
|
||||
) {
|
||||
exists(Instruction oldResult |
|
||||
oldResult =
|
||||
getDefinitionOrChiInstruction0(defBlock, defOffset, defLocation, actualDefLocation) and
|
||||
(
|
||||
result = remapGetDefinitionOrChiInstruction(oldResult)
|
||||
or
|
||||
not exists(remapGetDefinitionOrChiInstruction(oldResult)) and
|
||||
result = oldResult
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -842,8 +1170,20 @@ module DefUse {
|
||||
block.getInstruction(index) = def and
|
||||
overlap = Alias::getOverlap(defLocation, useLocation) and
|
||||
if overlap instanceof MayPartiallyOverlap
|
||||
then offset = (index * 2) + 1 // The use will be connected to the definition on the `Chi` instruction.
|
||||
else offset = index * 2 // The use will be connected to the definition on the original instruction.
|
||||
then offset = getChiOffset(index, block) // The use will be connected to the definition on the `Chi` instruction.
|
||||
else offset = getNonChiOffset(index, block) // The use will be connected to the definition on the original instruction.
|
||||
)
|
||||
or
|
||||
exists(UninitializedGroupInstruction initGroup, int index, Overlap overlap, VariableGroup vg |
|
||||
initGroup.getEnclosingIRFunction().getEntryBlock() = getNewBlock(block) and
|
||||
vg = defLocation.(Alias::GroupedMemoryLocation).getGroup() and
|
||||
// EnterFunction + AliasedDefinition + InitializeNonLocal + index
|
||||
index = 3 + vg.getInitializationOrder() and
|
||||
initGroup = uninitializedGroup(vg) and
|
||||
overlap = Alias::getOverlap(defLocation, useLocation) and
|
||||
if overlap instanceof MayPartiallyOverlap and hasChiNodeAfterUninitializedGroup(initGroup)
|
||||
then offset = 2 * index + 1 // The use will be connected to the definition on the `Chi` instruction.
|
||||
else offset = 2 * index // The use will be connected to the definition on the original instruction.
|
||||
)
|
||||
}
|
||||
|
||||
@@ -904,10 +1244,11 @@ module DefUse {
|
||||
block.getInstruction(index) = use and
|
||||
(
|
||||
// A direct use of the location.
|
||||
useLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and offset = index * 2
|
||||
useLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and
|
||||
offset = getNonChiOffset(index, block)
|
||||
or
|
||||
// A `Chi` instruction will include a use of the virtual variable.
|
||||
hasChiNode(useLocation, use) and offset = (index * 2) + 1
|
||||
hasChiNode(useLocation, use) and offset = getChiOffset(index, block)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1057,5 +1398,9 @@ module Ssa {
|
||||
|
||||
predicate hasChiInstruction = Cached::hasChiInstructionCached/1;
|
||||
|
||||
predicate hasChiNodeAfterUninitializedGroup = Cached::hasChiNodeAfterUninitializedGroup/1;
|
||||
|
||||
predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1;
|
||||
|
||||
class VariableGroup = Alias::VariableGroup;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ newtype TInstruction =
|
||||
TUnaliasedSsaUnreachedInstruction(IRFunctionBase irFunc) {
|
||||
UnaliasedSsa::Ssa::hasUnreachedInstruction(irFunc)
|
||||
} or
|
||||
TUnaliasedSsaUninitializedGroupInstruction(UnaliasedSsa::Ssa::VariableGroup vg) or
|
||||
TAliasedSsaPhiInstruction(
|
||||
TRawInstruction blockStartInstr, AliasedSsa::Ssa::MemoryLocation memoryLocation
|
||||
) {
|
||||
@@ -41,6 +42,12 @@ newtype TInstruction =
|
||||
} or
|
||||
TAliasedSsaUnreachedInstruction(IRFunctionBase irFunc) {
|
||||
AliasedSsa::Ssa::hasUnreachedInstruction(irFunc)
|
||||
} or
|
||||
TAliasedSsaUninitializedGroupInstruction(AliasedSsa::Ssa::VariableGroup vg) or
|
||||
TAliasedSsaChiAfterUninitializedGroupInstruction(
|
||||
TAliasedSsaUninitializedGroupInstruction initGroup
|
||||
) {
|
||||
AliasedSsa::Ssa::hasChiNodeAfterUninitializedGroup(initGroup)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,7 +69,11 @@ module UnaliasedSsaInstructions {
|
||||
|
||||
class TChiInstruction = TUnaliasedSsaChiInstruction;
|
||||
|
||||
TChiInstruction chiInstruction(TRawInstruction primaryInstruction) {
|
||||
class TUninitializedGroupInstruction = TUnaliasedSsaUninitializedGroupInstruction;
|
||||
|
||||
class TRawOrUninitializedGroupInstruction = TRawInstruction or TUninitializedGroupInstruction;
|
||||
|
||||
TChiInstruction chiInstruction(TRawOrUninitializedGroupInstruction primaryInstruction) {
|
||||
result = TUnaliasedSsaChiInstruction(primaryInstruction)
|
||||
}
|
||||
|
||||
@@ -71,6 +82,12 @@ module UnaliasedSsaInstructions {
|
||||
TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) {
|
||||
result = TUnaliasedSsaUnreachedInstruction(irFunc)
|
||||
}
|
||||
|
||||
class VariableGroup = UnaliasedSsa::Ssa::VariableGroup;
|
||||
|
||||
// This really should just be `TUnaliasedSsaUninitializedGroupInstruction`, but that makes the
|
||||
// compiler realize that certain expressions in `SSAConstruction` are unsatisfiable.
|
||||
TRawOrUninitializedGroupInstruction uninitializedGroup(VariableGroup vg) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,10 +109,16 @@ module AliasedSsaInstructions {
|
||||
result = TUnaliasedSsaPhiInstruction(blockStartInstr, _)
|
||||
}
|
||||
|
||||
class TChiInstruction = TAliasedSsaChiInstruction;
|
||||
class TChiInstruction =
|
||||
TAliasedSsaChiInstruction or TAliasedSsaChiAfterUninitializedGroupInstruction;
|
||||
|
||||
TChiInstruction chiInstruction(TRawInstruction primaryInstruction) {
|
||||
class TRawOrInitialzieGroupInstruction =
|
||||
TRawInstruction or TAliasedSsaUninitializedGroupInstruction;
|
||||
|
||||
TChiInstruction chiInstruction(TRawOrInitialzieGroupInstruction primaryInstruction) {
|
||||
result = TAliasedSsaChiInstruction(primaryInstruction)
|
||||
or
|
||||
result = TAliasedSsaChiAfterUninitializedGroupInstruction(primaryInstruction)
|
||||
}
|
||||
|
||||
class TUnreachedInstruction = TAliasedSsaUnreachedInstruction;
|
||||
@@ -103,4 +126,12 @@ module AliasedSsaInstructions {
|
||||
TUnreachedInstruction unreachedInstruction(IRFunctionBase irFunc) {
|
||||
result = TAliasedSsaUnreachedInstruction(irFunc)
|
||||
}
|
||||
|
||||
class VariableGroup = AliasedSsa::Ssa::VariableGroup;
|
||||
|
||||
class TUninitializedGroupInstruction = TAliasedSsaUninitializedGroupInstruction;
|
||||
|
||||
TUninitializedGroupInstruction uninitializedGroup(VariableGroup vg) {
|
||||
result = TAliasedSsaUninitializedGroupInstruction(vg)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,9 @@ private import semmle.code.cpp.ir.internal.Overlap
|
||||
* Provides the newtype used to represent operands across all phases of the IR.
|
||||
*/
|
||||
private module Internal {
|
||||
private class TAliasedChiInstruction =
|
||||
TAliasedSsaChiInstruction or TAliasedSsaChiAfterUninitializedGroupInstruction;
|
||||
|
||||
/**
|
||||
* An IR operand. `TOperand` is shared across all phases of the IR. There are branches of this
|
||||
* type for operands created directly from the AST (`TRegisterOperand` and `TNonSSAMemoryOperand`),
|
||||
@@ -52,7 +55,7 @@ private module Internal {
|
||||
) {
|
||||
exists(AliasedConstruction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap))
|
||||
} or
|
||||
TAliasedChiOperand(TAliasedSsaChiInstruction useInstr, ChiOperandTag tag) { any() }
|
||||
TAliasedChiOperand(TAliasedChiInstruction useInstr, ChiOperandTag tag) { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -198,10 +201,13 @@ module AliasedSsaOperands {
|
||||
)
|
||||
}
|
||||
|
||||
private class TChiInstruction =
|
||||
TAliasedSsaChiInstruction or TAliasedSsaChiAfterUninitializedGroupInstruction;
|
||||
|
||||
/**
|
||||
* Returns the Chi operand with the specified parameters.
|
||||
*/
|
||||
TChiOperand chiOperand(TAliasedSsaChiInstruction useInstr, ChiOperandTag tag) {
|
||||
TChiOperand chiOperand(TChiInstruction useInstr, ChiOperandTag tag) {
|
||||
result = Internal::TAliasedChiOperand(useInstr, tag)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2142,6 +2142,47 @@ class ChiInstruction extends Instruction {
|
||||
final predicate isPartialUpdate() { Construction::chiOnlyPartiallyUpdatesLocation(this) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that initializes a set of allocations that are each assigned
|
||||
* the same "virtual variable".
|
||||
*
|
||||
* As an example, consider the following snippet:
|
||||
* ```
|
||||
* int a;
|
||||
* int b;
|
||||
* int* p;
|
||||
* if(b) {
|
||||
* p = &a;
|
||||
* } else {
|
||||
* p = &b;
|
||||
* }
|
||||
* *p = 5;
|
||||
* int x = a;
|
||||
* ```
|
||||
*
|
||||
* Since both the address of `a` and `b` reach `p` at `*p = 5` the IR alias
|
||||
* analysis will create a region that contains both `a` and `b`. The region
|
||||
* containing both `a` and `b` are initialized by an `UninitializedGroup`
|
||||
* instruction in the entry block of the enclosing function.
|
||||
*/
|
||||
class UninitializedGroupInstruction extends Instruction {
|
||||
UninitializedGroupInstruction() { this.getOpcode() instanceof Opcode::UninitializedGroup }
|
||||
|
||||
/**
|
||||
* Gets an `IRVariable` whose memory is initialized by this instruction, if any.
|
||||
* Note: Allocations that are not represented as `IRVariable`s (such as
|
||||
* dynamic allocations) are not returned by this predicate even if this
|
||||
* instruction initializes such memory.
|
||||
*/
|
||||
final IRVariable getAnIRVariable() {
|
||||
result = Construction::getAnUninitializedGroupVariable(this)
|
||||
}
|
||||
|
||||
final override string getImmediateString() {
|
||||
result = strictconcat(this.getAnIRVariable().toString(), ",")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing unreachable code.
|
||||
*
|
||||
|
||||
@@ -407,6 +407,8 @@ predicate hasUnreachedInstruction(IRFunction func) {
|
||||
)
|
||||
}
|
||||
|
||||
IRVariable getAnUninitializedGroupVariable(UninitializedGroupInstruction instr) { none() }
|
||||
|
||||
import CachedForDebugging
|
||||
|
||||
cached
|
||||
|
||||
@@ -2142,6 +2142,47 @@ class ChiInstruction extends Instruction {
|
||||
final predicate isPartialUpdate() { Construction::chiOnlyPartiallyUpdatesLocation(this) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction that initializes a set of allocations that are each assigned
|
||||
* the same "virtual variable".
|
||||
*
|
||||
* As an example, consider the following snippet:
|
||||
* ```
|
||||
* int a;
|
||||
* int b;
|
||||
* int* p;
|
||||
* if(b) {
|
||||
* p = &a;
|
||||
* } else {
|
||||
* p = &b;
|
||||
* }
|
||||
* *p = 5;
|
||||
* int x = a;
|
||||
* ```
|
||||
*
|
||||
* Since both the address of `a` and `b` reach `p` at `*p = 5` the IR alias
|
||||
* analysis will create a region that contains both `a` and `b`. The region
|
||||
* containing both `a` and `b` are initialized by an `UninitializedGroup`
|
||||
* instruction in the entry block of the enclosing function.
|
||||
*/
|
||||
class UninitializedGroupInstruction extends Instruction {
|
||||
UninitializedGroupInstruction() { this.getOpcode() instanceof Opcode::UninitializedGroup }
|
||||
|
||||
/**
|
||||
* Gets an `IRVariable` whose memory is initialized by this instruction, if any.
|
||||
* Note: Allocations that are not represented as `IRVariable`s (such as
|
||||
* dynamic allocations) are not returned by this predicate even if this
|
||||
* instruction initializes such memory.
|
||||
*/
|
||||
final IRVariable getAnIRVariable() {
|
||||
result = Construction::getAnUninitializedGroupVariable(this)
|
||||
}
|
||||
|
||||
final override string getImmediateString() {
|
||||
result = strictconcat(this.getAnIRVariable().toString(), ",")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction representing unreachable code.
|
||||
*
|
||||
|
||||
@@ -106,8 +106,7 @@ private predicate operandEscapesDomain(Operand operand) {
|
||||
not isArgumentForParameter(_, operand, _) and
|
||||
not isOnlyEscapesViaReturnArgument(operand) and
|
||||
not operand.getUse() instanceof ReturnValueInstruction and
|
||||
not operand.getUse() instanceof ReturnIndirectionInstruction and
|
||||
not operand instanceof PhiInputOperand
|
||||
not operand.getUse() instanceof ReturnIndirectionInstruction
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -191,6 +190,11 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset, Instr
|
||||
// A copy propagates the source value.
|
||||
operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0
|
||||
)
|
||||
or
|
||||
operand = instr.(PhiInstruction).getAnInputOperand() and
|
||||
// Using `unknown` ensures termination since we cannot keep incrementing a bit offset
|
||||
// through the back edge of a loop (or through recursion).
|
||||
bitOffset = Ints::unknown()
|
||||
}
|
||||
|
||||
private predicate operandEscapesNonReturn(Operand operand) {
|
||||
@@ -212,9 +216,6 @@ private predicate operandEscapesNonReturn(Operand operand) {
|
||||
or
|
||||
isOnlyEscapesViaReturnArgument(operand) and resultEscapesNonReturn(operand.getUse())
|
||||
or
|
||||
operand instanceof PhiInputOperand and
|
||||
resultEscapesNonReturn(operand.getUse())
|
||||
or
|
||||
operandEscapesDomain(operand)
|
||||
}
|
||||
|
||||
@@ -236,9 +237,6 @@ private predicate operandMayReachReturn(Operand operand) {
|
||||
operand.getUse() instanceof ReturnValueInstruction
|
||||
or
|
||||
isOnlyEscapesViaReturnArgument(operand) and resultMayReachReturn(operand.getUse())
|
||||
or
|
||||
operand instanceof PhiInputOperand and
|
||||
resultMayReachReturn(operand.getUse())
|
||||
}
|
||||
|
||||
private predicate operandReturned(Operand operand, IntValue bitOffset) {
|
||||
@@ -340,6 +338,56 @@ private predicate resultEscapesNonReturn(Instruction instr) {
|
||||
not instr.isResultModeled()
|
||||
}
|
||||
|
||||
/** Holds if `operand` may (transitively) flow to an `AddressOperand`. */
|
||||
private predicate consumedAsAddressOperand(Operand operand) {
|
||||
operand instanceof AddressOperand
|
||||
or
|
||||
exists(Operand address |
|
||||
consumedAsAddressOperand(address) and
|
||||
operandIsPropagated(operand, _, address.getDef())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `operand` may originate from a base instruction of an allocation,
|
||||
* and that operand may transitively flow to an `AddressOperand`.
|
||||
*/
|
||||
private predicate propagatedFromAllocationBase(Operand operand, Configuration::Allocation allocation) {
|
||||
consumedAsAddressOperand(operand) and
|
||||
(
|
||||
not exists(Configuration::getOldAllocation(allocation)) and
|
||||
operand.getDef() = allocation.getABaseInstruction()
|
||||
or
|
||||
exists(Operand address |
|
||||
operandIsPropagated(address, _, operand.getDef()) and
|
||||
propagatedFromAllocationBase(address, allocation)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate propagatedFromNonAllocationBase(Operand operand) {
|
||||
exists(Instruction def |
|
||||
def = operand.getDef() and
|
||||
not operandIsPropagated(_, _, def) and
|
||||
not def = any(Configuration::Allocation allocation).getABaseInstruction()
|
||||
)
|
||||
or
|
||||
exists(Operand address |
|
||||
operandIsPropagated(address, _, operand.getDef()) and
|
||||
propagatedFromNonAllocationBase(address)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if we cannot see all producers of an operand for which allocation also flows into.
|
||||
*/
|
||||
private predicate operandConsumesEscaped(Configuration::Allocation allocation) {
|
||||
exists(AddressOperand address |
|
||||
propagatedFromAllocationBase(address, allocation) and
|
||||
propagatedFromNonAllocationBase(address)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the address of `allocation` escapes outside the domain of the analysis. This can occur
|
||||
* either because the allocation's address is taken within the function and escapes, or because the
|
||||
@@ -348,12 +396,14 @@ private predicate resultEscapesNonReturn(Instruction instr) {
|
||||
predicate allocationEscapes(Configuration::Allocation allocation) {
|
||||
allocation.alwaysEscapes()
|
||||
or
|
||||
exists(IREscapeAnalysisConfiguration config |
|
||||
config.useSoundEscapeAnalysis() and resultEscapesNonReturn(allocation.getABaseInstruction())
|
||||
exists(IREscapeAnalysisConfiguration config | config.useSoundEscapeAnalysis() |
|
||||
resultEscapesNonReturn(allocation.getABaseInstruction())
|
||||
or
|
||||
operandConsumesEscaped(allocation)
|
||||
)
|
||||
or
|
||||
Configuration::phaseNeedsSoundEscapeAnalysis() and
|
||||
resultEscapesNonReturn(allocation.getABaseInstruction())
|
||||
(resultEscapesNonReturn(allocation.getABaseInstruction()) or operandConsumesEscaped(allocation))
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
private import AliasConfigurationImports
|
||||
private import codeql.util.Unit
|
||||
|
||||
/**
|
||||
* A memory allocation that can be tracked by the SimpleSSA alias analysis.
|
||||
@@ -16,3 +17,5 @@ class Allocation extends IRAutomaticVariable {
|
||||
}
|
||||
|
||||
predicate phaseNeedsSoundEscapeAnalysis() { any() }
|
||||
|
||||
Unit getOldAllocation(Allocation allocation) { any() }
|
||||
|
||||
@@ -15,6 +15,51 @@ private class OldInstruction = Reachability::ReachableInstruction;
|
||||
|
||||
import Cached
|
||||
|
||||
/**
|
||||
* Holds if `instruction` is the first instruction that may be followed by
|
||||
* an `UninitializedGroup` instruction, and the enclosing function of
|
||||
* `instruction` is `func`.
|
||||
*/
|
||||
private predicate isFirstInstructionBeforeUninitializedGroup(
|
||||
Instruction instruction, IRFunction func
|
||||
) {
|
||||
instruction = getChi(any(OldIR::InitializeNonLocalInstruction init)) and
|
||||
func = instruction.getEnclosingIRFunction()
|
||||
}
|
||||
|
||||
/** Gets the `i`'th `UninitializedGroup` instruction in `func`. */
|
||||
private UninitializedGroupInstruction getInitGroupInstruction(int i, IRFunction func) {
|
||||
exists(Alias::VariableGroup vg |
|
||||
vg.getIRFunction() = func and
|
||||
vg.getInitializationOrder() = i and
|
||||
result = uninitializedGroup(vg)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instruction` is the last instruction in the chain of `UninitializedGroup`
|
||||
* instructions in `func`. The chain of instructions may be empty in which case
|
||||
* `instruction` satisfies
|
||||
* ```
|
||||
* isFirstInstructionBeforeUninitializedGroup(instruction, func)
|
||||
* ```
|
||||
*/
|
||||
predicate isLastInstructionForUninitializedGroups(Instruction instruction, IRFunction func) {
|
||||
exists(int i |
|
||||
instruction = getInitGroupInstruction(i, func) and
|
||||
not exists(getChi(instruction)) and
|
||||
not exists(getInitGroupInstruction(i + 1, func))
|
||||
)
|
||||
or
|
||||
exists(int i |
|
||||
instruction = getChi(getInitGroupInstruction(i, func)) and
|
||||
not exists(getInitGroupInstruction(i + 1, func))
|
||||
)
|
||||
or
|
||||
isFirstInstructionBeforeUninitializedGroup(instruction, func) and
|
||||
not exists(getInitGroupInstruction(0, func))
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
cached
|
||||
@@ -32,6 +77,11 @@ private module Cached {
|
||||
hasChiNode(_, primaryInstruction)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate hasChiNodeAfterUninitializedGroup(UninitializedGroupInstruction initGroup) {
|
||||
hasChiNodeAfterUninitializedGroup(_, initGroup)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate hasUnreachedInstructionCached(IRFunction irFunc) {
|
||||
exists(OldIR::Instruction oldInstruction |
|
||||
@@ -45,7 +95,8 @@ private module Cached {
|
||||
}
|
||||
|
||||
class TStageInstruction =
|
||||
TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction;
|
||||
TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction or
|
||||
TUninitializedGroupInstruction;
|
||||
|
||||
/**
|
||||
* If `oldInstruction` is a `Phi` instruction that has exactly one reachable predecessor block,
|
||||
@@ -78,6 +129,8 @@ private module Cached {
|
||||
or
|
||||
instr instanceof TChiInstruction
|
||||
or
|
||||
instr instanceof TUninitializedGroupInstruction
|
||||
or
|
||||
instr instanceof TUnreachedInstruction
|
||||
}
|
||||
|
||||
@@ -123,7 +176,8 @@ private module Cached {
|
||||
predicate hasModeledMemoryResult(Instruction instruction) {
|
||||
canModelResultForOldInstruction(getOldInstruction(instruction)) or
|
||||
instruction instanceof PhiInstruction or // Phis always have modeled results
|
||||
instruction instanceof ChiInstruction // Chis always have modeled results
|
||||
instruction instanceof ChiInstruction or // Chis always have modeled results
|
||||
instruction instanceof UninitializedGroupInstruction // Group initializers always have modeled results
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -134,16 +188,23 @@ private module Cached {
|
||||
or
|
||||
// Chi instructions track virtual variables, and therefore a chi instruction is
|
||||
// conflated if it's associated with the aliased virtual variable.
|
||||
exists(OldInstruction oldInstruction | instruction = getChi(oldInstruction) |
|
||||
Alias::getResultMemoryLocation(oldInstruction).getVirtualVariable() instanceof
|
||||
exists(Instruction input | instruction = getChi(input) |
|
||||
Alias::getResultMemoryLocation(input).getVirtualVariable() instanceof
|
||||
Alias::AliasedVirtualVariable
|
||||
or
|
||||
// A chi following an `UninitializedGroupInstruction` only happens when the virtual
|
||||
// variable of the grouped memory location is `{AllAliasedMemory}`.
|
||||
exists(Alias::GroupedMemoryLocation gml |
|
||||
input = uninitializedGroup(gml.getGroup()) and
|
||||
gml.getVirtualVariable() instanceof Alias::AliasedVirtualVariable
|
||||
)
|
||||
)
|
||||
or
|
||||
// Phi instructions track locations, and therefore a phi instruction is
|
||||
// conflated if it's associated with a conflated location.
|
||||
exists(Alias::MemoryLocation location |
|
||||
instruction = getPhi(_, location) and
|
||||
not exists(location.getAllocation())
|
||||
not exists(location.getAnAllocation())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -205,7 +266,11 @@ private module Cached {
|
||||
hasMemoryOperandDefinition(oldInstruction, oldOperand, overlap, result)
|
||||
)
|
||||
or
|
||||
instruction = getChi(getOldInstruction(result)) and
|
||||
(
|
||||
instruction = getChi(getOldInstruction(result))
|
||||
or
|
||||
instruction = getChi(result.(UninitializedGroupInstruction))
|
||||
) and
|
||||
tag instanceof ChiPartialOperandTag and
|
||||
overlap instanceof MustExactlyOverlap
|
||||
or
|
||||
@@ -263,6 +328,14 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
IRVariable getAnUninitializedGroupVariable(UninitializedGroupInstruction init) {
|
||||
exists(Alias::VariableGroup vg |
|
||||
init = uninitializedGroup(vg) and
|
||||
result = vg.getAnAllocation().getABaseInstruction().(VariableInstruction).getIRVariable()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
|
||||
* through a phi instruction and therefore should be impossible.
|
||||
@@ -316,6 +389,19 @@ private module Cached {
|
||||
result = getNewPhiOperandDefinitionFromOldSsa(instr, newPredecessorBlock, overlap)
|
||||
}
|
||||
|
||||
private ChiInstruction getChiAfterUninitializedGroup(int i, IRFunction func) {
|
||||
result =
|
||||
rank[i + 1](VariableGroup vg, UninitializedGroupInstruction initGroup, ChiInstruction chi,
|
||||
int r |
|
||||
initGroup.getEnclosingIRFunction() = func and
|
||||
chi = getChi(initGroup) and
|
||||
initGroup = uninitializedGroup(vg) and
|
||||
r = vg.getInitializationOrder()
|
||||
|
|
||||
chi order by r
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) {
|
||||
exists(
|
||||
@@ -329,6 +415,19 @@ private module Cached {
|
||||
definitionReachesUse(vvar, defBlock, defRank, useBlock, useRank) and
|
||||
result = getDefinitionOrChiInstruction(defBlock, defOffset, vvar, _)
|
||||
)
|
||||
or
|
||||
exists(UninitializedGroupInstruction initGroup, IRFunction func |
|
||||
chiInstr = getChi(initGroup) and
|
||||
func = initGroup.getEnclosingIRFunction()
|
||||
|
|
||||
chiInstr = getChiAfterUninitializedGroup(0, func) and
|
||||
isFirstInstructionBeforeUninitializedGroup(result, func)
|
||||
or
|
||||
exists(int i |
|
||||
chiInstr = getChiAfterUninitializedGroup(i + 1, func) and
|
||||
result = getChiAfterUninitializedGroup(i, func)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -344,14 +443,40 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
* This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
|
||||
* that node is its successor in the new successor relation, and the Chi node's successors are
|
||||
* the new instructions generated from the successors of the old instruction
|
||||
*/
|
||||
private UninitializedGroupInstruction firstInstructionToUninitializedGroup(
|
||||
Instruction instruction, EdgeKind kind
|
||||
) {
|
||||
exists(IRFunction func |
|
||||
isFirstInstructionBeforeUninitializedGroup(instruction, func) and
|
||||
result = getInitGroupInstruction(0, func) and
|
||||
kind instanceof GotoEdge
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
private Instruction getNextUninitializedGroupInstruction(Instruction instruction, EdgeKind kind) {
|
||||
exists(int i, IRFunction func |
|
||||
func = instruction.getEnclosingIRFunction() and
|
||||
instruction = getInitGroupInstruction(i, func) and
|
||||
kind instanceof GotoEdge
|
||||
|
|
||||
if hasChiNodeAfterUninitializedGroup(_, instruction)
|
||||
then result = getChi(instruction)
|
||||
else result = getInitGroupInstruction(i + 1, func)
|
||||
)
|
||||
or
|
||||
exists(int i, IRFunction func, UninitializedGroupInstruction initGroup |
|
||||
func = instruction.getEnclosingIRFunction() and
|
||||
instruction = getChi(initGroup) and
|
||||
initGroup = getInitGroupInstruction(i, func) and
|
||||
kind instanceof GotoEdge
|
||||
|
|
||||
result = getInitGroupInstruction(i + 1, func)
|
||||
)
|
||||
}
|
||||
|
||||
private Instruction getInstructionSuccessorAfterUninitializedGroup0(
|
||||
Instruction instruction, EdgeKind kind
|
||||
) {
|
||||
if hasChiNode(_, getOldInstruction(instruction))
|
||||
then
|
||||
result = getChi(getOldInstruction(instruction)) and
|
||||
@@ -371,6 +496,107 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
private Instruction getInstructionSuccessorAfterUninitializedGroup(
|
||||
Instruction instruction, EdgeKind kind
|
||||
) {
|
||||
exists(IRFunction func, Instruction firstBeforeUninitializedGroup |
|
||||
isLastInstructionForUninitializedGroups(instruction, func) and
|
||||
isFirstInstructionBeforeUninitializedGroup(firstBeforeUninitializedGroup, func) and
|
||||
result = getInstructionSuccessorAfterUninitializedGroup0(firstBeforeUninitializedGroup, kind)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* This adds Chi nodes to the instruction successor relation; if an instruction has a Chi node,
|
||||
* that node is its successor in the new successor relation, and the Chi node's successors are
|
||||
* the new instructions generated from the successors of the old instruction.
|
||||
*
|
||||
* Furthermore, the entry block is augmented with `UninitializedGroup` instructions and `Chi`
|
||||
* instructions. For example, consider this example:
|
||||
* ```cpp
|
||||
* int x, y;
|
||||
* int* p;
|
||||
* if(b) {
|
||||
* p = &x;
|
||||
* escape(&x);
|
||||
* } else {
|
||||
* p = &y;
|
||||
* }
|
||||
* *p = 42;
|
||||
*
|
||||
* int z, w;
|
||||
* int* q;
|
||||
* if(b) {
|
||||
* q = &z;
|
||||
* } else {
|
||||
* q = &w;
|
||||
* }
|
||||
* *q = 43;
|
||||
* ```
|
||||
*
|
||||
* the unaliased IR for the entry block of this snippet is:
|
||||
* ```
|
||||
* v1(void) = EnterFunction :
|
||||
* m1(unknown) = AliasedDefinition :
|
||||
* m2(unknown) = InitializeNonLocal :
|
||||
* r1(glval<bool>) = VariableAddress[b] :
|
||||
* m3(bool) = InitializeParameter[b] : &:r1
|
||||
* r2(glval<int>) = VariableAddress[x] :
|
||||
* m4(int) = Uninitialized[x] : &:r2
|
||||
* r3(glval<int>) = VariableAddress[y] :
|
||||
* m5(int) = Uninitialized[y] : &:r3
|
||||
* r4(glval<int *>) = VariableAddress[p] :
|
||||
* m6(int *) = Uninitialized[p] : &:r4
|
||||
* r5(glval<bool>) = VariableAddress[b] :
|
||||
* r6(bool) = Load[b] : &:r5, m3
|
||||
* v2(void) = ConditionalBranch : r6
|
||||
* ```
|
||||
* and we need to transform this to aliased IR by inserting an `UninitializedGroup`
|
||||
* instruction for every `VariableGroup` memory location in the function. Furthermore,
|
||||
* if the `VariableGroup` memory location contains an allocation that escapes we need
|
||||
* to insert a `Chi` that writes the memory produced by `UninitializedGroup` into
|
||||
* `{AllAliasedMemory}`. For the above snippet we then end up with:
|
||||
* ```
|
||||
* v1(void) = EnterFunction :
|
||||
* m2(unknown) = AliasedDefinition :
|
||||
* m3(unknown) = InitializeNonLocal :
|
||||
* m4(unknown) = Chi : total:m2, partial:m3
|
||||
* m5(int) = UninitializedGroup[x,y] :
|
||||
* m6(unknown) = Chi : total:m4, partial:m5
|
||||
* m7(int) = UninitializedGroup[w,z] :
|
||||
* r1(glval<bool>) = VariableAddress[b] :
|
||||
* m8(bool) = InitializeParameter[b] : &:r1
|
||||
* r2(glval<int>) = VariableAddress[x] :
|
||||
* m10(int) = Uninitialized[x] : &:r2
|
||||
* m11(unknown) = Chi : total:m6, partial:m10
|
||||
* r3(glval<int>) = VariableAddress[y] :
|
||||
* m12(int) = Uninitialized[y] : &:r3
|
||||
* m13(unknown) = Chi : total:m11, partial:m12
|
||||
* r4(glval<int *>) = VariableAddress[p] :
|
||||
* m14(int *) = Uninitialized[p] : &:r4
|
||||
* r5(glval<bool>) = VariableAddress[b] :
|
||||
* r6(bool) = Load[b] : &:r5, m8
|
||||
* v2(void) = ConditionalBranch : r6
|
||||
* ```
|
||||
*
|
||||
* Here, the group `{x, y}` contains an allocation that escapes (`x`), so there
|
||||
* is a `Chi` after the `UninitializedGroup` that initializes the memory for the
|
||||
* `VariableGroup` containing `x`. None of the allocations in `{w, z}` escape so
|
||||
* there is no `Chi` following that the `UninitializedGroup` that initializes the
|
||||
* memory of `{w, z}`.
|
||||
*/
|
||||
cached
|
||||
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
result = firstInstructionToUninitializedGroup(instruction, kind)
|
||||
or
|
||||
result = getNextUninitializedGroupInstruction(instruction, kind)
|
||||
or
|
||||
result = getInstructionSuccessorAfterUninitializedGroup(instruction, kind)
|
||||
or
|
||||
not isFirstInstructionBeforeUninitializedGroup(instruction, _) and
|
||||
result = getInstructionSuccessorAfterUninitializedGroup0(instruction, kind)
|
||||
}
|
||||
|
||||
cached
|
||||
Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
exists(OldInstruction oldInstruction |
|
||||
@@ -406,6 +632,16 @@ private module Cached {
|
||||
exists(IRFunctionBase irFunc |
|
||||
instr = unreachedInstruction(irFunc) and result = irFunc.getFunction()
|
||||
)
|
||||
or
|
||||
exists(Alias::VariableGroup vg |
|
||||
instr = uninitializedGroup(vg) and
|
||||
result = vg.getIRFunction().getFunction()
|
||||
)
|
||||
or
|
||||
exists(UninitializedGroupInstruction initGroup |
|
||||
instr = chiInstruction(initGroup) and
|
||||
result = getInstructionAst(initGroup)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -418,9 +654,16 @@ private module Cached {
|
||||
)
|
||||
or
|
||||
exists(Instruction primaryInstr, Alias::VirtualVariable vvar |
|
||||
instr = chiInstruction(primaryInstr) and
|
||||
hasChiNode(vvar, primaryInstr) and
|
||||
result = vvar.getType()
|
||||
instr = chiInstruction(primaryInstr) and result = vvar.getType()
|
||||
|
|
||||
hasChiNode(vvar, primaryInstr)
|
||||
or
|
||||
hasChiNodeAfterUninitializedGroup(vvar, primaryInstr)
|
||||
)
|
||||
or
|
||||
exists(Alias::VariableGroup vg |
|
||||
instr = uninitializedGroup(vg) and
|
||||
result = vg.getType()
|
||||
)
|
||||
or
|
||||
instr = reusedPhiInstruction(_) and
|
||||
@@ -448,6 +691,8 @@ private module Cached {
|
||||
or
|
||||
instr = chiInstruction(_) and opcode instanceof Opcode::Chi
|
||||
or
|
||||
instr = uninitializedGroup(_) and opcode instanceof Opcode::UninitializedGroup
|
||||
or
|
||||
instr = unreachedInstruction(_) and opcode instanceof Opcode::Unreached
|
||||
}
|
||||
|
||||
@@ -460,10 +705,15 @@ private module Cached {
|
||||
result = blockStartInstr.getEnclosingIRFunction()
|
||||
)
|
||||
or
|
||||
exists(OldInstruction primaryInstr |
|
||||
exists(Instruction primaryInstr |
|
||||
instr = chiInstruction(primaryInstr) and result = primaryInstr.getEnclosingIRFunction()
|
||||
)
|
||||
or
|
||||
exists(Alias::VariableGroup vg |
|
||||
instr = uninitializedGroup(vg) and
|
||||
result = vg.getIRFunction()
|
||||
)
|
||||
or
|
||||
instr = unreachedInstruction(result)
|
||||
}
|
||||
|
||||
@@ -478,6 +728,8 @@ private module Cached {
|
||||
instruction = getChi(oldInstruction) and
|
||||
result = getNewInstruction(oldInstruction)
|
||||
)
|
||||
or
|
||||
instruction = getChi(result.(UninitializedGroupInstruction))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -485,7 +737,7 @@ private Instruction getNewInstruction(OldInstruction instr) { getOldInstruction(
|
||||
|
||||
private OldInstruction getOldInstruction(Instruction instr) { instr = result }
|
||||
|
||||
private ChiInstruction getChi(OldInstruction primaryInstr) { result = chiInstruction(primaryInstr) }
|
||||
private ChiInstruction getChi(Instruction primaryInstr) { result = chiInstruction(primaryInstr) }
|
||||
|
||||
private PhiInstruction getPhi(OldBlock defBlock, Alias::MemoryLocation defLocation) {
|
||||
result = phiInstruction(defBlock.getFirstInstruction(), defLocation)
|
||||
@@ -506,6 +758,16 @@ private predicate hasChiNode(Alias::VirtualVariable vvar, OldInstruction def) {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate hasChiNodeAfterUninitializedGroup(
|
||||
Alias::AliasedVirtualVariable vvar, UninitializedGroupInstruction initGroup
|
||||
) {
|
||||
exists(Alias::GroupedMemoryLocation defLocation |
|
||||
initGroup = uninitializedGroup(defLocation.getGroup()) and
|
||||
defLocation.getVirtualVariable() = vvar and
|
||||
Alias::getOverlap(defLocation, vvar) instanceof MayPartiallyOverlap
|
||||
)
|
||||
}
|
||||
|
||||
private import PhiInsertion
|
||||
|
||||
/**
|
||||
@@ -668,19 +930,37 @@ private import DefUse
|
||||
* potentially very sparse.
|
||||
*/
|
||||
module DefUse {
|
||||
bindingset[index, block]
|
||||
pragma[inline_late]
|
||||
private int getNonChiOffset(int index, OldBlock block) {
|
||||
exists(OldIR::IRFunction func, Instruction i, OldBlock entryBlock |
|
||||
func = block.getEnclosingIRFunction() and
|
||||
i = block.getInstruction(index) and
|
||||
entryBlock = func.getEntryBlock()
|
||||
|
|
||||
if
|
||||
block = entryBlock and
|
||||
not i instanceof InitializeNonLocalInstruction and
|
||||
not i instanceof AliasedDefinitionInstruction
|
||||
then result = 2 * (index + count(VariableGroup vg | vg.getIRFunction() = func))
|
||||
else result = 2 * index
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[index, block]
|
||||
pragma[inline_late]
|
||||
private int getChiOffset(int index, OldBlock block) { result = getNonChiOffset(index, block) + 1 }
|
||||
|
||||
/**
|
||||
* Gets the `Instruction` for the definition at offset `defOffset` in block `defBlock`.
|
||||
*/
|
||||
Instruction getDefinitionOrChiInstruction(
|
||||
private Instruction getDefinitionOrChiInstruction0(
|
||||
OldBlock defBlock, int defOffset, Alias::MemoryLocation defLocation,
|
||||
Alias::MemoryLocation actualDefLocation
|
||||
) {
|
||||
exists(OldInstruction oldInstr, int oldOffset |
|
||||
oldInstr = defBlock.getInstruction(oldOffset) and
|
||||
oldOffset >= 0
|
||||
|
|
||||
exists(OldInstruction oldInstr, int oldOffset | oldInstr = defBlock.getInstruction(oldOffset) |
|
||||
// An odd offset corresponds to the `Chi` instruction.
|
||||
defOffset = oldOffset * 2 + 1 and
|
||||
defOffset = getChiOffset(oldOffset, defBlock) and
|
||||
result = getChi(oldInstr) and
|
||||
(
|
||||
defLocation = Alias::getResultMemoryLocation(oldInstr) or
|
||||
@@ -689,7 +969,7 @@ module DefUse {
|
||||
actualDefLocation = defLocation.getVirtualVariable()
|
||||
or
|
||||
// An even offset corresponds to the original instruction.
|
||||
defOffset = oldOffset * 2 and
|
||||
defOffset = getNonChiOffset(oldOffset, defBlock) and
|
||||
result = getNewInstruction(oldInstr) and
|
||||
(
|
||||
defLocation = Alias::getResultMemoryLocation(oldInstr) or
|
||||
@@ -702,6 +982,54 @@ module DefUse {
|
||||
hasDefinition(_, defLocation, defBlock, defOffset) and
|
||||
result = getPhi(defBlock, defLocation) and
|
||||
actualDefLocation = defLocation
|
||||
or
|
||||
exists(
|
||||
Alias::VariableGroup vg, int index, UninitializedGroupInstruction initGroup,
|
||||
Alias::GroupedMemoryLocation gml
|
||||
|
|
||||
// Add 3 to account for the function prologue:
|
||||
// v1(void) = EnterFunction
|
||||
// m1(unknown) = AliasedDefinition
|
||||
// m2(unknown) = InitializeNonLocal
|
||||
index = 3 + vg.getInitializationOrder() and
|
||||
not gml.isMayAccess() and
|
||||
gml.isSome() and
|
||||
gml.getGroup() = vg and
|
||||
vg.getIRFunction().getEntryBlock() = defBlock and
|
||||
initGroup = uninitializedGroup(vg) and
|
||||
(defLocation = gml or defLocation = gml.getVirtualVariable())
|
||||
|
|
||||
result = initGroup and
|
||||
defOffset = 2 * index and
|
||||
actualDefLocation = defLocation
|
||||
or
|
||||
result = getChi(initGroup) and
|
||||
defOffset = 2 * index + 1 and
|
||||
actualDefLocation = defLocation.getVirtualVariable()
|
||||
)
|
||||
}
|
||||
|
||||
private ChiInstruction remapGetDefinitionOrChiInstruction(Instruction oldResult) {
|
||||
exists(IRFunction func |
|
||||
isFirstInstructionBeforeUninitializedGroup(oldResult, func) and
|
||||
isLastInstructionForUninitializedGroups(result, func)
|
||||
)
|
||||
}
|
||||
|
||||
Instruction getDefinitionOrChiInstruction(
|
||||
OldBlock defBlock, int defOffset, Alias::MemoryLocation defLocation,
|
||||
Alias::MemoryLocation actualDefLocation
|
||||
) {
|
||||
exists(Instruction oldResult |
|
||||
oldResult =
|
||||
getDefinitionOrChiInstruction0(defBlock, defOffset, defLocation, actualDefLocation) and
|
||||
(
|
||||
result = remapGetDefinitionOrChiInstruction(oldResult)
|
||||
or
|
||||
not exists(remapGetDefinitionOrChiInstruction(oldResult)) and
|
||||
result = oldResult
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -842,8 +1170,20 @@ module DefUse {
|
||||
block.getInstruction(index) = def and
|
||||
overlap = Alias::getOverlap(defLocation, useLocation) and
|
||||
if overlap instanceof MayPartiallyOverlap
|
||||
then offset = (index * 2) + 1 // The use will be connected to the definition on the `Chi` instruction.
|
||||
else offset = index * 2 // The use will be connected to the definition on the original instruction.
|
||||
then offset = getChiOffset(index, block) // The use will be connected to the definition on the `Chi` instruction.
|
||||
else offset = getNonChiOffset(index, block) // The use will be connected to the definition on the original instruction.
|
||||
)
|
||||
or
|
||||
exists(UninitializedGroupInstruction initGroup, int index, Overlap overlap, VariableGroup vg |
|
||||
initGroup.getEnclosingIRFunction().getEntryBlock() = getNewBlock(block) and
|
||||
vg = defLocation.(Alias::GroupedMemoryLocation).getGroup() and
|
||||
// EnterFunction + AliasedDefinition + InitializeNonLocal + index
|
||||
index = 3 + vg.getInitializationOrder() and
|
||||
initGroup = uninitializedGroup(vg) and
|
||||
overlap = Alias::getOverlap(defLocation, useLocation) and
|
||||
if overlap instanceof MayPartiallyOverlap and hasChiNodeAfterUninitializedGroup(initGroup)
|
||||
then offset = 2 * index + 1 // The use will be connected to the definition on the `Chi` instruction.
|
||||
else offset = 2 * index // The use will be connected to the definition on the original instruction.
|
||||
)
|
||||
}
|
||||
|
||||
@@ -904,10 +1244,11 @@ module DefUse {
|
||||
block.getInstruction(index) = use and
|
||||
(
|
||||
// A direct use of the location.
|
||||
useLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and offset = index * 2
|
||||
useLocation = Alias::getOperandMemoryLocation(use.getAnOperand()) and
|
||||
offset = getNonChiOffset(index, block)
|
||||
or
|
||||
// A `Chi` instruction will include a use of the virtual variable.
|
||||
hasChiNode(useLocation, use) and offset = (index * 2) + 1
|
||||
hasChiNode(useLocation, use) and offset = getChiOffset(index, block)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1057,5 +1398,9 @@ module Ssa {
|
||||
|
||||
predicate hasChiInstruction = Cached::hasChiInstructionCached/1;
|
||||
|
||||
predicate hasChiNodeAfterUninitializedGroup = Cached::hasChiNodeAfterUninitializedGroup/1;
|
||||
|
||||
predicate hasUnreachedInstruction = Cached::hasUnreachedInstructionCached/1;
|
||||
|
||||
class VariableGroup = Alias::VariableGroup;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import AliasAnalysis
|
||||
private import SimpleSSAImports
|
||||
import SimpleSSAPublicImports
|
||||
private import AliasConfiguration
|
||||
import AliasConfiguration
|
||||
private import codeql.util.Unit
|
||||
|
||||
private predicate isTotalAccess(Allocation var, AddressOperand addrOperand, IRType type) {
|
||||
exists(Instruction constantBase, int bitOffset |
|
||||
@@ -48,7 +49,7 @@ predicate canReuseSsaForVariable(IRAutomaticVariable var) {
|
||||
|
||||
private newtype TMemoryLocation = MkMemoryLocation(Allocation var) { isVariableModeled(var) }
|
||||
|
||||
private MemoryLocation getMemoryLocation(Allocation var) { result.getAllocation() = var }
|
||||
private MemoryLocation getMemoryLocation(Allocation var) { result.getAnAllocation() = var }
|
||||
|
||||
class MemoryLocation extends TMemoryLocation {
|
||||
Allocation var;
|
||||
@@ -57,7 +58,7 @@ class MemoryLocation extends TMemoryLocation {
|
||||
|
||||
final string toString() { result = var.getAllocationString() }
|
||||
|
||||
final Allocation getAllocation() { result = var }
|
||||
final Allocation getAnAllocation() { result = var }
|
||||
|
||||
final Language::Location getLocation() { result = var.getLocation() }
|
||||
|
||||
@@ -77,6 +78,40 @@ class MemoryLocation extends TMemoryLocation {
|
||||
|
||||
predicate canReuseSsaForOldResult(Instruction instr) { none() }
|
||||
|
||||
abstract class VariableGroup extends Unit {
|
||||
abstract Allocation getAnAllocation();
|
||||
|
||||
string toString() { result = "{" + strictconcat(this.getAnAllocation().toString(), ", ") + "}" }
|
||||
|
||||
abstract Language::Location getLocation();
|
||||
|
||||
abstract IRFunction getIRFunction();
|
||||
|
||||
abstract Language::LanguageType getType();
|
||||
|
||||
abstract int getInitializationOrder();
|
||||
}
|
||||
|
||||
class GroupedMemoryLocation extends MemoryLocation {
|
||||
VariableGroup vg;
|
||||
|
||||
GroupedMemoryLocation() { none() }
|
||||
|
||||
/** Gets an allocation of this memory location. */
|
||||
Allocation getAnAllocation() { result = vg.getAnAllocation() }
|
||||
|
||||
/** Gets the set of allocations associated with this memory location. */
|
||||
VariableGroup getGroup() { result = vg }
|
||||
|
||||
predicate isMayAccess() { none() }
|
||||
|
||||
/** Holds if this memory location represents all the enclosing allocations. */
|
||||
predicate isAll() { none() }
|
||||
|
||||
/** Holds if this memory location represents one or more of the enclosing allocations. */
|
||||
predicate isSome() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a set of `MemoryLocation`s that cannot overlap with
|
||||
* `MemoryLocation`s outside of the set. The `VirtualVariable` will be
|
||||
|
||||
@@ -27,6 +27,11 @@ private import implementations.StdPair
|
||||
private import implementations.StdMap
|
||||
private import implementations.StdSet
|
||||
private import implementations.StdString
|
||||
private import implementations.StdFunction
|
||||
private import implementations.StdException
|
||||
private import implementations.StdAllocator
|
||||
private import implementations.StdAlgorithm
|
||||
private import implementations.StdMath
|
||||
private import implementations.Swap
|
||||
private import implementations.GetDelim
|
||||
private import implementations.SmartPointer
|
||||
|
||||
@@ -86,6 +86,41 @@ private class StdIterator extends Iterator, Class {
|
||||
override Type getValueType() { result = this.getTemplateArgument(1).(Type).getUnderlyingType() }
|
||||
}
|
||||
|
||||
private class StdReverseIterator extends Iterator, Class {
|
||||
StdReverseIterator() { this.hasQualifiedName(["std", "bsl"], "reverse_iterator") }
|
||||
|
||||
override Type getValueType() { result = this.getTemplateArgument(1).(Type).getUnderlyingType() }
|
||||
}
|
||||
|
||||
private class StdIstreamBufIterator extends Iterator, Class {
|
||||
StdIstreamBufIterator() { this.hasQualifiedName(["std", "bsl"], "istreambuf_iterator") }
|
||||
|
||||
override Type getValueType() { result = this.getTemplateArgument(1).(Type).getUnderlyingType() }
|
||||
}
|
||||
|
||||
private class StdIstreambufIteratorConstructor extends Constructor, SideEffectFunction,
|
||||
AliasFunction
|
||||
{
|
||||
StdIstreambufIteratorConstructor() { this.getDeclaringType() instanceof StdIstreamBufIterator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `FunctionInput` corresponding to an iterator parameter to
|
||||
* user-defined operator `op`, at `index`.
|
||||
@@ -579,23 +614,43 @@ private class IteratorAssignmentMemberOperatorModel extends IteratorAssignmentMe
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { index = -1 }
|
||||
}
|
||||
|
||||
private string beginName() {
|
||||
result = ["begin", "cbegin", "rbegin", "crbegin", "before_begin", "cbefore_begin"]
|
||||
}
|
||||
|
||||
/**
|
||||
* A `begin` member function, or a related function, that returns an iterator.
|
||||
*/
|
||||
class BeginFunction extends MemberFunction {
|
||||
class BeginFunction extends Function {
|
||||
BeginFunction() {
|
||||
this.hasName(["begin", "cbegin", "rbegin", "crbegin", "before_begin", "cbefore_begin"]) and
|
||||
this.getType().getUnspecifiedType() instanceof Iterator
|
||||
this.getUnspecifiedType() instanceof Iterator and
|
||||
(
|
||||
this.hasName(beginName()) and
|
||||
this instanceof MemberFunction
|
||||
or
|
||||
this.hasGlobalOrStdOrBslName(beginName()) and
|
||||
not this instanceof MemberFunction and
|
||||
this.getNumberOfParameters() = 1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private string endName() { result = ["end", "cend", "rend", "crend"] }
|
||||
|
||||
/**
|
||||
* An `end` member function, or a related function, that returns an iterator.
|
||||
*/
|
||||
class EndFunction extends MemberFunction {
|
||||
class EndFunction extends Function {
|
||||
EndFunction() {
|
||||
this.hasName(["end", "cend", "rend", "crend"]) and
|
||||
this.getType().getUnspecifiedType() instanceof Iterator
|
||||
this.getUnspecifiedType() instanceof Iterator and
|
||||
(
|
||||
this.hasName(endName()) and
|
||||
this instanceof MemberFunction
|
||||
or
|
||||
this.hasGlobalOrStdOrBslName(endName()) and
|
||||
this instanceof MemberFunction and
|
||||
this.getNumberOfParameters() = 1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -603,7 +658,7 @@ class EndFunction extends MemberFunction {
|
||||
* A `begin` or `end` member function, or a related member function, that
|
||||
* returns an iterator.
|
||||
*/
|
||||
class BeginOrEndFunction extends MemberFunction {
|
||||
class BeginOrEndFunction extends Function {
|
||||
BeginOrEndFunction() {
|
||||
this instanceof BeginFunction or
|
||||
this instanceof EndFunction
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
import semmle.code.cpp.models.interfaces.FormattingFunction
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
|
||||
/**
|
||||
* The standard functions `printf`, `wprintf` and their glib variants.
|
||||
@@ -96,7 +97,7 @@ private class Sprintf extends FormattingFunction {
|
||||
/**
|
||||
* Implements `Snprintf`.
|
||||
*/
|
||||
private class SnprintfImpl extends Snprintf {
|
||||
private class SnprintfImpl extends Snprintf, AliasFunction, SideEffectFunction {
|
||||
SnprintfImpl() {
|
||||
this instanceof TopLevelFunction and
|
||||
(
|
||||
@@ -143,6 +144,26 @@ private class SnprintfImpl extends Snprintf {
|
||||
}
|
||||
|
||||
override int getSizeParameterIndex() { result = 1 }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) {
|
||||
// We don't know how many parameters are passed to the function since it's varargs, but they also don't escape.
|
||||
index = this.getFormatParameterIndex()
|
||||
}
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = this.getOutputParameterIndex(false) and buffer = true and mustWrite = false
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
// We don't know how many parameters are passed to the function since it's varargs, but they also have read side effects.
|
||||
i = this.getFormatParameterIndex() and buffer = true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* Provides models for C++ functions from the `algorithms` header.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
import semmle.code.cpp.models.interfaces.DataFlow
|
||||
import semmle.code.cpp.models.interfaces.Iterator
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
|
||||
private class StdPartialSort extends Function, SideEffectFunction, AliasFunction {
|
||||
StdPartialSort() { this.hasGlobalOrStdName("partial_sort") }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = this.getAnIteratorParameterIndex() and buffer = true and mustWrite = false
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = this.getAnIteratorParameterIndex() and
|
||||
buffer = true and
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
|
||||
buffer = false
|
||||
}
|
||||
|
||||
private int getAnIteratorParameterIndex() {
|
||||
this.getParameter(result).getUnspecifiedType() instanceof Iterator
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) {
|
||||
index = this.getAnIteratorParameterIndex()
|
||||
or
|
||||
this.getParameter(index).getUnspecifiedType() instanceof ReferenceType
|
||||
}
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
}
|
||||
|
||||
private class StdSortHeap extends Function, SideEffectFunction, AliasFunction {
|
||||
StdSortHeap() { this.hasGlobalOrStdName("sort_heap") }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = this.getAnIteratorParameterIndex() and buffer = true and mustWrite = false
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = this.getAnIteratorParameterIndex() and
|
||||
buffer = true
|
||||
}
|
||||
|
||||
private int getAnIteratorParameterIndex() {
|
||||
this.getParameter(result).getUnspecifiedType() instanceof Iterator
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = this.getAnIteratorParameterIndex() }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
}
|
||||
|
||||
private class StdGenerateN extends Function, SideEffectFunction, AliasFunction {
|
||||
StdGenerateN() { this.hasGlobalOrStdName("generate_n") }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = this.getAnIteratorParameterIndex() and buffer = true and mustWrite = false
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and buffer = false
|
||||
}
|
||||
|
||||
private int getAnIteratorParameterIndex() {
|
||||
this.getParameter(result).getUnspecifiedType() instanceof Iterator
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = this.getAnIteratorParameterIndex() }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
}
|
||||
|
||||
private class StdFindIfOrIfNot extends Function, SideEffectFunction, AliasFunction {
|
||||
StdFindIfOrIfNot() { this.hasGlobalOrStdName(["find_if", "find_if_not"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = this.getAnIteratorParameterIndex() and buffer = true
|
||||
or
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and buffer = false
|
||||
}
|
||||
|
||||
private int getAnIteratorParameterIndex() {
|
||||
this.getParameter(result).getUnspecifiedType() instanceof Iterator
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) {
|
||||
this.getParameter(index).getUnspecifiedType() instanceof ReferenceType
|
||||
}
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) {
|
||||
index = this.getAnIteratorParameterIndex()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
/**
|
||||
* Provides models for C++ `allocator` and `allocator_traits` classes.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
|
||||
/** The `std::allocator` class. */
|
||||
class StdAllocator extends Class {
|
||||
StdAllocator() { this.hasGlobalOrStdOrBslName("allocator") }
|
||||
}
|
||||
|
||||
/** The `std::allocator_traits` class. */
|
||||
class StdAllocatorTraits extends Class {
|
||||
StdAllocatorTraits() { this.hasGlobalOrStdOrBslName("allocator_traits") }
|
||||
}
|
||||
|
||||
private class StdAllocatorConstructor extends Constructor, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorConstructor() { this.getDeclaringType() instanceof StdAllocator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and
|
||||
buffer = false and
|
||||
mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdAllocatorDestructor extends Destructor, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorDestructor() { this.getDeclaringType() instanceof StdAllocator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and
|
||||
buffer = false and
|
||||
mustWrite = true
|
||||
}
|
||||
}
|
||||
|
||||
private class StdAllocatorAddress extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorAddress() { this.getClassAndName("address") instanceof StdAllocator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class StdAllocatorAllocate extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorAllocate() { this.getClassAndName("allocate") instanceof StdAllocator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class StdAllocatorTraitsAllocate extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorTraitsAllocate() {
|
||||
this.getClassAndName(["allocate", "allocate_at_least"]) instanceof StdAllocatorTraits
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) {
|
||||
this.getParameter(index).getUnspecifiedType() instanceof ReferenceType
|
||||
}
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdAllocatorDeallocate extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorDeallocate() { this.getClassAndName("deallocate") instanceof StdAllocator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = 0 and
|
||||
buffer = false and
|
||||
mustWrite = false
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = 0 and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdAllocatorTraitsDeallocate extends MemberFunction, AliasFunction, SideEffectFunction
|
||||
{
|
||||
StdAllocatorTraitsDeallocate() {
|
||||
this.getClassAndName("deallocate") instanceof StdAllocatorTraits
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = [0, 1] }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = 1 and
|
||||
buffer = false and
|
||||
mustWrite = false
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = [0, 1] and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdAllocatorMaxSize extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorMaxSize() { this.getClassAndName("max_size") instanceof StdAllocator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class StdAllocatTraitsMaxSize extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatTraitsMaxSize() { this.getClassAndName("max_size") instanceof StdAllocatorTraits }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class StdAllocatorConstruct extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorConstruct() { this.getClassAndName("construct") instanceof StdAllocator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = 0 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
class StdAllocatorTraitsConstruct extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorTraitsConstruct() { this.getClassAndName("construct") instanceof StdAllocatorTraits }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) {
|
||||
index = 1 or this.getParameter(index).getUnspecifiedType() instanceof ReferenceType
|
||||
}
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = 1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
class StdAllocatorDestroy extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorDestroy() { this.getClassAndName("destroy") instanceof StdAllocator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = 0 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = 0 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
class StdAllocatorTraitsDestroy extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
StdAllocatorTraitsDestroy() { this.getClassAndName("destroy") instanceof StdAllocatorTraits }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = [0, 1] }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = 1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = 0 and buffer = false
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
import semmle.code.cpp.models.interfaces.FlowSource
|
||||
import semmle.code.cpp.models.interfaces.Iterator
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
|
||||
/**
|
||||
* A sequence container template class (for example, `std::vector`) from the
|
||||
@@ -58,7 +60,7 @@ private class Vector extends StdSequenceContainer {
|
||||
/**
|
||||
* The standard container functions `push_back` and `push_front`.
|
||||
*/
|
||||
class StdSequenceContainerPush extends MemberFunction {
|
||||
class StdSequenceContainerPush extends MemberFunction, SideEffectFunction, AliasFunction {
|
||||
StdSequenceContainerPush() {
|
||||
this.getClassAndName("push_back") instanceof Vector or
|
||||
this.getClassAndName(["push_back", "push_front"]) instanceof Deque or
|
||||
@@ -74,12 +76,115 @@ class StdSequenceContainerPush extends MemberFunction {
|
||||
this.getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() =
|
||||
this.getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. the `T` of this `std::vector<T>`
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and
|
||||
buffer = false and
|
||||
mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
// the `std::vector<bool>` specialization doesn't take a reference as a
|
||||
// parameter. So we need to check that the parameter is actually a
|
||||
// reference.
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdSequenceContainerPopFrontOrBack extends MemberFunction, SideEffectFunction,
|
||||
AliasFunction
|
||||
{
|
||||
StdSequenceContainerPopFrontOrBack() {
|
||||
this.getClassAndName("pop_back") instanceof Vector or
|
||||
this.getClassAndName("pop_front") instanceof ForwardList or
|
||||
this.getClassAndName(["pop_front", "pop_back"]) instanceof Deque or
|
||||
this.getClassAndName(["pop_front", "pop_back"]) instanceof List
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and
|
||||
buffer = false and
|
||||
mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdSequenceContainerClear extends MemberFunction, SideEffectFunction, AliasFunction {
|
||||
StdSequenceContainerClear() {
|
||||
this.getClassAndName("clear") instanceof Vector or
|
||||
this.getClassAndName("clear") instanceof Deque or
|
||||
this.getClassAndName("clear") instanceof ForwardList or
|
||||
this.getClassAndName("clear") instanceof List
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and
|
||||
buffer = false and
|
||||
mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdVectorReserve extends MemberFunction, SideEffectFunction, AliasFunction {
|
||||
StdVectorReserve() { this.getClassAndName("reserve") instanceof Vector }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and
|
||||
buffer = false and
|
||||
mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard container functions `insert` and `insert_after`.
|
||||
*/
|
||||
class StdSequenceContainerInsert extends MemberFunction {
|
||||
class StdSequenceContainerInsert extends MemberFunction, SideEffectFunction, AliasFunction {
|
||||
StdSequenceContainerInsert() {
|
||||
this.getClassAndName("insert") instanceof Deque or
|
||||
this.getClassAndName("insert") instanceof List or
|
||||
@@ -100,17 +205,138 @@ class StdSequenceContainerInsert extends MemberFunction {
|
||||
* Gets the index of a parameter to this function that is an iterator.
|
||||
*/
|
||||
int getAnIteratorParameterIndex() { this.getParameter(result).getType() instanceof Iterator }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and
|
||||
buffer = false and
|
||||
mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdSequenceContainerFrontBack extends MemberFunction, SideEffectFunction,
|
||||
AliasFunction
|
||||
{
|
||||
StdSequenceContainerFrontBack() {
|
||||
this.getClassAndName(["front", "back"]) instanceof Deque or
|
||||
this.getClassAndName(["front", "back"]) instanceof List or
|
||||
this.getClassAndName(["front", "back"]) instanceof Vector or
|
||||
// forward_list does not have a 'back' member function
|
||||
this.getClassAndName("front") instanceof ForwardList
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard container functions `at` and `operator[]`.
|
||||
*/
|
||||
class StdSequenceContainerAt extends MemberFunction {
|
||||
class StdSequenceContainerAt extends MemberFunction, SideEffectFunction, AliasFunction {
|
||||
StdSequenceContainerAt() {
|
||||
this.getClassAndName(["at", "operator[]"]) instanceof Array or
|
||||
this.getClassAndName(["at", "operator[]"]) instanceof Deque or
|
||||
this.getClassAndName(["at", "operator[]"]) instanceof Vector
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdSequenceContainerMemberEquals extends MemberFunction, SideEffectFunction,
|
||||
AliasFunction
|
||||
{
|
||||
StdSequenceContainerMemberEquals() {
|
||||
this.getClassAndName("operator==") instanceof Array or
|
||||
this.getClassAndName("operator==") instanceof Deque or
|
||||
this.getClassAndName("operator==") instanceof Vector
|
||||
}
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 or index = 0 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
or
|
||||
i = 0 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdSequenceContainerEquals extends Function, SideEffectFunction, AliasFunction {
|
||||
StdSequenceContainerEquals() {
|
||||
this.hasGlobalOrStdOrBslName("operator==") and
|
||||
not this instanceof MemberFunction and
|
||||
this.getNumberOfParameters() = 2 and
|
||||
(
|
||||
this.getParameter(0).getUnspecifiedType().(ReferenceType).getBaseType() instanceof Vector and
|
||||
this.getParameter(1).getUnspecifiedType().(ReferenceType).getBaseType() instanceof Vector
|
||||
or
|
||||
this.getParameter(0).getUnspecifiedType().(ReferenceType).getBaseType() instanceof List and
|
||||
this.getParameter(1).getUnspecifiedType().(ReferenceType).getBaseType() instanceof List
|
||||
or
|
||||
this.getParameter(0).getUnspecifiedType().(ReferenceType).getBaseType() instanceof Deque and
|
||||
this.getParameter(1).getUnspecifiedType().(ReferenceType).getBaseType() instanceof Deque
|
||||
)
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = 0 or index = 1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = [0, 1] and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,6 +368,115 @@ class StdVectorEmplace extends StdSequenceEmplace {
|
||||
StdVectorEmplace() { this.getDeclaringType() instanceof Vector }
|
||||
}
|
||||
|
||||
private class StdSequenceSize extends MemberFunction, SideEffectFunction, AliasFunction {
|
||||
StdSequenceSize() {
|
||||
this.getClassAndName("size") instanceof Vector
|
||||
or
|
||||
this.getClassAndName("size") instanceof List
|
||||
or
|
||||
this.getClassAndName("size") instanceof Deque
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdSequenceDestructor extends Destructor, SideEffectFunction, AliasFunction {
|
||||
StdSequenceDestructor() {
|
||||
this.getDeclaringType() instanceof Vector
|
||||
or
|
||||
this.getDeclaringType() instanceof List
|
||||
or
|
||||
this.getDeclaringType() instanceof Deque
|
||||
}
|
||||
|
||||
private Destructor getElementDestructor() {
|
||||
result.getDeclaringType() = this.getTemplateArgument(0)
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() {
|
||||
this.getElementDestructor().(SideEffectFunction).hasOnlySpecificReadSideEffects()
|
||||
or
|
||||
not exists(this.getElementDestructor())
|
||||
}
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() {
|
||||
this.getElementDestructor().(SideEffectFunction).hasOnlySpecificWriteSideEffects()
|
||||
or
|
||||
not exists(this.getElementDestructor())
|
||||
}
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdSequenceConstructor extends Constructor, SideEffectFunction, AliasFunction {
|
||||
StdSequenceConstructor() {
|
||||
this.getDeclaringType() instanceof Vector
|
||||
or
|
||||
this.getDeclaringType() instanceof List
|
||||
or
|
||||
this.getDeclaringType() instanceof Deque
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class InitializerList extends Class {
|
||||
InitializerList() { this.hasQualifiedName(["std", "bsl"], "initializer_list") }
|
||||
|
||||
Type getElementType() { result = this.getTemplateArgument(0) }
|
||||
}
|
||||
|
||||
private class InitializerListConstructor extends Constructor, SideEffectFunction, AliasFunction {
|
||||
InitializerListConstructor() { this.getDeclaringType() instanceof InitializerList }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard vector `emplace_back` function.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Provides models for the C++ `std::exception` class and subclasses.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
|
||||
/** The `std::exception` class. */
|
||||
class StdException extends Class {
|
||||
StdException() { this.hasGlobalOrStdOrBslName("exception") }
|
||||
}
|
||||
|
||||
/** The `std::bad_alloc` class. */
|
||||
class StdBadAllocException extends Class {
|
||||
StdBadAllocException() { this.hasGlobalOrStdOrBslName("bad_alloc") }
|
||||
}
|
||||
|
||||
private class StdBadAllocExceptionConstructor extends Constructor, SideEffectFunction, AliasFunction
|
||||
{
|
||||
StdBadAllocExceptionConstructor() { this.getDeclaringType() instanceof StdBadAllocException }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and buffer = false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Provides models for C++ `std::function` class.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
|
||||
/**
|
||||
* An instantiation of the `std::function` class template.
|
||||
*/
|
||||
class StdFunction extends ClassTemplateInstantiation {
|
||||
StdFunction() { this.hasGlobalOrStdOrBslName("function") }
|
||||
}
|
||||
|
||||
private class StdFunctionConstructor extends Constructor, SideEffectFunction, AliasFunction {
|
||||
StdFunctionConstructor() { this.getDeclaringType() instanceof StdFunction }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdFunctionDestructor extends Destructor, SideEffectFunction, AliasFunction {
|
||||
StdFunctionDestructor() { this.getDeclaringType() instanceof StdFunction }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
import semmle.code.cpp.models.interfaces.DataFlow
|
||||
import semmle.code.cpp.models.interfaces.Iterator
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
|
||||
/**
|
||||
* The `std::map` and `std::unordered_map` template classes.
|
||||
@@ -16,7 +18,9 @@ private class MapOrUnorderedMap extends Class {
|
||||
/**
|
||||
* Additional model for map constructors using iterator inputs.
|
||||
*/
|
||||
private class StdMapConstructor extends Constructor, TaintFunction {
|
||||
private class StdMapConstructor extends Constructor, TaintFunction, AliasFunction,
|
||||
SideEffectFunction
|
||||
{
|
||||
StdMapConstructor() { this.getDeclaringType() instanceof MapOrUnorderedMap }
|
||||
|
||||
/**
|
||||
@@ -35,6 +39,23 @@ private class StdMapConstructor extends Constructor, TaintFunction {
|
||||
output.isQualifierObject()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,7 +154,7 @@ class StdMapAt extends MemberFunction {
|
||||
StdMapAt() { this.getClassAndName(["at", "operator[]"]) instanceof MapOrUnorderedMap }
|
||||
}
|
||||
|
||||
private class StdMapAtModels extends StdMapAt, TaintFunction {
|
||||
private class StdMapAtModels extends StdMapAt, TaintFunction, AliasFunction, SideEffectFunction {
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
// flow from qualifier to referenced return value
|
||||
input.isQualifierObject() and
|
||||
@@ -144,6 +165,18 @@ private class StdMapAtModels extends StdMapAt, TaintFunction {
|
||||
output.isQualifierObject()
|
||||
}
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
|
||||
override predicate isPartialWrite(FunctionOutput output) { output.isQualifierObject() }
|
||||
}
|
||||
|
||||
@@ -187,3 +220,63 @@ private class StdMapEqualRange extends TaintFunction {
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
class StdMapDestructor extends Destructor, SideEffectFunction, AliasFunction {
|
||||
StdMapDestructor() { this.getDeclaringType() instanceof MapOrUnorderedMap }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdMapClear extends MemberFunction, SideEffectFunction, AliasFunction {
|
||||
StdMapClear() { this.getClassAndName("clear") instanceof MapOrUnorderedMap }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and
|
||||
buffer = false and
|
||||
mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
class StdMapSize extends MemberFunction, SideEffectFunction, AliasFunction {
|
||||
StdMapSize() { this.getClassAndName("size") instanceof MapOrUnorderedMap }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
108
cpp/ql/lib/semmle/code/cpp/models/implementations/StdMath.qll
Normal file
108
cpp/ql/lib/semmle/code/cpp/models/implementations/StdMath.qll
Normal file
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* Provides models for C++ functions from the `cmath` header.
|
||||
*/
|
||||
|
||||
private import semmle.code.cpp.models.interfaces.SideEffect
|
||||
private import semmle.code.cpp.models.interfaces.Alias
|
||||
|
||||
private class LdExp extends Function, SideEffectFunction {
|
||||
LdExp() { this.hasGlobalOrStdOrBslName(["ldexp", "ldexpf", "ldexpl"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class Abs extends Function, SideEffectFunction {
|
||||
Abs() { this.hasGlobalOrStdOrBslName(["abs", "fabs", "fabsf", "fabsl", "llabs", "imaxabs"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class Div extends Function, SideEffectFunction {
|
||||
Div() { this.hasGlobalOrStdOrBslName(["div", "ldiv", "lldiv", "imaxdiv"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class FMod extends Function, SideEffectFunction {
|
||||
FMod() { this.hasGlobalOrStdOrBslName(["fmod", "fmodf", "fmodl"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class Remainder extends Function, SideEffectFunction {
|
||||
Remainder() { this.hasGlobalOrStdOrBslName(["remainder", "remainderf", "remainderl"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class Remquo extends Function, SideEffectFunction {
|
||||
Remquo() { this.hasGlobalOrStdOrBslName(["remquo", "remquof", "remquol"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof PointerType and
|
||||
buffer = false and
|
||||
mustWrite = true
|
||||
}
|
||||
}
|
||||
|
||||
private class Fma extends Function, SideEffectFunction {
|
||||
Fma() { this.hasGlobalOrStdOrBslName(["fma", "fmaf", "fmal"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class Fmax extends Function, SideEffectFunction {
|
||||
Fmax() { this.hasGlobalOrStdOrBslName(["fmax", "fmaxf", "fmaxl"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class Fmin extends Function, SideEffectFunction {
|
||||
Fmin() { this.hasGlobalOrStdOrBslName(["fmin", "fminf", "fminl"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class Fdim extends Function, SideEffectFunction {
|
||||
Fdim() { this.hasGlobalOrStdOrBslName(["fdim", "fdimf", "fdiml"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
}
|
||||
|
||||
private class Nan extends Function, SideEffectFunction, AliasFunction {
|
||||
Nan() { this.hasGlobalOrStdOrBslName(["nan", "nanf", "nanl"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = 0 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = 0 and buffer = true
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
|
||||
/**
|
||||
* An instantiation of `std::pair<T1, T2>`.
|
||||
@@ -37,7 +39,9 @@ class StdPairCopyishConstructor extends Constructor, TaintFunction {
|
||||
/**
|
||||
* Additional model for `std::pair` constructors.
|
||||
*/
|
||||
private class StdPairConstructor extends Constructor, TaintFunction {
|
||||
private class StdPairConstructor extends Constructor, TaintFunction, AliasFunction,
|
||||
SideEffectFunction
|
||||
{
|
||||
StdPairConstructor() { this.getDeclaringType() instanceof StdPair }
|
||||
|
||||
/**
|
||||
@@ -59,4 +63,77 @@ private class StdPairConstructor extends Constructor, TaintFunction {
|
||||
output.isQualifierObject()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
// All the constructor parameters are references with the exception of this one:
|
||||
// ```
|
||||
// template<class... Args1, class... Args2>
|
||||
// pair(std::piecewise_construct_t, std::tuple<Args1...> first_args, std::tuple<Args2...> second_args);
|
||||
// ```
|
||||
// So we need to check that the parameters are actually references
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
|
||||
buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdPairDestructor extends Destructor, AliasFunction, SideEffectFunction {
|
||||
StdPairDestructor() { this.getDeclaringType() instanceof StdPair }
|
||||
|
||||
private Type getFirstType() { result = this.getDeclaringType().getTemplateArgument(0) }
|
||||
|
||||
private Type getSecondType() { result = this.getDeclaringType().getTemplateArgument(0) }
|
||||
|
||||
private Type getAType() { result = [this.getFirstType(), this.getSecondType()] }
|
||||
|
||||
/**
|
||||
* Gets the destructor associated with the base type of this pair
|
||||
*/
|
||||
private Destructor getADestructor() { result.getDeclaringType() = this.getAType() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() {
|
||||
this.getADestructor().(SideEffectFunction).hasOnlySpecificReadSideEffects()
|
||||
or
|
||||
// If there's no declared destructor for the base type then it won't have
|
||||
// any strange read side effects.
|
||||
not exists(this.getADestructor())
|
||||
}
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() {
|
||||
this.getADestructor().(SideEffectFunction).hasOnlySpecificWriteSideEffects()
|
||||
or
|
||||
// If there's no declared destructor for the base type then it won't have
|
||||
// any strange write side effects.
|
||||
not exists(this.getADestructor())
|
||||
}
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) {
|
||||
this.getADestructor().(AliasFunction).parameterNeverEscapes(index)
|
||||
or
|
||||
// If there's no declared destructor for the base type then it won't cause
|
||||
// anything to escape.
|
||||
not exists(this.getADestructor()) and
|
||||
index = -1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
import semmle.code.cpp.models.interfaces.Iterator
|
||||
import semmle.code.cpp.models.interfaces.DataFlow
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
|
||||
/**
|
||||
* The `std::basic_string` template class instantiations.
|
||||
@@ -66,7 +68,7 @@ abstract private class StdStringTaintFunction extends TaintFunction {
|
||||
* Gets the index of a parameter to this function that is an iterator.
|
||||
*/
|
||||
final int getAnIteratorParameterIndex() {
|
||||
this.getParameter(result).getType() instanceof Iterator
|
||||
this.getParameter(result).getUnspecifiedType() instanceof Iterator
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +80,9 @@ abstract private class StdStringTaintFunction extends TaintFunction {
|
||||
* std::string b(a.begin(), a.end());
|
||||
* ```
|
||||
*/
|
||||
private class StdStringConstructor extends Constructor, StdStringTaintFunction {
|
||||
private class StdStringConstructor extends Constructor, StdStringTaintFunction, SideEffectFunction,
|
||||
AliasFunction
|
||||
{
|
||||
StdStringConstructor() { this.getDeclaringType() instanceof StdBasicString }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -94,6 +98,42 @@ private class StdStringConstructor extends Constructor, StdStringTaintFunction {
|
||||
output.isQualifierObject()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
private class StdStringDestructor extends Destructor, SideEffectFunction, AliasFunction {
|
||||
StdStringDestructor() { this.getDeclaringType() instanceof StdBasicString }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,7 +204,7 @@ private class StdStringFrontBack extends StdStringTaintFunction {
|
||||
/**
|
||||
* The (non-member) `std::string` function `operator+`.
|
||||
*/
|
||||
private class StdStringPlus extends StdStringTaintFunction {
|
||||
private class StdStringPlus extends StdStringTaintFunction, SideEffectFunction, AliasFunction {
|
||||
StdStringPlus() {
|
||||
this.hasQualifiedName(["std", "bsl"], "operator+") and
|
||||
this.getUnspecifiedType() instanceof StdBasicString
|
||||
@@ -178,6 +218,22 @@ private class StdStringPlus extends StdStringTaintFunction {
|
||||
) and
|
||||
output.isReturnValue()
|
||||
}
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
this.getParameter(i).getUnspecifiedType() instanceof ReferenceType and
|
||||
buffer = false
|
||||
or
|
||||
this.getParameter(i).getUnspecifiedType() instanceof PointerType and
|
||||
buffer = true
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = [0, 1] }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,7 +241,7 @@ private class StdStringPlus extends StdStringTaintFunction {
|
||||
* All of these functions combine the existing string with a new
|
||||
* string (or character) from one of the arguments.
|
||||
*/
|
||||
private class StdStringAppend extends StdStringTaintFunction {
|
||||
private class StdStringAppend extends StdStringTaintFunction, SideEffectFunction, AliasFunction {
|
||||
StdStringAppend() {
|
||||
this.getClassAndName(["operator+=", "append", "replace"]) instanceof StdBasicString
|
||||
}
|
||||
@@ -210,6 +266,22 @@ private class StdStringAppend extends StdStringTaintFunction {
|
||||
}
|
||||
|
||||
override predicate isPartialWrite(FunctionOutput output) { output.isQualifierObject() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and mustWrite = false and buffer = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = [-1, 0] and buffer = true
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = [-1, 0] }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -301,7 +373,7 @@ private class StdStringSubstr extends StdStringTaintFunction {
|
||||
/**
|
||||
* The `std::string` functions `at` and `operator[]`.
|
||||
*/
|
||||
private class StdStringAt extends StdStringTaintFunction {
|
||||
private class StdStringAt extends StdStringTaintFunction, SideEffectFunction, AliasFunction {
|
||||
StdStringAt() { this.getClassAndName(["at", "operator[]"]) instanceof StdBasicString }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -315,6 +387,22 @@ private class StdStringAt extends StdStringTaintFunction {
|
||||
}
|
||||
|
||||
override predicate isPartialWrite(FunctionOutput output) { output.isQualifierObject() }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -324,6 +412,54 @@ private class StdBasicIStream extends ClassTemplateInstantiation {
|
||||
StdBasicIStream() { this.hasQualifiedName(["std", "bsl"], "basic_istream") }
|
||||
}
|
||||
|
||||
private class StdBasicIfStream extends ClassTemplateInstantiation {
|
||||
StdBasicIfStream() { this.hasQualifiedName(["std", "bsl"], "basic_ifstream") }
|
||||
}
|
||||
|
||||
class StdBasicIfStreamConstructor extends Constructor, SideEffectFunction, AliasFunction {
|
||||
StdBasicIfStreamConstructor() { this.getDeclaringType() instanceof StdBasicIfStream }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
exists(Type t | t = this.getParameter(i).getUnspecifiedType() |
|
||||
t instanceof PointerType and buffer = true
|
||||
or
|
||||
t instanceof ReferenceType and buffer = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class StdBasicIfStreamDestructor extends Destructor, SideEffectFunction, AliasFunction {
|
||||
StdBasicIfStreamDestructor() { this.getDeclaringType() instanceof StdBasicIfStream }
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `std::istream` function `operator>>` (defined as a member function).
|
||||
*/
|
||||
@@ -542,6 +678,33 @@ private class StdBasicOStream extends ClassTemplateInstantiation {
|
||||
StdBasicOStream() { this.hasQualifiedName(["std", "bsl"], "basic_ostream") }
|
||||
}
|
||||
|
||||
private class StdStringLessThan extends Function, AliasFunction, SideEffectFunction {
|
||||
StdStringLessThan() {
|
||||
this.hasQualifiedName(["std", "bsl"], "operator<") and
|
||||
this.getNumberOfParameters() = 2 and
|
||||
this.getParameter(0).getUnspecifiedType().(ReferenceType).getBaseType() instanceof
|
||||
StdBasicString and
|
||||
this.getParameter(1).getUnspecifiedType().(ReferenceType).getBaseType() instanceof
|
||||
StdBasicString
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = [0, 1] }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
i = [0, 1] and buffer = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `std::ostream` functions `operator<<` (defined as a member function),
|
||||
* `put` and `write`.
|
||||
|
||||
@@ -409,6 +409,11 @@ function_defaulted(unique int id: @function ref);
|
||||
|
||||
function_prototyped(unique int id: @function ref)
|
||||
|
||||
deduction_guide_for_class(
|
||||
int id: @function ref,
|
||||
int class_template: @usertype ref
|
||||
)
|
||||
|
||||
member_function_this_type(
|
||||
unique int id: @function ref,
|
||||
int this_type: @type ref
|
||||
@@ -485,10 +490,17 @@ namespace_decls(
|
||||
int bodylocation: @location_default ref
|
||||
);
|
||||
|
||||
case @using.kind of
|
||||
1 = @using_declaration
|
||||
| 2 = @using_directive
|
||||
| 3 = @using_enum_declaration
|
||||
;
|
||||
|
||||
usings(
|
||||
unique int id: @using,
|
||||
int element_id: @element ref,
|
||||
int location: @location_default ref
|
||||
int location: @location_default ref,
|
||||
int kind: int ref
|
||||
);
|
||||
|
||||
/** The element which contains the `using` declaration. */
|
||||
@@ -909,6 +921,11 @@ varspecifiers(
|
||||
int spec_id: @specifier ref
|
||||
);
|
||||
|
||||
explicit_specifier_exprs(
|
||||
unique int func_id: @function ref,
|
||||
int constant: @expr ref
|
||||
)
|
||||
|
||||
attributes(
|
||||
unique int id: @attribute,
|
||||
int kind: int ref,
|
||||
@@ -1358,6 +1375,8 @@ funbind(
|
||||
@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr
|
||||
|
||||
/*
|
||||
Binary encoding of the allocator form.
|
||||
|
||||
case @allocator.form of
|
||||
0 = plain
|
||||
| 1 = alignment
|
||||
@@ -1376,11 +1395,13 @@ expr_allocator(
|
||||
);
|
||||
|
||||
/*
|
||||
Binary encoding of the deallocator form.
|
||||
|
||||
case @deallocator.form of
|
||||
0 = plain
|
||||
| 1 = size
|
||||
| 2 = alignment
|
||||
| 3 = size_and_alignment
|
||||
| 4 = destroying_delete
|
||||
;
|
||||
*/
|
||||
|
||||
@@ -1748,6 +1769,25 @@ case @expr.kind of
|
||||
| 361 = @isvoid
|
||||
| 362 = @isvolatile
|
||||
| 363 = @reuseexpr
|
||||
| 364 = @istriviallycopyassignable
|
||||
| 365 = @isassignablenopreconditioncheck
|
||||
| 366 = @referencebindstotemporary
|
||||
| 367 = @issameas
|
||||
| 368 = @builtinhasattribute
|
||||
| 369 = @ispointerinterconvertiblewithclass
|
||||
| 370 = @builtinispointerinterconvertiblewithclass
|
||||
| 371 = @iscorrespondingmember
|
||||
| 372 = @builtiniscorrespondingmember
|
||||
| 373 = @isboundedarray
|
||||
| 374 = @isunboundedarray
|
||||
| 375 = @isreferenceable
|
||||
| 378 = @isnothrowconvertible
|
||||
| 379 = @referenceconstructsfromtemporary
|
||||
| 380 = @referenceconvertsfromtemporary
|
||||
| 381 = @isconvertible
|
||||
| 382 = @isvalidwinrttype
|
||||
| 383 = @iswinclass
|
||||
| 384 = @iswininterface
|
||||
;
|
||||
|
||||
@var_args_expr = @vastartexpr
|
||||
@@ -1842,6 +1882,25 @@ case @expr.kind of
|
||||
| @isunsigned
|
||||
| @isvoid
|
||||
| @isvolatile
|
||||
| @istriviallycopyassignable
|
||||
| @isassignablenopreconditioncheck
|
||||
| @referencebindstotemporary
|
||||
| @issameas
|
||||
| @builtinhasattribute
|
||||
| @ispointerinterconvertiblewithclass
|
||||
| @builtinispointerinterconvertiblewithclass
|
||||
| @iscorrespondingmember
|
||||
| @builtiniscorrespondingmember
|
||||
| @isboundedarray
|
||||
| @isunboundedarray
|
||||
| @isreferenceable
|
||||
| @isnothrowconvertible
|
||||
| @referenceconstructsfromtemporary
|
||||
| @referenceconvertsfromtemporary
|
||||
| @isconvertible
|
||||
| @isvalidwinrttype
|
||||
| @iswinclass
|
||||
| @iswininterface
|
||||
;
|
||||
|
||||
new_allocated_type(
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
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: Support destroying deletes
|
||||
compatibility: partial
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
description: Support using-enum declarations.
|
||||
compatibility: partial
|
||||
usings.rel: run usings.qlo
|
||||
@@ -0,0 +1,17 @@
|
||||
class UsingEntry extends @using {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Element extends @element {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Location extends @location_default {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from UsingEntry u, Element target, Location loc, int kind
|
||||
where
|
||||
usings(u, target, loc) and
|
||||
if target instanceof @namespace then kind = 2 else kind = 1
|
||||
select u, target, loc, kind
|
||||
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: Add relation between deduction guides and class templates
|
||||
compatibility: partial
|
||||
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: Add new builtin operations
|
||||
compatibility: backwards
|
||||
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: Support explicit(bool) specifiers
|
||||
compatibility: partial
|
||||
@@ -1,3 +1,33 @@
|
||||
## 1.2.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `cpp/uncontrolled-allocation-size` ("Uncontrolled allocation size") query now considers arithmetic operations that might reduce the size of user input as a barrier. The query therefore produces fewer false positive results.
|
||||
|
||||
## 1.2.0
|
||||
|
||||
### Query Metadata Changes
|
||||
|
||||
* The precision of `cpp/unsigned-difference-expression-compared-zero` ("Unsigned difference expression compared to zero") has been increased to `high`. As a result, it will be run by default as part of the Code Scanning suite.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Fixed false positives in the `cpp/memory-may-not-be-freed` ("Memory may not be freed") query involving class methods that returned an allocated field of that class being misidentified as allocators.
|
||||
* The `cpp/incorrectly-checked-scanf` ("Incorrect return-value check for a 'scanf'-like function") query now produces fewer false positive results.
|
||||
* The `cpp/incorrect-allocation-error-handling` ("Incorrect allocation-error handling") query no longer produces occasional false positive results inside template instantiations.
|
||||
* The `cpp/suspicious-allocation-size` ("Not enough memory allocated for array of pointer type") query no longer produces false positives on "variable size" `struct`s.
|
||||
|
||||
## 1.1.0
|
||||
|
||||
### Query Metadata Changes
|
||||
|
||||
* The precision of `cpp/iterator-to-expired-container` ("Iterator to expired container") has been increased to `high`. As a result, it will be run by default as part of the Code Scanning suite.
|
||||
* The precision of `cpp/unsafe-strncat` ("Potentially unsafe call to strncat") has been increased to `high`. As a result, it will be run by default as part of the Code Scanning suite.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `cpp/unsigned-difference-expression-compared-zero` ("Unsigned difference expression compared to zero") query now produces fewer false positives.
|
||||
|
||||
## 1.0.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -39,7 +39,7 @@ predicate allocCallOrIndirect(Expr e) {
|
||||
allocCallOrIndirect(rtn.getExpr())
|
||||
or
|
||||
// return variable assigned with alloc
|
||||
exists(Variable v |
|
||||
exists(StackVariable v |
|
||||
v = rtn.getExpr().(VariableAccess).getTarget() and
|
||||
allocCallOrIndirect(v.getAnAssignedValue()) and
|
||||
not assignedToFieldOrGlobal(v, _)
|
||||
|
||||
@@ -38,11 +38,18 @@ private string getEofValue() {
|
||||
private predicate checkedForEof(ScanfFunctionCall call) {
|
||||
exists(IRGuardCondition gc |
|
||||
exists(Instruction i | i.getUnconvertedResultExpression() = call |
|
||||
// call == EOF
|
||||
gc.comparesEq(valueNumber(i).getAUse(), getEofValue().toInt(), _, _)
|
||||
exists(int val | gc.comparesEq(valueNumber(i).getAUse(), val, _, _) |
|
||||
// call == EOF
|
||||
val = getEofValue().toInt()
|
||||
or
|
||||
// call == [any positive number]
|
||||
val > 0
|
||||
)
|
||||
or
|
||||
// call < 0 (EOF is guaranteed to be negative)
|
||||
gc.comparesLt(valueNumber(i).getAUse(), 0, true, _)
|
||||
exists(int val | gc.comparesLt(valueNumber(i).getAUse(), val, true, _) |
|
||||
// call < [any non-negative number] (EOF is guaranteed to be negative)
|
||||
val >= 0
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.models.Models
|
||||
import semmle.code.cpp.commons.Buffer
|
||||
|
||||
predicate baseType(AllocationExpr alloc, Type base) {
|
||||
exists(PointerType pointer |
|
||||
@@ -30,7 +31,8 @@ predicate baseType(AllocationExpr alloc, Type base) {
|
||||
}
|
||||
|
||||
predicate decideOnSize(Type t, int size) {
|
||||
// If the codebase has more than one type with the same name, it can have more than one size.
|
||||
// If the codebase has more than one type with the same name, it can have more than one size. For
|
||||
// most purposes in this query, we use the smallest.
|
||||
size = min(t.getSize())
|
||||
}
|
||||
|
||||
@@ -45,7 +47,8 @@ where
|
||||
size = 0 or
|
||||
(allocated / size) * size = allocated
|
||||
) and
|
||||
not basesize > allocated // covered by SizeCheck.ql
|
||||
not basesize > allocated and // covered by SizeCheck.ql
|
||||
not memberMayBeVarSize(base.getUnspecifiedType(), _) // exclude variable size types
|
||||
select alloc,
|
||||
"Allocated memory (" + allocated.toString() + " bytes) is not a multiple of the size of '" +
|
||||
base.getName() + "' (" + basesize.toString() + " bytes)."
|
||||
|
||||
@@ -172,5 +172,5 @@ where
|
||||
not arg.isFromUninstantiatedTemplate(_) and
|
||||
not actual.getUnspecifiedType() instanceof ErroneousType
|
||||
select arg,
|
||||
"This argument should be of type '" + expected.getName() + "' but is of type '" +
|
||||
"This format specifier for type '" + expected.getName() + "' does not match the argument type '" +
|
||||
actual.getUnspecifiedType().getName() + "'."
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
Record* fixRecord(Record* r) {
|
||||
Record myRecord = *r;
|
||||
delete r;
|
||||
|
||||
myRecord.fix();
|
||||
return &myRecord; //returns reference to myRecord, which is a stack-allocated object
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user