mirror of
https://github.com/github/codeql.git
synced 2026-05-20 22:27:18 +02:00
Compare commits
992 Commits
aml-auto-e
...
replace-as
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d62ae96763 | ||
|
|
1c51ad8d26 | ||
|
|
4c5953fce0 | ||
|
|
373c849b18 | ||
|
|
41cbef81ec | ||
|
|
d79a7e863a | ||
|
|
a65850e922 | ||
|
|
036724ce8d | ||
|
|
c4915b27e7 | ||
|
|
6c781b5b1a | ||
|
|
10aab81f42 | ||
|
|
c3af41b907 | ||
|
|
09c8a98761 | ||
|
|
bb1ce8973a | ||
|
|
adb8860b9b | ||
|
|
d28b9af8bd | ||
|
|
c7ae0728f3 | ||
|
|
98b317d1a5 | ||
|
|
370da943dc | ||
|
|
99b9101455 | ||
|
|
cfb9277cd7 | ||
|
|
87af5b7d71 | ||
|
|
ce740b47ae | ||
|
|
338ce838bf | ||
|
|
8791a20f0c | ||
|
|
2836c5eaef | ||
|
|
af12eedb32 | ||
|
|
7bfb3497eb | ||
|
|
7b90ba6189 | ||
|
|
83464d48a9 | ||
|
|
949d3e13fe | ||
|
|
695d8c6004 | ||
|
|
93c01371c3 | ||
|
|
b42b88338e | ||
|
|
0d6da9ca7f | ||
|
|
a56770999f | ||
|
|
d389a183f0 | ||
|
|
955336fb22 | ||
|
|
aa9dc3a764 | ||
|
|
3b49594c20 | ||
|
|
9eca56cbe2 | ||
|
|
9bd25220d4 | ||
|
|
56797c515b | ||
|
|
39107047bf | ||
|
|
202549bdd9 | ||
|
|
c92ce69f48 | ||
|
|
9d6ea28448 | ||
|
|
a8e5a12ec2 | ||
|
|
b9d8903bdb | ||
|
|
9eac158d7c | ||
|
|
08a79531cf | ||
|
|
1a14c06008 | ||
|
|
061d1ee9fe | ||
|
|
71b0613f9a | ||
|
|
ba0f34afed | ||
|
|
0919507565 | ||
|
|
7e0bbf1bdb | ||
|
|
114653162c | ||
|
|
c77f685c0c | ||
|
|
e55be83645 | ||
|
|
bf4dac78c5 | ||
|
|
d3c8ce3f48 | ||
|
|
bfa9765a6d | ||
|
|
06bbede92b | ||
|
|
4e3a6e60b2 | ||
|
|
ed165c6194 | ||
|
|
a64286b664 | ||
|
|
fc810ddbf4 | ||
|
|
f4d43deec4 | ||
|
|
f88aaf37a5 | ||
|
|
80cc3fc518 | ||
|
|
1f0a48de28 | ||
|
|
af79139c30 | ||
|
|
078c3e9d28 | ||
|
|
7ac9c1e832 | ||
|
|
b3f10311b3 | ||
|
|
9b2cc6c318 | ||
|
|
0892a5795d | ||
|
|
8523d21f8c | ||
|
|
e9835ec07e | ||
|
|
66c2de87b0 | ||
|
|
ac30cfa5c1 | ||
|
|
a826dbbdee | ||
|
|
7171fd1bb2 | ||
|
|
f1c44f72b5 | ||
|
|
2e8f46ddd9 | ||
|
|
95e798565b | ||
|
|
0883b1782d | ||
|
|
02656b16c3 | ||
|
|
01bc5f7226 | ||
|
|
5cfc3fe8df | ||
|
|
878654e0ff | ||
|
|
2b75562037 | ||
|
|
42e1735f2a | ||
|
|
8779da8c0b | ||
|
|
7d282c3d75 | ||
|
|
d6df69d481 | ||
|
|
53abdb3fb5 | ||
|
|
4da0508dae | ||
|
|
cdf9d65e44 | ||
|
|
f4e928eec4 | ||
|
|
9a9d2a6fe1 | ||
|
|
704aba8c1c | ||
|
|
22141e378e | ||
|
|
4e220330a7 | ||
|
|
8f7e76f0cb | ||
|
|
b6e07c0cd5 | ||
|
|
125761755a | ||
|
|
6daa1c432b | ||
|
|
38a3476d37 | ||
|
|
d55925d8d4 | ||
|
|
0a4c724b69 | ||
|
|
f06c15b86a | ||
|
|
29da681bbb | ||
|
|
86ee8c2d00 | ||
|
|
b5bed9cbf5 | ||
|
|
e8754967ea | ||
|
|
479a4fb4a2 | ||
|
|
cbea5ec40c | ||
|
|
3b9546f02e | ||
|
|
c08cfe23e0 | ||
|
|
3e6477f878 | ||
|
|
e6998d40c3 | ||
|
|
88408fbd59 | ||
|
|
9b372f3db4 | ||
|
|
0581f2fe1c | ||
|
|
879158a653 | ||
|
|
5755159f08 | ||
|
|
6db36616cd | ||
|
|
c2a0dbe715 | ||
|
|
3358c5f664 | ||
|
|
b95af76dab | ||
|
|
b1052992fe | ||
|
|
21caa4b03f | ||
|
|
6c2eee3eb8 | ||
|
|
b6270ebe52 | ||
|
|
b94b78115e | ||
|
|
9bbbece8a7 | ||
|
|
f2e2e3bc1d | ||
|
|
15aab711c7 | ||
|
|
5756a33604 | ||
|
|
70b8224a8b | ||
|
|
b1a165ee98 | ||
|
|
ecf7ed38e0 | ||
|
|
67cef92f94 | ||
|
|
dfdfd39bcc | ||
|
|
b597896bf2 | ||
|
|
ffb2b1c15e | ||
|
|
85344bfb13 | ||
|
|
f7203bfcb8 | ||
|
|
13cb4f9241 | ||
|
|
8cc52a4b55 | ||
|
|
544e2e4107 | ||
|
|
fd571538fb | ||
|
|
dba42d6bb8 | ||
|
|
669f4f38b9 | ||
|
|
4ee71ae4a1 | ||
|
|
60fe370f2a | ||
|
|
099251a30a | ||
|
|
1cf2db1a0b | ||
|
|
87b971c78f | ||
|
|
cd8ac1a835 | ||
|
|
b1d33a404c | ||
|
|
584ccf1992 | ||
|
|
08d6b2f30a | ||
|
|
9f2f6ac491 | ||
|
|
38c17c5d0c | ||
|
|
059864587e | ||
|
|
e38cfd5f7d | ||
|
|
d61f0559a0 | ||
|
|
4b1f6f0865 | ||
|
|
efa6b3c0c6 | ||
|
|
9f34bf80fd | ||
|
|
296ec94a2a | ||
|
|
d1c8c40c17 | ||
|
|
02192acd5f | ||
|
|
d39b0fd3f4 | ||
|
|
262a74d03d | ||
|
|
d707c526e5 | ||
|
|
73f88fbdb6 | ||
|
|
6fdfd40880 | ||
|
|
5cadd3c0e6 | ||
|
|
bb0f2f7d36 | ||
|
|
5ee7986649 | ||
|
|
5dcb70e482 | ||
|
|
9c0cdfde6b | ||
|
|
68967c40bc | ||
|
|
85f92ff80a | ||
|
|
bef4011947 | ||
|
|
b8ef9e0ddc | ||
|
|
b4510200b4 | ||
|
|
dd50fe3c10 | ||
|
|
115d4de0e0 | ||
|
|
4d75d885cb | ||
|
|
be95b91878 | ||
|
|
a6674a5313 | ||
|
|
e8b9dc2e83 | ||
|
|
cbeefd418b | ||
|
|
10a014f18c | ||
|
|
99b7c77abc | ||
|
|
b065d2d3ab | ||
|
|
1bdc2374e4 | ||
|
|
2df1d63d1c | ||
|
|
5d9c68c962 | ||
|
|
da43a36a51 | ||
|
|
a0725fba71 | ||
|
|
bb6e575689 | ||
|
|
0d98eba604 | ||
|
|
f3f3b9417b | ||
|
|
944ca4a0da | ||
|
|
26c4216fef | ||
|
|
9f6240b38c | ||
|
|
75cb0efecb | ||
|
|
d5c45056bd | ||
|
|
66c9705502 | ||
|
|
a30b7120a7 | ||
|
|
5f740a5598 | ||
|
|
69fc59930f | ||
|
|
f51c13f0c1 | ||
|
|
51f9314a50 | ||
|
|
f7f12076df | ||
|
|
cd64faf635 | ||
|
|
e9a304bad0 | ||
|
|
a02dcdc5e1 | ||
|
|
47c461a241 | ||
|
|
10eb548156 | ||
|
|
e147a6032e | ||
|
|
65a538ed41 | ||
|
|
3fcb825e7f | ||
|
|
cfbb9e3339 | ||
|
|
7a425ffcc3 | ||
|
|
28fa06ab9c | ||
|
|
289843eb83 | ||
|
|
c1fae91a1f | ||
|
|
812a5e5c74 | ||
|
|
4e161c867e | ||
|
|
7d98b74eec | ||
|
|
7a7d164b07 | ||
|
|
fcf24f7671 | ||
|
|
1d8547d4c1 | ||
|
|
0024e54e63 | ||
|
|
86e5e4c4bc | ||
|
|
020f29a1ab | ||
|
|
764c139e3e | ||
|
|
34b83f01d0 | ||
|
|
5e182755a5 | ||
|
|
bec948682d | ||
|
|
b79d273de4 | ||
|
|
3452dcbced | ||
|
|
be655432d6 | ||
|
|
03c895853b | ||
|
|
6119670be8 | ||
|
|
720cf5682b | ||
|
|
6cc74da004 | ||
|
|
34a0a0d080 | ||
|
|
169965cfb9 | ||
|
|
9960d11042 | ||
|
|
c6b7bb436d | ||
|
|
6f3c9e4403 | ||
|
|
a856bc8678 | ||
|
|
48bdf13c89 | ||
|
|
0065a5af96 | ||
|
|
1edd4d855a | ||
|
|
197f036797 | ||
|
|
9d069b32b0 | ||
|
|
0b6ea703ea | ||
|
|
bba70a70fb | ||
|
|
ddc8f72ef7 | ||
|
|
32d0b58923 | ||
|
|
7608276397 | ||
|
|
5b67ba2939 | ||
|
|
cbeff4efc8 | ||
|
|
db056aae1b | ||
|
|
86756538f2 | ||
|
|
3f78a244b9 | ||
|
|
9a365d83cf | ||
|
|
0e6735b804 | ||
|
|
0bbc7adca0 | ||
|
|
d80d39504f | ||
|
|
387e57546b | ||
|
|
46fb9865ac | ||
|
|
7f8bcf76bf | ||
|
|
0beea9fd1a | ||
|
|
082544e88c | ||
|
|
61a05c2b6c | ||
|
|
decd4c93c7 | ||
|
|
c9c36985b2 | ||
|
|
d0d8ef1236 | ||
|
|
6509c19aad | ||
|
|
6f518c1996 | ||
|
|
3f0f16afc4 | ||
|
|
e51c20bfc7 | ||
|
|
527425b397 | ||
|
|
5984b8db4d | ||
|
|
ec2549a38b | ||
|
|
6db0db431f | ||
|
|
a080f498be | ||
|
|
9d23742ed6 | ||
|
|
ab6e488efe | ||
|
|
f664a77a02 | ||
|
|
4ff85d5275 | ||
|
|
fcd69a005f | ||
|
|
525fe12671 | ||
|
|
7cf969f9c8 | ||
|
|
6f74a52542 | ||
|
|
8b7ec20573 | ||
|
|
1496c4f0e2 | ||
|
|
93e8434e08 | ||
|
|
f5f351e26c | ||
|
|
a9a99c5b18 | ||
|
|
4c19d2d71e | ||
|
|
ecfbd5edfe | ||
|
|
ad83fc8a98 | ||
|
|
d8cfdc5e26 | ||
|
|
d0ea7ea2e3 | ||
|
|
c45a04a2c8 | ||
|
|
321c858cd1 | ||
|
|
c1c16e44ee | ||
|
|
2541af6587 | ||
|
|
05bca0249c | ||
|
|
aae9a58ca3 | ||
|
|
d69a658e06 | ||
|
|
4d697cd369 | ||
|
|
2e80926951 | ||
|
|
32839021f8 | ||
|
|
445241fd95 | ||
|
|
2315a177fe | ||
|
|
227100d883 | ||
|
|
3c7f5420db | ||
|
|
6380cc82ce | ||
|
|
f888c4b279 | ||
|
|
0ed89fb11a | ||
|
|
d4742d22a0 | ||
|
|
e196caa7bd | ||
|
|
ea0a04a74f | ||
|
|
2e72ec748f | ||
|
|
264d74f996 | ||
|
|
52d2dd71c0 | ||
|
|
6c6b4ce131 | ||
|
|
db673c0355 | ||
|
|
60527dfc17 | ||
|
|
dedbe66619 | ||
|
|
3455dd5e06 | ||
|
|
81fffce79b | ||
|
|
2bbfdcf598 | ||
|
|
5ba7c13ecd | ||
|
|
d370b2a51e | ||
|
|
bf74481f65 | ||
|
|
09051e76cf | ||
|
|
876bea653d | ||
|
|
d2861361d9 | ||
|
|
d50be83f57 | ||
|
|
88b5d4da16 | ||
|
|
ab3a62de3c | ||
|
|
6e61ef10b8 | ||
|
|
9d7d6c29f9 | ||
|
|
77c47bc856 | ||
|
|
44cc6f7350 | ||
|
|
0160c374e4 | ||
|
|
5d55daa491 | ||
|
|
c2b98a4761 | ||
|
|
09bc78eafc | ||
|
|
e95b5468d9 | ||
|
|
f9b952f04f | ||
|
|
25cb3236a2 | ||
|
|
91db1be399 | ||
|
|
960e9db2fb | ||
|
|
1857a5d311 | ||
|
|
00b0a6bf38 | ||
|
|
834927c50b | ||
|
|
9a7cf7db65 | ||
|
|
c7e7e24cf8 | ||
|
|
012cfebd7a | ||
|
|
da7f27a7f2 | ||
|
|
66b3c4687d | ||
|
|
0a135a7f21 | ||
|
|
0f64361065 | ||
|
|
af812cf407 | ||
|
|
47fcbdd4b4 | ||
|
|
d07babe3c5 | ||
|
|
6cf3898101 | ||
|
|
9947b32446 | ||
|
|
11ce910c38 | ||
|
|
7576047214 | ||
|
|
dd1b302fce | ||
|
|
9db65eae7f | ||
|
|
b8fa9433be | ||
|
|
264d6db9d7 | ||
|
|
90020b6aab | ||
|
|
69d1895175 | ||
|
|
6fcaae20e7 | ||
|
|
f19eb783be | ||
|
|
4e29c39c78 | ||
|
|
89d905cc03 | ||
|
|
08c67fb174 | ||
|
|
dff878e531 | ||
|
|
5706e8b377 | ||
|
|
50ad234694 | ||
|
|
d5478a01ab | ||
|
|
e29be411ef | ||
|
|
a738f1d5cf | ||
|
|
948594043d | ||
|
|
28f4dff1d3 | ||
|
|
b6231e82ec | ||
|
|
3ccc3a2058 | ||
|
|
94d41b9fa4 | ||
|
|
96711b2810 | ||
|
|
6e7aea85ef | ||
|
|
c220f4e103 | ||
|
|
ff4ce4a151 | ||
|
|
fd9c1e4507 | ||
|
|
00e52ad109 | ||
|
|
9302271c15 | ||
|
|
bd11946aec | ||
|
|
323abf45ca | ||
|
|
a7d764d2a7 | ||
|
|
8c43ab627f | ||
|
|
2deb3e5625 | ||
|
|
8b389fe5f9 | ||
|
|
74c3886167 | ||
|
|
c06743afb5 | ||
|
|
f75f27d30e | ||
|
|
5b2d8b0894 | ||
|
|
fbab0f50f2 | ||
|
|
0000a7d429 | ||
|
|
a4d4e406c6 | ||
|
|
1c484d80aa | ||
|
|
ab672ded6a | ||
|
|
7205903a36 | ||
|
|
58cb5446c3 | ||
|
|
281e49daf7 | ||
|
|
01b950f68b | ||
|
|
df29e05b9f | ||
|
|
12536578d4 | ||
|
|
f47c02431a | ||
|
|
6ec2abbd2d | ||
|
|
c1654ce7cc | ||
|
|
192c1f3d89 | ||
|
|
2593120300 | ||
|
|
726cd2ca8a | ||
|
|
9df0720da9 | ||
|
|
2006ae8332 | ||
|
|
76abf6fbd6 | ||
|
|
01830904ff | ||
|
|
2c467376ea | ||
|
|
8a7f23a8ea | ||
|
|
33d204913c | ||
|
|
888d756472 | ||
|
|
536276a82b | ||
|
|
35948b097d | ||
|
|
d7be27a1c0 | ||
|
|
42a97b26bb | ||
|
|
b01a0ae696 | ||
|
|
98f4caf76f | ||
|
|
8d1817bc48 | ||
|
|
e57c3bec63 | ||
|
|
bc3e9339dc | ||
|
|
bff2633f8d | ||
|
|
c6f91500f0 | ||
|
|
872615bd58 | ||
|
|
52d519765a | ||
|
|
09077935b1 | ||
|
|
071f082b64 | ||
|
|
2970e8c76a | ||
|
|
cfc0bb595f | ||
|
|
a589d8f647 | ||
|
|
28e7049722 | ||
|
|
f7d455efc5 | ||
|
|
5e2c607650 | ||
|
|
d3d3ce843a | ||
|
|
ba9eb8c73c | ||
|
|
a5172791ed | ||
|
|
d52d3d7b75 | ||
|
|
9942dfff21 | ||
|
|
d44f6b0f41 | ||
|
|
90b28f04d8 | ||
|
|
7524f3372d | ||
|
|
a0fcd4a9bf | ||
|
|
f860ae8c82 | ||
|
|
2036453176 | ||
|
|
0645f62a0d | ||
|
|
66e6f4d25e | ||
|
|
8a3ed6bdcf | ||
|
|
6f7b7c9efe | ||
|
|
6f1124d7e7 | ||
|
|
1ece12efd7 | ||
|
|
d4499a10d2 | ||
|
|
ee7507386c | ||
|
|
eda676df3e | ||
|
|
ffc7e6b7b6 | ||
|
|
54b210f176 | ||
|
|
a2d0b38a6d | ||
|
|
3d00a61dac | ||
|
|
47e5623b90 | ||
|
|
683cacb8b5 | ||
|
|
eaf6eb009b | ||
|
|
e48665ad9f | ||
|
|
236b628ee2 | ||
|
|
32baf67b07 | ||
|
|
5c20039e09 | ||
|
|
fa1ae26fab | ||
|
|
a5998fbe4d | ||
|
|
ba83b7c6c7 | ||
|
|
39ffa558f1 | ||
|
|
5c32c8badf | ||
|
|
9e3d5f49c5 | ||
|
|
72ba77d900 | ||
|
|
5e189b8c75 | ||
|
|
677946d19d | ||
|
|
dbc86b2cd8 | ||
|
|
a23e17a370 | ||
|
|
2409ba2c05 | ||
|
|
2080f0dd36 | ||
|
|
f060f056c2 | ||
|
|
fe024ef91e | ||
|
|
21d5e417d1 | ||
|
|
9576e4c008 | ||
|
|
746f535ee5 | ||
|
|
2f673efc67 | ||
|
|
129cda00db | ||
|
|
acfcc4bfe2 | ||
|
|
7d643e41f3 | ||
|
|
17e6b2af37 | ||
|
|
fdd71d4647 | ||
|
|
e2fe63f94a | ||
|
|
84f9c9b224 | ||
|
|
159f11cd28 | ||
|
|
8972176242 | ||
|
|
292bc67125 | ||
|
|
cd65e73ade | ||
|
|
343e45ee0f | ||
|
|
8ac8101a75 | ||
|
|
423e0bf99a | ||
|
|
e490a854ce | ||
|
|
c4487110db | ||
|
|
11de55e3cb | ||
|
|
dd7458acc8 | ||
|
|
32d002ed60 | ||
|
|
56b5010f6b | ||
|
|
d14b2c2880 | ||
|
|
c4c7c95db2 | ||
|
|
5017b21579 | ||
|
|
d54a3059b4 | ||
|
|
3ec43dbd16 | ||
|
|
dc432c7774 | ||
|
|
e5d884a905 | ||
|
|
299339f817 | ||
|
|
318718c428 | ||
|
|
28606c561d | ||
|
|
6e1914ad01 | ||
|
|
121a5645b8 | ||
|
|
0f9b6d4a8b | ||
|
|
7098e7b102 | ||
|
|
ef8ec0878a | ||
|
|
b66e5c5aee | ||
|
|
9a94222dbe | ||
|
|
4938de9185 | ||
|
|
fa12bd3cdf | ||
|
|
c7b01975c1 | ||
|
|
ee59bdab25 | ||
|
|
9be2ca2f1e | ||
|
|
ed74e0aad1 | ||
|
|
483ff58c39 | ||
|
|
476960e699 | ||
|
|
b0af4cba30 | ||
|
|
6d5de66e6a | ||
|
|
585cbe2b95 | ||
|
|
06ea829537 | ||
|
|
074fac8f2f | ||
|
|
82294c1349 | ||
|
|
c867f2ba5b | ||
|
|
4a39bc8f47 | ||
|
|
c37c6a004e | ||
|
|
818be2765e | ||
|
|
6eac4f52d9 | ||
|
|
a124dcf436 | ||
|
|
981a9798b8 | ||
|
|
68b473377a | ||
|
|
2a046352ce | ||
|
|
9f2d7dfb29 | ||
|
|
2a2878fc7b | ||
|
|
e3c0e6f52a | ||
|
|
90590429e3 | ||
|
|
f17b563692 | ||
|
|
29e34ac970 | ||
|
|
0a5ff1b79a | ||
|
|
8ab5617b51 | ||
|
|
2a514d60d4 | ||
|
|
d12a76559a | ||
|
|
a9710453f4 | ||
|
|
f2bda1525a | ||
|
|
84ab860600 | ||
|
|
0654e39e72 | ||
|
|
7ffbc738fb | ||
|
|
e72963986f | ||
|
|
dedd29e1b3 | ||
|
|
99d7512881 | ||
|
|
35e9e7d233 | ||
|
|
891bc342be | ||
|
|
8f6de12785 | ||
|
|
d75b1e399d | ||
|
|
ea27f4e20f | ||
|
|
66a8bc5a96 | ||
|
|
0cb8e121e9 | ||
|
|
28bd591107 | ||
|
|
447c11cd07 | ||
|
|
e46b215c9d | ||
|
|
29d7c0e21b | ||
|
|
9b03e1c0b1 | ||
|
|
a5fbe751f1 | ||
|
|
ed36f1983b | ||
|
|
ae60b0ae6d | ||
|
|
64903336f7 | ||
|
|
700eaf5e41 | ||
|
|
4e3b445515 | ||
|
|
70837dbd93 | ||
|
|
6537c817ef | ||
|
|
b79c10c419 | ||
|
|
64c953bee0 | ||
|
|
dd0f19d0b0 | ||
|
|
999eb19c3d | ||
|
|
f1de5a2ffd | ||
|
|
1fcd22b0f6 | ||
|
|
af4db77046 | ||
|
|
9ee831a378 | ||
|
|
77eeabe8e5 | ||
|
|
909b36a078 | ||
|
|
3129f0fc8c | ||
|
|
dc03557aea | ||
|
|
2bf087677f | ||
|
|
e9b96c19b8 | ||
|
|
296c0a7925 | ||
|
|
58b7556bdf | ||
|
|
95488bf133 | ||
|
|
903abd0f3e | ||
|
|
131a6ac492 | ||
|
|
e06afb69cc | ||
|
|
9ced3956d6 | ||
|
|
e1ea1a464d | ||
|
|
3d971d239f | ||
|
|
58bf283023 | ||
|
|
940e925c31 | ||
|
|
b24fd13946 | ||
|
|
d54406d599 | ||
|
|
65b32b665d | ||
|
|
6b74e433ee | ||
|
|
11d67744f7 | ||
|
|
2e5fc19e38 | ||
|
|
3c6f538d5c | ||
|
|
ba4794790e | ||
|
|
d3530b0083 | ||
|
|
c49a16c840 | ||
|
|
b95566b02a | ||
|
|
cda05ed3ea | ||
|
|
2046ece2de | ||
|
|
229c95a765 | ||
|
|
fa2d84c38c | ||
|
|
4ed4d31efd | ||
|
|
0e5aa97c46 | ||
|
|
76cfd44478 | ||
|
|
4217a50900 | ||
|
|
424f31a24a | ||
|
|
63309150e0 | ||
|
|
e7d19e849f | ||
|
|
0ce0ada4df | ||
|
|
19a9c5d7d3 | ||
|
|
e3b54efb68 | ||
|
|
c187ae04f4 | ||
|
|
96c73bcb19 | ||
|
|
6d5df14547 | ||
|
|
592bc18a97 | ||
|
|
67d12cdc7d | ||
|
|
ffd58861f0 | ||
|
|
e8a0d07217 | ||
|
|
470908f53e | ||
|
|
3af3772041 | ||
|
|
823b0109f0 | ||
|
|
4ab676774e | ||
|
|
769ff5c6f3 | ||
|
|
ccbbb5754e | ||
|
|
51758aa928 | ||
|
|
a11948bea0 | ||
|
|
d122a64e74 | ||
|
|
0128b1702e | ||
|
|
ac85741da8 | ||
|
|
76cab235d9 | ||
|
|
375698f975 | ||
|
|
8704ccee77 | ||
|
|
e7c1fadd94 | ||
|
|
f761e57365 | ||
|
|
a36bba94f1 | ||
|
|
c07c10a808 | ||
|
|
2d0a377b7a | ||
|
|
e8fd2bfc78 | ||
|
|
e5711380f8 | ||
|
|
7b6e684eaf | ||
|
|
51daae01f1 | ||
|
|
d3c3f3bed9 | ||
|
|
e0c68c3a27 | ||
|
|
b448206c19 | ||
|
|
2b316471c5 | ||
|
|
b48b5d45ef | ||
|
|
a10a2c2b01 | ||
|
|
65de5d014c | ||
|
|
24f2a3cdff | ||
|
|
c8162f80bf | ||
|
|
05102f9007 | ||
|
|
a48b893ed6 | ||
|
|
6cb26d5129 | ||
|
|
b1ae3bfdb2 | ||
|
|
fea47c85f3 | ||
|
|
63ee51a4e2 | ||
|
|
70d47f313e | ||
|
|
971657245d | ||
|
|
99b2df0605 | ||
|
|
ce1c258273 | ||
|
|
ee7dea1ab6 | ||
|
|
22946b176f | ||
|
|
e56630a485 | ||
|
|
e1dfed0fcb | ||
|
|
14e384aaa2 | ||
|
|
ce3665d50e | ||
|
|
665ee81967 | ||
|
|
032847f331 | ||
|
|
e09a5e87dd | ||
|
|
588b31d15d | ||
|
|
a7b92295a2 | ||
|
|
7dfa58b50d | ||
|
|
9c93ad904f | ||
|
|
dd23e125e5 | ||
|
|
6abf77d40d | ||
|
|
85d0c63ec7 | ||
|
|
a5ed3d791b | ||
|
|
e47deaffbf | ||
|
|
7737e75427 | ||
|
|
576e320bf5 | ||
|
|
cbf16579ed | ||
|
|
b13b2ce319 | ||
|
|
3498a04b89 | ||
|
|
497258eda5 | ||
|
|
ac1b7eb0b9 | ||
|
|
a64f7cd146 | ||
|
|
a51a540582 | ||
|
|
d5e2b93554 | ||
|
|
e104b65106 | ||
|
|
cd9cddf45a | ||
|
|
f1b99e867c | ||
|
|
53ef054c53 | ||
|
|
182d7d38a8 | ||
|
|
1fb54ad3e3 | ||
|
|
463173eae4 | ||
|
|
9780dffa79 | ||
|
|
13fb032b1c | ||
|
|
92a38b30cf | ||
|
|
adb8368e07 | ||
|
|
24a10aa5ff | ||
|
|
eada74a15c | ||
|
|
82bbe67267 | ||
|
|
61e24a888f | ||
|
|
31806b84ba | ||
|
|
2351c0288a | ||
|
|
28a23209a5 | ||
|
|
fea1e47daa | ||
|
|
df2b586e7c | ||
|
|
1248810e35 | ||
|
|
fa5e03a53d | ||
|
|
69dd2c0eec | ||
|
|
3ffb2a3ee6 | ||
|
|
286fcb672c | ||
|
|
d2c74913c8 | ||
|
|
13b2b1f304 | ||
|
|
62aa5de781 | ||
|
|
485568331a | ||
|
|
6e60a6ff2e | ||
|
|
cacf78838c | ||
|
|
56e3334c6d | ||
|
|
aefd51601c | ||
|
|
549eca1b17 | ||
|
|
e4305948ef | ||
|
|
8ca1e1b2d1 | ||
|
|
7e0c61de2c | ||
|
|
847a64c03b | ||
|
|
be9509ceb9 | ||
|
|
52b6dd5bec | ||
|
|
162edd6883 | ||
|
|
b9937269b9 | ||
|
|
335e1a8233 | ||
|
|
7ff82bbed3 | ||
|
|
7675571daa | ||
|
|
bfda08e69c | ||
|
|
7c30d333ad | ||
|
|
9358070ae9 | ||
|
|
8a6d56a57d | ||
|
|
ae6dd05249 | ||
|
|
d23b128457 | ||
|
|
0c79c2836c | ||
|
|
ea4ba27297 | ||
|
|
9f1bbf2bbd | ||
|
|
9709aa87fb | ||
|
|
cb8865f3ff | ||
|
|
6803d96000 | ||
|
|
49572a5218 | ||
|
|
3717cb30eb | ||
|
|
92715bac3a | ||
|
|
5cdaae7378 | ||
|
|
4df7fd248e | ||
|
|
d90257fd50 | ||
|
|
bda4cfbe5d | ||
|
|
79abb36faf | ||
|
|
97e9eab7fc | ||
|
|
d7f40c41c5 | ||
|
|
5e9196e51c | ||
|
|
494fb4c966 | ||
|
|
1d728b234f | ||
|
|
58dd521ee9 | ||
|
|
c5f36613da | ||
|
|
3beed54e35 | ||
|
|
dea5036912 | ||
|
|
45fc62f16b | ||
|
|
1273db5a22 | ||
|
|
0f1a8a6f5b | ||
|
|
b83ca08854 | ||
|
|
88baf0883a | ||
|
|
11b2a12392 | ||
|
|
40a75fdd12 | ||
|
|
1687d08587 | ||
|
|
17dba00264 | ||
|
|
441fc1bb28 | ||
|
|
57fcfd5e7d | ||
|
|
fa503ec3f2 | ||
|
|
37795226a4 | ||
|
|
29639a0ad5 | ||
|
|
85eee886ac | ||
|
|
f2ada3d547 | ||
|
|
a7011e11c4 | ||
|
|
72429cb9e8 | ||
|
|
eed04696a9 | ||
|
|
f05d4b8410 | ||
|
|
fc10212e68 | ||
|
|
c96b938e7d | ||
|
|
853a80bdbc | ||
|
|
3d281fbb71 | ||
|
|
56055bd76a | ||
|
|
f27b5d5588 | ||
|
|
105462a1fc | ||
|
|
af41f2b903 | ||
|
|
326666ac85 | ||
|
|
9b1ec03d70 | ||
|
|
bc963b2386 | ||
|
|
6114d71d3d | ||
|
|
7f610405a0 | ||
|
|
69640f3c20 | ||
|
|
0581b91c32 | ||
|
|
1c55bbe2e8 | ||
|
|
b018706afd | ||
|
|
06e435fd84 | ||
|
|
46b5bf32f9 | ||
|
|
c40b6285a2 | ||
|
|
f4ef4342c2 | ||
|
|
257bcefaf9 | ||
|
|
fa20a476a6 | ||
|
|
9f234e9f5a | ||
|
|
7b9519fe7c | ||
|
|
7d3f9580ff | ||
|
|
9f99a3ca1f | ||
|
|
9e625acd3d | ||
|
|
1d693d336f | ||
|
|
35a05f6dea | ||
|
|
ed0c85e3af | ||
|
|
f9ba190812 | ||
|
|
2a2b939078 | ||
|
|
fd99ae78b3 | ||
|
|
f774467892 | ||
|
|
a8197b27aa | ||
|
|
9aebe87c67 | ||
|
|
8ce176f2dc | ||
|
|
60f6772f9e | ||
|
|
c2b5c39436 | ||
|
|
9b4201f880 | ||
|
|
1e01657577 | ||
|
|
9acda05dbd | ||
|
|
65f3ae9829 | ||
|
|
7e13610d24 | ||
|
|
24b34cd32f | ||
|
|
7a96727c59 | ||
|
|
367c31bf17 | ||
|
|
decba39c09 | ||
|
|
3bd456e52d | ||
|
|
79c0178a7c | ||
|
|
6cef0af5df | ||
|
|
ed3d3e4ff0 | ||
|
|
b93a2b06bf | ||
|
|
e96377572e | ||
|
|
8920d73f38 | ||
|
|
a7f23b9cc7 | ||
|
|
d94b196843 | ||
|
|
73f279d6e7 | ||
|
|
c2dfbd47a3 | ||
|
|
8f9dafcce9 | ||
|
|
364bc883ba | ||
|
|
8c13738199 | ||
|
|
87cc0481a0 | ||
|
|
55b1d89fd3 | ||
|
|
e695630822 | ||
|
|
85bfc1d79e | ||
|
|
a792a7005b | ||
|
|
c3c90dd1b4 | ||
|
|
96b46de7c8 | ||
|
|
edd03020c2 | ||
|
|
639aaff9c7 | ||
|
|
9e4843d53e | ||
|
|
2351884352 | ||
|
|
a3c051bf96 | ||
|
|
40bea78186 | ||
|
|
d55993a37b | ||
|
|
33165f4f55 | ||
|
|
a30c38f38c | ||
|
|
8effbff817 | ||
|
|
dcc3f9e0a2 | ||
|
|
e33d786745 | ||
|
|
251f67dcf3 | ||
|
|
b3572747f0 | ||
|
|
311c9e4719 | ||
|
|
ce3654c6ec | ||
|
|
f3212fe01c | ||
|
|
162ec2884e | ||
|
|
70dae17d2f | ||
|
|
8056131901 | ||
|
|
494afdde96 | ||
|
|
ac03242cfc | ||
|
|
9ace52114c | ||
|
|
6d4f1ebcc6 | ||
|
|
7c74cc6420 | ||
|
|
e45e06b675 | ||
|
|
39402b842e | ||
|
|
96a46a007f | ||
|
|
6d06234048 | ||
|
|
0e9b77e7c3 | ||
|
|
f8d2e0e6a8 | ||
|
|
fa6da788dc | ||
|
|
5aecf0e31d | ||
|
|
f5cf8cffa3 | ||
|
|
3fe1550943 | ||
|
|
cea90d535d | ||
|
|
dca13f5c89 | ||
|
|
c4afb3a2b5 | ||
|
|
f1efc76e8c | ||
|
|
9937ae8ef9 | ||
|
|
64978b0138 | ||
|
|
40f77b25d1 | ||
|
|
a09e27f863 | ||
|
|
32ab636c77 | ||
|
|
fcd0bb13b3 | ||
|
|
260a3004f4 | ||
|
|
2414239e50 | ||
|
|
7607e67d59 | ||
|
|
633f99df6c | ||
|
|
7927e1dcd4 | ||
|
|
eb3655da1c | ||
|
|
ed8ec89497 | ||
|
|
44bd038339 | ||
|
|
a6a500ade2 | ||
|
|
6014a75e0e | ||
|
|
eed2df0fb3 | ||
|
|
414e0b20b3 | ||
|
|
f934554143 | ||
|
|
b3d9d08750 | ||
|
|
d32540469b | ||
|
|
20b2956322 | ||
|
|
01a2d16974 | ||
|
|
431aa2cb79 | ||
|
|
d9487a07b1 | ||
|
|
6d3f87f610 | ||
|
|
bc1723c0ee | ||
|
|
cdc640b544 | ||
|
|
d5ef853343 | ||
|
|
54b05e48a9 | ||
|
|
d68674a660 | ||
|
|
ba5cd08a09 | ||
|
|
c97fadd7a3 | ||
|
|
24b582d77a | ||
|
|
96a34c3690 | ||
|
|
53a34174b9 | ||
|
|
39a1cf5bd8 | ||
|
|
e37f62bb5e | ||
|
|
00891fa455 | ||
|
|
027365c246 | ||
|
|
c7ccff2e20 | ||
|
|
4130616ab1 | ||
|
|
ededfaa40b | ||
|
|
0fcfe5772f | ||
|
|
61017a7997 |
2
.github/workflows/go-tests.yml
vendored
2
.github/workflows/go-tests.yml
vendored
@@ -43,7 +43,7 @@ jobs:
|
||||
env QHELP_OUT_DIR=qhelp-out make qhelp-to-markdown
|
||||
|
||||
- name: Upload qhelp markdown
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: qhelp-markdown
|
||||
path: go/qhelp-out/**/*.md
|
||||
|
||||
4
.github/workflows/qhelp-pr-preview.yml
vendored
4
.github/workflows/qhelp-pr-preview.yml
vendored
@@ -27,7 +27,7 @@ on:
|
||||
- main
|
||||
- "rc/*"
|
||||
paths:
|
||||
- "ruby/**/*.qhelp"
|
||||
- "**/*.qhelp"
|
||||
|
||||
jobs:
|
||||
qhelp:
|
||||
@@ -52,7 +52,7 @@ jobs:
|
||||
id: changes
|
||||
run: |
|
||||
(git diff -z --name-only --diff-filter=ACMRT HEAD~1 HEAD | grep -z '.qhelp$' | grep -z -v '.inc.qhelp';
|
||||
git diff -z --name-only --diff-filter=ACMRT HEAD~1 HEAD | grep -z '.inc.qhelp$' | xargs --null -rn1 basename | xargs --null -rn1 git grep -z -l) |
|
||||
git diff -z --name-only --diff-filter=ACMRT HEAD~1 HEAD | grep -z '.inc.qhelp$' | xargs --null -rn1 basename -z | xargs --null -rn1 git grep -z -l) |
|
||||
grep -z '.qhelp$' | grep -z -v '^-' | sort -z -u > "${RUNNER_TEMP}/paths.txt"
|
||||
|
||||
- name: QHelp preview
|
||||
|
||||
@@ -4,8 +4,7 @@ This open source repository contains the standard CodeQL libraries and queries t
|
||||
|
||||
## How do I learn CodeQL and run queries?
|
||||
|
||||
There is [extensive documentation](https://codeql.github.com/docs/) on getting started with writing CodeQL.
|
||||
You can use the [CodeQL for Visual Studio Code](https://codeql.github.com/docs/codeql-for-visual-studio-code/) extension or the [interactive query console](https://lgtm.com/help/lgtm/using-query-console) on LGTM.com (Semmle Legacy product) to try out your queries on any open source project that's currently being analyzed.
|
||||
There is [extensive documentation](https://codeql.github.com/docs/) on getting started with writing CodeQL using the [CodeQL extension for Visual Studio Code](https://codeql.github.com/docs/codeql-for-visual-studio-code/) and the [CodeQL CLI](https://codeql.github.com/docs/codeql-cli/).
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll",
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll",
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForOnActivityResult.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/old/internal/DataFlowImpl.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/old/internal/DataFlowImpl2.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/old/internal/DataFlowImpl3.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/old/internal/DataFlowImpl4.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/old/internal/DataFlowImplLocal.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll",
|
||||
@@ -33,13 +33,14 @@
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForLibraries.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForRegExp.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForHttpClientLibraries.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForPathname.qll",
|
||||
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll"
|
||||
],
|
||||
"DataFlow Java/C++/C#/Python Common": [
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/old/internal/DataFlowImplCommon.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll",
|
||||
"cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll",
|
||||
@@ -48,8 +49,8 @@
|
||||
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImplCommon.qll"
|
||||
],
|
||||
"TaintTracking::Configuration Java/C++/C#/Python": [
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/old/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/old/internal/tainttracking2/TaintTrackingImpl.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking3/TaintTrackingImpl.qll",
|
||||
@@ -69,12 +70,11 @@
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking3/TaintTrackingImpl.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking4/TaintTrackingImpl.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttrackingforlibraries/TaintTrackingImpl.qll",
|
||||
"swift/ql/lib/codeql/swift/dataflow/internal/tainttracking1/TaintTrackingImpl.qll"
|
||||
],
|
||||
"DataFlow Java/C++/C#/Python Consistency checks": [
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/old/internal/DataFlowImplConsistency.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll",
|
||||
"cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll",
|
||||
@@ -115,7 +115,7 @@
|
||||
],
|
||||
"C++ SubBasicBlocks": [
|
||||
"cpp/ql/lib/semmle/code/cpp/controlflow/SubBasicBlocks.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/SubBasicBlocks.qll"
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/old/internal/SubBasicBlocks.qll"
|
||||
],
|
||||
"IR Instruction": [
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll",
|
||||
|
||||
@@ -1,3 +1,22 @@
|
||||
## 0.4.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.0
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* Some classes/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
|
||||
The old name still exists as a deprecated alias.
|
||||
|
||||
### New Features
|
||||
|
||||
* Added subclasses of `BuiltInOperations` for `__is_same`, `__is_function`, `__is_layout_compatible`, `__is_pointer_interconvertible_base_of`, `__is_array`, `__array_rank`, `__array_extent`, `__is_arithmetic`, `__is_complete_type`, `__is_compound`, `__is_const`, `__is_floating_point`, `__is_fundamental`, `__is_integral`, `__is_lvalue_reference`, `__is_member_function_pointer`, `__is_member_object_pointer`, `__is_member_pointer`, `__is_object`, `__is_pointer`, `__is_reference`, `__is_rvalue_reference`, `__is_scalar`, `__is_signed`, `__is_unsigned`, `__is_void`, and `__is_volatile`.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixed an issue in the taint tracking analysis where implicit reads were not allowed by default in sinks or additional taint steps that used flow states.
|
||||
|
||||
## 0.3.5
|
||||
|
||||
## 0.3.4
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: fix
|
||||
---
|
||||
* Fixed an issue in the taint tracking analysis where implicit reads were not allowed by default in sinks or additional taint steps that used flow states.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
category: deprecated
|
||||
---
|
||||
* Some classes/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
|
||||
The old name still exists as a deprecated alias.
|
||||
@@ -1,4 +1,14 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
## 0.4.0
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* Some classes/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
|
||||
The old name still exists as a deprecated alias.
|
||||
|
||||
### New Features
|
||||
|
||||
* Added subclasses of `BuiltInOperations` for `__is_same`, `__is_function`, `__is_layout_compatible`, `__is_pointer_interconvertible_base_of`, `__is_array`, `__array_rank`, `__array_extent`, `__is_arithmetic`, `__is_complete_type`, `__is_compound`, `__is_const`, `__is_floating_point`, `__is_fundamental`, `__is_integral`, `__is_lvalue_reference`, `__is_member_function_pointer`, `__is_member_object_pointer`, `__is_member_pointer`, `__is_object`, `__is_pointer`, `__is_reference`, `__is_rvalue_reference`, `__is_scalar`, `__is_signed`, `__is_unsigned`, `__is_void`, and `__is_volatile`.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixed an issue in the taint tracking analysis where implicit reads were not allowed by default in sinks or additional taint steps that used flow states.
|
||||
3
cpp/ql/lib/change-notes/released/0.4.1.md
Normal file
3
cpp/ql/lib/change-notes/released/0.4.1.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.4.1
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.3.5
|
||||
lastReleaseVersion: 0.4.1
|
||||
|
||||
@@ -20,7 +20,8 @@ module ProductFlow {
|
||||
* `source1` and `source2` must belong to the same callable.
|
||||
*/
|
||||
predicate isSourcePair(
|
||||
DataFlow::Node source1, string state1, DataFlow::Node source2, string state2
|
||||
DataFlow::Node source1, DataFlow::FlowState state1, DataFlow::Node source2,
|
||||
DataFlow::FlowState state2
|
||||
) {
|
||||
state1 = "" and
|
||||
state2 = "" and
|
||||
@@ -49,6 +50,101 @@ module ProductFlow {
|
||||
this.isSinkPair(sink1, sink2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited through the first projection of the product
|
||||
* dataflow graph when the flow state is `state`.
|
||||
*/
|
||||
predicate isBarrier1(DataFlow::Node node, DataFlow::FlowState state) {
|
||||
this.isBarrier1(node) and state = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited through the second projection of the product
|
||||
* dataflow graph when the flow state is `state`.
|
||||
*/
|
||||
predicate isBarrier2(DataFlow::Node node, DataFlow::FlowState state) {
|
||||
this.isBarrier2(node) and state = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited through the first projection of the product
|
||||
* dataflow graph.
|
||||
*/
|
||||
predicate isBarrier1(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited through the second projection of the product
|
||||
* dataflow graph.
|
||||
*/
|
||||
predicate isBarrier2(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow out of `node` is prohibited in the first projection of the product
|
||||
* dataflow graph.
|
||||
*/
|
||||
predicate isBarrierOut1(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow out of `node` is prohibited in the second projection of the product
|
||||
* dataflow graph.
|
||||
*/
|
||||
predicate isBarrierOut2(DataFlow::Node node) { none() }
|
||||
|
||||
/*
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps in
|
||||
* the first projection of the product dataflow graph.
|
||||
*/
|
||||
|
||||
predicate isAdditionalFlowStep1(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps in
|
||||
* the first projection of the product dataflow graph.
|
||||
*
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep1(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
) {
|
||||
state1 instanceof DataFlow::FlowStateEmpty and
|
||||
state2 instanceof DataFlow::FlowStateEmpty and
|
||||
this.isAdditionalFlowStep1(node1, node2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps in
|
||||
* the second projection of the product dataflow graph.
|
||||
*/
|
||||
predicate isAdditionalFlowStep2(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps in
|
||||
* the second projection of the product dataflow graph.
|
||||
*
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep2(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
) {
|
||||
state1 instanceof DataFlow::FlowStateEmpty and
|
||||
state2 instanceof DataFlow::FlowStateEmpty and
|
||||
this.isAdditionalFlowStep2(node1, node2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data flow into `node` is prohibited in the first projection of the product
|
||||
* dataflow graph.
|
||||
*/
|
||||
predicate isBarrierIn1(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow into `node` is prohibited in the second projection of the product
|
||||
* dataflow graph.
|
||||
*/
|
||||
predicate isBarrierIn2(DataFlow::Node node) { none() }
|
||||
|
||||
predicate hasFlowPath(
|
||||
DataFlow::PathNode source1, DataFlow2::PathNode source2, DataFlow::PathNode sink1,
|
||||
DataFlow2::PathNode sink2
|
||||
@@ -63,38 +159,78 @@ module ProductFlow {
|
||||
class Conf1 extends DataFlow::Configuration {
|
||||
Conf1() { this = "Conf1" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source, string state) {
|
||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
|
||||
exists(Configuration conf | conf.isSourcePair(source, state, _, _))
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink, string state) {
|
||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
|
||||
exists(Configuration conf | conf.isSinkPair(sink, state, _, _))
|
||||
}
|
||||
|
||||
override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
|
||||
exists(Configuration conf | conf.isBarrier1(node, state))
|
||||
}
|
||||
|
||||
override predicate isBarrierOut(DataFlow::Node node) {
|
||||
exists(Configuration conf | conf.isBarrierOut1(node))
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
) {
|
||||
exists(Configuration conf | conf.isAdditionalFlowStep1(node1, state1, node2, state2))
|
||||
}
|
||||
|
||||
override predicate isBarrierIn(DataFlow::Node node) {
|
||||
exists(Configuration conf | conf.isBarrierIn1(node))
|
||||
}
|
||||
}
|
||||
|
||||
class Conf2 extends DataFlow2::Configuration {
|
||||
Conf2() { this = "Conf2" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source, string state) {
|
||||
exists(Configuration conf, DataFlow::Node source1 |
|
||||
conf.isSourcePair(source1, _, source, state) and
|
||||
any(Conf1 c).hasFlow(source1, _)
|
||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
|
||||
exists(Configuration conf, DataFlow::PathNode source1 |
|
||||
conf.isSourcePair(source1.getNode(), source1.getState(), source, state) and
|
||||
any(Conf1 c).hasFlowPath(source1, _)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink, string state) {
|
||||
exists(Configuration conf, DataFlow::Node sink1 |
|
||||
conf.isSinkPair(sink1, _, sink, state) and any(Conf1 c).hasFlow(_, sink1)
|
||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
|
||||
exists(Configuration conf, DataFlow::PathNode sink1 |
|
||||
conf.isSinkPair(sink1.getNode(), sink1.getState(), sink, state) and
|
||||
any(Conf1 c).hasFlowPath(_, sink1)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isBarrier(DataFlow::Node node, DataFlow::FlowState state) {
|
||||
exists(Configuration conf | conf.isBarrier2(node, state))
|
||||
}
|
||||
|
||||
override predicate isBarrierOut(DataFlow::Node node) {
|
||||
exists(Configuration conf | conf.isBarrierOut2(node))
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
) {
|
||||
exists(Configuration conf | conf.isAdditionalFlowStep2(node1, state1, node2, state2))
|
||||
}
|
||||
|
||||
override predicate isBarrierIn(DataFlow::Node node) {
|
||||
exists(Configuration conf | conf.isBarrierIn2(node))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate reachableInterprocEntry(
|
||||
Configuration conf, DataFlow::PathNode source1, DataFlow2::PathNode source2,
|
||||
DataFlow::PathNode node1, DataFlow2::PathNode node2
|
||||
) {
|
||||
conf.isSourcePair(node1.getNode(), _, node2.getNode(), _) and
|
||||
conf.isSourcePair(node1.getNode(), node1.getState(), node2.getNode(), node2.getState()) and
|
||||
node1 = source1 and
|
||||
node2 = source2
|
||||
or
|
||||
@@ -157,7 +293,7 @@ module ProductFlow {
|
||||
) {
|
||||
exists(DataFlow::PathNode mid1, DataFlow2::PathNode mid2 |
|
||||
reachableInterprocEntry(conf, source1, source2, mid1, mid2) and
|
||||
conf.isSinkPair(sink1.getNode(), _, sink2.getNode(), _) and
|
||||
conf.isSinkPair(sink1.getNode(), sink1.getState(), sink2.getNode(), sink2.getState()) and
|
||||
localPathStep1*(mid1, sink1) and
|
||||
localPathStep2*(mid2, sink2)
|
||||
)
|
||||
|
||||
@@ -163,7 +163,9 @@ abstract class Configuration extends string {
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
|
||||
predicate hasFlowTo(Node sink) {
|
||||
sink = any(PathNodeSink n | this = n.getConfiguration()).getNodeEx().asNode()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -558,13 +560,16 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
hasReadStep(tc.getContent(), config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
|
||||
@@ -598,13 +603,9 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class ApApprox = Unit;
|
||||
|
||||
class Ap = Unit;
|
||||
|
||||
class ApOption = Unit;
|
||||
|
||||
class Cc = boolean;
|
||||
private class Cc = boolean;
|
||||
|
||||
/* Begin: Stage 1 logic. */
|
||||
/**
|
||||
@@ -613,7 +614,7 @@ private module Stage1 implements StageSig {
|
||||
* The Boolean `cc` records whether the node is reached through an
|
||||
* argument in a call.
|
||||
*/
|
||||
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
sourceNode(node, _, config) and
|
||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||
or
|
||||
@@ -753,7 +754,7 @@ private module Stage1 implements StageSig {
|
||||
* the enclosing callable in order to reach a sink.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
revFlow0(node, toReturn, config) and
|
||||
fwdFlow(node, config)
|
||||
}
|
||||
@@ -837,13 +838,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -859,7 +860,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -906,7 +907,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -998,7 +999,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1259,7 +1260,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1483,7 +1484,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(
|
||||
additional predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1661,7 +1662,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1674,11 +1675,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1699,7 +1702,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1741,7 +1744,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -2926,12 +2929,17 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
pragma[nomagic]
|
||||
private PathNodeImpl getANonHiddenSuccessor0() {
|
||||
result = this.getASuccessorIfHidden*() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getANonHiddenSuccessor0() and
|
||||
not this.isHidden()
|
||||
}
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
|
||||
@@ -163,7 +163,9 @@ abstract class Configuration extends string {
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
|
||||
predicate hasFlowTo(Node sink) {
|
||||
sink = any(PathNodeSink n | this = n.getConfiguration()).getNodeEx().asNode()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -558,13 +560,16 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
hasReadStep(tc.getContent(), config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
|
||||
@@ -598,13 +603,9 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class ApApprox = Unit;
|
||||
|
||||
class Ap = Unit;
|
||||
|
||||
class ApOption = Unit;
|
||||
|
||||
class Cc = boolean;
|
||||
private class Cc = boolean;
|
||||
|
||||
/* Begin: Stage 1 logic. */
|
||||
/**
|
||||
@@ -613,7 +614,7 @@ private module Stage1 implements StageSig {
|
||||
* The Boolean `cc` records whether the node is reached through an
|
||||
* argument in a call.
|
||||
*/
|
||||
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
sourceNode(node, _, config) and
|
||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||
or
|
||||
@@ -753,7 +754,7 @@ private module Stage1 implements StageSig {
|
||||
* the enclosing callable in order to reach a sink.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
revFlow0(node, toReturn, config) and
|
||||
fwdFlow(node, config)
|
||||
}
|
||||
@@ -837,13 +838,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -859,7 +860,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -906,7 +907,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -998,7 +999,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1259,7 +1260,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1483,7 +1484,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(
|
||||
additional predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1661,7 +1662,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1674,11 +1675,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1699,7 +1702,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1741,7 +1744,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -2926,12 +2929,17 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
pragma[nomagic]
|
||||
private PathNodeImpl getANonHiddenSuccessor0() {
|
||||
result = this.getASuccessorIfHidden*() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getANonHiddenSuccessor0() and
|
||||
not this.isHidden()
|
||||
}
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
|
||||
@@ -163,7 +163,9 @@ abstract class Configuration extends string {
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
|
||||
predicate hasFlowTo(Node sink) {
|
||||
sink = any(PathNodeSink n | this = n.getConfiguration()).getNodeEx().asNode()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -558,13 +560,16 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
hasReadStep(tc.getContent(), config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
|
||||
@@ -598,13 +603,9 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class ApApprox = Unit;
|
||||
|
||||
class Ap = Unit;
|
||||
|
||||
class ApOption = Unit;
|
||||
|
||||
class Cc = boolean;
|
||||
private class Cc = boolean;
|
||||
|
||||
/* Begin: Stage 1 logic. */
|
||||
/**
|
||||
@@ -613,7 +614,7 @@ private module Stage1 implements StageSig {
|
||||
* The Boolean `cc` records whether the node is reached through an
|
||||
* argument in a call.
|
||||
*/
|
||||
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
sourceNode(node, _, config) and
|
||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||
or
|
||||
@@ -753,7 +754,7 @@ private module Stage1 implements StageSig {
|
||||
* the enclosing callable in order to reach a sink.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
revFlow0(node, toReturn, config) and
|
||||
fwdFlow(node, config)
|
||||
}
|
||||
@@ -837,13 +838,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -859,7 +860,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -906,7 +907,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -998,7 +999,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1259,7 +1260,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1483,7 +1484,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(
|
||||
additional predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1661,7 +1662,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1674,11 +1675,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1699,7 +1702,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1741,7 +1744,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -2926,12 +2929,17 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
pragma[nomagic]
|
||||
private PathNodeImpl getANonHiddenSuccessor0() {
|
||||
result = this.getASuccessorIfHidden*() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getANonHiddenSuccessor0() and
|
||||
not this.isHidden()
|
||||
}
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
|
||||
@@ -163,7 +163,9 @@ abstract class Configuration extends string {
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
|
||||
predicate hasFlowTo(Node sink) {
|
||||
sink = any(PathNodeSink n | this = n.getConfiguration()).getNodeEx().asNode()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -558,13 +560,16 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
hasReadStep(tc.getContent(), config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
|
||||
@@ -598,13 +603,9 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class ApApprox = Unit;
|
||||
|
||||
class Ap = Unit;
|
||||
|
||||
class ApOption = Unit;
|
||||
|
||||
class Cc = boolean;
|
||||
private class Cc = boolean;
|
||||
|
||||
/* Begin: Stage 1 logic. */
|
||||
/**
|
||||
@@ -613,7 +614,7 @@ private module Stage1 implements StageSig {
|
||||
* The Boolean `cc` records whether the node is reached through an
|
||||
* argument in a call.
|
||||
*/
|
||||
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
sourceNode(node, _, config) and
|
||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||
or
|
||||
@@ -753,7 +754,7 @@ private module Stage1 implements StageSig {
|
||||
* the enclosing callable in order to reach a sink.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
revFlow0(node, toReturn, config) and
|
||||
fwdFlow(node, config)
|
||||
}
|
||||
@@ -837,13 +838,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -859,7 +860,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -906,7 +907,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -998,7 +999,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1259,7 +1260,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1483,7 +1484,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(
|
||||
additional predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1661,7 +1662,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1674,11 +1675,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1699,7 +1702,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1741,7 +1744,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -2926,12 +2929,17 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
pragma[nomagic]
|
||||
private PathNodeImpl getANonHiddenSuccessor0() {
|
||||
result = this.getASuccessorIfHidden*() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getANonHiddenSuccessor0() and
|
||||
not this.isHidden()
|
||||
}
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
|
||||
@@ -137,7 +137,7 @@ private newtype TReturnKind =
|
||||
exists(IndirectReturnNode return, ReturnIndirectionInstruction returnInd |
|
||||
returnInd.hasIndex(argumentIndex) and
|
||||
return.getAddressOperand() = returnInd.getSourceAddressOperand() and
|
||||
indirectionIndex = return.getIndirectionIndex() - 1 // We subtract one because the return loads the value.
|
||||
indirectionIndex = return.getIndirectionIndex()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ class ReturnIndirectionNode extends IndirectReturnNode, ReturnNode {
|
||||
exists(int argumentIndex, ReturnIndirectionInstruction returnInd |
|
||||
returnInd.hasIndex(argumentIndex) and
|
||||
this.getAddressOperand() = returnInd.getSourceAddressOperand() and
|
||||
result = TIndirectReturnKind(argumentIndex, this.getIndirectionIndex() - 1) and
|
||||
result = TIndirectReturnKind(argumentIndex, this.getIndirectionIndex()) and
|
||||
hasNonInitializeParameterDef(returnInd.getIRVariable())
|
||||
)
|
||||
or
|
||||
@@ -365,7 +365,7 @@ predicate jumpStep(Node n1, Node n2) {
|
||||
predicate storeStep(Node node1, Content c, PostFieldUpdateNode node2) {
|
||||
exists(int indirectionIndex1, int numberOfLoads, StoreInstruction store |
|
||||
nodeHasInstruction(node1, store, pragma[only_bind_into](indirectionIndex1)) and
|
||||
node2.getIndirectionIndex() = 0 and
|
||||
node2.getIndirectionIndex() = 1 and
|
||||
numberOfLoadsFromOperand(node2.getFieldAddress(), store.getDestinationAddressOperand(),
|
||||
numberOfLoads)
|
||||
|
|
||||
@@ -465,20 +465,20 @@ predicate clearsContent(Node n, Content c) {
|
||||
predicate expectsContent(Node n, ContentSet c) { none() }
|
||||
|
||||
/** Gets the type of `n` used for type pruning. */
|
||||
IRType getNodeType(Node n) {
|
||||
DataFlowType getNodeType(Node n) {
|
||||
suppressUnusedNode(n) and
|
||||
result instanceof IRVoidType // stub implementation
|
||||
result instanceof VoidType // stub implementation
|
||||
}
|
||||
|
||||
/** Gets a string representation of a type returned by `getNodeType`. */
|
||||
string ppReprType(IRType t) { none() } // stub implementation
|
||||
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`.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate compatibleTypes(IRType t1, IRType t2) {
|
||||
predicate compatibleTypes(DataFlowType t1, DataFlowType t2) {
|
||||
any() // stub implementation
|
||||
}
|
||||
|
||||
@@ -502,7 +502,7 @@ class DataFlowCallable = Cpp::Declaration;
|
||||
|
||||
class DataFlowExpr = Expr;
|
||||
|
||||
class DataFlowType = IRType;
|
||||
class DataFlowType = Type;
|
||||
|
||||
/** A function call relevant for data flow. */
|
||||
class DataFlowCall extends CallInstruction {
|
||||
|
||||
@@ -38,13 +38,12 @@ private module Cached {
|
||||
TVariableNode(Variable var) or
|
||||
TPostFieldUpdateNode(FieldAddress operand, int indirectionIndex) {
|
||||
indirectionIndex =
|
||||
[0 .. Ssa::countIndirectionsForCppType(operand.getObjectAddress().getResultLanguageType()) -
|
||||
1]
|
||||
[1 .. Ssa::countIndirectionsForCppType(operand.getObjectAddress().getResultLanguageType())]
|
||||
} or
|
||||
TSsaPhiNode(Ssa::PhiNode phi) or
|
||||
TIndirectArgumentOutNode(ArgumentOperand operand, int indirectionIndex) {
|
||||
Ssa::isModifiableByCall(operand) and
|
||||
indirectionIndex = [0 .. Ssa::countIndirectionsForCppType(operand.getLanguageType()) - 1]
|
||||
indirectionIndex = [1 .. Ssa::countIndirectionsForCppType(operand.getLanguageType())]
|
||||
} or
|
||||
TIndirectOperand(Operand op, int indirectionIndex) {
|
||||
Ssa::hasIndirectOperand(op, indirectionIndex)
|
||||
@@ -113,7 +112,7 @@ class Node extends TIRDataFlowNode {
|
||||
Declaration getFunction() { none() } // overridden in subclasses
|
||||
|
||||
/** Gets the type of this node. */
|
||||
IRType getType() { none() } // overridden in subclasses
|
||||
DataFlowType getType() { none() } // overridden in subclasses
|
||||
|
||||
/** Gets the instruction corresponding to this node, if any. */
|
||||
Instruction asInstruction() { result = this.(InstructionNode).getInstruction() }
|
||||
@@ -230,7 +229,13 @@ class Node extends TIRDataFlowNode {
|
||||
Expr asIndirectArgument() { result = this.asIndirectArgument(_) }
|
||||
|
||||
/** Gets the positional parameter corresponding to this node, if any. */
|
||||
Parameter asParameter() { result = asParameter(0) }
|
||||
Parameter asParameter() { result = this.asParameter(0) }
|
||||
|
||||
/**
|
||||
* Gets the uninitialized local variable corresponding to this node, if
|
||||
* any.
|
||||
*/
|
||||
LocalVariable asUninitialized() { result = this.(UninitializedNode).getLocalVariable() }
|
||||
|
||||
/**
|
||||
* Gets the positional parameter corresponding to the node that represents
|
||||
@@ -273,7 +278,7 @@ class Node extends TIRDataFlowNode {
|
||||
/**
|
||||
* Gets an upper bound on the type of this node.
|
||||
*/
|
||||
IRType getTypeBound() { result = this.getType() }
|
||||
DataFlowType getTypeBound() { result = this.getType() }
|
||||
|
||||
/** Gets the location of this element. */
|
||||
cached
|
||||
@@ -322,7 +327,7 @@ class InstructionNode extends Node, TInstructionNode {
|
||||
|
||||
override Declaration getFunction() { result = instr.getEnclosingFunction() }
|
||||
|
||||
override IRType getType() { result = instr.getResultIRType() }
|
||||
override DataFlowType getType() { result = instr.getResultType() }
|
||||
|
||||
final override Location getLocationImpl() { result = instr.getLocation() }
|
||||
|
||||
@@ -348,13 +353,32 @@ class OperandNode extends Node, TOperandNode {
|
||||
|
||||
override Declaration getFunction() { result = op.getUse().getEnclosingFunction() }
|
||||
|
||||
override IRType getType() { result = op.getIRType() }
|
||||
override DataFlowType getType() { result = op.getType() }
|
||||
|
||||
final override Location getLocationImpl() { result = op.getLocation() }
|
||||
|
||||
override string toStringImpl() { result = this.getOperand().toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `t`, but stripped of the `n` outermost pointers, references, etc.
|
||||
*
|
||||
* For example, `stripPointers(int*&, 2)` is `int` and `stripPointers(int*, 0)` is `int*`.
|
||||
*/
|
||||
private Type stripPointers(Type t, int n) {
|
||||
result = t and n = 0
|
||||
or
|
||||
result = stripPointers(t.(PointerType).getBaseType(), n - 1)
|
||||
or
|
||||
result = stripPointers(t.(ArrayType).getBaseType(), n - 1)
|
||||
or
|
||||
result = stripPointers(t.(ReferenceType).getBaseType(), n - 1)
|
||||
or
|
||||
result = stripPointers(t.(PointerToMemberType).getBaseType(), n - 1)
|
||||
or
|
||||
result = stripPointers(t.(FunctionPointerIshType).getBaseType(), n - 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: do not use.
|
||||
*
|
||||
@@ -370,8 +394,6 @@ class PostFieldUpdateNode extends TPostFieldUpdateNode, PartialDefinitionNode {
|
||||
|
||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||
|
||||
override IRType getType() { result = fieldAddress.getIRType() }
|
||||
|
||||
FieldAddress getFieldAddress() { result = fieldAddress }
|
||||
|
||||
Field getUpdatedField() { result = fieldAddress.getField() }
|
||||
@@ -379,10 +401,8 @@ class PostFieldUpdateNode extends TPostFieldUpdateNode, PartialDefinitionNode {
|
||||
int getIndirectionIndex() { result = indirectionIndex }
|
||||
|
||||
override Node getPreUpdateNode() {
|
||||
// + 1 because we're storing into an lvalue, and the original node should be the rvalue of
|
||||
// the same address.
|
||||
hasOperandAndIndex(result, pragma[only_bind_into](fieldAddress).getObjectAddressOperand(),
|
||||
indirectionIndex + 1)
|
||||
indirectionIndex)
|
||||
}
|
||||
|
||||
override Expr getDefinedExpr() {
|
||||
@@ -411,11 +431,26 @@ class SsaPhiNode extends Node, TSsaPhiNode {
|
||||
|
||||
override Declaration getFunction() { result = phi.getBasicBlock().getEnclosingFunction() }
|
||||
|
||||
override IRType getType() { result instanceof IRVoidType }
|
||||
override DataFlowType getType() { result = this.getAnInput().getType() }
|
||||
|
||||
final override Location getLocationImpl() { result = phi.getBasicBlock().getLocation() }
|
||||
|
||||
override string toStringImpl() { result = "Phi" }
|
||||
|
||||
/**
|
||||
* Gets a node that is used as input to this phi node.
|
||||
* `fromBackEdge` is true if data flows along a back-edge,
|
||||
* and `false` otherwise.
|
||||
*/
|
||||
final Node getAnInput(boolean fromBackEdge) {
|
||||
localFlowStep(result, this) and
|
||||
if phi.getBasicBlock().dominates(getBasicBlock(result))
|
||||
then fromBackEdge = true
|
||||
else fromBackEdge = false
|
||||
}
|
||||
|
||||
/** Gets a node that is used as input to this phi node. */
|
||||
final Node getAnInput() { result = this.getAnInput(_) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -439,8 +474,6 @@ class SideEffectOperandNode extends Node, IndirectOperand {
|
||||
|
||||
override Function getFunction() { result = call.getEnclosingFunction() }
|
||||
|
||||
override IRType getType() { result instanceof IRVoidType }
|
||||
|
||||
Expr getArgument() { result = call.getArgument(argumentIndex).getUnconvertedResultExpression() }
|
||||
}
|
||||
|
||||
@@ -463,8 +496,6 @@ class IndirectParameterNode extends Node, IndirectInstruction {
|
||||
|
||||
override Function getFunction() { result = this.getInstruction().getEnclosingFunction() }
|
||||
|
||||
override IRType getType() { result instanceof IRVoidType }
|
||||
|
||||
override string toStringImpl() {
|
||||
result = this.getParameter().toString() + " indirection"
|
||||
or
|
||||
@@ -489,8 +520,6 @@ class IndirectReturnNode extends IndirectOperand {
|
||||
Operand getAddressOperand() { result = operand }
|
||||
|
||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||
|
||||
override IRType getType() { result instanceof IRVoidType }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -521,9 +550,7 @@ class IndirectArgumentOutNode extends Node, TIndirectArgumentOutNode, PostUpdate
|
||||
|
||||
override Function getFunction() { result = this.getCallInstruction().getEnclosingFunction() }
|
||||
|
||||
override IRType getType() { result instanceof IRVoidType }
|
||||
|
||||
override Node getPreUpdateNode() { hasOperandAndIndex(result, operand, indirectionIndex + 1) }
|
||||
override Node getPreUpdateNode() { hasOperandAndIndex(result, operand, indirectionIndex) }
|
||||
|
||||
override string toStringImpl() {
|
||||
// This string should be unique enough to be helpful but common enough to
|
||||
@@ -579,6 +606,38 @@ class IndirectReturnOutNode extends Node {
|
||||
int getIndirectionIndex() { result = indirectionIndex }
|
||||
}
|
||||
|
||||
private PointerType getGLValueType(Type t, int indirectionIndex) {
|
||||
result.getBaseType() = stripPointers(t, indirectionIndex - 1)
|
||||
}
|
||||
|
||||
bindingset[isGLValue]
|
||||
private DataFlowType getTypeImpl(Type t, int indirectionIndex, boolean isGLValue) {
|
||||
if isGLValue = true
|
||||
then
|
||||
result = getGLValueType(t, indirectionIndex)
|
||||
or
|
||||
// Ideally, the above case would cover all glvalue cases. However, consider the case where
|
||||
// the database consists only of:
|
||||
// ```
|
||||
// void test() {
|
||||
// int* x;
|
||||
// x = nullptr;
|
||||
// }
|
||||
// ```
|
||||
// and we want to compute the type of `*x` in the assignment `x = nullptr`. Here, `x` is an lvalue
|
||||
// of type int* (which morally is an int**). So when we call `getTypeImpl` it will be with the
|
||||
// parameters:
|
||||
// - t = int*
|
||||
// - indirectionIndex = 1 (when we want to model the dataflow node corresponding to *x)
|
||||
// - isGLValue = true
|
||||
// In this case, `getTypeImpl(t, indirectionIndex, isGLValue)` should give back `int**`. In this
|
||||
// case, however, `int**` does not exist in the database. So instead we return int* (which is
|
||||
// wrong, but at least we have a type).
|
||||
not exists(getGLValueType(t, indirectionIndex)) and
|
||||
result = stripPointers(t, indirectionIndex - 1)
|
||||
else result = stripPointers(t, indirectionIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
@@ -600,7 +659,11 @@ class IndirectOperand extends Node, TIndirectOperand {
|
||||
|
||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||
|
||||
override IRType getType() { result = this.getOperand().getIRType() }
|
||||
override DataFlowType getType() {
|
||||
exists(boolean isGLValue | if operand.isGLValue() then isGLValue = true else isGLValue = false |
|
||||
result = getTypeImpl(operand.getType().getUnspecifiedType(), indirectionIndex, isGLValue)
|
||||
)
|
||||
}
|
||||
|
||||
final override Location getLocationImpl() { result = this.getOperand().getLocation() }
|
||||
|
||||
@@ -609,6 +672,25 @@ class IndirectOperand extends Node, TIndirectOperand {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The value of an uninitialized local variable, viewed as a node in a data
|
||||
* flow graph.
|
||||
*/
|
||||
class UninitializedNode extends Node {
|
||||
LocalVariable v;
|
||||
|
||||
UninitializedNode() {
|
||||
exists(Ssa::Def def |
|
||||
def.getDefiningInstruction() instanceof UninitializedInstruction and
|
||||
Ssa::nodeToDefOrUse(this, def) and
|
||||
v = def.getSourceVariable().getBaseVariable().(Ssa::BaseIRVariable).getIRVariable().getAst()
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the uninitialized local variable corresponding to this node. */
|
||||
LocalVariable getLocalVariable() { result = v }
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
@@ -630,7 +712,11 @@ class IndirectInstruction extends Node, TIndirectInstruction {
|
||||
|
||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||
|
||||
override IRType getType() { result = this.getInstruction().getResultIRType() }
|
||||
override DataFlowType getType() {
|
||||
exists(boolean isGLValue | if instr.isGLValue() then isGLValue = true else isGLValue = false |
|
||||
result = getTypeImpl(instr.getResultType().getUnspecifiedType(), indirectionIndex, isGLValue)
|
||||
)
|
||||
}
|
||||
|
||||
final override Location getLocationImpl() { result = this.getInstruction().getLocation() }
|
||||
|
||||
@@ -801,7 +887,7 @@ class ThisParameterNode extends ParameterNode, InstructionNode {
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate indirectPostionHasArgumentIndexAndIndex(
|
||||
private predicate indirectPositionHasArgumentIndexAndIndex(
|
||||
IndirectionPosition pos, int argumentIndex, int indirectionIndex
|
||||
) {
|
||||
pos.getArgumentIndex() = argumentIndex and
|
||||
@@ -821,7 +907,7 @@ class ParameterIndirectionNode extends ParameterNode instanceof IndirectParamete
|
||||
override predicate isParameterOf(Function f, ParameterPosition pos) {
|
||||
IndirectParameterNode.super.getEnclosingCallable() = f and
|
||||
exists(int argumentIndex, int indirectionIndex |
|
||||
indirectPostionHasArgumentIndexAndIndex(pos, argumentIndex, indirectionIndex) and
|
||||
indirectPositionHasArgumentIndexAndIndex(pos, argumentIndex, indirectionIndex) and
|
||||
indirectParameterNodeHasArgumentIndexAndIndex(this, argumentIndex, indirectionIndex)
|
||||
)
|
||||
}
|
||||
@@ -844,6 +930,8 @@ abstract class PostUpdateNode extends Node {
|
||||
* Gets the node before the state update.
|
||||
*/
|
||||
abstract Node getPreUpdateNode();
|
||||
|
||||
final override DataFlowType getType() { result = this.getPreUpdateNode().getType() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -907,7 +995,7 @@ class VariableNode extends Node, TVariableNode {
|
||||
result = v
|
||||
}
|
||||
|
||||
override IRType getType() { result.getCanonicalLanguageType().hasUnspecifiedType(v.getType(), _) }
|
||||
override DataFlowType getType() { result = v.getType() }
|
||||
|
||||
final override Location getLocationImpl() { result = v.getLocation() }
|
||||
|
||||
@@ -1060,7 +1148,7 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
store.getDestinationAddressOperand() = address
|
||||
)
|
||||
or
|
||||
Ssa::outNodeHasAddressAndIndex(nodeFrom, address, indirectionIndex - 1)
|
||||
Ssa::outNodeHasAddressAndIndex(nodeFrom, address, indirectionIndex)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ Node callOutput(CallInstruction call, FunctionOutput output) {
|
||||
// The side effect of a call on the value pointed to by an argument or qualifier
|
||||
exists(int index, int indirectionIndex |
|
||||
result.(IndirectArgumentOutNode).getArgumentIndex() = index and
|
||||
result.(IndirectArgumentOutNode).getIndirectionIndex() + 1 = indirectionIndex and
|
||||
result.(IndirectArgumentOutNode).getIndirectionIndex() = indirectionIndex and
|
||||
result.(IndirectArgumentOutNode).getCallInstruction() = call and
|
||||
output.isParameterDerefOrQualifierObject(index, indirectionIndex)
|
||||
)
|
||||
|
||||
@@ -301,7 +301,12 @@ private predicate defToNode(Node nodeFrom, Def def) {
|
||||
nodeHasInstruction(nodeFrom, def.getDefiningInstruction(), def.getIndirectionIndex())
|
||||
}
|
||||
|
||||
private predicate nodeToDefOrUse(Node nodeFrom, SsaDefOrUse defOrUse) {
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Holds if `nodeFrom` is the node that correspond to the definition or use `defOrUse`.
|
||||
*/
|
||||
predicate nodeToDefOrUse(Node nodeFrom, SsaDefOrUse defOrUse) {
|
||||
// Node -> Def
|
||||
defToNode(nodeFrom, defOrUse)
|
||||
or
|
||||
|
||||
@@ -11,7 +11,9 @@ private import DataFlowUtil
|
||||
* corresponding `(Indirect)OperandNode`.
|
||||
*/
|
||||
predicate ignoreOperand(Operand operand) {
|
||||
operand = any(Instruction instr | ignoreInstruction(instr)).getAnOperand()
|
||||
operand = any(Instruction instr | ignoreInstruction(instr)).getAnOperand() or
|
||||
operand = any(Instruction instr | ignoreInstruction(instr)).getAUse() or
|
||||
operand instanceof MemoryOperand
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,7 +36,7 @@ private module SourceVariables {
|
||||
|
||||
override string toString() { result = var.toString() }
|
||||
|
||||
override DataFlowType getType() { result = var.getIRType() }
|
||||
override DataFlowType getType() { result = var.getType() }
|
||||
}
|
||||
|
||||
class BaseCallVariable extends BaseSourceVariable, TBaseCallVariable {
|
||||
@@ -48,7 +48,7 @@ private module SourceVariables {
|
||||
|
||||
override string toString() { result = call.toString() }
|
||||
|
||||
override DataFlowType getType() { result = call.getResultIRType() }
|
||||
override DataFlowType getType() { result = call.getResultType() }
|
||||
}
|
||||
|
||||
private newtype TSourceVariable =
|
||||
|
||||
@@ -7,6 +7,7 @@ private import semmle.code.cpp.ir.IR as IR
|
||||
private import Semantic
|
||||
private import experimental.semmle.code.cpp.rangeanalysis.Bound as IRBound
|
||||
private import semmle.code.cpp.controlflow.IRGuards as IRGuards
|
||||
private import semmle.code.cpp.ir.ValueNumbering
|
||||
|
||||
module SemanticExprConfig {
|
||||
class Location = Cpp::Location;
|
||||
@@ -120,7 +121,15 @@ module SemanticExprConfig {
|
||||
|
||||
newtype TSsaVariable =
|
||||
TSsaInstruction(IR::Instruction instr) { instr.hasMemoryResult() } or
|
||||
TSsaOperand(IR::Operand op) { op.isDefinitionInexact() }
|
||||
TSsaOperand(IR::Operand op) { op.isDefinitionInexact() } or
|
||||
TSsaPointerArithmeticGuard(IR::PointerArithmeticInstruction instr) {
|
||||
exists(Guard g, IR::Operand use | use = instr.getAUse() |
|
||||
g.comparesLt(use, _, _, _, _) or
|
||||
g.comparesLt(_, use, _, _, _) or
|
||||
g.comparesEq(use, _, _, _, _) or
|
||||
g.comparesEq(_, use, _, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
class SsaVariable extends TSsaVariable {
|
||||
string toString() { none() }
|
||||
@@ -129,6 +138,8 @@ module SemanticExprConfig {
|
||||
|
||||
IR::Instruction asInstruction() { none() }
|
||||
|
||||
IR::PointerArithmeticInstruction asPointerArithGuard() { none() }
|
||||
|
||||
IR::Operand asOperand() { none() }
|
||||
}
|
||||
|
||||
@@ -144,6 +155,18 @@ module SemanticExprConfig {
|
||||
final override IR::Instruction asInstruction() { result = instr }
|
||||
}
|
||||
|
||||
class SsaPointerArithmeticGuard extends SsaVariable, TSsaPointerArithmeticGuard {
|
||||
IR::PointerArithmeticInstruction instr;
|
||||
|
||||
SsaPointerArithmeticGuard() { this = TSsaPointerArithmeticGuard(instr) }
|
||||
|
||||
final override string toString() { result = instr.toString() }
|
||||
|
||||
final override Location getLocation() { result = instr.getLocation() }
|
||||
|
||||
final override IR::PointerArithmeticInstruction asPointerArithGuard() { result = instr }
|
||||
}
|
||||
|
||||
class SsaOperand extends SsaVariable, TSsaOperand {
|
||||
IR::Operand op;
|
||||
|
||||
@@ -168,7 +191,11 @@ module SemanticExprConfig {
|
||||
)
|
||||
}
|
||||
|
||||
Expr getAUse(SsaVariable v) { result.(IR::LoadInstruction).getSourceValue() = v.asInstruction() }
|
||||
Expr getAUse(SsaVariable v) {
|
||||
result.(IR::LoadInstruction).getSourceValue() = v.asInstruction()
|
||||
or
|
||||
result = valueNumber(v.asPointerArithGuard()).getAnInstruction()
|
||||
}
|
||||
|
||||
SemType getSsaVariableType(SsaVariable v) {
|
||||
result = getSemanticType(v.asInstruction().getResultIRType())
|
||||
@@ -208,7 +235,9 @@ module SemanticExprConfig {
|
||||
|
||||
final override predicate hasRead(SsaVariable v) {
|
||||
exists(IR::Operand operand |
|
||||
operand.getDef() = v.asInstruction() and
|
||||
operand.getDef() = v.asInstruction() or
|
||||
operand.getDef() = valueNumber(v.asPointerArithGuard()).getAnInstruction()
|
||||
|
|
||||
not operand instanceof IR::PhiInputOperand and
|
||||
operand.getUse().getBlock() = block
|
||||
)
|
||||
@@ -227,7 +256,9 @@ module SemanticExprConfig {
|
||||
|
||||
final override predicate hasRead(SsaVariable v) {
|
||||
exists(IR::PhiInputOperand operand |
|
||||
operand.getDef() = v.asInstruction() and
|
||||
operand.getDef() = v.asInstruction() or
|
||||
operand.getDef() = valueNumber(v.asPointerArithGuard()).getAnInstruction()
|
||||
|
|
||||
operand.getPredecessorBlock() = pred and
|
||||
operand.getUse().getBlock() = succ
|
||||
)
|
||||
|
||||
@@ -10,7 +10,7 @@ class SemSsaVariable instanceof Specific::SsaVariable {
|
||||
|
||||
final Specific::Location getLocation() { result = super.getLocation() }
|
||||
|
||||
final SemLoadExpr getAUse() { result = Specific::getAUse(this) }
|
||||
final SemExpr getAUse() { result = Specific::getAUse(this) }
|
||||
|
||||
final SemType getType() { result = Specific::getSsaVariableType(this) }
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 0.4.0-dev
|
||||
version: 0.4.2-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -6,7 +6,7 @@ import cpp
|
||||
* A function that concatenates the string from its second argument
|
||||
* to the string from its first argument, for example `strcat`.
|
||||
*/
|
||||
class StrcatFunction extends Function {
|
||||
deprecated class StrcatFunction extends Function {
|
||||
StrcatFunction() {
|
||||
getName() =
|
||||
[
|
||||
|
||||
@@ -4,10 +4,7 @@
|
||||
* _sink_.
|
||||
*
|
||||
* Unless configured otherwise, _flow_ means that the exact value of
|
||||
* the source may reach the sink. We do not track flow across pointer
|
||||
* dereferences or array indexing. To track these types of flow, where the
|
||||
* exact value may not be preserved, import
|
||||
* `semmle.code.cpp.dataflow.TaintTracking`.
|
||||
* the source may reach the sink.
|
||||
*
|
||||
* To use global (interprocedural) data flow, extend the class
|
||||
* `DataFlow::Configuration` as documented on that class. To use local
|
||||
@@ -17,8 +14,4 @@
|
||||
* `DataFlow::Node`.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
module DataFlow {
|
||||
import semmle.code.cpp.dataflow.internal.DataFlowImpl
|
||||
}
|
||||
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
|
||||
@@ -9,8 +9,4 @@
|
||||
* See `semmle.code.cpp.dataflow.DataFlow` for the full documentation.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
module DataFlow2 {
|
||||
import semmle.code.cpp.dataflow.internal.DataFlowImpl2
|
||||
}
|
||||
import semmle.code.cpp.ir.dataflow.DataFlow2
|
||||
|
||||
@@ -9,8 +9,4 @@
|
||||
* See `semmle.code.cpp.dataflow.DataFlow` for the full documentation.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
module DataFlow3 {
|
||||
import semmle.code.cpp.dataflow.internal.DataFlowImpl3
|
||||
}
|
||||
import semmle.code.cpp.ir.dataflow.DataFlow3
|
||||
|
||||
@@ -9,8 +9,4 @@
|
||||
* See `semmle.code.cpp.dataflow.DataFlow` for the full documentation.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
module DataFlow4 {
|
||||
import semmle.code.cpp.dataflow.internal.DataFlowImpl4
|
||||
}
|
||||
import semmle.code.cpp.ir.dataflow.DataFlow4
|
||||
|
||||
@@ -95,6 +95,11 @@ predicate stackPointerFlowsToUse(Expr use, Type useType, Expr source, boolean is
|
||||
cached
|
||||
private PointerType getExprPtrType(Expr use) { result = use.getUnspecifiedType() }
|
||||
|
||||
/**
|
||||
* Holds if `use` has type `useType` and `source` is an access to a stack variable
|
||||
* that flows to `use`. `isLocal` is `true` if `use` is accessed via a parameter, and
|
||||
* `false` otherwise.
|
||||
*/
|
||||
predicate stackReferenceFlowsToUse(Expr use, Type useType, Expr source, boolean isLocal) {
|
||||
// Stack variables
|
||||
exists(StackVariable var |
|
||||
|
||||
@@ -15,9 +15,4 @@
|
||||
* `TaintTracking::localTaintStep` with arguments of type `DataFlow::Node`.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.dataflow.DataFlow
|
||||
import semmle.code.cpp.dataflow.DataFlow2
|
||||
|
||||
module TaintTracking {
|
||||
import semmle.code.cpp.dataflow.internal.tainttracking1.TaintTrackingImpl
|
||||
}
|
||||
import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||
|
||||
@@ -10,6 +10,5 @@
|
||||
*
|
||||
* See `semmle.code.cpp.dataflow.TaintTracking` for the full documentation.
|
||||
*/
|
||||
module TaintTracking2 {
|
||||
import semmle.code.cpp.dataflow.internal.tainttracking2.TaintTrackingImpl
|
||||
}
|
||||
|
||||
import semmle.code.cpp.ir.dataflow.TaintTracking2
|
||||
|
||||
14
cpp/ql/lib/semmle/code/cpp/dataflow/TaintTracking3.qll
Normal file
14
cpp/ql/lib/semmle/code/cpp/dataflow/TaintTracking3.qll
Normal file
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Provides a `TaintTracking3` module, which is a copy of the `TaintTracking`
|
||||
* module. Use this class when data-flow configurations or taint-tracking
|
||||
* configurations must depend on each other. Two classes extending
|
||||
* `DataFlow::Configuration` should never depend on each other, but one of them
|
||||
* should instead depend on a `DataFlow2::Configuration`, a
|
||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`. The
|
||||
* `TaintTracking::Configuration` class extends `DataFlow::Configuration`, and
|
||||
* `TaintTracking2::Configuration` extends `DataFlow2::Configuration`.
|
||||
*
|
||||
* See `semmle.code.cpp.dataflow.TaintTracking` for the full documentation.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.ir.dataflow.TaintTracking3
|
||||
@@ -1,5 +0,0 @@
|
||||
import semmle.code.cpp.dataflow.internal.TaintTrackingUtil as Public
|
||||
|
||||
module Private {
|
||||
import semmle.code.cpp.dataflow.DataFlow::DataFlow as DataFlow
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import semmle.code.cpp.dataflow.internal.TaintTrackingUtil as Public
|
||||
|
||||
module Private {
|
||||
import semmle.code.cpp.dataflow.DataFlow2::DataFlow2 as DataFlow
|
||||
}
|
||||
25
cpp/ql/lib/semmle/code/cpp/dataflow/old/DataFlow.qll
Normal file
25
cpp/ql/lib/semmle/code/cpp/dataflow/old/DataFlow.qll
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Provides a library for local (intra-procedural) and global (inter-procedural)
|
||||
* data flow analysis: deciding whether data can flow from a _source_ to a
|
||||
* _sink_.
|
||||
*
|
||||
* Unless configured otherwise, _flow_ means that the exact value of
|
||||
* the source may reach the sink.
|
||||
*
|
||||
* To use global (interprocedural) data flow, extend the class
|
||||
* `DataFlow::Configuration` as documented on that class. To use local
|
||||
* (intraprocedural) data flow between expressions, call
|
||||
* `DataFlow::localExprFlow`. For more general cases of local data flow, call
|
||||
* `DataFlow::localFlow` or `DataFlow::localFlowStep` with arguments of type
|
||||
* `DataFlow::Node`.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* Provides classes for performing local (intra-procedural) and
|
||||
* global (inter-procedural) data flow analyses.
|
||||
*/
|
||||
module DataFlow {
|
||||
import semmle.code.cpp.dataflow.old.internal.DataFlowImpl
|
||||
}
|
||||
20
cpp/ql/lib/semmle/code/cpp/dataflow/old/DataFlow2.qll
Normal file
20
cpp/ql/lib/semmle/code/cpp/dataflow/old/DataFlow2.qll
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Provides a `DataFlow2` module, which is a copy of the `DataFlow` module. Use
|
||||
* this class when data-flow configurations must depend on each other. Two
|
||||
* classes extending `DataFlow::Configuration` should never depend on each
|
||||
* other, but one of them should instead depend on a
|
||||
* `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a
|
||||
* `DataFlow4::Configuration`.
|
||||
*
|
||||
* See `semmle.code.cpp.ir.dataflow.DataFlow` for the full documentation.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* Provides classes for performing local (intra-procedural) and
|
||||
* global (inter-procedural) data flow analyses.
|
||||
*/
|
||||
module DataFlow {
|
||||
import semmle.code.cpp.dataflow.old.internal.DataFlowImpl2
|
||||
}
|
||||
20
cpp/ql/lib/semmle/code/cpp/dataflow/old/DataFlow3.qll
Normal file
20
cpp/ql/lib/semmle/code/cpp/dataflow/old/DataFlow3.qll
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Provides a `DataFlow3` module, which is a copy of the `DataFlow` module. Use
|
||||
* this class when data-flow configurations must depend on each other. Two
|
||||
* classes extending `DataFlow::Configuration` should never depend on each
|
||||
* other, but one of them should instead depend on a
|
||||
* `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a
|
||||
* `DataFlow4::Configuration`.
|
||||
*
|
||||
* See `semmle.code.cpp.ir.dataflow.DataFlow` for the full documentation.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* Provides classes for performing local (intra-procedural) and
|
||||
* global (inter-procedural) data flow analyses.
|
||||
*/
|
||||
module DataFlow {
|
||||
import semmle.code.cpp.dataflow.old.internal.DataFlowImpl3
|
||||
}
|
||||
20
cpp/ql/lib/semmle/code/cpp/dataflow/old/DataFlow4.qll
Normal file
20
cpp/ql/lib/semmle/code/cpp/dataflow/old/DataFlow4.qll
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Provides a `DataFlow4` module, which is a copy of the `DataFlow` module. Use
|
||||
* this class when data-flow configurations must depend on each other. Two
|
||||
* classes extending `DataFlow::Configuration` should never depend on each
|
||||
* other, but one of them should instead depend on a
|
||||
* `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a
|
||||
* `DataFlow4::Configuration`.
|
||||
*
|
||||
* See `semmle.code.cpp.ir.dataflow.DataFlow` for the full documentation.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* Provides classes for performing local (intra-procedural) and
|
||||
* global (inter-procedural) data flow analyses.
|
||||
*/
|
||||
module DataFlow {
|
||||
import semmle.code.cpp.dataflow.old.internal.DataFlowImpl4
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* DEPRECATED: Recursion through `DataFlow::Configuration` is impossible in
|
||||
* any supported tooling. There is no need for this module because it's
|
||||
* impossible to accidentally depend on recursion through
|
||||
* `DataFlow::Configuration` in current releases.
|
||||
*
|
||||
* When this module is imported, recursive use of `DataFlow::Configuration` is
|
||||
* disallowed. Importing this module will guarantee the absence of such
|
||||
* recursion, which is unsupported and will be unconditionally disallowed in a
|
||||
* future release.
|
||||
*
|
||||
* Recursive use of `DataFlow{2..4}::Configuration` is always disallowed, so no
|
||||
* import is needed for those.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
private import semmle.code.cpp.dataflow.DataFlow
|
||||
|
||||
/**
|
||||
* This class exists to prevent mutual recursion between the user-overridden
|
||||
* member predicates of `Configuration` and the rest of the data-flow library.
|
||||
* Good performance cannot be guaranteed in the presence of such recursion, so
|
||||
* it should be replaced by using more than one copy of the data flow library.
|
||||
* Four copies are available: `DataFlow` through `DataFlow4`.
|
||||
*/
|
||||
abstract private class ConfigurationRecursionPrevention extends DataFlow::Configuration {
|
||||
bindingset[this]
|
||||
ConfigurationRecursionPrevention() { any() }
|
||||
|
||||
override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) {
|
||||
strictcount(DataFlow::Node n | this.isSource(n)) < 0
|
||||
or
|
||||
strictcount(DataFlow::Node n | this.isSink(n)) < 0
|
||||
or
|
||||
strictcount(DataFlow::Node n1, DataFlow::Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
|
||||
or
|
||||
super.hasFlow(source, sink)
|
||||
}
|
||||
}
|
||||
18
cpp/ql/lib/semmle/code/cpp/dataflow/old/TaintTracking.qll
Normal file
18
cpp/ql/lib/semmle/code/cpp/dataflow/old/TaintTracking.qll
Normal file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Provides classes for performing local (intra-procedural) and
|
||||
* global (inter-procedural) taint-tracking analyses.
|
||||
*
|
||||
* We define _taint propagation_ informally to mean that a substantial part of
|
||||
* the information from the source is preserved at the sink. For example, taint
|
||||
* propagates from `x` to `x + 100`, but it does not propagate from `x` to `x >
|
||||
* 100` since we consider a single bit of information to be too little.
|
||||
*
|
||||
* To use global (interprocedural) taint tracking, extend the class
|
||||
* `TaintTracking::Configuration` as documented on that class. To use local
|
||||
* (intraprocedural) taint tracking between expressions, call
|
||||
* `TaintTracking::localExprTaint`. For more general cases of local taint
|
||||
* tracking, call `TaintTracking::localTaint` or
|
||||
* `TaintTracking::localTaintStep` with arguments of type `DataFlow::Node`.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||
14
cpp/ql/lib/semmle/code/cpp/dataflow/old/TaintTracking2.qll
Normal file
14
cpp/ql/lib/semmle/code/cpp/dataflow/old/TaintTracking2.qll
Normal file
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Provides a `TaintTracking2` module, which is a copy of the `TaintTracking`
|
||||
* module. Use this class when data-flow configurations or taint-tracking
|
||||
* configurations must depend on each other. Two classes extending
|
||||
* `DataFlow::Configuration` should never depend on each other, but one of them
|
||||
* should instead depend on a `DataFlow2::Configuration`, a
|
||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`. The
|
||||
* `TaintTracking::Configuration` class extends `DataFlow::Configuration`, and
|
||||
* `TaintTracking2::Configuration` extends `DataFlow2::Configuration`.
|
||||
*
|
||||
* See `semmle.code.cpp.ir.dataflow.TaintTracking` for the full documentation.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.ir.dataflow.TaintTracking2
|
||||
14
cpp/ql/lib/semmle/code/cpp/dataflow/old/TaintTracking3.qll
Normal file
14
cpp/ql/lib/semmle/code/cpp/dataflow/old/TaintTracking3.qll
Normal file
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Provides a `TaintTracking3` module, which is a copy of the `TaintTracking`
|
||||
* module. Use this class when data-flow configurations or taint-tracking
|
||||
* configurations must depend on each other. Two classes extending
|
||||
* `DataFlow::Configuration` should never depend on each other, but one of them
|
||||
* should instead depend on a `DataFlow2::Configuration`, a
|
||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`. The
|
||||
* `TaintTracking::Configuration` class extends `DataFlow::Configuration`, and
|
||||
* `TaintTracking2::Configuration` extends `DataFlow2::Configuration`.
|
||||
*
|
||||
* See `semmle.code.cpp.ir.dataflow.TaintTracking` for the full documentation.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.ir.dataflow.TaintTracking3
|
||||
@@ -1,6 +1,6 @@
|
||||
private import cpp
|
||||
private import semmle.code.cpp.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.cpp.dataflow.internal.DataFlowUtil
|
||||
private import DataFlowPrivate
|
||||
private import DataFlowUtil
|
||||
|
||||
/**
|
||||
* Gets a function that might be called by `call`.
|
||||
@@ -163,7 +163,9 @@ abstract class Configuration extends string {
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
|
||||
predicate hasFlowTo(Node sink) {
|
||||
sink = any(PathNodeSink n | this = n.getConfiguration()).getNodeEx().asNode()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -558,13 +560,16 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
hasReadStep(tc.getContent(), config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
|
||||
@@ -598,13 +603,9 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class ApApprox = Unit;
|
||||
|
||||
class Ap = Unit;
|
||||
|
||||
class ApOption = Unit;
|
||||
|
||||
class Cc = boolean;
|
||||
private class Cc = boolean;
|
||||
|
||||
/* Begin: Stage 1 logic. */
|
||||
/**
|
||||
@@ -613,7 +614,7 @@ private module Stage1 implements StageSig {
|
||||
* The Boolean `cc` records whether the node is reached through an
|
||||
* argument in a call.
|
||||
*/
|
||||
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
sourceNode(node, _, config) and
|
||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||
or
|
||||
@@ -753,7 +754,7 @@ private module Stage1 implements StageSig {
|
||||
* the enclosing callable in order to reach a sink.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
revFlow0(node, toReturn, config) and
|
||||
fwdFlow(node, config)
|
||||
}
|
||||
@@ -837,13 +838,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -859,7 +860,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -906,7 +907,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -998,7 +999,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1259,7 +1260,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1483,7 +1484,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(
|
||||
additional predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1661,7 +1662,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1674,11 +1675,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1699,7 +1702,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1741,7 +1744,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -2926,12 +2929,17 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
pragma[nomagic]
|
||||
private PathNodeImpl getANonHiddenSuccessor0() {
|
||||
result = this.getASuccessorIfHidden*() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getANonHiddenSuccessor0() and
|
||||
not this.isHidden()
|
||||
}
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
@@ -163,7 +163,9 @@ abstract class Configuration extends string {
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
|
||||
predicate hasFlowTo(Node sink) {
|
||||
sink = any(PathNodeSink n | this = n.getConfiguration()).getNodeEx().asNode()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -558,13 +560,16 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
hasReadStep(tc.getContent(), config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
|
||||
@@ -598,13 +603,9 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class ApApprox = Unit;
|
||||
|
||||
class Ap = Unit;
|
||||
|
||||
class ApOption = Unit;
|
||||
|
||||
class Cc = boolean;
|
||||
private class Cc = boolean;
|
||||
|
||||
/* Begin: Stage 1 logic. */
|
||||
/**
|
||||
@@ -613,7 +614,7 @@ private module Stage1 implements StageSig {
|
||||
* The Boolean `cc` records whether the node is reached through an
|
||||
* argument in a call.
|
||||
*/
|
||||
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
sourceNode(node, _, config) and
|
||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||
or
|
||||
@@ -753,7 +754,7 @@ private module Stage1 implements StageSig {
|
||||
* the enclosing callable in order to reach a sink.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
revFlow0(node, toReturn, config) and
|
||||
fwdFlow(node, config)
|
||||
}
|
||||
@@ -837,13 +838,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -859,7 +860,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -906,7 +907,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -998,7 +999,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1259,7 +1260,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1483,7 +1484,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(
|
||||
additional predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1661,7 +1662,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1674,11 +1675,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1699,7 +1702,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1741,7 +1744,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -2926,12 +2929,17 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
pragma[nomagic]
|
||||
private PathNodeImpl getANonHiddenSuccessor0() {
|
||||
result = this.getASuccessorIfHidden*() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getANonHiddenSuccessor0() and
|
||||
not this.isHidden()
|
||||
}
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
@@ -163,7 +163,9 @@ abstract class Configuration extends string {
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
|
||||
predicate hasFlowTo(Node sink) {
|
||||
sink = any(PathNodeSink n | this = n.getConfiguration()).getNodeEx().asNode()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -558,13 +560,16 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
hasReadStep(tc.getContent(), config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
|
||||
@@ -598,13 +603,9 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class ApApprox = Unit;
|
||||
|
||||
class Ap = Unit;
|
||||
|
||||
class ApOption = Unit;
|
||||
|
||||
class Cc = boolean;
|
||||
private class Cc = boolean;
|
||||
|
||||
/* Begin: Stage 1 logic. */
|
||||
/**
|
||||
@@ -613,7 +614,7 @@ private module Stage1 implements StageSig {
|
||||
* The Boolean `cc` records whether the node is reached through an
|
||||
* argument in a call.
|
||||
*/
|
||||
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
sourceNode(node, _, config) and
|
||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||
or
|
||||
@@ -753,7 +754,7 @@ private module Stage1 implements StageSig {
|
||||
* the enclosing callable in order to reach a sink.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
revFlow0(node, toReturn, config) and
|
||||
fwdFlow(node, config)
|
||||
}
|
||||
@@ -837,13 +838,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -859,7 +860,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -906,7 +907,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -998,7 +999,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1259,7 +1260,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1483,7 +1484,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(
|
||||
additional predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1661,7 +1662,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1674,11 +1675,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1699,7 +1702,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1741,7 +1744,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -2926,12 +2929,17 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
pragma[nomagic]
|
||||
private PathNodeImpl getANonHiddenSuccessor0() {
|
||||
result = this.getASuccessorIfHidden*() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getANonHiddenSuccessor0() and
|
||||
not this.isHidden()
|
||||
}
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
@@ -163,7 +163,9 @@ abstract class Configuration extends string {
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
|
||||
predicate hasFlowTo(Node sink) {
|
||||
sink = any(PathNodeSink n | this = n.getConfiguration()).getNodeEx().asNode()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -558,13 +560,16 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
hasReadStep(tc.getContent(), config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
|
||||
@@ -598,13 +603,9 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class ApApprox = Unit;
|
||||
|
||||
class Ap = Unit;
|
||||
|
||||
class ApOption = Unit;
|
||||
|
||||
class Cc = boolean;
|
||||
private class Cc = boolean;
|
||||
|
||||
/* Begin: Stage 1 logic. */
|
||||
/**
|
||||
@@ -613,7 +614,7 @@ private module Stage1 implements StageSig {
|
||||
* The Boolean `cc` records whether the node is reached through an
|
||||
* argument in a call.
|
||||
*/
|
||||
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
sourceNode(node, _, config) and
|
||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||
or
|
||||
@@ -753,7 +754,7 @@ private module Stage1 implements StageSig {
|
||||
* the enclosing callable in order to reach a sink.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
revFlow0(node, toReturn, config) and
|
||||
fwdFlow(node, config)
|
||||
}
|
||||
@@ -837,13 +838,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -859,7 +860,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -906,7 +907,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -998,7 +999,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1259,7 +1260,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1483,7 +1484,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(
|
||||
additional predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1661,7 +1662,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1674,11 +1675,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1699,7 +1702,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1741,7 +1744,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -2926,12 +2929,17 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
pragma[nomagic]
|
||||
private PathNodeImpl getANonHiddenSuccessor0() {
|
||||
result = this.getASuccessorIfHidden*() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getANonHiddenSuccessor0() and
|
||||
not this.isHidden()
|
||||
}
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
@@ -163,7 +163,9 @@ abstract class Configuration extends string {
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
|
||||
predicate hasFlowTo(Node sink) {
|
||||
sink = any(PathNodeSink n | this = n.getConfiguration()).getNodeEx().asNode()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -558,13 +560,16 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
hasReadStep(tc.getContent(), config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
|
||||
@@ -598,13 +603,9 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class ApApprox = Unit;
|
||||
|
||||
class Ap = Unit;
|
||||
|
||||
class ApOption = Unit;
|
||||
|
||||
class Cc = boolean;
|
||||
private class Cc = boolean;
|
||||
|
||||
/* Begin: Stage 1 logic. */
|
||||
/**
|
||||
@@ -613,7 +614,7 @@ private module Stage1 implements StageSig {
|
||||
* The Boolean `cc` records whether the node is reached through an
|
||||
* argument in a call.
|
||||
*/
|
||||
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
sourceNode(node, _, config) and
|
||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||
or
|
||||
@@ -753,7 +754,7 @@ private module Stage1 implements StageSig {
|
||||
* the enclosing callable in order to reach a sink.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
revFlow0(node, toReturn, config) and
|
||||
fwdFlow(node, config)
|
||||
}
|
||||
@@ -837,13 +838,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -859,7 +860,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -906,7 +907,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -998,7 +999,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1259,7 +1260,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1483,7 +1484,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(
|
||||
additional predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1661,7 +1662,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1674,11 +1675,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1699,7 +1702,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1741,7 +1744,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -2926,12 +2929,17 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
pragma[nomagic]
|
||||
private PathNodeImpl getANonHiddenSuccessor0() {
|
||||
result = this.getASuccessorIfHidden*() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getANonHiddenSuccessor0() and
|
||||
not this.isHidden()
|
||||
}
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
@@ -3,10 +3,10 @@
|
||||
*/
|
||||
|
||||
private import cpp
|
||||
private import semmle.code.cpp.dataflow.internal.FlowVar
|
||||
private import FlowVar
|
||||
private import semmle.code.cpp.models.interfaces.DataFlow
|
||||
private import semmle.code.cpp.controlflow.Guards
|
||||
private import semmle.code.cpp.dataflow.internal.AddressFlow
|
||||
private import AddressFlow
|
||||
|
||||
cached
|
||||
private newtype TNode =
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
import cpp
|
||||
private import semmle.code.cpp.controlflow.SSA
|
||||
private import semmle.code.cpp.dataflow.internal.SubBasicBlocks
|
||||
private import semmle.code.cpp.dataflow.internal.AddressFlow
|
||||
private import SubBasicBlocks
|
||||
private import AddressFlow
|
||||
private import semmle.code.cpp.models.implementations.Iterator
|
||||
private import semmle.code.cpp.models.interfaces.PointerWrapper
|
||||
|
||||
@@ -14,7 +14,7 @@ private import semmle.code.cpp.models.interfaces.Iterator
|
||||
private import semmle.code.cpp.models.interfaces.PointerWrapper
|
||||
|
||||
private module DataFlow {
|
||||
import semmle.code.cpp.dataflow.internal.DataFlowUtil
|
||||
import DataFlowUtil
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -0,0 +1,5 @@
|
||||
import semmle.code.cpp.dataflow.old.internal.TaintTrackingUtil as Public
|
||||
|
||||
module Private {
|
||||
import semmle.code.cpp.dataflow.old.DataFlow::DataFlow as DataFlow
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import semmle.code.cpp.dataflow.old.internal.TaintTrackingUtil as Public
|
||||
|
||||
module Private {
|
||||
import semmle.code.cpp.dataflow.old.DataFlow2::DataFlow as DataFlow
|
||||
}
|
||||
@@ -282,7 +282,7 @@ private module Cached {
|
||||
cached
|
||||
predicate additionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) {
|
||||
exists(CallInstruction call, Function func, FunctionInput modelIn, FunctionOutput modelOut |
|
||||
n1.asOperand() = callInput(call, modelIn) and
|
||||
n1 = callInput(call, modelIn) and
|
||||
(
|
||||
func.(TaintFunction).hasTaintFlow(modelIn, modelOut)
|
||||
or
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import DataFlowPrivate
|
||||
private import DataFlowUtil
|
||||
private import DataFlowImplCommon as DataFlowImplCommon
|
||||
|
||||
/**
|
||||
|
||||
@@ -163,7 +163,9 @@ abstract class Configuration extends string {
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
|
||||
predicate hasFlowTo(Node sink) {
|
||||
sink = any(PathNodeSink n | this = n.getConfiguration()).getNodeEx().asNode()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -558,13 +560,16 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
hasReadStep(tc.getContent(), config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
|
||||
@@ -598,13 +603,9 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class ApApprox = Unit;
|
||||
|
||||
class Ap = Unit;
|
||||
|
||||
class ApOption = Unit;
|
||||
|
||||
class Cc = boolean;
|
||||
private class Cc = boolean;
|
||||
|
||||
/* Begin: Stage 1 logic. */
|
||||
/**
|
||||
@@ -613,7 +614,7 @@ private module Stage1 implements StageSig {
|
||||
* The Boolean `cc` records whether the node is reached through an
|
||||
* argument in a call.
|
||||
*/
|
||||
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
sourceNode(node, _, config) and
|
||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||
or
|
||||
@@ -753,7 +754,7 @@ private module Stage1 implements StageSig {
|
||||
* the enclosing callable in order to reach a sink.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
revFlow0(node, toReturn, config) and
|
||||
fwdFlow(node, config)
|
||||
}
|
||||
@@ -837,13 +838,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -859,7 +860,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -906,7 +907,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -998,7 +999,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1259,7 +1260,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1483,7 +1484,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(
|
||||
additional predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1661,7 +1662,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1674,11 +1675,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1699,7 +1702,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1741,7 +1744,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -2926,12 +2929,17 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
pragma[nomagic]
|
||||
private PathNodeImpl getANonHiddenSuccessor0() {
|
||||
result = this.getASuccessorIfHidden*() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getANonHiddenSuccessor0() and
|
||||
not this.isHidden()
|
||||
}
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
|
||||
@@ -163,7 +163,9 @@ abstract class Configuration extends string {
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
|
||||
predicate hasFlowTo(Node sink) {
|
||||
sink = any(PathNodeSink n | this = n.getConfiguration()).getNodeEx().asNode()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -558,13 +560,16 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
hasReadStep(tc.getContent(), config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
|
||||
@@ -598,13 +603,9 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class ApApprox = Unit;
|
||||
|
||||
class Ap = Unit;
|
||||
|
||||
class ApOption = Unit;
|
||||
|
||||
class Cc = boolean;
|
||||
private class Cc = boolean;
|
||||
|
||||
/* Begin: Stage 1 logic. */
|
||||
/**
|
||||
@@ -613,7 +614,7 @@ private module Stage1 implements StageSig {
|
||||
* The Boolean `cc` records whether the node is reached through an
|
||||
* argument in a call.
|
||||
*/
|
||||
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
sourceNode(node, _, config) and
|
||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||
or
|
||||
@@ -753,7 +754,7 @@ private module Stage1 implements StageSig {
|
||||
* the enclosing callable in order to reach a sink.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
revFlow0(node, toReturn, config) and
|
||||
fwdFlow(node, config)
|
||||
}
|
||||
@@ -837,13 +838,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -859,7 +860,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -906,7 +907,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -998,7 +999,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1259,7 +1260,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1483,7 +1484,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(
|
||||
additional predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1661,7 +1662,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1674,11 +1675,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1699,7 +1702,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1741,7 +1744,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -2926,12 +2929,17 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
pragma[nomagic]
|
||||
private PathNodeImpl getANonHiddenSuccessor0() {
|
||||
result = this.getASuccessorIfHidden*() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getANonHiddenSuccessor0() and
|
||||
not this.isHidden()
|
||||
}
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
|
||||
@@ -163,7 +163,9 @@ abstract class Configuration extends string {
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
|
||||
predicate hasFlowTo(Node sink) {
|
||||
sink = any(PathNodeSink n | this = n.getConfiguration()).getNodeEx().asNode()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -558,13 +560,16 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
hasReadStep(tc.getContent(), config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
|
||||
@@ -598,13 +603,9 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class ApApprox = Unit;
|
||||
|
||||
class Ap = Unit;
|
||||
|
||||
class ApOption = Unit;
|
||||
|
||||
class Cc = boolean;
|
||||
private class Cc = boolean;
|
||||
|
||||
/* Begin: Stage 1 logic. */
|
||||
/**
|
||||
@@ -613,7 +614,7 @@ private module Stage1 implements StageSig {
|
||||
* The Boolean `cc` records whether the node is reached through an
|
||||
* argument in a call.
|
||||
*/
|
||||
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
sourceNode(node, _, config) and
|
||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||
or
|
||||
@@ -753,7 +754,7 @@ private module Stage1 implements StageSig {
|
||||
* the enclosing callable in order to reach a sink.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
revFlow0(node, toReturn, config) and
|
||||
fwdFlow(node, config)
|
||||
}
|
||||
@@ -837,13 +838,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -859,7 +860,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -906,7 +907,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -998,7 +999,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1259,7 +1260,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1483,7 +1484,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(
|
||||
additional predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1661,7 +1662,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1674,11 +1675,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1699,7 +1702,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1741,7 +1744,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -2926,12 +2929,17 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
pragma[nomagic]
|
||||
private PathNodeImpl getANonHiddenSuccessor0() {
|
||||
result = this.getASuccessorIfHidden*() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getANonHiddenSuccessor0() and
|
||||
not this.isHidden()
|
||||
}
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
|
||||
@@ -163,7 +163,9 @@ abstract class Configuration extends string {
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { this.hasFlow(_, sink) }
|
||||
predicate hasFlowTo(Node sink) {
|
||||
sink = any(PathNodeSink n | this = n.getConfiguration()).getNodeEx().asNode()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -558,13 +560,16 @@ private predicate expectsContentEx(NodeEx n, Content c) {
|
||||
pragma[nomagic]
|
||||
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate hasReadStep(Content c, Configuration config) { read(_, c, _, config) }
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate store(
|
||||
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
|
||||
) {
|
||||
store(pragma[only_bind_into](node1.asNode()), tc, pragma[only_bind_into](node2.asNode()),
|
||||
contentType) and
|
||||
read(_, tc.getContent(), _, config) and
|
||||
hasReadStep(tc.getContent(), config) and
|
||||
stepFilter(node1, node2, config)
|
||||
}
|
||||
|
||||
@@ -598,13 +603,9 @@ private predicate hasSinkCallCtx(Configuration config) {
|
||||
}
|
||||
|
||||
private module Stage1 implements StageSig {
|
||||
class ApApprox = Unit;
|
||||
|
||||
class Ap = Unit;
|
||||
|
||||
class ApOption = Unit;
|
||||
|
||||
class Cc = boolean;
|
||||
private class Cc = boolean;
|
||||
|
||||
/* Begin: Stage 1 logic. */
|
||||
/**
|
||||
@@ -613,7 +614,7 @@ private module Stage1 implements StageSig {
|
||||
* The Boolean `cc` records whether the node is reached through an
|
||||
* argument in a call.
|
||||
*/
|
||||
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
private predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
|
||||
sourceNode(node, _, config) and
|
||||
if hasSourceCallCtx(config) then cc = true else cc = false
|
||||
or
|
||||
@@ -753,7 +754,7 @@ private module Stage1 implements StageSig {
|
||||
* the enclosing callable in order to reach a sink.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
private predicate revFlow(NodeEx node, boolean toReturn, Configuration config) {
|
||||
revFlow0(node, toReturn, config) and
|
||||
fwdFlow(node, config)
|
||||
}
|
||||
@@ -837,13 +838,13 @@ private module Stage1 implements StageSig {
|
||||
* by `revFlow`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
additional predicate revFlowIsReadAndStored(Content c, Configuration conf) {
|
||||
revFlowConsCand(c, conf) and
|
||||
revFlowStore(c, _, _, conf)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableReturnPosOutNodeCandFwd1(
|
||||
additional predicate viableReturnPosOutNodeCandFwd1(
|
||||
DataFlowCall call, ReturnPosition pos, NodeEx out, Configuration config
|
||||
) {
|
||||
fwdFlowReturnPosition(pos, _, config) and
|
||||
@@ -859,7 +860,7 @@ private module Stage1 implements StageSig {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate viableParamArgNodeCandFwd1(
|
||||
additional predicate viableParamArgNodeCandFwd1(
|
||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||
) {
|
||||
viableParamArgEx(call, p, arg) and
|
||||
@@ -906,7 +907,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlowState(FlowState state, Configuration config) {
|
||||
additional predicate revFlowState(FlowState state, Configuration config) {
|
||||
exists(NodeEx node |
|
||||
sinkNode(node, state, config) and
|
||||
revFlow(node, _, pragma[only_bind_into](config)) and
|
||||
@@ -998,7 +999,7 @@ private module Stage1 implements StageSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -1259,7 +1260,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* argument.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(
|
||||
additional predicate fwdFlow(
|
||||
NodeEx node, FlowState state, Cc cc, ApOption argAp, Ap ap, Configuration config
|
||||
) {
|
||||
fwdFlow0(node, state, cc, argAp, ap, config) and
|
||||
@@ -1483,7 +1484,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
* the access path of the returned value.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate revFlow(
|
||||
additional predicate revFlow(
|
||||
NodeEx node, FlowState state, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
|
||||
) {
|
||||
revFlow0(node, state, toReturn, returnAp, ap, config) and
|
||||
@@ -1661,7 +1662,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
additional predicate revFlow(NodeEx node, FlowState state, Configuration config) {
|
||||
revFlow(node, state, _, _, _, config)
|
||||
}
|
||||
|
||||
@@ -1674,11 +1675,13 @@ private module MkStage<StageSig PrevStage> {
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, Configuration config) { revFlow(node, _, _, _, _, config) }
|
||||
additional predicate revFlowAlias(NodeEx node, Configuration config) {
|
||||
revFlow(node, _, _, _, _, config)
|
||||
}
|
||||
|
||||
// use an alias as a workaround for bad functionality-induced joins
|
||||
pragma[nomagic]
|
||||
predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
additional predicate revFlowAlias(NodeEx node, FlowState state, Ap ap, Configuration config) {
|
||||
revFlow(node, state, ap, config)
|
||||
}
|
||||
|
||||
@@ -1699,7 +1702,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
additional predicate consCand(TypedContent tc, Ap ap, Configuration config) {
|
||||
revConsCand(tc, ap, config) and
|
||||
validAp(ap, config)
|
||||
}
|
||||
@@ -1741,7 +1744,7 @@ private module MkStage<StageSig PrevStage> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate stats(
|
||||
additional predicate stats(
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples, Configuration config
|
||||
) {
|
||||
fwd = true and
|
||||
@@ -2926,12 +2929,17 @@ abstract private class PathNodeImpl extends PathNode {
|
||||
result = this.getASuccessorImpl()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getASuccessorIfHidden*() and
|
||||
not this.isHidden() and
|
||||
pragma[nomagic]
|
||||
private PathNodeImpl getANonHiddenSuccessor0() {
|
||||
result = this.getASuccessorIfHidden*() and
|
||||
not result.isHidden()
|
||||
}
|
||||
|
||||
final PathNodeImpl getANonHiddenSuccessor() {
|
||||
result = this.getASuccessorImpl().getANonHiddenSuccessor0() and
|
||||
not this.isHidden()
|
||||
}
|
||||
|
||||
abstract NodeEx getNodeEx();
|
||||
|
||||
predicate isHidden() {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
private import cpp
|
||||
private import cpp as Cpp
|
||||
private import DataFlowUtil
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import DataFlowDispatch
|
||||
private import DataFlowImplConsistency
|
||||
private import semmle.code.cpp.ir.internal.IRCppLanguage
|
||||
private import SsaInternals as Ssa
|
||||
|
||||
/** Gets the callable in which this node occurs. */
|
||||
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() }
|
||||
@@ -22,7 +24,7 @@ predicate isArgumentNode(ArgumentNode arg, DataFlowCall c, ArgumentPosition pos)
|
||||
* to the callable. Instance arguments (`this` pointer) and read side effects
|
||||
* on parameters are also included.
|
||||
*/
|
||||
abstract class ArgumentNode extends OperandNode {
|
||||
abstract class ArgumentNode extends Node {
|
||||
/**
|
||||
* Holds if this argument occurs at the given position in the given call.
|
||||
* The instance argument is considered to have index `-1`.
|
||||
@@ -37,7 +39,7 @@ abstract class ArgumentNode extends OperandNode {
|
||||
* A data flow node that occurs as the argument to a call, or an
|
||||
* implicit `this` pointer argument.
|
||||
*/
|
||||
private class PrimaryArgumentNode extends ArgumentNode {
|
||||
private class PrimaryArgumentNode extends ArgumentNode, OperandNode {
|
||||
override ArgumentOperand op;
|
||||
|
||||
PrimaryArgumentNode() { exists(CallInstruction call | op = call.getAnArgumentOperand()) }
|
||||
@@ -46,49 +48,34 @@ private class PrimaryArgumentNode extends ArgumentNode {
|
||||
op = call.getArgumentOperand(pos.(DirectPosition).getIndex())
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
exists(Expr unconverted |
|
||||
unconverted = op.getDef().getUnconvertedResultExpression() and
|
||||
result = unconverted.toString()
|
||||
)
|
||||
or
|
||||
// Certain instructions don't map to an unconverted result expression. For these cases
|
||||
// we fall back to a simpler naming scheme. This can happen in IR-generated constructors.
|
||||
not exists(op.getDef().getUnconvertedResultExpression()) and
|
||||
(
|
||||
result = "Argument " + op.(PositionalArgumentOperand).getIndex()
|
||||
or
|
||||
op instanceof ThisArgumentOperand and result = "Argument this"
|
||||
)
|
||||
}
|
||||
override string toStringImpl() { result = argumentOperandToString(op) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node representing the read side effect of a call on a
|
||||
* specific parameter.
|
||||
*/
|
||||
private class SideEffectArgumentNode extends ArgumentNode {
|
||||
override SideEffectOperand op;
|
||||
ReadSideEffectInstruction read;
|
||||
private string argumentOperandToString(ArgumentOperand op) {
|
||||
exists(Expr unconverted |
|
||||
unconverted = op.getDef().getUnconvertedResultExpression() and
|
||||
result = unconverted.toString()
|
||||
)
|
||||
or
|
||||
// Certain instructions don't map to an unconverted result expression. For these cases
|
||||
// we fall back to a simpler naming scheme. This can happen in IR-generated constructors.
|
||||
not exists(op.getDef().getUnconvertedResultExpression()) and
|
||||
(
|
||||
result = "Argument " + op.(PositionalArgumentOperand).getIndex()
|
||||
or
|
||||
op instanceof ThisArgumentOperand and result = "Argument this"
|
||||
)
|
||||
}
|
||||
|
||||
SideEffectArgumentNode() { op = read.getSideEffectOperand() }
|
||||
|
||||
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
|
||||
read.getPrimaryInstruction() = call and
|
||||
pos.(IndirectionPosition).getIndex() = read.getIndex()
|
||||
private class SideEffectArgumentNode extends ArgumentNode, SideEffectOperandNode {
|
||||
override predicate argumentOf(DataFlowCall dfCall, ArgumentPosition pos) {
|
||||
this.getCallInstruction() = dfCall and
|
||||
pos.(IndirectionPosition).getArgumentIndex() = this.getArgumentIndex() and
|
||||
pos.(IndirectionPosition).getIndirectionIndex() = super.getIndirectionIndex()
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = read.getArgumentDef().getUnconvertedResultExpression().toString() + " indirection"
|
||||
or
|
||||
// Some instructions don't map to an unconverted result expression. For these cases
|
||||
// we fall back to a simpler naming scheme. This can happen in IR-generated constructors.
|
||||
not exists(read.getArgumentDef().getUnconvertedResultExpression()) and
|
||||
(
|
||||
if read.getIndex() = -1
|
||||
then result = "Argument this indirection"
|
||||
else result = "Argument " + read.getIndex() + " indirection"
|
||||
)
|
||||
override string toStringImpl() {
|
||||
result = argumentOperandToString(this.getAddressOperand()) + " indirection"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,47 +89,57 @@ class Position extends TPosition {
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
class DirectPosition extends TDirectPosition {
|
||||
class DirectPosition extends Position, TDirectPosition {
|
||||
int index;
|
||||
|
||||
DirectPosition() { this = TDirectPosition(index) }
|
||||
|
||||
string toString() {
|
||||
index = -1 and
|
||||
result = "this"
|
||||
or
|
||||
index != -1 and
|
||||
result = index.toString()
|
||||
}
|
||||
override string toString() { if index = -1 then result = "this" else result = index.toString() }
|
||||
|
||||
int getIndex() { result = index }
|
||||
}
|
||||
|
||||
class IndirectionPosition extends TIndirectionPosition {
|
||||
int index;
|
||||
class IndirectionPosition extends Position, TIndirectionPosition {
|
||||
int argumentIndex;
|
||||
int indirectionIndex;
|
||||
|
||||
IndirectionPosition() { this = TIndirectionPosition(index) }
|
||||
IndirectionPosition() { this = TIndirectionPosition(argumentIndex, indirectionIndex) }
|
||||
|
||||
string toString() {
|
||||
index = -1 and
|
||||
result = "this"
|
||||
or
|
||||
index != -1 and
|
||||
result = index.toString()
|
||||
override string toString() {
|
||||
if argumentIndex = -1
|
||||
then if indirectionIndex > 0 then result = "this indirection" else result = "this"
|
||||
else
|
||||
if indirectionIndex > 0
|
||||
then result = argumentIndex.toString() + " indirection"
|
||||
else result = argumentIndex.toString()
|
||||
}
|
||||
|
||||
int getIndex() { result = index }
|
||||
int getArgumentIndex() { result = argumentIndex }
|
||||
|
||||
int getIndirectionIndex() { result = indirectionIndex }
|
||||
}
|
||||
|
||||
newtype TPosition =
|
||||
TDirectPosition(int index) { exists(any(CallInstruction c).getArgument(index)) } or
|
||||
TIndirectionPosition(int index) {
|
||||
exists(ReadSideEffectInstruction instr | instr.getIndex() = index)
|
||||
TIndirectionPosition(int argumentIndex, int indirectionIndex) {
|
||||
hasOperandAndIndex(_, any(CallInstruction call).getArgumentOperand(argumentIndex),
|
||||
indirectionIndex)
|
||||
}
|
||||
|
||||
private newtype TReturnKind =
|
||||
TNormalReturnKind() or
|
||||
TIndirectReturnKind(ParameterIndex index)
|
||||
TNormalReturnKind(int index) {
|
||||
exists(IndirectReturnNode return |
|
||||
return.getAddressOperand() = any(ReturnValueInstruction r).getReturnAddressOperand() and
|
||||
index = return.getIndirectionIndex() - 1 // We subtract one because the return loads the value.
|
||||
)
|
||||
} or
|
||||
TIndirectReturnKind(int argumentIndex, int indirectionIndex) {
|
||||
exists(IndirectReturnNode return, ReturnIndirectionInstruction returnInd |
|
||||
returnInd.hasIndex(argumentIndex) and
|
||||
return.getAddressOperand() = returnInd.getSourceAddressOperand() and
|
||||
indirectionIndex = return.getIndirectionIndex()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A return kind. A return kind describes how a value can be returned
|
||||
@@ -154,53 +151,146 @@ class ReturnKind extends TReturnKind {
|
||||
}
|
||||
|
||||
private class NormalReturnKind extends ReturnKind, TNormalReturnKind {
|
||||
override string toString() { result = "return" }
|
||||
int index;
|
||||
|
||||
NormalReturnKind() { this = TNormalReturnKind(index) }
|
||||
|
||||
override string toString() { result = "indirect return" }
|
||||
}
|
||||
|
||||
private class IndirectReturnKind extends ReturnKind, TIndirectReturnKind {
|
||||
ParameterIndex index;
|
||||
int argumentIndex;
|
||||
int indirectionIndex;
|
||||
|
||||
IndirectReturnKind() { this = TIndirectReturnKind(index) }
|
||||
IndirectReturnKind() { this = TIndirectReturnKind(argumentIndex, indirectionIndex) }
|
||||
|
||||
override string toString() { result = "outparam[" + index.toString() + "]" }
|
||||
override string toString() { result = "indirect outparam[" + argumentIndex.toString() + "]" }
|
||||
}
|
||||
|
||||
/** A data flow node that occurs as the result of a `ReturnStmt`. */
|
||||
class ReturnNode extends InstructionNode {
|
||||
Instruction primary;
|
||||
|
||||
ReturnNode() {
|
||||
exists(ReturnValueInstruction ret | instr = ret and primary = ret)
|
||||
or
|
||||
exists(ReturnIndirectionInstruction rii | instr = rii and primary = rii)
|
||||
}
|
||||
|
||||
class ReturnNode extends Node instanceof IndirectReturnNode {
|
||||
/** Gets the kind of this returned value. */
|
||||
abstract ReturnKind getKind();
|
||||
}
|
||||
|
||||
class ReturnValueNode extends ReturnNode {
|
||||
override ReturnValueInstruction primary;
|
||||
|
||||
override ReturnKind getKind() { result = TNormalReturnKind() }
|
||||
/**
|
||||
* This predicate represents an annoying hack that we have to do. We use the
|
||||
* `ReturnIndirectionInstruction` to determine which variables need flow back
|
||||
* out of a function. However, the IR will unconditionally create those for a
|
||||
* variable passed to a function even though the variable was never updated by
|
||||
* the function. And if a function has too many `ReturnNode`s the dataflow
|
||||
* library lowers its precision for that function by disabling field flow.
|
||||
*
|
||||
* So we those eliminate `ReturnNode`s that would have otherwise been created
|
||||
* by this unconditional `ReturnIndirectionInstruction` by requiring that there
|
||||
* must exist an SSA definition of the IR variable in the function.
|
||||
*/
|
||||
private predicate hasNonInitializeParameterDef(IRVariable v) {
|
||||
exists(Ssa::Def def |
|
||||
not def.getDefiningInstruction() instanceof InitializeParameterInstruction and
|
||||
v = def.getSourceVariable().getBaseVariable().(Ssa::BaseIRVariable).getIRVariable()
|
||||
)
|
||||
}
|
||||
|
||||
class ReturnIndirectionNode extends ReturnNode {
|
||||
override ReturnIndirectionInstruction primary;
|
||||
|
||||
class ReturnIndirectionNode extends IndirectReturnNode, ReturnNode {
|
||||
override ReturnKind getKind() {
|
||||
exists(int index |
|
||||
primary.hasIndex(index) and
|
||||
result = TIndirectReturnKind(index)
|
||||
exists(int argumentIndex, ReturnIndirectionInstruction returnInd |
|
||||
returnInd.hasIndex(argumentIndex) and
|
||||
this.getAddressOperand() = returnInd.getSourceAddressOperand() and
|
||||
result = TIndirectReturnKind(argumentIndex, this.getIndirectionIndex()) and
|
||||
hasNonInitializeParameterDef(returnInd.getIRVariable())
|
||||
)
|
||||
or
|
||||
this.getAddressOperand() = any(ReturnValueInstruction r).getReturnAddressOperand() and
|
||||
result = TNormalReturnKind(this.getIndirectionIndex() - 1)
|
||||
}
|
||||
}
|
||||
|
||||
private Operand fullyConvertedCallStep(Operand op) {
|
||||
not exists(getANonConversionUse(op)) and
|
||||
exists(Instruction instr |
|
||||
conversionFlow(op, instr, _) and
|
||||
result = getAUse(instr)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instruction that uses this operand, if the instruction is not
|
||||
* ignored for dataflow purposes.
|
||||
*/
|
||||
private Instruction getUse(Operand op) {
|
||||
result = op.getUse() and
|
||||
not Ssa::ignoreOperand(op)
|
||||
}
|
||||
|
||||
/** Gets a use of the instruction `instr` that is not ignored for dataflow purposes. */
|
||||
Operand getAUse(Instruction instr) {
|
||||
result = instr.getAUse() and
|
||||
not Ssa::ignoreOperand(result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a use of `operand` that is:
|
||||
* - not ignored for dataflow purposes, and
|
||||
* - not a conversion-like instruction.
|
||||
*/
|
||||
private Instruction getANonConversionUse(Operand operand) {
|
||||
result = getUse(operand) and
|
||||
not conversionFlow(_, result, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the operand that represents the first use of the value of `call` following
|
||||
* a sequnce of conversion-like instructions.
|
||||
*/
|
||||
predicate operandForfullyConvertedCall(Operand operand, CallInstruction call) {
|
||||
exists(getANonConversionUse(operand)) and
|
||||
(
|
||||
operand = getAUse(call)
|
||||
or
|
||||
operand = fullyConvertedCallStep*(getAUse(call))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instruction that represents the first use of the value of `call` following
|
||||
* a sequnce of conversion-like instructions.
|
||||
*
|
||||
* This predicate only holds if there is no suitable operand (i.e., no operand of a non-
|
||||
* conversion instruction) to use to represent the value of `call` after conversions.
|
||||
*/
|
||||
predicate instructionForfullyConvertedCall(Instruction instr, CallInstruction call) {
|
||||
not operandForfullyConvertedCall(_, call) and
|
||||
(
|
||||
// If there is no use of the call then we pick the call instruction
|
||||
not exists(getAUse(call)) and
|
||||
instr = call
|
||||
or
|
||||
// Otherwise, flow to the first non-conversion use.
|
||||
exists(Operand operand | operand = fullyConvertedCallStep*(getAUse(call)) |
|
||||
instr = getANonConversionUse(operand)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `node` represents the output node for `call`. */
|
||||
private predicate simpleOutNode(Node node, CallInstruction call) {
|
||||
operandForfullyConvertedCall(node.asOperand(), call)
|
||||
or
|
||||
instructionForfullyConvertedCall(node.asInstruction(), call)
|
||||
}
|
||||
|
||||
/** A data flow node that represents the output of a call. */
|
||||
class OutNode extends InstructionNode {
|
||||
class OutNode extends Node {
|
||||
OutNode() {
|
||||
instr instanceof CallInstruction or
|
||||
instr instanceof WriteSideEffectInstruction
|
||||
// Return values not hidden behind indirections
|
||||
simpleOutNode(this, _)
|
||||
or
|
||||
// Return values hidden behind indirections
|
||||
this instanceof IndirectReturnOutNode
|
||||
or
|
||||
// Modified arguments hidden behind indirections
|
||||
this instanceof IndirectArgumentOutNode
|
||||
}
|
||||
|
||||
/** Gets the underlying call. */
|
||||
@@ -209,20 +299,28 @@ class OutNode extends InstructionNode {
|
||||
abstract ReturnKind getReturnKind();
|
||||
}
|
||||
|
||||
private class CallOutNode extends OutNode {
|
||||
override CallInstruction instr;
|
||||
private class DirectCallOutNode extends OutNode {
|
||||
CallInstruction call;
|
||||
|
||||
override DataFlowCall getCall() { result = instr }
|
||||
DirectCallOutNode() { simpleOutNode(this, call) }
|
||||
|
||||
override ReturnKind getReturnKind() { result instanceof NormalReturnKind }
|
||||
override DataFlowCall getCall() { result = call }
|
||||
|
||||
override ReturnKind getReturnKind() { result = TNormalReturnKind(0) }
|
||||
}
|
||||
|
||||
private class SideEffectOutNode extends OutNode {
|
||||
override WriteSideEffectInstruction instr;
|
||||
private class IndirectCallOutNode extends OutNode, IndirectReturnOutNode {
|
||||
override DataFlowCall getCall() { result = this.getCallInstruction() }
|
||||
|
||||
override DataFlowCall getCall() { result = instr.getPrimaryInstruction() }
|
||||
override ReturnKind getReturnKind() { result = TNormalReturnKind(this.getIndirectionIndex()) }
|
||||
}
|
||||
|
||||
override ReturnKind getReturnKind() { result = TIndirectReturnKind(instr.getIndex()) }
|
||||
private class SideEffectOutNode extends OutNode, IndirectArgumentOutNode {
|
||||
override DataFlowCall getCall() { result = this.getCallInstruction() }
|
||||
|
||||
override ReturnKind getReturnKind() {
|
||||
result = TIndirectReturnKind(this.getArgumentIndex(), this.getIndirectionIndex())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -230,13 +328,8 @@ private class SideEffectOutNode extends OutNode {
|
||||
* `kind`.
|
||||
*/
|
||||
OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) {
|
||||
// There should be only one `OutNode` for a given `(call, kind)` pair. Showing the optimizer that
|
||||
// this is true helps it make better decisions downstream, especially in virtual dispatch.
|
||||
result =
|
||||
unique(OutNode outNode |
|
||||
outNode.getCall() = call and
|
||||
outNode.getReturnKind() = kind
|
||||
)
|
||||
result.getCall() = call and
|
||||
result.getReturnKind() = kind
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -245,7 +338,7 @@ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) {
|
||||
* global or static variable.
|
||||
*/
|
||||
predicate jumpStep(Node n1, Node n2) {
|
||||
exists(GlobalOrNamespaceVariable v |
|
||||
exists(Cpp::GlobalOrNamespaceVariable v |
|
||||
v =
|
||||
n1.asInstruction()
|
||||
.(StoreInstruction)
|
||||
@@ -269,24 +362,92 @@ predicate jumpStep(Node n1, Node n2) {
|
||||
* Thus, `node2` references an object with a field `f` that contains the
|
||||
* value of `node1`.
|
||||
*/
|
||||
predicate storeStep(StoreNodeInstr node1, FieldContent f, StoreNodeInstr node2) {
|
||||
exists(FieldAddressInstruction fai |
|
||||
node1.getInstruction() = fai and
|
||||
node2.getInstruction() = fai.getObjectAddress() and
|
||||
f.getField() = fai.getField()
|
||||
predicate storeStep(Node node1, Content c, PostFieldUpdateNode node2) {
|
||||
exists(int indirectionIndex1, int numberOfLoads, StoreInstruction store |
|
||||
nodeHasInstruction(node1, store, pragma[only_bind_into](indirectionIndex1)) and
|
||||
node2.getIndirectionIndex() = 1 and
|
||||
numberOfLoadsFromOperand(node2.getFieldAddress(), store.getDestinationAddressOperand(),
|
||||
numberOfLoads)
|
||||
|
|
||||
exists(FieldContent fc | fc = c |
|
||||
fc.getField() = node2.getUpdatedField() and
|
||||
fc.getIndirectionIndex() = 1 + indirectionIndex1 + numberOfLoads
|
||||
)
|
||||
or
|
||||
exists(UnionContent uc | uc = c |
|
||||
uc.getAField() = node2.getUpdatedField() and
|
||||
uc.getIndirectionIndex() = 1 + indirectionIndex1 + numberOfLoads
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `operandFrom` flows to `operandTo` using a sequence of conversion-like
|
||||
* operations and exactly `n` `LoadInstruction` operations.
|
||||
*/
|
||||
private predicate numberOfLoadsFromOperandRec(Operand operandFrom, Operand operandTo, int ind) {
|
||||
exists(LoadInstruction load | load.getSourceAddressOperand() = operandFrom |
|
||||
operandTo = operandFrom and ind = 0
|
||||
or
|
||||
numberOfLoadsFromOperand(load.getAUse(), operandTo, ind - 1)
|
||||
)
|
||||
or
|
||||
exists(Operand op, Instruction instr |
|
||||
instr = op.getDef() and
|
||||
conversionFlow(operandFrom, instr, _) and
|
||||
numberOfLoadsFromOperand(op, operandTo, ind)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `operandFrom` flows to `operandTo` using a sequence of conversion-like
|
||||
* operations and exactly `n` `LoadInstruction` operations.
|
||||
*/
|
||||
private predicate numberOfLoadsFromOperand(Operand operandFrom, Operand operandTo, int n) {
|
||||
numberOfLoadsFromOperandRec(operandFrom, operandTo, n)
|
||||
or
|
||||
not any(LoadInstruction load).getSourceAddressOperand() = operandFrom and
|
||||
not conversionFlow(operandFrom, _, _) and
|
||||
operandFrom = operandTo and
|
||||
n = 0
|
||||
}
|
||||
|
||||
// Needed to join on both an operand and an index at the same time.
|
||||
pragma[noinline]
|
||||
predicate nodeHasOperand(Node node, Operand operand, int indirectionIndex) {
|
||||
node.asOperand() = operand and indirectionIndex = 0
|
||||
or
|
||||
hasOperandAndIndex(node, operand, indirectionIndex)
|
||||
}
|
||||
|
||||
// Needed to join on both an instruction and an index at the same time.
|
||||
pragma[noinline]
|
||||
predicate nodeHasInstruction(Node node, Instruction instr, int indirectionIndex) {
|
||||
node.asInstruction() = instr and indirectionIndex = 0
|
||||
or
|
||||
hasInstructionAndIndex(node, instr, indirectionIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via a read of `f`.
|
||||
* Thus, `node1` references an object with a field `f` whose value ends up in
|
||||
* `node2`.
|
||||
*/
|
||||
predicate readStep(ReadNode node1, FieldContent f, ReadNode node2) {
|
||||
exists(FieldAddressInstruction fai |
|
||||
node1.getInstruction() = fai.getObjectAddress() and
|
||||
node2.getInstruction() = fai and
|
||||
f.getField() = fai.getField()
|
||||
predicate readStep(Node node1, Content c, Node node2) {
|
||||
exists(FieldAddress fa1, Operand operand, int numberOfLoads, int indirectionIndex2 |
|
||||
nodeHasOperand(node2, operand, indirectionIndex2) and
|
||||
nodeHasOperand(node1, fa1.getObjectAddressOperand(), _) and
|
||||
numberOfLoadsFromOperand(fa1, operand, numberOfLoads)
|
||||
|
|
||||
exists(FieldContent fc | fc = c |
|
||||
fc.getField() = fa1.getField() and
|
||||
fc.getIndirectionIndex() = indirectionIndex2 + numberOfLoads
|
||||
)
|
||||
or
|
||||
exists(UnionContent uc | uc = c |
|
||||
uc.getAField() = fa1.getField() and
|
||||
uc.getIndirectionIndex() = indirectionIndex2 + numberOfLoads
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -304,20 +465,20 @@ predicate clearsContent(Node n, Content c) {
|
||||
predicate expectsContent(Node n, ContentSet c) { none() }
|
||||
|
||||
/** Gets the type of `n` used for type pruning. */
|
||||
IRType getNodeType(Node n) {
|
||||
DataFlowType getNodeType(Node n) {
|
||||
suppressUnusedNode(n) and
|
||||
result instanceof IRVoidType // stub implementation
|
||||
result instanceof VoidType // stub implementation
|
||||
}
|
||||
|
||||
/** Gets a string representation of a type returned by `getNodeType`. */
|
||||
string ppReprType(IRType t) { none() } // stub implementation
|
||||
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`.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate compatibleTypes(IRType t1, IRType t2) {
|
||||
predicate compatibleTypes(DataFlowType t1, DataFlowType t2) {
|
||||
any() // stub implementation
|
||||
}
|
||||
|
||||
@@ -337,11 +498,11 @@ class CastNode extends Node {
|
||||
* data-flow library discards call contexts and inserts a node in the big-step
|
||||
* relation used for human-readable path explanations.
|
||||
*/
|
||||
class DataFlowCallable = Declaration;
|
||||
class DataFlowCallable = Cpp::Declaration;
|
||||
|
||||
class DataFlowExpr = Expr;
|
||||
|
||||
class DataFlowType = IRType;
|
||||
class DataFlowType = Type;
|
||||
|
||||
/** A function call relevant for data flow. */
|
||||
class DataFlowCall extends CallInstruction {
|
||||
@@ -368,17 +529,7 @@ class Unit extends TUnit {
|
||||
}
|
||||
|
||||
/** Holds if `n` should be hidden from path explanations. */
|
||||
predicate nodeIsHidden(Node n) {
|
||||
n instanceof OperandNode and not n instanceof ArgumentNode
|
||||
or
|
||||
StoreNodeFlow::flowThrough(n, _) and
|
||||
not StoreNodeFlow::flowOutOf(n, _) and
|
||||
not StoreNodeFlow::flowInto(_, n)
|
||||
or
|
||||
ReadNodeFlow::flowThrough(n, _) and
|
||||
not ReadNodeFlow::flowOutOf(n, _) and
|
||||
not ReadNodeFlow::flowInto(_, n)
|
||||
}
|
||||
predicate nodeIsHidden(Node n) { n instanceof OperandNode and not n instanceof ArgumentNode }
|
||||
|
||||
class LambdaCallKind = Unit;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,41 +5,89 @@
|
||||
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
private import DataFlowUtil
|
||||
private import SsaInternals as Ssa
|
||||
|
||||
/**
|
||||
* Gets the instruction that goes into `input` for `call`.
|
||||
*/
|
||||
Operand callInput(CallInstruction call, FunctionInput input) {
|
||||
DataFlow::Node callInput(CallInstruction call, FunctionInput input) {
|
||||
// An argument or qualifier
|
||||
exists(int index |
|
||||
result = call.getArgumentOperand(index) and
|
||||
result.asOperand() = call.getArgumentOperand(index) and
|
||||
input.isParameterOrQualifierAddress(index)
|
||||
)
|
||||
or
|
||||
// A value pointed to by an argument or qualifier
|
||||
exists(ReadSideEffectInstruction read |
|
||||
result = read.getSideEffectOperand() and
|
||||
read.getPrimaryInstruction() = call and
|
||||
input.isParameterDerefOrQualifierObject(read.getIndex())
|
||||
exists(int index, int indirectionIndex |
|
||||
hasOperandAndIndex(result, call.getArgumentOperand(index), indirectionIndex) and
|
||||
input.isParameterDerefOrQualifierObject(index, indirectionIndex)
|
||||
)
|
||||
or
|
||||
exists(int ind |
|
||||
result = getIndirectReturnOutNode(call, ind) and
|
||||
input.isReturnValueDeref(ind)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instruction that holds the `output` for `call`.
|
||||
*/
|
||||
Instruction callOutput(CallInstruction call, FunctionOutput output) {
|
||||
Node callOutput(CallInstruction call, FunctionOutput output) {
|
||||
// The return value
|
||||
result = call and
|
||||
result.asInstruction() = call and
|
||||
output.isReturnValue()
|
||||
or
|
||||
// The side effect of a call on the value pointed to by an argument or qualifier
|
||||
exists(WriteSideEffectInstruction effect |
|
||||
result = effect and
|
||||
effect.getPrimaryInstruction() = call and
|
||||
output.isParameterDerefOrQualifierObject(effect.getIndex())
|
||||
exists(int index, int indirectionIndex |
|
||||
result.(IndirectArgumentOutNode).getArgumentIndex() = index and
|
||||
result.(IndirectArgumentOutNode).getIndirectionIndex() = indirectionIndex and
|
||||
result.(IndirectArgumentOutNode).getCallInstruction() = call and
|
||||
output.isParameterDerefOrQualifierObject(index, indirectionIndex)
|
||||
)
|
||||
or
|
||||
// TODO: modify this when we get return value dereferences
|
||||
result = call and
|
||||
output.isReturnValueDeref()
|
||||
exists(int ind |
|
||||
result = getIndirectReturnOutNode(call, ind) and
|
||||
output.isReturnValueDeref(ind)
|
||||
)
|
||||
}
|
||||
|
||||
DataFlow::Node callInput(CallInstruction call, FunctionInput input, int d) {
|
||||
exists(DataFlow::Node n | n = callInput(call, input) and d > 0 |
|
||||
// An argument or qualifier
|
||||
hasOperandAndIndex(result, n.asOperand(), d)
|
||||
or
|
||||
exists(Operand operand, int indirectionIndex |
|
||||
// A value pointed to by an argument or qualifier
|
||||
hasOperandAndIndex(n, operand, indirectionIndex) and
|
||||
hasOperandAndIndex(result, operand, indirectionIndex + d)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private IndirectReturnOutNode getIndirectReturnOutNode(CallInstruction call, int d) {
|
||||
result.getCallInstruction() = call and
|
||||
result.getIndirectionIndex() = d
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instruction that holds the `output` for `call`.
|
||||
*/
|
||||
bindingset[d]
|
||||
Node callOutput(CallInstruction call, FunctionOutput output, int d) {
|
||||
exists(DataFlow::Node n | n = callOutput(call, output) and d > 0 |
|
||||
// The return value
|
||||
result = getIndirectReturnOutNode(n.asInstruction(), d)
|
||||
or
|
||||
// If there isn't an indirect out node for the call with indirection `d` then
|
||||
// we conflate this with the underlying `CallInstruction`.
|
||||
not exists(getIndirectReturnOutNode(call, d)) and
|
||||
n.asInstruction() = result.asInstruction()
|
||||
or
|
||||
// The side effect of a call on the value pointed to by an argument or qualifier
|
||||
exists(Operand operand, int indirectionIndex |
|
||||
Ssa::outNodeHasAddressAndIndex(n, operand, indirectionIndex) and
|
||||
Ssa::outNodeHasAddressAndIndex(result, operand, indirectionIndex + d)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,270 @@
|
||||
import cpp as Cpp
|
||||
import semmle.code.cpp.ir.IR
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.SideEffects as SideEffects
|
||||
private import DataFlowImplCommon as DataFlowImplCommon
|
||||
private import DataFlowUtil
|
||||
|
||||
/**
|
||||
* Holds if `operand` is an operand that is not used by the dataflow library.
|
||||
* Ignored operands are not recognizd as uses by SSA, and they don't have a
|
||||
* corresponding `(Indirect)OperandNode`.
|
||||
*/
|
||||
predicate ignoreOperand(Operand operand) {
|
||||
operand = any(Instruction instr | ignoreInstruction(instr)).getAnOperand() or
|
||||
operand = any(Instruction instr | ignoreInstruction(instr)).getAUse() or
|
||||
operand instanceof MemoryOperand
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` is an instruction that is not used by the dataflow library.
|
||||
* Ignored instructions are not recognized as reads/writes by SSA, and they
|
||||
* don't have a corresponding `(Indirect)InstructionNode`.
|
||||
*/
|
||||
predicate ignoreInstruction(Instruction instr) {
|
||||
DataFlowImplCommon::forceCachingInSameStage() and
|
||||
(
|
||||
instr instanceof WriteSideEffectInstruction or
|
||||
instr instanceof PhiInstruction or
|
||||
instr instanceof ReadSideEffectInstruction or
|
||||
instr instanceof ChiInstruction or
|
||||
instr instanceof InitializeIndirectionInstruction
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the C++ type of `this` in the member function `f`.
|
||||
* The result is a glvalue if `isGLValue` is true, and
|
||||
* a prvalue if `isGLValue` is false.
|
||||
*/
|
||||
bindingset[isGLValue]
|
||||
private CppType getThisType(Cpp::MemberFunction f, boolean isGLValue) {
|
||||
result.hasType(f.getTypeOfThis(), isGLValue)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the C++ type of the instruction `i`.
|
||||
*
|
||||
* This is equivalent to `i.getResultLanguageType()` with the exception
|
||||
* of instructions that directly references a `this` IRVariable. In this
|
||||
* case, `i.getResultLanguageType()` gives an unknown type, whereas the
|
||||
* predicate gives the expected type (i.e., a potentially cv-qualified
|
||||
* type `A*` where `A` is the declaring type of the member function that
|
||||
* contains `i`).
|
||||
*/
|
||||
cached
|
||||
CppType getResultLanguageType(Instruction i) {
|
||||
if i.(VariableAddressInstruction).getIRVariable() instanceof IRThisVariable
|
||||
then
|
||||
if i.isGLValue()
|
||||
then result = getThisType(i.getEnclosingFunction(), true)
|
||||
else result = getThisType(i.getEnclosingFunction(), false)
|
||||
else result = i.getResultLanguageType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the C++ type of the operand `operand`.
|
||||
* This is equivalent to the type of the operand's defining instruction.
|
||||
*
|
||||
* See `getResultLanguageType` for a description of this behavior.
|
||||
*/
|
||||
CppType getLanguageType(Operand operand) { result = getResultLanguageType(operand.getDef()) }
|
||||
|
||||
/**
|
||||
* Gets the maximum number of indirections a glvalue of type `type` can have.
|
||||
* For example:
|
||||
* - If `type = int`, the result is 1
|
||||
* - If `type = MyStruct`, the result is 1
|
||||
* - If `type = char*`, the result is 2
|
||||
*/
|
||||
int getMaxIndirectionsForType(Type type) {
|
||||
result = countIndirectionsForCppType(getTypeForGLValue(type))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum number of indirections a value of type `type` can have.
|
||||
*
|
||||
* Note that this predicate is intended to be called on unspecified types
|
||||
* (i.e., `countIndirections(e.getUnspecifiedType())`).
|
||||
*/
|
||||
private int countIndirections(Type t) {
|
||||
result =
|
||||
1 +
|
||||
countIndirections([t.(Cpp::PointerType).getBaseType(), t.(Cpp::ReferenceType).getBaseType()])
|
||||
or
|
||||
not t instanceof Cpp::PointerType and
|
||||
not t instanceof Cpp::ReferenceType and
|
||||
result = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum number of indirections a value of C++
|
||||
* type `langType` can have.
|
||||
*/
|
||||
int countIndirectionsForCppType(LanguageType langType) {
|
||||
exists(Type type | langType.hasType(type, true) |
|
||||
result = 1 + countIndirections(type.getUnspecifiedType())
|
||||
)
|
||||
or
|
||||
exists(Type type | langType.hasType(type, false) |
|
||||
result = countIndirections(type.getUnspecifiedType())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A `CallInstruction` that calls an allocation function such
|
||||
* as `malloc` or `operator new`.
|
||||
*/
|
||||
class AllocationInstruction extends CallInstruction {
|
||||
AllocationInstruction() { this.getStaticCallTarget() instanceof Cpp::AllocationFunction }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `i` is a base instruction that starts a sequence of uses
|
||||
* of some variable that SSA can handle.
|
||||
*
|
||||
* This is either when `i` is a `VariableAddressInstruction` or when
|
||||
* `i` is a fresh allocation produced by an `AllocationInstruction`.
|
||||
*/
|
||||
private predicate isSourceVariableBase(Instruction i) {
|
||||
i instanceof VariableAddressInstruction or i instanceof AllocationInstruction
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the value pointed to by `operand` can potentially be
|
||||
* modified be the caller.
|
||||
*/
|
||||
predicate isModifiableByCall(ArgumentOperand operand) {
|
||||
exists(CallInstruction call, int index, CppType type |
|
||||
type = getLanguageType(operand) and
|
||||
call.getArgumentOperand(index) = operand and
|
||||
if index = -1
|
||||
then not call.getStaticCallTarget() instanceof Cpp::ConstMemberFunction
|
||||
else not SideEffects::isConstPointerLike(any(Type t | type.hasType(t, _)))
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
/**
|
||||
* Holds if `op` is a use of an SSA variable rooted at `base` with `ind` number
|
||||
* of indirections.
|
||||
*
|
||||
* `certain` is `true` if the operand is guaranteed to read the variable, and
|
||||
* `indirectionIndex` specifies the number of loads required to read the variable.
|
||||
*/
|
||||
cached
|
||||
predicate isUse(boolean certain, Operand op, Instruction base, int ind, int indirectionIndex) {
|
||||
not ignoreOperand(op) and
|
||||
certain = true and
|
||||
exists(LanguageType type, int m, int ind0 |
|
||||
type = getLanguageType(op) and
|
||||
m = countIndirectionsForCppType(type) and
|
||||
isUseImpl(op, base, ind0) and
|
||||
ind = ind0 + [0 .. m] and
|
||||
indirectionIndex = ind - ind0
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `operand` is a use of an SSA variable rooted at `base`, and the
|
||||
* path from `base` to `operand` passes through `ind` load-like instructions.
|
||||
*/
|
||||
private predicate isUseImpl(Operand operand, Instruction base, int ind) {
|
||||
DataFlowImplCommon::forceCachingInSameStage() and
|
||||
ind = 0 and
|
||||
operand.getDef() = base and
|
||||
isSourceVariableBase(base)
|
||||
or
|
||||
exists(Operand mid, Instruction instr |
|
||||
isUseImpl(mid, base, ind) and
|
||||
instr = operand.getDef() and
|
||||
conversionFlow(mid, instr, false)
|
||||
)
|
||||
or
|
||||
exists(int ind0 |
|
||||
isUseImpl(operand.getDef().(LoadInstruction).getSourceAddressOperand(), base, ind0)
|
||||
or
|
||||
isUseImpl(operand.getDef().(InitializeParameterInstruction).getAnOperand(), base, ind0)
|
||||
|
|
||||
ind0 = ind - 1
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `address` is an address of an SSA variable rooted at `base`,
|
||||
* and `instr` is a definition of the SSA variable with `ind` number of indirections.
|
||||
*
|
||||
* `certain` is `true` if `instr` is guaranteed to write to the variable, and
|
||||
* `indirectionIndex` specifies the number of loads required to read the variable
|
||||
* after the write operation.
|
||||
*/
|
||||
cached
|
||||
predicate isDef(
|
||||
boolean certain, Instruction instr, Operand address, Instruction base, int ind,
|
||||
int indirectionIndex
|
||||
) {
|
||||
certain = true and
|
||||
exists(int ind0, CppType type, int m |
|
||||
address =
|
||||
[
|
||||
instr.(StoreInstruction).getDestinationAddressOperand(),
|
||||
instr.(InitializeParameterInstruction).getAnOperand(),
|
||||
instr.(InitializeDynamicAllocationInstruction).getAllocationAddressOperand(),
|
||||
instr.(UninitializedInstruction).getAnOperand()
|
||||
]
|
||||
|
|
||||
isDefImpl(address, base, ind0) and
|
||||
type = getLanguageType(address) and
|
||||
m = countIndirectionsForCppType(type) and
|
||||
ind = ind0 + [1 .. m] and
|
||||
indirectionIndex = ind - (ind0 + 1)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `address` is a use of an SSA variable rooted at `base`, and the
|
||||
* path from `base` to `address` passes through `ind` load-like instructions.
|
||||
*
|
||||
* Note: Unlike `isUseImpl`, this predicate recurses through pointer-arithmetic
|
||||
* instructions.
|
||||
*/
|
||||
private predicate isDefImpl(Operand address, Instruction base, int ind) {
|
||||
DataFlowImplCommon::forceCachingInSameStage() and
|
||||
ind = 0 and
|
||||
address.getDef() = base and
|
||||
isSourceVariableBase(base)
|
||||
or
|
||||
exists(Operand mid, Instruction instr |
|
||||
isDefImpl(mid, base, ind) and
|
||||
instr = address.getDef() and
|
||||
conversionFlow(mid, instr, _)
|
||||
)
|
||||
or
|
||||
exists(int ind0 |
|
||||
isDefImpl(address.getDef().(LoadInstruction).getSourceAddressOperand(), base, ind0)
|
||||
or
|
||||
isDefImpl(address.getDef().(InitializeParameterInstruction).getAnOperand(), base, ind0)
|
||||
|
|
||||
ind0 = ind - 1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import Cached
|
||||
|
||||
/**
|
||||
* Inputs to the shared SSA library's parameterized module that is shared
|
||||
* between the SSA pruning stage, and the final SSA stage.
|
||||
*/
|
||||
module InputSigCommon {
|
||||
class BasicBlock = IRBlock;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result.immediatelyDominates(bb) }
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
class ExitBasicBlock extends IRBlock {
|
||||
ExitBasicBlock() { this.getLastInstruction() instanceof ExitFunctionInstruction }
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ private import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
private import ModelUtil
|
||||
private import semmle.code.cpp.models.interfaces.DataFlow
|
||||
private import semmle.code.cpp.models.interfaces.SideEffect
|
||||
private import DataFlowUtil
|
||||
private import DataFlowPrivate
|
||||
|
||||
/**
|
||||
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
|
||||
@@ -23,26 +25,26 @@ cached
|
||||
predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
operandToInstructionTaintStep(nodeFrom.asOperand(), nodeTo.asInstruction())
|
||||
or
|
||||
instructionToOperandTaintStep(nodeFrom.asInstruction(), nodeTo.asOperand())
|
||||
}
|
||||
|
||||
private predicate instructionToOperandTaintStep(Instruction fromInstr, Operand toOperand) {
|
||||
// Propagate flow from the definition of an operand to the operand, even when the overlap is inexact.
|
||||
// We only do this in certain cases:
|
||||
// 1. The instruction's result must not be conflated, and
|
||||
// 2. The instruction's result type is one the types where we expect element-to-object flow. Currently
|
||||
// this is array types and union types. This matches the other two cases of element-to-object flow in
|
||||
// `DefaultTaintTracking`.
|
||||
toOperand.getAnyDef() = fromInstr and
|
||||
not fromInstr.isResultConflated() and
|
||||
(
|
||||
fromInstr.getResultType() instanceof ArrayType or
|
||||
fromInstr.getResultType() instanceof Union
|
||||
modeledTaintStep(nodeFrom, nodeTo)
|
||||
or
|
||||
// Flow from `op` to `*op`.
|
||||
exists(Operand operand, int indirectionIndex |
|
||||
nodeHasOperand(nodeFrom, operand, indirectionIndex) and
|
||||
nodeHasOperand(nodeTo, operand, indirectionIndex - 1)
|
||||
)
|
||||
or
|
||||
exists(ReadSideEffectInstruction readInstr |
|
||||
fromInstr = readInstr.getArgumentDef() and
|
||||
toOperand = readInstr.getSideEffectOperand()
|
||||
// Flow from `instr` to `*instr`.
|
||||
exists(Instruction instr, int indirectionIndex |
|
||||
nodeHasInstruction(nodeFrom, instr, indirectionIndex) and
|
||||
nodeHasInstruction(nodeTo, instr, indirectionIndex - 1)
|
||||
)
|
||||
or
|
||||
// Flow from (the indirection of) an operand of a pointer arithmetic instruction to the
|
||||
// indirection of the pointer arithmetic instruction. This provides flow from `source`
|
||||
// in `x[source]` to the result of the associated load instruction.
|
||||
exists(PointerArithmeticInstruction pai, int indirectionIndex |
|
||||
nodeHasOperand(nodeFrom, pai.getAnOperand(), pragma[only_bind_into](indirectionIndex)) and
|
||||
hasInstructionAndIndex(nodeTo, pai, indirectionIndex + 1)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -61,13 +63,13 @@ private predicate operandToInstructionTaintStep(Operand opFrom, Instruction inst
|
||||
instrTo instanceof BitwiseInstruction
|
||||
or
|
||||
instrTo instanceof PointerArithmeticInstruction
|
||||
or
|
||||
// The `CopyInstruction` case is also present in non-taint data flow, but
|
||||
// that uses `getDef` rather than `getAnyDef`. For taint, we want flow
|
||||
// from a definition of `myStruct` to a `myStruct.myField` expression.
|
||||
instrTo instanceof CopyInstruction
|
||||
)
|
||||
or
|
||||
// The `CopyInstruction` case is also present in non-taint data flow, but
|
||||
// that uses `getDef` rather than `getAnyDef`. For taint, we want flow
|
||||
// from a definition of `myStruct` to a `myStruct.myField` expression.
|
||||
instrTo.(LoadInstruction).getSourceAddressOperand() = opFrom
|
||||
or
|
||||
// Unary instructions tend to preserve enough information in practice that we
|
||||
// want taint to flow through.
|
||||
// The exception is `FieldAddressInstruction`. Together with the rules below for
|
||||
@@ -81,40 +83,6 @@ private predicate operandToInstructionTaintStep(Operand opFrom, Instruction inst
|
||||
or
|
||||
instrTo.(FieldAddressInstruction).getField().getDeclaringType() instanceof Union
|
||||
)
|
||||
or
|
||||
// Flow from an element to an array or union that contains it.
|
||||
instrTo.(ChiInstruction).getPartialOperand() = opFrom and
|
||||
not instrTo.isResultConflated() and
|
||||
exists(Type t | instrTo.getResultLanguageType().hasType(t, false) |
|
||||
t instanceof Union
|
||||
or
|
||||
t instanceof ArrayType
|
||||
)
|
||||
or
|
||||
// Until we have flow through indirections across calls, we'll take flow out
|
||||
// of the indirection and into the argument.
|
||||
// When we get proper flow through indirections across calls, this code can be
|
||||
// moved to `adjusedSink` or possibly into the `DataFlow::ExprNode` class.
|
||||
exists(ReadSideEffectInstruction read |
|
||||
read.getSideEffectOperand() = opFrom and
|
||||
read.getArgumentDef() = instrTo
|
||||
)
|
||||
or
|
||||
// Until we have from through indirections across calls, we'll take flow out
|
||||
// of the parameter and into its indirection.
|
||||
// `InitializeIndirectionInstruction` only has a single operand: the address of the
|
||||
// value whose indirection we are initializing. When initializing an indirection of a parameter `p`,
|
||||
// the IR looks like this:
|
||||
// ```
|
||||
// m1 = InitializeParameter[p] : &r1
|
||||
// r2 = Load[p] : r2, m1
|
||||
// m3 = InitializeIndirection[p] : &r2
|
||||
// ```
|
||||
// So by having flow from `r2` to `m3` we're enabling flow from `m1` to `m3`. This relies on the
|
||||
// `LoadOperand`'s overlap being exact.
|
||||
instrTo.(InitializeIndirectionInstruction).getAnOperand() = opFrom
|
||||
or
|
||||
modeledTaintStep(opFrom, instrTo)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,24 +132,42 @@ predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::Content c) { n
|
||||
predicate defaultTaintSanitizer(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if taint can flow from `instrIn` to `instrOut` through a call to a
|
||||
* Holds if taint can flow from `nodeIn` to `nodeOut` through a call to a
|
||||
* modeled function.
|
||||
*/
|
||||
predicate modeledTaintStep(Operand nodeIn, Instruction nodeOut) {
|
||||
predicate modeledTaintStep(DataFlow::Node nodeIn, DataFlow::Node nodeOut) {
|
||||
// Normal taint steps
|
||||
exists(CallInstruction call, TaintFunction func, FunctionInput modelIn, FunctionOutput modelOut |
|
||||
call.getStaticCallTarget() = func and
|
||||
func.hasTaintFlow(modelIn, modelOut)
|
||||
|
|
||||
(
|
||||
nodeIn = callInput(call, modelIn)
|
||||
or
|
||||
exists(int n |
|
||||
modelIn.isParameterDerefOrQualifierObject(n) and
|
||||
if n = -1
|
||||
then nodeIn = callInput(call, any(InQualifierObject inQualifier))
|
||||
then nodeIn = callInput(call, any(InQualifierAddress inQualifier))
|
||||
else nodeIn = callInput(call, any(InParameter inParam | inParam.getIndex() = n))
|
||||
)
|
||||
) and
|
||||
nodeOut = callOutput(call, modelOut) and
|
||||
call.getStaticCallTarget() = func and
|
||||
func.hasTaintFlow(modelIn, modelOut)
|
||||
nodeOut = callOutput(call, modelOut)
|
||||
or
|
||||
exists(int d |
|
||||
nodeIn = callInput(call, modelIn, d)
|
||||
or
|
||||
exists(int n |
|
||||
d = 1 and
|
||||
modelIn.isParameterDerefOrQualifierObject(n) and
|
||||
if n = -1
|
||||
then nodeIn = callInput(call, any(InQualifierAddress inQualifier))
|
||||
else nodeIn = callInput(call, any(InParameter inParam | inParam.getIndex() = n))
|
||||
)
|
||||
|
|
||||
call.getStaticCallTarget() = func and
|
||||
func.hasTaintFlow(modelIn, modelOut) and
|
||||
nodeOut = callOutput(call, modelOut, d)
|
||||
)
|
||||
)
|
||||
or
|
||||
// Taint flow from one argument to another and data flow from an argument to a
|
||||
@@ -205,12 +191,11 @@ predicate modeledTaintStep(Operand nodeIn, Instruction nodeOut) {
|
||||
// Taint flow from a pointer argument to an output, when the model specifies flow from the deref
|
||||
// to that output, but the deref is not modeled in the IR for the caller.
|
||||
exists(
|
||||
CallInstruction call, ReadSideEffectInstruction read, Function func, FunctionInput modelIn,
|
||||
FunctionOutput modelOut
|
||||
CallInstruction call, DataFlow::SideEffectOperandNode indirectArgument, Function func,
|
||||
FunctionInput modelIn, FunctionOutput modelOut
|
||||
|
|
||||
read.getSideEffectOperand() = callInput(call, modelIn) and
|
||||
read.getArgumentDef() = nodeIn.getDef() and
|
||||
not read.getSideEffect().isResultModeled() and
|
||||
indirectArgument = callInput(call, modelIn) and
|
||||
indirectArgument.getAddressOperand() = nodeIn.asOperand() and
|
||||
call.getStaticCallTarget() = func and
|
||||
(
|
||||
func.(DataFlowFunction).hasDataFlow(modelIn, modelOut)
|
||||
|
||||
@@ -0,0 +1,314 @@
|
||||
/**
|
||||
* This module defines an initial SSA pruning stage that doesn't take
|
||||
* indirections into account.
|
||||
*/
|
||||
|
||||
private import codeql.ssa.Ssa as SsaImplCommon
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
|
||||
private import semmle.code.cpp.models.interfaces.Allocation as Alloc
|
||||
private import semmle.code.cpp.models.interfaces.DataFlow as DataFlow
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.SideEffects as SideEffects
|
||||
private import semmle.code.cpp.ir.internal.IRCppLanguage
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import semmle.code.cpp.ir.dataflow.internal.SsaInternalsCommon
|
||||
|
||||
private module SourceVariables {
|
||||
newtype TBaseSourceVariable =
|
||||
// Each IR variable gets its own source variable
|
||||
TBaseIRVariable(IRVariable var) or
|
||||
// Each allocation gets its own source variable
|
||||
TBaseCallVariable(AllocationInstruction call)
|
||||
|
||||
abstract class BaseSourceVariable extends TBaseSourceVariable {
|
||||
abstract string toString();
|
||||
|
||||
abstract DataFlowType getType();
|
||||
}
|
||||
|
||||
class BaseIRVariable extends BaseSourceVariable, TBaseIRVariable {
|
||||
IRVariable var;
|
||||
|
||||
IRVariable getIRVariable() { result = var }
|
||||
|
||||
BaseIRVariable() { this = TBaseIRVariable(var) }
|
||||
|
||||
override string toString() { result = var.toString() }
|
||||
|
||||
override DataFlowType getType() { result = var.getType() }
|
||||
}
|
||||
|
||||
class BaseCallVariable extends BaseSourceVariable, TBaseCallVariable {
|
||||
AllocationInstruction call;
|
||||
|
||||
BaseCallVariable() { this = TBaseCallVariable(call) }
|
||||
|
||||
AllocationInstruction getCallInstruction() { result = call }
|
||||
|
||||
override string toString() { result = call.toString() }
|
||||
|
||||
override DataFlowType getType() { result = call.getResultType() }
|
||||
}
|
||||
|
||||
private newtype TSourceVariable =
|
||||
TSourceIRVariable(BaseIRVariable baseVar) or
|
||||
TCallVariable(AllocationInstruction call)
|
||||
|
||||
abstract class SourceVariable extends TSourceVariable {
|
||||
abstract string toString();
|
||||
|
||||
abstract BaseSourceVariable getBaseVariable();
|
||||
}
|
||||
|
||||
class SourceIRVariable extends SourceVariable, TSourceIRVariable {
|
||||
BaseIRVariable var;
|
||||
|
||||
SourceIRVariable() { this = TSourceIRVariable(var) }
|
||||
|
||||
IRVariable getIRVariable() { result = var.getIRVariable() }
|
||||
|
||||
override BaseIRVariable getBaseVariable() { result.getIRVariable() = this.getIRVariable() }
|
||||
|
||||
override string toString() { result = this.getIRVariable().toString() }
|
||||
}
|
||||
|
||||
class CallVariable extends SourceVariable, TCallVariable {
|
||||
AllocationInstruction call;
|
||||
|
||||
CallVariable() { this = TCallVariable(call) }
|
||||
|
||||
AllocationInstruction getCall() { result = call }
|
||||
|
||||
override BaseCallVariable getBaseVariable() { result.getCallInstruction() = call }
|
||||
|
||||
override string toString() { result = "Call" }
|
||||
}
|
||||
}
|
||||
|
||||
import SourceVariables
|
||||
|
||||
private newtype TDefOrUseImpl =
|
||||
TDefImpl(Operand address) { isDef(_, _, address, _, _, _) } or
|
||||
TUseImpl(Operand operand) {
|
||||
isUse(_, operand, _, _, _) and
|
||||
not isDef(_, _, operand, _, _, _)
|
||||
}
|
||||
|
||||
abstract private class DefOrUseImpl extends TDefOrUseImpl {
|
||||
/** Gets a textual representation of this element. */
|
||||
abstract string toString();
|
||||
|
||||
/** Gets the block of this definition or use. */
|
||||
abstract IRBlock getBlock();
|
||||
|
||||
/** Holds if this definition or use has index `index` in block `block`. */
|
||||
abstract predicate hasIndexInBlock(IRBlock block, int index);
|
||||
|
||||
final predicate hasIndexInBlock(IRBlock block, int index, SourceVariable sv) {
|
||||
this.hasIndexInBlock(block, index) and
|
||||
sv = this.getSourceVariable()
|
||||
}
|
||||
|
||||
/** Gets the location of this element. */
|
||||
abstract Cpp::Location getLocation();
|
||||
|
||||
abstract Instruction getBase();
|
||||
|
||||
final BaseSourceVariable getBaseSourceVariable() {
|
||||
exists(IRVariable var |
|
||||
result.(BaseIRVariable).getIRVariable() = var and
|
||||
instructionHasIRVariable(this.getBase(), var)
|
||||
)
|
||||
or
|
||||
result.(BaseCallVariable).getCallInstruction() = this.getBase()
|
||||
}
|
||||
|
||||
/** Gets the variable that is defined or used. */
|
||||
final SourceVariable getSourceVariable() {
|
||||
exists(BaseSourceVariable v |
|
||||
sourceVariableHasBaseAndIndex(result, v) and
|
||||
defOrUseHasSourceVariable(this, v)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate instructionHasIRVariable(VariableAddressInstruction vai, IRVariable var) {
|
||||
vai.getIRVariable() = var
|
||||
}
|
||||
|
||||
private predicate defOrUseHasSourceVariable(DefOrUseImpl defOrUse, BaseSourceVariable bv) {
|
||||
defHasSourceVariable(defOrUse, bv)
|
||||
or
|
||||
useHasSourceVariable(defOrUse, bv)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate defHasSourceVariable(DefImpl def, BaseSourceVariable bv) {
|
||||
bv = def.getBaseSourceVariable()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate useHasSourceVariable(UseImpl use, BaseSourceVariable bv) {
|
||||
bv = use.getBaseSourceVariable()
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate sourceVariableHasBaseAndIndex(SourceVariable v, BaseSourceVariable bv) {
|
||||
v.getBaseVariable() = bv
|
||||
}
|
||||
|
||||
class DefImpl extends DefOrUseImpl, TDefImpl {
|
||||
Operand address;
|
||||
|
||||
DefImpl() { this = TDefImpl(address) }
|
||||
|
||||
override Instruction getBase() { isDef(_, _, address, result, _, _) }
|
||||
|
||||
Operand getAddressOperand() { result = address }
|
||||
|
||||
Instruction getDefiningInstruction() { isDef(_, result, address, _, _, _) }
|
||||
|
||||
override string toString() { result = address.toString() }
|
||||
|
||||
override IRBlock getBlock() { result = this.getDefiningInstruction().getBlock() }
|
||||
|
||||
override Cpp::Location getLocation() { result = this.getDefiningInstruction().getLocation() }
|
||||
|
||||
final override predicate hasIndexInBlock(IRBlock block, int index) {
|
||||
this.getDefiningInstruction() = block.getInstruction(index)
|
||||
}
|
||||
|
||||
predicate isCertain() { isDef(true, _, address, _, _, _) }
|
||||
}
|
||||
|
||||
class UseImpl extends DefOrUseImpl, TUseImpl {
|
||||
Operand operand;
|
||||
|
||||
UseImpl() { this = TUseImpl(operand) }
|
||||
|
||||
Operand getOperand() { result = operand }
|
||||
|
||||
override string toString() { result = operand.toString() }
|
||||
|
||||
final override predicate hasIndexInBlock(IRBlock block, int index) {
|
||||
operand.getUse() = block.getInstruction(index)
|
||||
}
|
||||
|
||||
final override IRBlock getBlock() { result = operand.getUse().getBlock() }
|
||||
|
||||
final override Cpp::Location getLocation() { result = operand.getLocation() }
|
||||
|
||||
override Instruction getBase() { isUse(_, operand, result, _, _) }
|
||||
|
||||
predicate isCertain() { isUse(true, operand, _, _, _) }
|
||||
}
|
||||
|
||||
private module SsaInput implements SsaImplCommon::InputSig {
|
||||
import InputSigCommon
|
||||
import SourceVariables
|
||||
|
||||
/**
|
||||
* Holds if the `i`'th write in block `bb` writes to the variable `v`.
|
||||
* `certain` is `true` if the write is guaranteed to overwrite the entire variable.
|
||||
*/
|
||||
predicate variableWrite(IRBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
DataFlowImplCommon::forceCachingInSameStage() and
|
||||
exists(DefImpl def | def.hasIndexInBlock(bb, i, v) |
|
||||
if def.isCertain() then certain = true else certain = false
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `i`'th read in block `bb` reads to the variable `v`.
|
||||
* `certain` is `true` if the read is guaranteed.
|
||||
*/
|
||||
predicate variableRead(IRBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
exists(UseImpl use | use.hasIndexInBlock(bb, i, v) |
|
||||
if use.isCertain() then certain = true else certain = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private newtype TSsaDefOrUse =
|
||||
TDefOrUse(DefOrUseImpl defOrUse) {
|
||||
defOrUse instanceof UseImpl
|
||||
or
|
||||
// If `defOrUse` is a definition we only include it if the
|
||||
// SSA library concludes that it's live after the write.
|
||||
exists(Definition def, SourceVariable sv, IRBlock bb, int i |
|
||||
def.definesAt(sv, bb, i) and
|
||||
defOrUse.(DefImpl).hasIndexInBlock(bb, i, sv)
|
||||
)
|
||||
} or
|
||||
TPhi(PhiNode phi)
|
||||
|
||||
abstract private class SsaDefOrUse extends TSsaDefOrUse {
|
||||
string toString() { result = "SsaDefOrUse" }
|
||||
|
||||
DefOrUseImpl asDefOrUse() { none() }
|
||||
|
||||
PhiNode asPhi() { none() }
|
||||
|
||||
abstract Location getLocation();
|
||||
}
|
||||
|
||||
class DefOrUse extends TDefOrUse, SsaDefOrUse {
|
||||
DefOrUseImpl defOrUse;
|
||||
|
||||
DefOrUse() { this = TDefOrUse(defOrUse) }
|
||||
|
||||
final override DefOrUseImpl asDefOrUse() { result = defOrUse }
|
||||
|
||||
final override Location getLocation() { result = defOrUse.getLocation() }
|
||||
|
||||
final SourceVariable getSourceVariable() { result = defOrUse.getSourceVariable() }
|
||||
}
|
||||
|
||||
class Phi extends TPhi, SsaDefOrUse {
|
||||
PhiNode phi;
|
||||
|
||||
Phi() { this = TPhi(phi) }
|
||||
|
||||
final override PhiNode asPhi() { result = phi }
|
||||
|
||||
final override Location getLocation() { result = phi.getBasicBlock().getLocation() }
|
||||
}
|
||||
|
||||
class UseOrPhi extends SsaDefOrUse {
|
||||
UseOrPhi() {
|
||||
this.asDefOrUse() instanceof UseImpl
|
||||
or
|
||||
this instanceof Phi
|
||||
}
|
||||
|
||||
final override Location getLocation() {
|
||||
result = this.asDefOrUse().getLocation() or result = this.(Phi).getLocation()
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = this.asDefOrUse().toString()
|
||||
or
|
||||
this instanceof Phi and
|
||||
result = "Phi"
|
||||
}
|
||||
}
|
||||
|
||||
class Def extends DefOrUse {
|
||||
override DefImpl defOrUse;
|
||||
|
||||
Operand getAddressOperand() { result = defOrUse.getAddressOperand() }
|
||||
|
||||
Instruction getAddress() { result = this.getAddressOperand().getDef() }
|
||||
|
||||
Instruction getDefiningInstruction() { result = defOrUse.getDefiningInstruction() }
|
||||
|
||||
override string toString() { result = this.asDefOrUse().toString() + " (def)" }
|
||||
}
|
||||
|
||||
private module SsaImpl = SsaImplCommon::Make<SsaInput>;
|
||||
|
||||
class PhiNode = SsaImpl::PhiNode;
|
||||
|
||||
class Definition = SsaImpl::Definition;
|
||||
@@ -143,16 +143,6 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) {
|
||||
exists(OldInstruction oldInstruction, OldIR::RegisterOperand oldOperand |
|
||||
oldInstruction = getOldInstruction(instruction) and
|
||||
oldOperand = oldInstruction.getAnOperand() and
|
||||
tag = oldOperand.getOperandTag() and
|
||||
result = getNewInstruction(oldOperand.getAnyDef())
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noopt]
|
||||
private predicate hasMemoryOperandDefinition(
|
||||
OldInstruction oldInstruction, OldIR::NonPhiMemoryOperand oldOperand, Overlap overlap,
|
||||
|
||||
@@ -256,12 +256,6 @@ CppType getInstructionOperandType(Instruction instruction, TypedOperandTag tag)
|
||||
.getInstructionMemoryOperandType(getInstructionTag(instruction), tag)
|
||||
}
|
||||
|
||||
Instruction getPhiOperandDefinition(
|
||||
PhiInstruction instruction, IRBlock predecessorBlock, Overlap overlap
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
Instruction getPhiInstructionBlockStart(PhiInstruction instr) { none() }
|
||||
|
||||
Instruction getInstructionSuccessor(Instruction instruction, EdgeKind kind) {
|
||||
|
||||
@@ -143,16 +143,6 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
Instruction getRegisterOperandDefinition(Instruction instruction, RegisterOperandTag tag) {
|
||||
exists(OldInstruction oldInstruction, OldIR::RegisterOperand oldOperand |
|
||||
oldInstruction = getOldInstruction(instruction) and
|
||||
oldOperand = oldInstruction.getAnOperand() and
|
||||
tag = oldOperand.getOperandTag() and
|
||||
result = getNewInstruction(oldOperand.getAnyDef())
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noopt]
|
||||
private predicate hasMemoryOperandDefinition(
|
||||
OldInstruction oldInstruction, OldIR::NonPhiMemoryOperand oldOperand, Overlap overlap,
|
||||
|
||||
@@ -205,57 +205,149 @@ private predicate deconstructSizeExpr(Expr sizeExpr, Expr lengthExpr, int sizeof
|
||||
sizeof = 1
|
||||
}
|
||||
|
||||
/** A `Function` that is a call target of an allocation. */
|
||||
private signature class CallAllocationExprTarget extends Function;
|
||||
|
||||
/**
|
||||
* An allocation expression that is a function call, such as call to `malloc`.
|
||||
* This module abstracts over the type of allocation call-targets and provides a
|
||||
* class `CallAllocationExprImpl` which contains the implementation of the various
|
||||
* predicates required by the `Allocation` class.
|
||||
*
|
||||
* This module is then instantiated for two types of allocation call-targets:
|
||||
* - `AllocationFunction`: Functions that we've explicitly modeled as functions that
|
||||
* perform allocations (i.e., `malloc`).
|
||||
* - `HeuristicAllocationFunction`: Functions that we deduce as behaving like an allocation
|
||||
* function using various heuristics.
|
||||
*/
|
||||
private class CallAllocationExpr extends AllocationExpr, FunctionCall {
|
||||
AllocationFunction target;
|
||||
private module CallAllocationExprBase<CallAllocationExprTarget Target> {
|
||||
/** A module that contains the collection of member-predicates required on `Target`. */
|
||||
signature module Param {
|
||||
/**
|
||||
* Gets the index of the input pointer argument to be reallocated, if
|
||||
* this is a `realloc` function.
|
||||
*/
|
||||
int getReallocPtrArg(Target target);
|
||||
|
||||
CallAllocationExpr() {
|
||||
target = this.getTarget() and
|
||||
// realloc(ptr, 0) only frees the pointer
|
||||
not (
|
||||
exists(target.getReallocPtrArg()) and
|
||||
this.getArgument(target.getSizeArg()).getValue().toInt() = 0
|
||||
) and
|
||||
// these are modeled directly (and more accurately), avoid duplication
|
||||
not exists(NewOrNewArrayExpr new | new.getAllocatorCall() = this)
|
||||
/**
|
||||
* Gets the index of the argument for the allocation size, if any. The actual
|
||||
* allocation size is the value of this argument multiplied by the result of
|
||||
* `getSizeMult()`, in bytes.
|
||||
*/
|
||||
int getSizeArg(Target target);
|
||||
|
||||
/**
|
||||
* Gets the index of an argument that multiplies the allocation size given
|
||||
* by `getSizeArg`, if any.
|
||||
*/
|
||||
int getSizeMult(Target target);
|
||||
|
||||
/**
|
||||
* Holds if this allocation requires a
|
||||
* corresponding deallocation of some sort (most do, but `alloca` for example
|
||||
* does not). If it is unclear, we default to no (for example a placement `new`
|
||||
* allocation may or may not require a corresponding `delete`).
|
||||
*/
|
||||
predicate requiresDealloc(Target target);
|
||||
}
|
||||
|
||||
override Expr getSizeExpr() {
|
||||
exists(Expr sizeExpr | sizeExpr = this.getArgument(target.getSizeArg()) |
|
||||
if exists(target.getSizeMult())
|
||||
then result = sizeExpr
|
||||
else
|
||||
exists(Expr lengthExpr |
|
||||
deconstructSizeExpr(sizeExpr, lengthExpr, _) and
|
||||
result = lengthExpr
|
||||
/**
|
||||
* A module that abstracts over a collection of predicates in
|
||||
* the `Param` module). This should really be member-predicates
|
||||
* on `CallAllocationExprTarget`, but we cannot yet write this in QL.
|
||||
*/
|
||||
module With<Param P> {
|
||||
private import P
|
||||
|
||||
/**
|
||||
* An allocation expression that is a function call, such as call to `malloc`.
|
||||
*/
|
||||
class CallAllocationExprImpl instanceof FunctionCall {
|
||||
Target target;
|
||||
|
||||
CallAllocationExprImpl() {
|
||||
target = this.getTarget() and
|
||||
// realloc(ptr, 0) only frees the pointer
|
||||
not (
|
||||
exists(getReallocPtrArg(target)) and
|
||||
this.getArgument(getSizeArg(target)).getValue().toInt() = 0
|
||||
) and
|
||||
// these are modeled directly (and more accurately), avoid duplication
|
||||
not exists(NewOrNewArrayExpr new | new.getAllocatorCall() = this)
|
||||
}
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
Expr getSizeExprImpl() {
|
||||
exists(Expr sizeExpr | sizeExpr = super.getArgument(getSizeArg(target)) |
|
||||
if exists(getSizeMult(target))
|
||||
then result = sizeExpr
|
||||
else
|
||||
exists(Expr lengthExpr |
|
||||
deconstructSizeExpr(sizeExpr, lengthExpr, _) and
|
||||
result = lengthExpr
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
int getSizeMultImpl() {
|
||||
// malloc with multiplier argument that is a constant
|
||||
result = super.getArgument(getSizeMult(target)).getValue().toInt()
|
||||
or
|
||||
// malloc with no multiplier argument
|
||||
not exists(getSizeMult(target)) and
|
||||
deconstructSizeExpr(super.getArgument(getSizeArg(target)), _, result)
|
||||
}
|
||||
|
||||
int getSizeBytesImpl() {
|
||||
result = this.getSizeExprImpl().getValue().toInt() * this.getSizeMultImpl()
|
||||
}
|
||||
|
||||
Expr getReallocPtrImpl() { result = super.getArgument(getReallocPtrArg(target)) }
|
||||
|
||||
Type getAllocatedElementTypeImpl() {
|
||||
result =
|
||||
super.getFullyConverted().getType().stripTopLevelSpecifiers().(PointerType).getBaseType() and
|
||||
not result instanceof VoidType
|
||||
}
|
||||
|
||||
predicate requiresDeallocImpl() { requiresDealloc(target) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private module CallAllocationExpr {
|
||||
private module Param implements CallAllocationExprBase<AllocationFunction>::Param {
|
||||
int getReallocPtrArg(AllocationFunction f) { result = f.getReallocPtrArg() }
|
||||
|
||||
int getSizeArg(AllocationFunction f) { result = f.getSizeArg() }
|
||||
|
||||
int getSizeMult(AllocationFunction f) { result = f.getSizeMult() }
|
||||
|
||||
predicate requiresDealloc(AllocationFunction f) { f.requiresDealloc() }
|
||||
}
|
||||
|
||||
override int getSizeMult() {
|
||||
// malloc with multiplier argument that is a constant
|
||||
result = this.getArgument(target.getSizeMult()).getValue().toInt()
|
||||
or
|
||||
// malloc with no multiplier argument
|
||||
not exists(target.getSizeMult()) and
|
||||
deconstructSizeExpr(this.getArgument(target.getSizeArg()), _, result)
|
||||
/**
|
||||
* A class that provides the implementation of `AllocationExpr` for an allocation
|
||||
* that calls an `AllocationFunction`.
|
||||
*/
|
||||
private class Base =
|
||||
CallAllocationExprBase<AllocationFunction>::With<Param>::CallAllocationExprImpl;
|
||||
|
||||
class CallAllocationExpr extends AllocationExpr, Base {
|
||||
override Expr getSizeExpr() { result = super.getSizeExprImpl() }
|
||||
|
||||
override int getSizeMult() { result = super.getSizeMultImpl() }
|
||||
|
||||
override Type getAllocatedElementType() { result = super.getAllocatedElementTypeImpl() }
|
||||
|
||||
override predicate requiresDealloc() { super.requiresDeallocImpl() }
|
||||
|
||||
override int getSizeBytes() { result = super.getSizeBytesImpl() }
|
||||
|
||||
override Expr getReallocPtr() { result = super.getReallocPtrImpl() }
|
||||
|
||||
override string toString() { result = AllocationExpr.super.toString() }
|
||||
}
|
||||
|
||||
override int getSizeBytes() {
|
||||
result = this.getSizeExpr().getValue().toInt() * this.getSizeMult()
|
||||
}
|
||||
|
||||
override Expr getReallocPtr() { result = this.getArgument(target.getReallocPtrArg()) }
|
||||
|
||||
override Type getAllocatedElementType() {
|
||||
result =
|
||||
this.getFullyConverted().getType().stripTopLevelSpecifiers().(PointerType).getBaseType() and
|
||||
not result instanceof VoidType
|
||||
}
|
||||
|
||||
override predicate requiresDealloc() { target.requiresDealloc() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -294,3 +386,99 @@ private class NewArrayAllocationExpr extends AllocationExpr, NewArrayExpr {
|
||||
|
||||
override predicate requiresDealloc() { not exists(this.getPlacementPointer()) }
|
||||
}
|
||||
|
||||
private module HeuristicAllocation {
|
||||
/** A class that maps an `AllocationExpr` to an `HeuristicAllocationExpr`. */
|
||||
private class HeuristicAllocationModeled extends HeuristicAllocationExpr instanceof AllocationExpr {
|
||||
override Expr getSizeExpr() { result = AllocationExpr.super.getSizeExpr() }
|
||||
|
||||
override int getSizeMult() { result = AllocationExpr.super.getSizeMult() }
|
||||
|
||||
override int getSizeBytes() { result = AllocationExpr.super.getSizeBytes() }
|
||||
|
||||
override Expr getReallocPtr() { result = AllocationExpr.super.getReallocPtr() }
|
||||
|
||||
override Type getAllocatedElementType() {
|
||||
result = AllocationExpr.super.getAllocatedElementType()
|
||||
}
|
||||
|
||||
override predicate requiresDealloc() { AllocationExpr.super.requiresDealloc() }
|
||||
}
|
||||
|
||||
/** A class that maps an `AllocationFunction` to an `HeuristicAllocationFunction`. */
|
||||
private class HeuristicAllocationFunctionModeled extends HeuristicAllocationFunction instanceof AllocationFunction {
|
||||
override int getSizeArg() { result = AllocationFunction.super.getSizeArg() }
|
||||
|
||||
override int getSizeMult() { result = AllocationFunction.super.getSizeMult() }
|
||||
|
||||
override int getReallocPtrArg() { result = AllocationFunction.super.getReallocPtrArg() }
|
||||
|
||||
override predicate requiresDealloc() { AllocationFunction.super.requiresDealloc() }
|
||||
}
|
||||
|
||||
private int getAnUnsignedParameter(Function f) {
|
||||
f.getParameter(result).getUnspecifiedType().(IntegralType).isUnsigned()
|
||||
}
|
||||
|
||||
private int getAPointerParameter(Function f) {
|
||||
f.getParameter(result).getUnspecifiedType() instanceof PointerType
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that uses heuristics to find additional allocation functions. The required are as follows:
|
||||
* 1. The word `alloc` must appear in the function name
|
||||
* 2. The function must return a pointer type
|
||||
* 3. There must be a unique parameter of unsigned integral type.
|
||||
*/
|
||||
private class HeuristicAllocationFunctionByName extends HeuristicAllocationFunction instanceof Function {
|
||||
int sizeArg;
|
||||
|
||||
HeuristicAllocationFunctionByName() {
|
||||
Function.super.getName().matches("%alloc%") and
|
||||
Function.super.getUnspecifiedType() instanceof PointerType and
|
||||
sizeArg = unique( | | getAnUnsignedParameter(this))
|
||||
}
|
||||
|
||||
override int getSizeArg() { result = sizeArg }
|
||||
|
||||
override int getReallocPtrArg() {
|
||||
Function.super.getName().matches("%realloc%") and
|
||||
result = unique( | | getAPointerParameter(this))
|
||||
}
|
||||
|
||||
override predicate requiresDealloc() { none() }
|
||||
}
|
||||
|
||||
private module Param implements CallAllocationExprBase<HeuristicAllocationFunction>::Param {
|
||||
int getReallocPtrArg(HeuristicAllocationFunction f) { result = f.getReallocPtrArg() }
|
||||
|
||||
int getSizeArg(HeuristicAllocationFunction f) { result = f.getSizeArg() }
|
||||
|
||||
int getSizeMult(HeuristicAllocationFunction f) { result = f.getSizeMult() }
|
||||
|
||||
predicate requiresDealloc(HeuristicAllocationFunction f) { f.requiresDealloc() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that provides the implementation of `AllocationExpr` for an allocation
|
||||
* that calls an `HeuristicAllocationFunction`.
|
||||
*/
|
||||
private class Base =
|
||||
CallAllocationExprBase<HeuristicAllocationFunction>::With<Param>::CallAllocationExprImpl;
|
||||
|
||||
private class CallAllocationExpr extends HeuristicAllocationExpr, Base {
|
||||
override Expr getSizeExpr() { result = super.getSizeExprImpl() }
|
||||
|
||||
override int getSizeMult() { result = super.getSizeMultImpl() }
|
||||
|
||||
override Type getAllocatedElementType() { result = super.getAllocatedElementTypeImpl() }
|
||||
|
||||
override predicate requiresDealloc() { super.requiresDeallocImpl() }
|
||||
|
||||
override int getSizeBytes() { result = super.getSizeBytesImpl() }
|
||||
|
||||
override Expr getReallocPtr() { result = super.getReallocPtrImpl() }
|
||||
|
||||
override string toString() { result = HeuristicAllocationExpr.super.toString() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,3 +113,84 @@ class OperatorNewAllocationFunction extends AllocationFunction {
|
||||
result = 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression that _might_ allocate memory.
|
||||
*
|
||||
* Unlike `AllocationExpr`, this class uses heuristics (such as a call target's
|
||||
* name and parameters) to include additional expressions.
|
||||
*/
|
||||
abstract class HeuristicAllocationExpr extends Expr {
|
||||
/**
|
||||
* Gets an expression for the allocation size, if any. The actual allocation
|
||||
* size is the value of this expression multiplied by the result of
|
||||
* `getSizeMult()`, in bytes.
|
||||
*/
|
||||
Expr getSizeExpr() { none() }
|
||||
|
||||
/**
|
||||
* Gets a constant multiplier for the allocation size given by `getSizeExpr`,
|
||||
* in bytes.
|
||||
*/
|
||||
int getSizeMult() { none() }
|
||||
|
||||
/**
|
||||
* Gets the size of this allocation in bytes, if it is a fixed size and that
|
||||
* size can be determined.
|
||||
*/
|
||||
int getSizeBytes() { none() }
|
||||
|
||||
/**
|
||||
* Gets the expression for the input pointer argument to be reallocated, if
|
||||
* this is a `realloc` function.
|
||||
*/
|
||||
Expr getReallocPtr() { none() }
|
||||
|
||||
/**
|
||||
* Gets the type of the elements that are allocated, if it can be determined.
|
||||
*/
|
||||
Type getAllocatedElementType() { none() }
|
||||
|
||||
/**
|
||||
* Whether or not this allocation requires a corresponding deallocation of
|
||||
* some sort (most do, but `alloca` for example does not). If it is unclear,
|
||||
* we default to no (for example a placement `new` allocation may or may not
|
||||
* require a corresponding `delete`).
|
||||
*/
|
||||
predicate requiresDealloc() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An function that _might_ allocate memory.
|
||||
*
|
||||
* Unlike `AllocationFunction`, this class uses heuristics (such as the function's
|
||||
* name and its parameters) to include additional functions.
|
||||
*/
|
||||
abstract class HeuristicAllocationFunction extends Function {
|
||||
/**
|
||||
* Gets the index of the argument for the allocation size, if any. The actual
|
||||
* allocation size is the value of this argument multiplied by the result of
|
||||
* `getSizeMult()`, in bytes.
|
||||
*/
|
||||
int getSizeArg() { none() }
|
||||
|
||||
/**
|
||||
* Gets the index of an argument that multiplies the allocation size given by
|
||||
* `getSizeArg`, if any.
|
||||
*/
|
||||
int getSizeMult() { none() }
|
||||
|
||||
/**
|
||||
* Gets the index of the input pointer argument to be reallocated, if this
|
||||
* is a `realloc` function.
|
||||
*/
|
||||
int getReallocPtrArg() { none() }
|
||||
|
||||
/**
|
||||
* Whether or not this allocation requires a corresponding deallocation of
|
||||
* some sort (most do, but `alloca` for example does not). If it is unclear,
|
||||
* we default to no (for example a placement `new` allocation may or may not
|
||||
* require a corresponding `delete`).
|
||||
*/
|
||||
predicate requiresDealloc() { any() }
|
||||
}
|
||||
|
||||
@@ -15,4 +15,4 @@ where
|
||||
c.fromSource() and
|
||||
c.isTopLevel() and
|
||||
c.getParentScope() instanceof GlobalNamespace
|
||||
select c, "This class is not declared in any namespace"
|
||||
select c, "This class is not declared in any namespace."
|
||||
|
||||
@@ -16,4 +16,4 @@ where
|
||||
t.fromSource() and
|
||||
n = t.getMetrics().getEfferentSourceCoupling() and
|
||||
n > 10
|
||||
select t as class_, "This class has too many dependencies (" + n.toString() + ")"
|
||||
select t as class_, "This class has too many dependencies (" + n.toString() + ")."
|
||||
|
||||
@@ -17,4 +17,4 @@ where
|
||||
n = f.getMetrics().getNumberOfCalls() and
|
||||
n > 99 and
|
||||
not f.isMultiplyDefined()
|
||||
select f as function, "This function makes too many calls (" + n.toString() + ")"
|
||||
select f as function, "This function makes too many calls (" + n.toString() + ")."
|
||||
|
||||
@@ -18,4 +18,4 @@ where
|
||||
f.getMetrics().getNumberOfParameters() > 15
|
||||
select f,
|
||||
"This function has too many parameters (" + f.getMetrics().getNumberOfParameters().toString() +
|
||||
")"
|
||||
")."
|
||||
|
||||
@@ -35,4 +35,4 @@ from LocalVariableOrParameter lv, GlobalVariable gv
|
||||
where
|
||||
lv.getName() = gv.getName() and
|
||||
lv.getFile() = gv.getFile()
|
||||
select lv, lv.type() + gv.getName() + " hides $@ with the same name.", gv, "a global variable"
|
||||
select lv, lv.type() + gv.getName() + " hides a $@ with the same name.", gv, "global variable"
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* In this example, the developer intended to use a semicolon but accidentally used a comma:
|
||||
*/
|
||||
|
||||
enum privileges entitlements = NONE;
|
||||
|
||||
if (is_admin)
|
||||
entitlements = FULL, // BAD
|
||||
|
||||
restrict_privileges(entitlements);
|
||||
|
||||
/*
|
||||
* The use of a comma means that the first example is equivalent to this second example:
|
||||
*/
|
||||
|
||||
enum privileges entitlements = NONE;
|
||||
|
||||
if (is_admin) {
|
||||
entitlements = FULL;
|
||||
restrict_privileges(entitlements);
|
||||
}
|
||||
|
||||
/*
|
||||
* The indentation of the first example suggests that the developer probably intended the following code:
|
||||
*/
|
||||
|
||||
enum privileges entitlements = NONE;
|
||||
|
||||
if (is_admin)
|
||||
entitlements = FULL; // GOOD
|
||||
|
||||
restrict_privileges(entitlements);
|
||||
@@ -0,0 +1,39 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
If the expression after the comma operator starts at an earlier column than the expression before the comma, then
|
||||
this suspicious indentation possibly indicates a logic error, caused by a typo that may escape visual inspection.
|
||||
</p>
|
||||
<warning>
|
||||
This query has medium precision because CodeQL currently does not distinguish between tabs and spaces in whitespace.
|
||||
If a file contains mixed tabs and spaces, alerts may highlight code that is correctly indented for one value of tab size but not for other tab sizes.
|
||||
</warning>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
To ensure that your code is easy to read and review, use standard indentation around the comma operator. Always begin the right-hand-side operand at the same level of
|
||||
indentation (column number) as the left-hand-side operand. This makes it easier for other developers to see the intended behavior of your code.
|
||||
</p>
|
||||
<p>
|
||||
Use whitespace consistently to communicate your coding intentions. Where possible, avoid mixing tabs and spaces within a file. If you need to mix them, use them consistently.
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
This example shows three different ways of writing the same code. The first example contains a comma instead of a semicolon which means that the final line is part of the <code>if</code> statement, even though the indentation suggests that it is intended to be separate. The second example looks different but is functionally the same as the first example. It is more likely that the developer intended to write the third example.
|
||||
</p>
|
||||
<sample src="CommaBeforeMisleadingIndentation.cpp" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>Wikipedia: <a href="https://en.wikipedia.org/wiki/Comma_operator">Comma operator</a></li>
|
||||
<li>Wikipedia: <a href="https://en.wikipedia.org/wiki/Indentation_style#Tabs,_spaces,_and_size_of_indentations">Indentation style — Tabs, spaces, and size of indentations</a></li>
|
||||
</references>
|
||||
|
||||
</qhelp>
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* @name Comma before misleading indentation
|
||||
* @description If expressions before and after a comma operator use different indentation, it is easy to misread the purpose of the code.
|
||||
* @kind problem
|
||||
* @id cpp/comma-before-misleading-indentation
|
||||
* @problem.severity warning
|
||||
* @security-severity 7.8
|
||||
* @precision medium
|
||||
* @tags maintainability
|
||||
* readability
|
||||
* security
|
||||
* external/cwe/cwe-1078
|
||||
* external/cwe/cwe-670
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.commons.Exclusions
|
||||
|
||||
/** Gets the sub-expression of 'e' with the earliest-starting Location */
|
||||
Expr normalizeExpr(Expr e) {
|
||||
result =
|
||||
min(Expr child |
|
||||
child.getParentWithConversions*() = e.getFullyConverted() and
|
||||
not child.getParentWithConversions*() = any(Call c).getAnArgument()
|
||||
|
|
||||
child order by child.getLocation().getStartColumn(), count(child.getParentWithConversions*())
|
||||
)
|
||||
}
|
||||
|
||||
predicate isParenthesized(CommaExpr ce) {
|
||||
ce.getParent*().(Expr).isParenthesised()
|
||||
or
|
||||
ce.isUnevaluated() // sizeof(), decltype(), alignof(), noexcept(), typeid()
|
||||
or
|
||||
ce.getParent*() = [any(IfStmt i).getCondition(), any(SwitchStmt s).getExpr()]
|
||||
or
|
||||
ce.getParent*() = [any(Loop l).getCondition(), any(ForStmt f).getUpdate()]
|
||||
or
|
||||
ce.getEnclosingStmt() = any(ForStmt f).getInitialization()
|
||||
}
|
||||
|
||||
from CommaExpr ce, Expr left, Expr right, Location leftLoc, Location rightLoc
|
||||
where
|
||||
ce.fromSource() and
|
||||
not isFromMacroDefinition(ce) and
|
||||
left = normalizeExpr(ce.getLeftOperand()) and
|
||||
right = normalizeExpr(ce.getRightOperand()) and
|
||||
leftLoc = left.getLocation() and
|
||||
rightLoc = right.getLocation() and
|
||||
not isParenthesized(ce) and
|
||||
leftLoc.getEndLine() < rightLoc.getStartLine() and
|
||||
leftLoc.getStartColumn() > rightLoc.getStartColumn()
|
||||
select right, "The indentation level may be misleading for some tab sizes."
|
||||
@@ -21,5 +21,5 @@ where
|
||||
rhsType.getAMember() = m and
|
||||
not m.(VirtualFunction).isPure()
|
||||
) // add additional checks for concrete members in in-between supertypes
|
||||
select e, "This assignment expression slices from type $@ to $@", rhsType, rhsType.getName(),
|
||||
select e, "This assignment expression slices from type $@ to $@.", rhsType, rhsType.getName(),
|
||||
lhsType, lhsType.getName()
|
||||
|
||||
@@ -72,18 +72,6 @@ predicate floatTrivial(Literal lit) {
|
||||
|
||||
predicate charLiteral(Literal lit) { lit instanceof CharLiteral }
|
||||
|
||||
Type literalType(Literal literal) { result = literal.getType() }
|
||||
|
||||
predicate stringType(DerivedType t) {
|
||||
t.getBaseType() instanceof CharType
|
||||
or
|
||||
exists(SpecifiedType constCharType |
|
||||
t.getBaseType() = constCharType and
|
||||
constCharType.isConst() and
|
||||
constCharType.getBaseType() instanceof CharType
|
||||
)
|
||||
}
|
||||
|
||||
predicate numberType(Type t) { t instanceof FloatingPointType or t instanceof IntegralType }
|
||||
|
||||
predicate stringLiteral(Literal literal) { literal instanceof StringLiteral }
|
||||
|
||||
@@ -18,4 +18,4 @@ where
|
||||
f.hasSpecifier("virtual") and
|
||||
f.getFile().fromSource() and
|
||||
not f instanceof Destructor
|
||||
select f, "Avoid having public virtual methods (NVI idiom)"
|
||||
select f, "Avoid having public virtual methods (NVI idiom)."
|
||||
|
||||
@@ -23,4 +23,4 @@ where
|
||||
fclass = f.getDeclaringType() and
|
||||
hubIndex = fclass.getMetrics().getAfferentCoupling() * fclass.getMetrics().getEfferentCoupling() and
|
||||
hubIndex > 100
|
||||
select f, "Avoid having public virtual methods (NVI idiom)"
|
||||
select f, "Avoid having public virtual methods (NVI idiom)."
|
||||
|
||||
@@ -38,5 +38,5 @@ where
|
||||
sc = switch.getASwitchCase() and
|
||||
tooLong(sc) and
|
||||
switchCaseLength(sc, lines)
|
||||
select switch, "Switch has at least one case that is too long: $@", sc,
|
||||
select switch, "Switch has at least one case that is too long: $@.", sc,
|
||||
sc.getExpr().toString() + " (" + lines.toString() + " lines)"
|
||||
|
||||
@@ -58,4 +58,4 @@ where
|
||||
not exists(AsmStmt s | f = s.getEnclosingFunction()) and
|
||||
not v.getAnAttribute().getName() = "unused" and
|
||||
not any(ErrorExpr e).getEnclosingFunction() = f // unextracted expr may use `v`
|
||||
select v, "Variable " + v.getName() + " is not used"
|
||||
select v, "Variable " + v.getName() + " is not used."
|
||||
|
||||
@@ -11,7 +11,7 @@ caused by an unhandled case.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>Check that the unused static variable does not indicate a defect, for example, an unhandled case. If the static variable is genuinuely not needed,
|
||||
<p>Check that the unused static variable does not indicate a defect, for example, an unhandled case. If the static variable is genuinely not needed,
|
||||
then removing it will make code more readable. If the static variable is needed then you should update the code to fix the defect.</p>
|
||||
|
||||
</recommendation>
|
||||
|
||||
@@ -27,4 +27,4 @@ where
|
||||
not declarationHasSideEffects(v) and
|
||||
not v.getAnAttribute().hasName("used") and
|
||||
not v.getAnAttribute().hasName("unused")
|
||||
select v, "Static variable " + v.getName() + " is never read"
|
||||
select v, "Static variable " + v.getName() + " is never read."
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
## 0.4.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The alert message of many queries have been changed to better follow the style guide and make the message consistent with other languages.
|
||||
|
||||
## 0.4.0
|
||||
|
||||
### New Queries
|
||||
|
||||
* Added a new medium-precision query, `cpp/missing-check-scanf`, which detects `scanf` output variables that are used without a proper return-value check to see that they were actually written. A variation of this query was originally contributed as an [experimental query by @ihsinme](https://github.com/github/codeql/pull/8246).
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Modernizations from "Cleartext storage of sensitive information in buffer" (`cpp/cleartext-storage-buffer`) have been ported to the "Cleartext storage of sensitive information in file" (`cpp/cleartext-storage-file`), "Cleartext transmission of sensitive information" (`cpp/cleartext-transmission`) and "Cleartext storage of sensitive information in an SQLite database" (`cpp/cleartext-storage-database`) queries. These changes may result in more correct results and fewer false positive results from these queries.
|
||||
* The alert message of many queries have been changed to make the message consistent with other languages.
|
||||
|
||||
## 0.3.4
|
||||
|
||||
## 0.3.3
|
||||
|
||||
@@ -64,5 +64,5 @@ where
|
||||
) and
|
||||
(if context = test then testresult = "succeed" else testresult = "fail")
|
||||
select cond,
|
||||
"Variable '" + v.getName() + "' is always " + context + " here, this check will always " +
|
||||
testresult + "."
|
||||
"Variable '" + v.getName() + "' is always " + context + ", this check will always " + testresult +
|
||||
"."
|
||||
|
||||
@@ -19,7 +19,7 @@ This can occur when an operation performed on the open descriptor fails, and the
|
||||
|
||||
<example>
|
||||
<p>In the example below, the <code>sockfd</code> socket may remain open if an error is triggered.
|
||||
The code should be updated to ensure that the socket is always closed when when the function ends.
|
||||
The code should be updated to ensure that the socket is always closed when the function ends.
|
||||
</p>
|
||||
<sample src="DescriptorMayNotBeClosed.cpp" />
|
||||
</example>
|
||||
|
||||
@@ -29,4 +29,4 @@ from Expr alloc
|
||||
where
|
||||
allocateDescriptorCall(alloc) and
|
||||
not exists(ClosedExpr closed | closed.pointsTo() = alloc)
|
||||
select alloc, "This file descriptor is never closed"
|
||||
select alloc, "This file descriptor is never closed."
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user