mirror of
https://github.com/github/codeql.git
synced 2026-07-05 03:25:31 +02:00
Compare commits
578 Commits
codeql-cli
...
structured
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca5e0cf378 | ||
|
|
844fc617aa | ||
|
|
2b91dfb908 | ||
|
|
dc2eada781 | ||
|
|
db5cc73754 | ||
|
|
10d26d4f9d | ||
|
|
ad8d9c5b91 | ||
|
|
aac65b0df0 | ||
|
|
b5ebd1a0fd | ||
|
|
814bef021d | ||
|
|
c462e010d1 | ||
|
|
9b117fefd7 | ||
|
|
a5bb336647 | ||
|
|
87c0b6195f | ||
|
|
3038543242 | ||
|
|
779c2365fe | ||
|
|
e19e28fbb9 | ||
|
|
6894803b14 | ||
|
|
31967cc032 | ||
|
|
389b7ceff5 | ||
|
|
f6fdf45359 | ||
|
|
690b5debf4 | ||
|
|
dd7f54677b | ||
|
|
1fb27354b9 | ||
|
|
774030a8db | ||
|
|
52dd1f451c | ||
|
|
b66ed57e17 | ||
|
|
9e97877938 | ||
|
|
d9f2d348f4 | ||
|
|
658cc33bb8 | ||
|
|
6cec8ece3f | ||
|
|
9aea725f3d | ||
|
|
49be5fd19a | ||
|
|
879eff41ea | ||
|
|
efc75e02cc | ||
|
|
4e07fd3eb1 | ||
|
|
89aec093c8 | ||
|
|
cd823d7495 | ||
|
|
52a9d5379b | ||
|
|
db9a0d1c52 | ||
|
|
6f8ae703ca | ||
|
|
1a308316c6 | ||
|
|
fcff18aa3c | ||
|
|
4f97c0470b | ||
|
|
655aa700bc | ||
|
|
f72cb5f650 | ||
|
|
7a9bbb1414 | ||
|
|
c7da1c9e0d | ||
|
|
be468fe122 | ||
|
|
4e86edf4fe | ||
|
|
4d1608aafa | ||
|
|
5d125572ec | ||
|
|
cef6765890 | ||
|
|
c72a5d5dc0 | ||
|
|
7205f30803 | ||
|
|
e400a1ad77 | ||
|
|
a9f1436930 | ||
|
|
5929c99eb1 | ||
|
|
71c8bb20f9 | ||
|
|
3e5534f0ba | ||
|
|
9f4f7a76c9 | ||
|
|
2cfd6c5597 | ||
|
|
35a53fa990 | ||
|
|
94467e638e | ||
|
|
59efcd593a | ||
|
|
0bceefc930 | ||
|
|
87cb3fd59f | ||
|
|
c167919ff6 | ||
|
|
db748fae6b | ||
|
|
59c1cfb43a | ||
|
|
0e0ec89e60 | ||
|
|
d3e73891b5 | ||
|
|
37fc8f5039 | ||
|
|
18c6b68232 | ||
|
|
e9bce9f8cd | ||
|
|
85e4707e0c | ||
|
|
4356d359a6 | ||
|
|
d1cd4cd099 | ||
|
|
39e7bba563 | ||
|
|
2f8dddabb6 | ||
|
|
2f6ffdd88f | ||
|
|
6fc5bdd871 | ||
|
|
b87de911ba | ||
|
|
3971dedcf6 | ||
|
|
c0b8e852c5 | ||
|
|
2d46dd2936 | ||
|
|
ff9e738d38 | ||
|
|
a894fc6ce8 | ||
|
|
f64cb2983a | ||
|
|
8eb8daa4d4 | ||
|
|
300db4f236 | ||
|
|
cb11524dde | ||
|
|
2b529fbf53 | ||
|
|
35b60167e1 | ||
|
|
94fd412809 | ||
|
|
767da59397 | ||
|
|
f50382ba70 | ||
|
|
45d00ae9dd | ||
|
|
44dc5a1f0b | ||
|
|
7cfe15c304 | ||
|
|
9ed021ad66 | ||
|
|
b4d59ff932 | ||
|
|
b0315119c6 | ||
|
|
430b432add | ||
|
|
eab3c6dd5e | ||
|
|
e28be5d98f | ||
|
|
75c75ea49c | ||
|
|
3ec2a3c711 | ||
|
|
3b1b3b46ae | ||
|
|
29c8260004 | ||
|
|
766e6c400e | ||
|
|
80f5342a6d | ||
|
|
87b54e674e | ||
|
|
9db1366e4b | ||
|
|
f1adb4319a | ||
|
|
e2d7a6910c | ||
|
|
180246b99c | ||
|
|
f3124d3239 | ||
|
|
2f1bd93a49 | ||
|
|
2f576a4fe9 | ||
|
|
45c1537f06 | ||
|
|
ee5382d8a6 | ||
|
|
3ce7fafb67 | ||
|
|
14655e1d8c | ||
|
|
261a1348f0 | ||
|
|
c65fd69374 | ||
|
|
233bd8ce8c | ||
|
|
7e7850374e | ||
|
|
d9e5c6c48a | ||
|
|
74782bf6a2 | ||
|
|
7d2b78b463 | ||
|
|
801ed1ce7c | ||
|
|
95a131d0d3 | ||
|
|
8ee36a5278 | ||
|
|
c72dbc49fc | ||
|
|
7e16fa9cbe | ||
|
|
220f227707 | ||
|
|
66c3529465 | ||
|
|
df6039d6cf | ||
|
|
e1ae3c3cfb | ||
|
|
368ca6cb30 | ||
|
|
2cd1e09a7e | ||
|
|
5f0b1973ee | ||
|
|
4be2e431ea | ||
|
|
b52df0de0c | ||
|
|
fb14920281 | ||
|
|
5f07d1f385 | ||
|
|
194316d1c0 | ||
|
|
d075e016b2 | ||
|
|
9e584eb241 | ||
|
|
62d10f91d8 | ||
|
|
d5f7ef08b7 | ||
|
|
7f76d8ae55 | ||
|
|
82a2f4349a | ||
|
|
f48d87ba55 | ||
|
|
3514dd1e4d | ||
|
|
029e1d47fe | ||
|
|
e40bb6ac87 | ||
|
|
1b30043422 | ||
|
|
4644a88b89 | ||
|
|
4f7c598ffc | ||
|
|
2f8c9a5a2c | ||
|
|
e3e2df3247 | ||
|
|
39516862c1 | ||
|
|
028fcc7edf | ||
|
|
a498936f16 | ||
|
|
bca3fa94fd | ||
|
|
469b289db9 | ||
|
|
b3c234d020 | ||
|
|
238a70fc55 | ||
|
|
b7123aaa89 | ||
|
|
dc5bb4fb77 | ||
|
|
f68083872d | ||
|
|
81de500301 | ||
|
|
0600a2ba96 | ||
|
|
935e22d10d | ||
|
|
8e079320f3 | ||
|
|
781aab3eb7 | ||
|
|
b0c8992eef | ||
|
|
cfe169a4f9 | ||
|
|
4140598769 | ||
|
|
c17d057520 | ||
|
|
0b722bfe30 | ||
|
|
68656274f4 | ||
|
|
e4c8387815 | ||
|
|
1c57aa0456 | ||
|
|
8372ad9d84 | ||
|
|
2113c3c3d9 | ||
|
|
29ce9bfe24 | ||
|
|
97f79602a9 | ||
|
|
1c7fe97427 | ||
|
|
df22181963 | ||
|
|
6192544fb4 | ||
|
|
1c3d4b98c8 | ||
|
|
191613e8bf | ||
|
|
4fa484dad2 | ||
|
|
39e50f745d | ||
|
|
b3602a5b7f | ||
|
|
c66a44f2e2 | ||
|
|
e877b161d8 | ||
|
|
7ebe472cfe | ||
|
|
37d3793e87 | ||
|
|
1f1e2dbf98 | ||
|
|
3ee3acd8fd | ||
|
|
e635140eae | ||
|
|
f2c541a461 | ||
|
|
f062a8d204 | ||
|
|
947a9f12a1 | ||
|
|
11204987f1 | ||
|
|
34c6b24882 | ||
|
|
457a2bb2a2 | ||
|
|
ac54caac35 | ||
|
|
426425a7ca | ||
|
|
0537579b28 | ||
|
|
2f404df17c | ||
|
|
b85bfc8ba6 | ||
|
|
c258e44772 | ||
|
|
26d5fb2412 | ||
|
|
74472d786c | ||
|
|
634087b417 | ||
|
|
2ce6d5f920 | ||
|
|
5235964b07 | ||
|
|
b2e79e2948 | ||
|
|
f07c598a22 | ||
|
|
80628596dd | ||
|
|
124e4ddd4f | ||
|
|
0b8173e2e7 | ||
|
|
55aacd6fe9 | ||
|
|
483a87abe9 | ||
|
|
4fad01a739 | ||
|
|
f3e0b6e62c | ||
|
|
422eb0d1bb | ||
|
|
5555b5cd19 | ||
|
|
542c9218de | ||
|
|
f7a5a33474 | ||
|
|
91393a7bc8 | ||
|
|
6474cfd4c8 | ||
|
|
ad8849c6b8 | ||
|
|
676e4e8461 | ||
|
|
d7af80136e | ||
|
|
518684b736 | ||
|
|
80d4fb5e33 | ||
|
|
ce1c814daa | ||
|
|
c87c3e30c7 | ||
|
|
685b8b4abd | ||
|
|
7042f67375 | ||
|
|
778826b528 | ||
|
|
202c0be303 | ||
|
|
eed19a3e15 | ||
|
|
ad85b37585 | ||
|
|
d0efbbf5b8 | ||
|
|
82f09b8511 | ||
|
|
679f02c274 | ||
|
|
8624098318 | ||
|
|
d55e9d5dac | ||
|
|
eda331ebc2 | ||
|
|
11f022c69f | ||
|
|
15b8aa1979 | ||
|
|
6cb9198ee2 | ||
|
|
9d433eb420 | ||
|
|
db41463d72 | ||
|
|
38f4f65fc0 | ||
|
|
1bd223b8c8 | ||
|
|
fc7c72db77 | ||
|
|
adf47b9a9c | ||
|
|
c92fd97783 | ||
|
|
224bc9381a | ||
|
|
8d8ebeade1 | ||
|
|
7fa85b34ea | ||
|
|
09df055d86 | ||
|
|
b04d5684fb | ||
|
|
770f3c24bb | ||
|
|
16ef50401b | ||
|
|
968f588893 | ||
|
|
1e279125dc | ||
|
|
0f469ee0f7 | ||
|
|
07947e6528 | ||
|
|
80a397b4a5 | ||
|
|
d4985a99e0 | ||
|
|
59ab353827 | ||
|
|
54b45134ef | ||
|
|
c00b089aa8 | ||
|
|
955f23d021 | ||
|
|
dd6ceb7053 | ||
|
|
7e174dce8b | ||
|
|
89bebe9d36 | ||
|
|
ad4ae1c331 | ||
|
|
70a6ff84af | ||
|
|
0f6b05dedf | ||
|
|
b895065be9 | ||
|
|
3e2bf23bfe | ||
|
|
bd98ae0dcc | ||
|
|
f2904ca29b | ||
|
|
5e2f9e1568 | ||
|
|
f113eaa77d | ||
|
|
4196230a8a | ||
|
|
9e285020a1 | ||
|
|
46d49cd66f | ||
|
|
f6a02310d3 | ||
|
|
18335854b6 | ||
|
|
3ebac65167 | ||
|
|
13c7c8449c | ||
|
|
78ad9d67b4 | ||
|
|
844e372651 | ||
|
|
069c9674d1 | ||
|
|
6255298876 | ||
|
|
99bed0b089 | ||
|
|
02364d072e | ||
|
|
764155ce97 | ||
|
|
3abf321071 | ||
|
|
931c683146 | ||
|
|
eb564760be | ||
|
|
7f09684577 | ||
|
|
f8dbbe006e | ||
|
|
c427f8fc95 | ||
|
|
6e9484970f | ||
|
|
e972cb069e | ||
|
|
4f76ebbb0b | ||
|
|
30b2644f17 | ||
|
|
99d3f689dc | ||
|
|
15b293c56d | ||
|
|
60e7d6b540 | ||
|
|
7cb665cde1 | ||
|
|
d17c7bb0e8 | ||
|
|
3586926157 | ||
|
|
080ce09bd7 | ||
|
|
8dea993f41 | ||
|
|
49a3dd6131 | ||
|
|
334c41c3e1 | ||
|
|
b69d8625e5 | ||
|
|
f9f08fff83 | ||
|
|
8e8897b08b | ||
|
|
10534b62c9 | ||
|
|
80a503b65d | ||
|
|
1980e25ac9 | ||
|
|
3448cde048 | ||
|
|
712c25e6f4 | ||
|
|
522a892d32 | ||
|
|
746f04bafc | ||
|
|
984729f9b0 | ||
|
|
ff29356ae9 | ||
|
|
c9397a5abf | ||
|
|
642a138eaa | ||
|
|
d8616e77d5 | ||
|
|
a3b443c310 | ||
|
|
ad04a408c7 | ||
|
|
50889b8fa1 | ||
|
|
c0e3186607 | ||
|
|
d201c1eadd | ||
|
|
a244b825df | ||
|
|
3c580896dc | ||
|
|
43ce26e4d0 | ||
|
|
a4c3ea2efc | ||
|
|
1c35109675 | ||
|
|
868f07bc91 | ||
|
|
996536b08e | ||
|
|
4016299aa8 | ||
|
|
4eebeab8a8 | ||
|
|
1c9a526afa | ||
|
|
9364a85e49 | ||
|
|
9360ae9638 | ||
|
|
b4607d3fab | ||
|
|
dc59ed08f9 | ||
|
|
cd2fc6566f | ||
|
|
00fe448e3a | ||
|
|
f32fa25c1a | ||
|
|
e382d6d000 | ||
|
|
ec46f33a01 | ||
|
|
f391948b53 | ||
|
|
4af0c4bb03 | ||
|
|
3c15fd266d | ||
|
|
edbba85b96 | ||
|
|
e390ca50b0 | ||
|
|
90c51ef404 | ||
|
|
c554a10e06 | ||
|
|
f7a2a8677a | ||
|
|
6c0d2bdee1 | ||
|
|
25f907867b | ||
|
|
abe38373da | ||
|
|
c252ec0414 | ||
|
|
e05bce9863 | ||
|
|
314ecab90a | ||
|
|
85a339030b | ||
|
|
199c8641ec | ||
|
|
f648b021a9 | ||
|
|
bd6c167be6 | ||
|
|
f866e16679 | ||
|
|
5ab6056b26 | ||
|
|
3f446bc76e | ||
|
|
07041bb659 | ||
|
|
416ed57583 | ||
|
|
f321adf9f4 | ||
|
|
10109b4925 | ||
|
|
49ce91fd5b | ||
|
|
7e9617f3ce | ||
|
|
c03fe70b8d | ||
|
|
9ed7836367 | ||
|
|
33e8414fc4 | ||
|
|
ec82d61991 | ||
|
|
03385ac0b5 | ||
|
|
8cefde36bf | ||
|
|
f8b574c654 | ||
|
|
02b09ca9f7 | ||
|
|
cfb3bc9dce | ||
|
|
0711326619 | ||
|
|
dbbef0534b | ||
|
|
b5d98d9011 | ||
|
|
6c816d5602 | ||
|
|
58d7af4018 | ||
|
|
7642245747 | ||
|
|
2d7e71dfce | ||
|
|
57f40ccd48 | ||
|
|
23c7bc8143 | ||
|
|
b6805c6913 | ||
|
|
364c173fc3 | ||
|
|
1f69fff26c | ||
|
|
f82a548cf9 | ||
|
|
c666f9c845 | ||
|
|
ec72c7504c | ||
|
|
e357b44943 | ||
|
|
4bb0bbf488 | ||
|
|
e230951a14 | ||
|
|
41f7c7ae53 | ||
|
|
04d5b7e579 | ||
|
|
4b198f9af8 | ||
|
|
844193d065 | ||
|
|
1d0e80c2f5 | ||
|
|
3002230af9 | ||
|
|
1ec2c2591b | ||
|
|
2f637e2c8e | ||
|
|
c517eb89b2 | ||
|
|
73112e401c | ||
|
|
7d8b624a71 | ||
|
|
a354e776bf | ||
|
|
20dc30d7e8 | ||
|
|
a639f13fd9 | ||
|
|
6b3d458865 | ||
|
|
c7637a7e1f | ||
|
|
2d6d8aaa74 | ||
|
|
a1aeb995e6 | ||
|
|
e8dbd65d77 | ||
|
|
a0cf8e786c | ||
|
|
7140b956e8 | ||
|
|
f90c5346bf | ||
|
|
38eeb9c747 | ||
|
|
1077dcd2e3 | ||
|
|
b8bd98e476 | ||
|
|
142ca0c9fb | ||
|
|
d888510688 | ||
|
|
d25de8c764 | ||
|
|
e552a6206d | ||
|
|
21abe54d8d | ||
|
|
09fdf744d4 | ||
|
|
bf6ef43451 | ||
|
|
3545bb0819 | ||
|
|
4e7ca1a175 | ||
|
|
808d3e3a1f | ||
|
|
50bd0707ce | ||
|
|
3a9d650cb9 | ||
|
|
56e0b19df8 | ||
|
|
8cb022713e | ||
|
|
9a4cec7691 | ||
|
|
13242df149 | ||
|
|
dd31be43e0 | ||
|
|
faf21f3edb | ||
|
|
6e712b293a | ||
|
|
30b1a2edbc | ||
|
|
61a8f5e425 | ||
|
|
34266cfa4c | ||
|
|
a0150849cb | ||
|
|
1a8c9abee2 | ||
|
|
52959d7c0a | ||
|
|
c8cfb6a0cc | ||
|
|
55cd436b06 | ||
|
|
1542353af7 | ||
|
|
2576a09af9 | ||
|
|
a3a01ddc11 | ||
|
|
ab184ebd78 | ||
|
|
21b4931fbb | ||
|
|
231110ddca | ||
|
|
65863f1fc7 | ||
|
|
1472d4b782 | ||
|
|
67d4ed53b9 | ||
|
|
8cb233df1a | ||
|
|
77283be6c0 | ||
|
|
960f776e29 | ||
|
|
4282e1a18e | ||
|
|
2b719d503d | ||
|
|
ae10a6beb0 | ||
|
|
ad5dbe18a4 | ||
|
|
50e5b29eb7 | ||
|
|
ce2e7f1d12 | ||
|
|
d230431006 | ||
|
|
6895c113cf | ||
|
|
87f7bc3a63 | ||
|
|
470e4b64ea | ||
|
|
787fe38d90 | ||
|
|
dc5eb40d5f | ||
|
|
d6f1dfa205 | ||
|
|
c5deb8544b | ||
|
|
4d6b35f891 | ||
|
|
70a151af02 | ||
|
|
a3188f2e10 | ||
|
|
3502ab6523 | ||
|
|
afa6b1cec5 | ||
|
|
a46061541b | ||
|
|
fa81d9da18 | ||
|
|
57012714d6 | ||
|
|
d944c2bd79 | ||
|
|
31743afa87 | ||
|
|
e01002368f | ||
|
|
907ebb723e | ||
|
|
7079def7ce | ||
|
|
0707064ab5 | ||
|
|
a4aaf0ec6f | ||
|
|
0e2f37825d | ||
|
|
ee213123ac | ||
|
|
0b27b1314a | ||
|
|
7a126a2317 | ||
|
|
8ef2aa00e7 | ||
|
|
207ed3da9c | ||
|
|
18d8bbc9a4 | ||
|
|
e41042418a | ||
|
|
5f0bf1053a | ||
|
|
bca053f855 | ||
|
|
998f1bf215 | ||
|
|
5993b60980 | ||
|
|
1a211485a4 | ||
|
|
51b11de44a | ||
|
|
54cc4d6498 | ||
|
|
aaa0040612 | ||
|
|
9464940214 | ||
|
|
2e4cb63049 | ||
|
|
f867c9008f | ||
|
|
9b5b0c60b8 | ||
|
|
22af6f5182 | ||
|
|
2d38993075 | ||
|
|
0ed480855a | ||
|
|
10d6ebf95b | ||
|
|
b5a6f6e165 | ||
|
|
80d05c0425 | ||
|
|
a017b7500b | ||
|
|
49f5e89f36 | ||
|
|
3cece50f78 | ||
|
|
be8ef1b324 | ||
|
|
2b9bc3c7e3 | ||
|
|
d5e60dfb22 | ||
|
|
e85e61b6d7 | ||
|
|
c725c447ac | ||
|
|
faae811be7 | ||
|
|
65aa064838 | ||
|
|
d67e756f42 | ||
|
|
4376870a51 | ||
|
|
de2e92d5e1 | ||
|
|
fb5b6eab19 | ||
|
|
54109b8ea7 | ||
|
|
2f68b54b27 | ||
|
|
b19452467d | ||
|
|
eff132512c | ||
|
|
545aab0e07 | ||
|
|
9336f4f1a2 | ||
|
|
2801b8495a | ||
|
|
4896e62117 | ||
|
|
58570b4d2c | ||
|
|
9a60202de6 | ||
|
|
c22c0b5029 | ||
|
|
a5849eb9b0 | ||
|
|
054c06be65 | ||
|
|
68fd75ca34 | ||
|
|
2ad28ab4db | ||
|
|
65c9a7b278 | ||
|
|
c1f0940b6a | ||
|
|
5609d5200b | ||
|
|
9499961a9c | ||
|
|
d489c12014 | ||
|
|
475e36e6fc | ||
|
|
df1ea5b679 | ||
|
|
5a9061e45b |
111
.github/actions/cache-query-compilation/action.yml
vendored
111
.github/actions/cache-query-compilation/action.yml
vendored
@@ -9,7 +9,7 @@ inputs:
|
|||||||
outputs:
|
outputs:
|
||||||
cache-dir:
|
cache-dir:
|
||||||
description: "The directory where the cache was stored"
|
description: "The directory where the cache was stored"
|
||||||
value: ${{ steps.fill-compilation-dir.outputs.compdir }}
|
value: ${{ steps.output-compilation-dir.outputs.compdir }}
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: composite
|
using: composite
|
||||||
@@ -27,7 +27,9 @@ runs:
|
|||||||
if: ${{ github.event_name == 'pull_request' }}
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v3
|
||||||
with:
|
with:
|
||||||
path: '**/.cache'
|
path: |
|
||||||
|
**/.cache
|
||||||
|
~/.codeql/compile-cache
|
||||||
key: codeql-compile-${{ inputs.key }}-pr-${{ github.sha }}
|
key: codeql-compile-${{ inputs.key }}-pr-${{ github.sha }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
codeql-compile-${{ inputs.key }}-${{ github.base_ref }}-${{ env.merge_base }}
|
codeql-compile-${{ inputs.key }}-${{ github.base_ref }}-${{ env.merge_base }}
|
||||||
@@ -37,18 +39,111 @@ runs:
|
|||||||
if: ${{ github.event_name != 'pull_request' }}
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: '**/.cache'
|
path: |
|
||||||
|
**/.cache
|
||||||
|
~/.codeql/compile-cache
|
||||||
key: codeql-compile-${{ inputs.key }}-${{ github.ref_name }}-${{ github.sha }} # just fill on main
|
key: codeql-compile-${{ inputs.key }}-${{ github.ref_name }}-${{ github.sha }} # just fill on main
|
||||||
restore-keys: | # restore the latest cache if the exact cache is unavailable, to speed up compilation.
|
restore-keys: | # restore the latest cache if the exact cache is unavailable, to speed up compilation.
|
||||||
codeql-compile-${{ inputs.key }}-${{ github.ref_name }}-
|
codeql-compile-${{ inputs.key }}-${{ github.ref_name }}-
|
||||||
codeql-compile-${{ inputs.key }}-main-
|
codeql-compile-${{ inputs.key }}-main-
|
||||||
- name: Fill compilation cache directory
|
- name: Output-compilationdir
|
||||||
id: fill-compilation-dir
|
id: output-compilation-dir
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
# Move all the existing cache into another folder, so we only preserve the cache for the current queries.
|
|
||||||
node $GITHUB_WORKSPACE/.github/actions/cache-query-compilation/move-caches.js ${COMBINED_CACHE_DIR}
|
|
||||||
|
|
||||||
echo "compdir=${COMBINED_CACHE_DIR}" >> $GITHUB_OUTPUT
|
echo "compdir=${COMBINED_CACHE_DIR}" >> $GITHUB_OUTPUT
|
||||||
env:
|
env:
|
||||||
COMBINED_CACHE_DIR: ${{ runner.temp }}/compilation-dir
|
COMBINED_CACHE_DIR: ${{ runner.temp }}/compilation-dir
|
||||||
|
- name: Fill compilation cache directory
|
||||||
|
id: fill-compilation-dir
|
||||||
|
uses: actions/github-script@v6
|
||||||
|
env:
|
||||||
|
COMBINED_CACHE_DIR: ${{ runner.temp }}/compilation-dir
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
// # Move all the existing cache into another folder, so we only preserve the cache for the current queries.
|
||||||
|
// mkdir -p ${COMBINED_CACHE_DIR}
|
||||||
|
// rm -f **/.cache/{lock,size} # -f to avoid errors if the cache is empty.
|
||||||
|
// # copy the contents of the .cache folders into the combined cache folder.
|
||||||
|
// cp -r **/.cache/* ${COMBINED_CACHE_DIR}/ || : # ignore missing files
|
||||||
|
// # clean up the .cache folders
|
||||||
|
// rm -rf **/.cache/*
|
||||||
|
|
||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
const os = require("os");
|
||||||
|
|
||||||
|
// the first argv is the cache folder to create.
|
||||||
|
const COMBINED_CACHE_DIR = process.env.COMBINED_CACHE_DIR;
|
||||||
|
|
||||||
|
function* walkCaches(dir) {
|
||||||
|
const files = fs.readdirSync(dir, { withFileTypes: true });
|
||||||
|
for (const file of files) {
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
const filePath = path.join(dir, file.name);
|
||||||
|
yield* walkCaches(filePath);
|
||||||
|
if (file.name === ".cache") {
|
||||||
|
yield filePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function copyDir(src, dest) {
|
||||||
|
for await (const file of await fs.promises.readdir(src, { withFileTypes: true })) {
|
||||||
|
const srcPath = path.join(src, file.name);
|
||||||
|
const destPath = path.join(dest, file.name);
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
if (!fs.existsSync(destPath)) {
|
||||||
|
fs.mkdirSync(destPath);
|
||||||
|
}
|
||||||
|
await copyDir(srcPath, destPath);
|
||||||
|
} else {
|
||||||
|
await fs.promises.copyFile(srcPath, destPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const cacheDirs = [...walkCaches(".")];
|
||||||
|
|
||||||
|
for (const dir of cacheDirs) {
|
||||||
|
console.log(`Found .cache dir at ${dir}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const globalCacheDir = path.join(os.homedir(), ".codeql", "compile-cache");
|
||||||
|
if (fs.existsSync(globalCacheDir)) {
|
||||||
|
console.log("Found global home dir: " + globalCacheDir);
|
||||||
|
cacheDirs.push(globalCacheDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cacheDirs.length === 0) {
|
||||||
|
console.log("No cache dirs found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mkdir -p ${COMBINED_CACHE_DIR}
|
||||||
|
fs.mkdirSync(COMBINED_CACHE_DIR, { recursive: true });
|
||||||
|
|
||||||
|
// rm -f **/.cache/{lock,size} # -f to avoid errors if the cache is empty.
|
||||||
|
await Promise.all(
|
||||||
|
cacheDirs.map((cacheDir) =>
|
||||||
|
(async function () {
|
||||||
|
await fs.promises.rm(path.join(cacheDir, "lock"), { force: true });
|
||||||
|
await fs.promises.rm(path.join(cacheDir, "size"), { force: true });
|
||||||
|
})()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// # copy the contents of the .cache folders into the combined cache folder.
|
||||||
|
// cp -r **/.cache/* ${COMBINED_CACHE_DIR}/ || : # ignore missing files
|
||||||
|
await Promise.all(
|
||||||
|
cacheDirs.map((cacheDir) => copyDir(cacheDir, COMBINED_CACHE_DIR))
|
||||||
|
);
|
||||||
|
|
||||||
|
// # clean up the .cache folders
|
||||||
|
// rm -rf **/.cache/*
|
||||||
|
await Promise.all(
|
||||||
|
cacheDirs.map((cacheDir) => fs.promises.rm(cacheDir, { recursive: true }))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
main();
|
||||||
|
|||||||
@@ -1,75 +0,0 @@
|
|||||||
// # Move all the existing cache into another folder, so we only preserve the cache for the current queries.
|
|
||||||
// mkdir -p ${COMBINED_CACHE_DIR}
|
|
||||||
// rm -f **/.cache/{lock,size} # -f to avoid errors if the cache is empty.
|
|
||||||
// # copy the contents of the .cache folders into the combined cache folder.
|
|
||||||
// cp -r **/.cache/* ${COMBINED_CACHE_DIR}/ || : # ignore missing files
|
|
||||||
// # clean up the .cache folders
|
|
||||||
// rm -rf **/.cache/*
|
|
||||||
|
|
||||||
const fs = require("fs");
|
|
||||||
const path = require("path");
|
|
||||||
|
|
||||||
// the first argv is the cache folder to create.
|
|
||||||
const COMBINED_CACHE_DIR = process.argv[2];
|
|
||||||
|
|
||||||
function* walkCaches(dir) {
|
|
||||||
const files = fs.readdirSync(dir, { withFileTypes: true });
|
|
||||||
for (const file of files) {
|
|
||||||
if (file.isDirectory()) {
|
|
||||||
const filePath = path.join(dir, file.name);
|
|
||||||
yield* walkCaches(filePath);
|
|
||||||
if (file.name === ".cache") {
|
|
||||||
yield filePath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function copyDir(src, dest) {
|
|
||||||
for await (const file of await fs.promises.readdir(src, { withFileTypes: true })) {
|
|
||||||
const srcPath = path.join(src, file.name);
|
|
||||||
const destPath = path.join(dest, file.name);
|
|
||||||
if (file.isDirectory()) {
|
|
||||||
if (!fs.existsSync(destPath)) {
|
|
||||||
fs.mkdirSync(destPath);
|
|
||||||
}
|
|
||||||
await copyDir(srcPath, destPath);
|
|
||||||
} else {
|
|
||||||
await fs.promises.copyFile(srcPath, destPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
const cacheDirs = [...walkCaches(".")];
|
|
||||||
|
|
||||||
for (const dir of cacheDirs) {
|
|
||||||
console.log(`Found .cache dir at ${dir}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// mkdir -p ${COMBINED_CACHE_DIR}
|
|
||||||
fs.mkdirSync(COMBINED_CACHE_DIR, { recursive: true });
|
|
||||||
|
|
||||||
// rm -f **/.cache/{lock,size} # -f to avoid errors if the cache is empty.
|
|
||||||
await Promise.all(
|
|
||||||
cacheDirs.map((cacheDir) =>
|
|
||||||
(async function () {
|
|
||||||
await fs.promises.rm(path.join(cacheDir, "lock"), { force: true });
|
|
||||||
await fs.promises.rm(path.join(cacheDir, "size"), { force: true });
|
|
||||||
})()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// # copy the contents of the .cache folders into the combined cache folder.
|
|
||||||
// cp -r **/.cache/* ${COMBINED_CACHE_DIR}/ || : # ignore missing files
|
|
||||||
await Promise.all(
|
|
||||||
cacheDirs.map((cacheDir) => copyDir(cacheDir, COMBINED_CACHE_DIR))
|
|
||||||
);
|
|
||||||
|
|
||||||
// # clean up the .cache folders
|
|
||||||
// rm -rf **/.cache/*
|
|
||||||
await Promise.all(
|
|
||||||
cacheDirs.map((cacheDir) => fs.promises.rm(cacheDir, { recursive: true }))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
main();
|
|
||||||
26
.github/actions/find-latest-bundle/action.yml
vendored
26
.github/actions/find-latest-bundle/action.yml
vendored
@@ -1,26 +0,0 @@
|
|||||||
name: Find Latest CodeQL Bundle
|
|
||||||
description: Finds the URL of the latest released version of the CodeQL bundle.
|
|
||||||
outputs:
|
|
||||||
url:
|
|
||||||
description: The download URL of the latest CodeQL bundle release
|
|
||||||
value: ${{ steps.find-latest.outputs.url }}
|
|
||||||
runs:
|
|
||||||
using: composite
|
|
||||||
steps:
|
|
||||||
- name: Find Latest Release
|
|
||||||
id: find-latest
|
|
||||||
shell: pwsh
|
|
||||||
run: |
|
|
||||||
$Latest = gh release list --repo github/codeql-action --exclude-drafts --limit 1000 |
|
|
||||||
ForEach-Object { $C = $_ -split "`t"; return @{ type = $C[1]; tag = $C[2]; } } |
|
|
||||||
Where-Object { $_.type -eq 'Latest' }
|
|
||||||
|
|
||||||
$Tag = $Latest.tag
|
|
||||||
if ($Tag -eq '') {
|
|
||||||
throw 'Failed to find latest bundle release.'
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Output "Latest bundle tag is '${Tag}'."
|
|
||||||
"url=https://github.com/github/codeql-action/releases/download/${Tag}/codeql-bundle-linux64.tar.gz" >> $env:GITHUB_OUTPUT
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ github.token }}
|
|
||||||
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
@@ -28,7 +28,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Setup dotnet
|
- name: Setup dotnet
|
||||||
uses: actions/setup-dotnet@v2
|
uses: actions/setup-dotnet@v3
|
||||||
with:
|
with:
|
||||||
dotnet-version: 7.0.102
|
dotnet-version: 7.0.102
|
||||||
|
|
||||||
|
|||||||
6
.github/workflows/compile-queries.yml
vendored
6
.github/workflows/compile-queries.yml
vendored
@@ -24,14 +24,14 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
key: all-queries
|
key: all-queries
|
||||||
- name: check formatting
|
- name: check formatting
|
||||||
run: find */ql -type f \( -name "*.qll" -o -name "*.ql" \) -print0 | xargs -0 codeql query format --check-only
|
run: find */ql -type f \( -name "*.qll" -o -name "*.ql" \) -print0 | xargs -0 -n 3000 -P 10 codeql query format -q --check-only
|
||||||
- name: compile queries - check-only
|
- name: compile queries - check-only
|
||||||
# run with --check-only if running in a PR (github.sha != main)
|
# run with --check-only if running in a PR (github.sha != main)
|
||||||
if : ${{ github.event_name == 'pull_request' }}
|
if : ${{ github.event_name == 'pull_request' }}
|
||||||
shell: bash
|
shell: bash
|
||||||
run: codeql query compile -j0 */ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --check-only --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||||
- name: compile queries - full
|
- name: compile queries - full
|
||||||
# do full compile if running on main - this populates the cache
|
# do full compile if running on main - this populates the cache
|
||||||
if : ${{ github.event_name != 'pull_request' }}
|
if : ${{ github.event_name != 'pull_request' }}
|
||||||
shell: bash
|
shell: bash
|
||||||
run: codeql query compile -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
run: codeql query compile -q -j0 */ql/{src,examples} --keep-going --warnings=error --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||||
|
|||||||
8
.github/workflows/go-tests-other-os.yml
vendored
8
.github/workflows/go-tests-other-os.yml
vendored
@@ -12,10 +12,10 @@ jobs:
|
|||||||
name: Test MacOS
|
name: Test MacOS
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Set up Go 1.19
|
- name: Set up Go 1.20
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: 1.19
|
go-version: 1.20.0
|
||||||
id: go
|
id: go
|
||||||
|
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
@@ -47,10 +47,10 @@ jobs:
|
|||||||
name: Test Windows
|
name: Test Windows
|
||||||
runs-on: windows-latest-xl
|
runs-on: windows-latest-xl
|
||||||
steps:
|
steps:
|
||||||
- name: Set up Go 1.19
|
- name: Set up Go 1.20
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: 1.19
|
go-version: 1.20.0
|
||||||
id: go
|
id: go
|
||||||
|
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
|
|||||||
4
.github/workflows/go-tests.yml
vendored
4
.github/workflows/go-tests.yml
vendored
@@ -20,10 +20,10 @@ jobs:
|
|||||||
name: Test Linux (Ubuntu)
|
name: Test Linux (Ubuntu)
|
||||||
runs-on: ubuntu-latest-xl
|
runs-on: ubuntu-latest-xl
|
||||||
steps:
|
steps:
|
||||||
- name: Set up Go 1.19
|
- name: Set up Go 1.20
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: 1.19
|
go-version: 1.20.0
|
||||||
id: go
|
id: go
|
||||||
|
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
|
|||||||
145
.github/workflows/ql-for-ql-build.yml
vendored
145
.github/workflows/ql-for-ql-build.yml
vendored
@@ -5,13 +5,6 @@ on:
|
|||||||
branches: [main]
|
branches: [main]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
paths:
|
|
||||||
- "ql/**"
|
|
||||||
- "**.qll"
|
|
||||||
- "**.ql"
|
|
||||||
- "**.dbscheme"
|
|
||||||
- "**/qlpack.yml"
|
|
||||||
- ".github/workflows/ql-for-ql-build.yml"
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
CARGO_TERM_COLOR: always
|
CARGO_TERM_COLOR: always
|
||||||
@@ -22,66 +15,26 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
### Build the queries ###
|
### Build the queries ###
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Find latest bundle
|
with:
|
||||||
id: find-latest-bundle
|
fetch-depth: 0
|
||||||
uses: ./.github/actions/find-latest-bundle
|
|
||||||
- name: Find codeql
|
- name: Find codeql
|
||||||
id: find-codeql
|
id: find-codeql
|
||||||
uses: github/codeql-action/init@beae46e6b1da530ed5e9fc6a756f92433ca47ae1
|
uses: github/codeql-action/init@v2
|
||||||
with:
|
with:
|
||||||
languages: javascript # does not matter
|
languages: javascript # does not matter
|
||||||
tools: ${{ steps.find-latest-bundle.outputs.url }}
|
|
||||||
- name: Get CodeQL version
|
|
||||||
id: get-codeql-version
|
|
||||||
run: |
|
|
||||||
echo "version=$("${CODEQL}" --version | head -n 1 | rev | cut -d " " -f 1 | rev)" >> $GITHUB_OUTPUT
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
|
||||||
- uses: ./.github/actions/os-version
|
- uses: ./.github/actions/os-version
|
||||||
id: os_version
|
id: os_version
|
||||||
- name: Cache entire pack
|
|
||||||
id: cache-pack
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ runner.temp }}/pack
|
|
||||||
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-pack-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }}-${{ hashFiles('ql/**/*.ql*') }}-${{ hashFiles('ql/**/qlpack.yml') }}-${{ hashFiles('ql/ql/src/ql.dbscheme*') }}-${{ steps.get-codeql-version.outputs.version }}--${{ hashFiles('.github/workflows/ql-for-ql-build.yml') }}
|
|
||||||
- name: Cache queries
|
|
||||||
if: steps.cache-pack.outputs.cache-hit != 'true'
|
|
||||||
id: cache-queries
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: ${{ runner.temp }}/queries
|
|
||||||
key: queries-${{ hashFiles('ql/**/*.ql*') }}-${{ hashFiles('ql/**/qlpack.yml') }}-${{ hashFiles('ql/ql/src/ql.dbscheme*') }}-${{ steps.get-codeql-version.outputs.version }}--${{ hashFiles('.github/workflows/ql-for-ql-build.yml') }}
|
|
||||||
- name: Build query pack
|
|
||||||
if: steps.cache-queries.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
|
|
||||||
run: |
|
|
||||||
cd ql/ql/src
|
|
||||||
"${CODEQL}" pack create -j 16
|
|
||||||
mv .codeql/pack/codeql/ql/0.0.0 ${{ runner.temp }}/queries
|
|
||||||
env:
|
|
||||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
|
||||||
- name: Move cache queries to pack
|
|
||||||
if: steps.cache-pack.outputs.cache-hit != 'true'
|
|
||||||
run: |
|
|
||||||
cp -r ${{ runner.temp }}/queries ${{ runner.temp }}/pack
|
|
||||||
env:
|
|
||||||
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
|
||||||
|
|
||||||
### Build the extractor ###
|
### Build the extractor ###
|
||||||
- name: Cache entire extractor
|
- name: Cache entire extractor
|
||||||
if: steps.cache-pack.outputs.cache-hit != 'true'
|
|
||||||
id: cache-extractor
|
id: cache-extractor
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
ql/target/release/ql-autobuilder
|
ql/extractor-pack/
|
||||||
ql/target/release/ql-autobuilder.exe
|
ql/target/release/buramu
|
||||||
ql/target/release/ql-extractor
|
|
||||||
ql/target/release/ql-extractor.exe
|
|
||||||
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-extractor-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }}
|
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-extractor-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }}
|
||||||
- name: Cache cargo
|
- name: Cache cargo
|
||||||
if: steps.cache-extractor.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
|
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
@@ -89,77 +42,33 @@ jobs:
|
|||||||
~/.cargo/git
|
~/.cargo/git
|
||||||
ql/target
|
ql/target
|
||||||
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-rust-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
|
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-rust-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
|
||||||
- name: Check formatting
|
|
||||||
if: steps.cache-extractor.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
|
|
||||||
run: cd ql; cargo fmt --all -- --check
|
|
||||||
- name: Build
|
|
||||||
if: steps.cache-extractor.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
|
|
||||||
run: cd ql; cargo build --verbose
|
|
||||||
- name: Run tests
|
|
||||||
if: steps.cache-extractor.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
|
|
||||||
run: cd ql; cargo test --verbose
|
|
||||||
- name: Release build
|
- name: Release build
|
||||||
if: steps.cache-extractor.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
|
if: steps.cache-extractor.outputs.cache-hit != 'true'
|
||||||
run: cd ql; cargo build --release
|
run: cd ql; ./scripts/create-extractor-pack.sh
|
||||||
- name: Generate dbscheme
|
|
||||||
if: steps.cache-extractor.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
|
|
||||||
run: ql/target/release/ql-generator --dbscheme ql/ql/src/ql.dbscheme --library ql/ql/src/codeql_ql/ast/internal/TreeSitter.qll
|
|
||||||
|
|
||||||
### Package the queries and extractor ###
|
|
||||||
- name: Package pack
|
|
||||||
if: steps.cache-pack.outputs.cache-hit != 'true'
|
|
||||||
run: |
|
|
||||||
cp -r ql/codeql-extractor.yml ql/tools ql/ql/src/ql.dbscheme.stats ${PACK}/
|
|
||||||
mkdir -p ${PACK}/tools/linux64
|
|
||||||
cp ql/target/release/ql-autobuilder ${PACK}/tools/linux64/autobuilder
|
|
||||||
cp ql/target/release/ql-extractor ${PACK}/tools/linux64/extractor
|
|
||||||
chmod +x ${PACK}/tools/linux64/autobuilder
|
|
||||||
chmod +x ${PACK}/tools/linux64/extractor
|
|
||||||
env:
|
env:
|
||||||
PACK: ${{ runner.temp }}/pack
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
- name: Cache compilation cache
|
||||||
### Run the analysis ###
|
id: query-cache
|
||||||
- name: Hack codeql-action options
|
uses: ./.github/actions/cache-query-compilation
|
||||||
run: |
|
|
||||||
JSON=$(jq -nc --arg pack "${PACK}" '.database."run-queries"=["--search-path", $pack] | .resolve.queries=["--search-path", $pack] | .resolve.extractor=["--search-path", $pack] | .resolve.languages=["--search-path", $pack] | .database.init=["--search-path", $pack]')
|
|
||||||
echo "CODEQL_ACTION_EXTRA_OPTIONS=${JSON}" >> ${GITHUB_ENV}
|
|
||||||
env:
|
|
||||||
PACK: ${{ runner.temp }}/pack
|
|
||||||
|
|
||||||
- name: Create CodeQL config file
|
|
||||||
run: |
|
|
||||||
echo "paths-ignore:" >> ${CONF}
|
|
||||||
echo " - ql/ql/test" >> ${CONF}
|
|
||||||
echo " - \"*/ql/lib/upgrades/\"" >> ${CONF}
|
|
||||||
echo "disable-default-queries: true" >> ${CONF}
|
|
||||||
echo "queries:" >> ${CONF}
|
|
||||||
echo " - uses: ./ql/ql/src/codeql-suites/ql-code-scanning.qls" >> ${CONF}
|
|
||||||
echo "Config file: "
|
|
||||||
cat ${CONF}
|
|
||||||
env:
|
|
||||||
CONF: ./ql-for-ql-config.yml
|
|
||||||
- name: Initialize CodeQL
|
|
||||||
uses: github/codeql-action/init@beae46e6b1da530ed5e9fc6a756f92433ca47ae1
|
|
||||||
with:
|
with:
|
||||||
languages: ql
|
key: run-ql-for-ql
|
||||||
db-location: ${{ runner.temp }}/db
|
- name: Make database and analyze
|
||||||
config-file: ./ql-for-ql-config.yml
|
|
||||||
tools: ${{ steps.find-latest-bundle.outputs.url }}
|
|
||||||
- name: Move pack queries
|
|
||||||
run: |
|
run: |
|
||||||
cp -r ${PACK}/queries ql/ql/src
|
./ql/target/release/buramu | tee deprecated.blame # Add a blame file for the extractor to parse.
|
||||||
|
${CODEQL} database create -l=ql --search-path ql/extractor-pack ${DB}
|
||||||
|
${CODEQL} database analyze -j0 --format=sarif-latest --output=ql-for-ql.sarif ${DB} ql/ql/src/codeql-suites/ql-code-scanning.qls --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
|
||||||
env:
|
env:
|
||||||
PACK: ${{ runner.temp }}/pack
|
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
|
||||||
|
DB: ${{ runner.temp }}/DB
|
||||||
- name: Perform CodeQL Analysis
|
LGTM_INDEX_FILTERS: |
|
||||||
uses: github/codeql-action/analyze@beae46e6b1da530ed5e9fc6a756f92433ca47ae1
|
exclude:ql/ql/test
|
||||||
|
exclude:*/ql/lib/upgrades/
|
||||||
|
exclude:java/ql/integration-tests
|
||||||
|
- name: Upload sarif to code-scanning
|
||||||
|
uses: github/codeql-action/upload-sarif@v2
|
||||||
with:
|
with:
|
||||||
category: "ql-for-ql"
|
sarif_file: ql-for-ql.sarif
|
||||||
- name: Copy sarif file to CWD
|
category: ql-for-ql
|
||||||
run: cp ../results/ql.sarif ./ql-for-ql.sarif
|
|
||||||
- name: Fixup the $scema in sarif # Until https://github.com/microsoft/sarif-vscode-extension/pull/436/ is part in a stable release
|
|
||||||
run: |
|
|
||||||
sed -i 's/\$schema.*/\$schema": "https:\/\/raw.githubusercontent.com\/oasis-tcs\/sarif-spec\/master\/Schemata\/sarif-schema-2.1.0",/' ql-for-ql.sarif
|
|
||||||
- name: Sarif as artifact
|
- name: Sarif as artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Find codeql
|
- name: Find codeql
|
||||||
id: find-codeql
|
id: find-codeql
|
||||||
uses: github/codeql-action/init@beae46e6b1da530ed5e9fc6a756f92433ca47ae1
|
uses: github/codeql-action/init@v2
|
||||||
with:
|
with:
|
||||||
languages: javascript # does not matter
|
languages: javascript # does not matter
|
||||||
- uses: ./.github/actions/os-version
|
- uses: ./.github/actions/os-version
|
||||||
|
|||||||
6
.github/workflows/ql-for-ql-tests.yml
vendored
6
.github/workflows/ql-for-ql-tests.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Find codeql
|
- name: Find codeql
|
||||||
id: find-codeql
|
id: find-codeql
|
||||||
uses: github/codeql-action/init@beae46e6b1da530ed5e9fc6a756f92433ca47ae1
|
uses: github/codeql-action/init@v2
|
||||||
with:
|
with:
|
||||||
languages: javascript # does not matter
|
languages: javascript # does not matter
|
||||||
- uses: ./.github/actions/os-version
|
- uses: ./.github/actions/os-version
|
||||||
@@ -36,6 +36,8 @@ jobs:
|
|||||||
~/.cargo/git
|
~/.cargo/git
|
||||||
ql/target
|
ql/target
|
||||||
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-qltest-cargo-${{ hashFiles('ql/rust-toolchain.toml', 'ql/**/Cargo.lock') }}
|
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-qltest-cargo-${{ hashFiles('ql/rust-toolchain.toml', 'ql/**/Cargo.lock') }}
|
||||||
|
- name: Check formatting
|
||||||
|
run: cd ql; cargo fmt --all -- --check
|
||||||
- name: Build extractor
|
- name: Build extractor
|
||||||
run: |
|
run: |
|
||||||
cd ql;
|
cd ql;
|
||||||
@@ -67,7 +69,7 @@ jobs:
|
|||||||
echo "/usr/local/opt/gnu-tar/libexec/gnubin" >> $GITHUB_PATH
|
echo "/usr/local/opt/gnu-tar/libexec/gnubin" >> $GITHUB_PATH
|
||||||
- name: Find codeql
|
- name: Find codeql
|
||||||
id: find-codeql
|
id: find-codeql
|
||||||
uses: github/codeql-action/init@beae46e6b1da530ed5e9fc6a756f92433ca47ae1
|
uses: github/codeql-action/init@v2
|
||||||
with:
|
with:
|
||||||
languages: javascript # does not matter
|
languages: javascript # does not matter
|
||||||
- uses: ./.github/actions/os-version
|
- uses: ./.github/actions/os-version
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
/csharp/ @github/codeql-csharp
|
/csharp/ @github/codeql-csharp
|
||||||
/go/ @github/codeql-go
|
/go/ @github/codeql-go
|
||||||
/java/ @github/codeql-java
|
/java/ @github/codeql-java
|
||||||
/javascript/ @github/codeql-javascript
|
/javascript/ @github/codeql-dynamic
|
||||||
/python/ @github/codeql-python
|
/python/ @github/codeql-dynamic
|
||||||
/ruby/ @github/codeql-ruby
|
/ruby/ @github/codeql-dynamic
|
||||||
/swift/ @github/codeql-swift
|
/swift/ @github/codeql-swift
|
||||||
/java/kotlin-extractor/ @github/codeql-kotlin
|
/java/kotlin-extractor/ @github/codeql-kotlin
|
||||||
/java/kotlin-explorer/ @github/codeql-kotlin
|
/java/kotlin-explorer/ @github/codeql-kotlin
|
||||||
|
|||||||
@@ -131,6 +131,14 @@ namespace Semmle.Autobuild.Cpp.Tests
|
|||||||
|
|
||||||
bool IBuildActions.IsWindows() => IsWindows;
|
bool IBuildActions.IsWindows() => IsWindows;
|
||||||
|
|
||||||
|
public bool IsMacOs { get; set; }
|
||||||
|
|
||||||
|
bool IBuildActions.IsMacOs() => IsMacOs;
|
||||||
|
|
||||||
|
public bool IsArm { get; set; }
|
||||||
|
|
||||||
|
bool IBuildActions.IsArm() => IsArm;
|
||||||
|
|
||||||
string IBuildActions.PathCombine(params string[] parts)
|
string IBuildActions.PathCombine(params string[] parts)
|
||||||
{
|
{
|
||||||
return string.Join(IsWindows ? '\\' : '/', parts.Where(p => !string.IsNullOrWhiteSpace(p)));
|
return string.Join(IsWindows ? '\\' : '/', parts.Where(p => !string.IsNullOrWhiteSpace(p)));
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
## 0.5.3
|
||||||
|
|
||||||
|
No user-facing changes.
|
||||||
|
|
||||||
## 0.5.2
|
## 0.5.2
|
||||||
|
|
||||||
No user-facing changes.
|
No user-facing changes.
|
||||||
|
|||||||
3
cpp/ql/lib/change-notes/released/0.5.3.md
Normal file
3
cpp/ql/lib/change-notes/released/0.5.3.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
## 0.5.3
|
||||||
|
|
||||||
|
No user-facing changes.
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
---
|
---
|
||||||
lastReleaseVersion: 0.5.2
|
lastReleaseVersion: 0.5.3
|
||||||
|
|||||||
@@ -667,23 +667,78 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(NodeEx arg |
|
fwdFlowIn(_, _, _, node, config) and
|
||||||
fwdFlow(arg, _, config) and
|
cc = true
|
||||||
viableParamArgEx(_, node, arg) and
|
|
||||||
cc = true and
|
|
||||||
not fullBarrier(node, config)
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(DataFlowCall call |
|
fwdFlowOut(_, node, false, config) and
|
||||||
fwdFlowOut(call, node, false, config) and
|
|
||||||
cc = false
|
cc = false
|
||||||
or
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
fwdFlowOutFromArg(call, node, config) and
|
fwdFlowOutFromArg(call, node, config) and
|
||||||
fwdFlowIsEntered(call, cc, config)
|
fwdFlowIsEntered(call, cc, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowIn(
|
||||||
|
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||||
|
) {
|
||||||
|
// call context cannot help reduce virtual dispatch
|
||||||
|
fwdFlow(arg, cc, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
not fullBarrier(p, config) and
|
||||||
|
(
|
||||||
|
cc = false
|
||||||
|
or
|
||||||
|
cc = true and
|
||||||
|
not reducedViableImplInCallContext(call, _, _)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// call context may help reduce virtual dispatch
|
||||||
|
exists(DataFlowCallable target |
|
||||||
|
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||||
|
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||||
|
cc = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||||
|
fwdFlowIn(call, _, cc, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||||
|
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(arg, true, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
reducedViableImplInCallContext(call, _, _) and
|
||||||
|
target = p.getEnclosingCallable() and
|
||||||
|
not fullBarrier(p, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||||
|
* restricted to those `call`s for which a context might make a difference,
|
||||||
|
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||||
|
DataFlowCall call, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCall ctx |
|
||||||
|
fwdFlowIsEntered(ctx, _, config) and
|
||||||
|
result = viableImplInCallContextExt(call, ctx)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -726,7 +781,8 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
fwdFlowReturnPosition(pos, cc, config) and
|
fwdFlowReturnPosition(pos, cc, config) and
|
||||||
@@ -740,17 +796,6 @@ private module Stage1 implements StageSig {
|
|||||||
fwdFlowOut(call, out, true, config)
|
fwdFlowOut(call, out, true, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
|
||||||
*/
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
|
||||||
exists(ArgNodeEx arg |
|
|
||||||
fwdFlow(arg, cc, config) and
|
|
||||||
viableParamArgEx(call, _, arg)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||||
exists(NodeEx node1 |
|
exists(NodeEx node1 |
|
||||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||||
@@ -817,20 +862,21 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(DataFlowCall call |
|
revFlowIn(_, node, false, config) and
|
||||||
revFlowIn(call, node, false, config) and
|
|
||||||
toReturn = false
|
toReturn = false
|
||||||
or
|
or
|
||||||
revFlowInToReturn(call, node, config) and
|
|
||||||
revFlowIsReturned(call, toReturn, config)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
revFlowOut(pos, config) and
|
revFlowOut(pos, config) and
|
||||||
node.(RetNodeEx).getReturnPosition() = pos and
|
node.(RetNodeEx).getReturnPosition() = pos and
|
||||||
toReturn = true
|
toReturn = true
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
|
revFlowInToReturn(call, node, config) and
|
||||||
|
revFlowIsReturned(call, toReturn, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -886,11 +932,11 @@ private module Stage1 implements StageSig {
|
|||||||
additional predicate viableParamArgNodeCandFwd1(
|
additional predicate viableParamArgNodeCandFwd1(
|
||||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||||
) {
|
) {
|
||||||
viableParamArgEx(call, p, arg) and
|
fwdFlowIn(call, arg, _, p, config)
|
||||||
fwdFlow(arg, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate revFlowIn(
|
private predicate revFlowIn(
|
||||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -1223,7 +1269,16 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail);
|
Ap apCons(TypedContent tc, Ap tail);
|
||||||
|
|
||||||
Content getHeadContent(Ap ap);
|
/**
|
||||||
|
* An approximation of `Content` that corresponds to the precision level of
|
||||||
|
* `Ap`, such that the mappings from both `Ap` and `Content` to this type
|
||||||
|
* are functional.
|
||||||
|
*/
|
||||||
|
class ApHeadContent;
|
||||||
|
|
||||||
|
ApHeadContent getHeadContent(Ap ap);
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c);
|
||||||
|
|
||||||
class ApOption;
|
class ApOption;
|
||||||
|
|
||||||
@@ -1471,34 +1526,32 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ApNonNil instanceof Ap {
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
ApNonNil() { not this instanceof ApNil }
|
private predicate readStepCand(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
string toString() { result = "" }
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowRead0(
|
|
||||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
|
||||||
Configuration config
|
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
PrevStage::readStepCand(node1, _, _, config)
|
apc = projectToHeadContent(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, c]
|
bindingset[node1, apc]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
private predicate hasHeadContent(Ap ap, Content c) { getHeadContent(ap) = c }
|
private predicate readStepCand0(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
|
) {
|
||||||
|
readStepCand(node1, apc, c, node2, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
exists(ApHeadContent apc |
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
hasHeadContent(ap, c)
|
apc = getHeadContent(ap) and
|
||||||
|
readStepCand0(node1, apc, c, node2, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -2072,8 +2125,12 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Unit;
|
||||||
|
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
Content getHeadContent(Ap ap) { exists(result) and ap = true }
|
ApHeadContent getHeadContent(Ap ap) { exists(result) and ap = true }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { any() }
|
||||||
|
|
||||||
class ApOption = BooleanOption;
|
class ApOption = BooleanOption;
|
||||||
|
|
||||||
@@ -2337,8 +2394,12 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = ContentApprox;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
predicate projectToHeadContent = getContentApprox/1;
|
||||||
|
|
||||||
class ApOption = ApproxAccessPathFrontOption;
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2413,8 +2474,12 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathFrontOption;
|
class ApOption = AccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2743,8 +2808,12 @@ private module Stage5Param implements MkStage<Stage4>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathApproxOption;
|
class ApOption = AccessPathApproxOption;
|
||||||
|
|
||||||
|
|||||||
@@ -667,23 +667,78 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(NodeEx arg |
|
fwdFlowIn(_, _, _, node, config) and
|
||||||
fwdFlow(arg, _, config) and
|
cc = true
|
||||||
viableParamArgEx(_, node, arg) and
|
|
||||||
cc = true and
|
|
||||||
not fullBarrier(node, config)
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(DataFlowCall call |
|
fwdFlowOut(_, node, false, config) and
|
||||||
fwdFlowOut(call, node, false, config) and
|
|
||||||
cc = false
|
cc = false
|
||||||
or
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
fwdFlowOutFromArg(call, node, config) and
|
fwdFlowOutFromArg(call, node, config) and
|
||||||
fwdFlowIsEntered(call, cc, config)
|
fwdFlowIsEntered(call, cc, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowIn(
|
||||||
|
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||||
|
) {
|
||||||
|
// call context cannot help reduce virtual dispatch
|
||||||
|
fwdFlow(arg, cc, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
not fullBarrier(p, config) and
|
||||||
|
(
|
||||||
|
cc = false
|
||||||
|
or
|
||||||
|
cc = true and
|
||||||
|
not reducedViableImplInCallContext(call, _, _)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// call context may help reduce virtual dispatch
|
||||||
|
exists(DataFlowCallable target |
|
||||||
|
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||||
|
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||||
|
cc = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||||
|
fwdFlowIn(call, _, cc, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||||
|
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(arg, true, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
reducedViableImplInCallContext(call, _, _) and
|
||||||
|
target = p.getEnclosingCallable() and
|
||||||
|
not fullBarrier(p, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||||
|
* restricted to those `call`s for which a context might make a difference,
|
||||||
|
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||||
|
DataFlowCall call, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCall ctx |
|
||||||
|
fwdFlowIsEntered(ctx, _, config) and
|
||||||
|
result = viableImplInCallContextExt(call, ctx)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -726,7 +781,8 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
fwdFlowReturnPosition(pos, cc, config) and
|
fwdFlowReturnPosition(pos, cc, config) and
|
||||||
@@ -740,17 +796,6 @@ private module Stage1 implements StageSig {
|
|||||||
fwdFlowOut(call, out, true, config)
|
fwdFlowOut(call, out, true, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
|
||||||
*/
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
|
||||||
exists(ArgNodeEx arg |
|
|
||||||
fwdFlow(arg, cc, config) and
|
|
||||||
viableParamArgEx(call, _, arg)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||||
exists(NodeEx node1 |
|
exists(NodeEx node1 |
|
||||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||||
@@ -817,20 +862,21 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(DataFlowCall call |
|
revFlowIn(_, node, false, config) and
|
||||||
revFlowIn(call, node, false, config) and
|
|
||||||
toReturn = false
|
toReturn = false
|
||||||
or
|
or
|
||||||
revFlowInToReturn(call, node, config) and
|
|
||||||
revFlowIsReturned(call, toReturn, config)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
revFlowOut(pos, config) and
|
revFlowOut(pos, config) and
|
||||||
node.(RetNodeEx).getReturnPosition() = pos and
|
node.(RetNodeEx).getReturnPosition() = pos and
|
||||||
toReturn = true
|
toReturn = true
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
|
revFlowInToReturn(call, node, config) and
|
||||||
|
revFlowIsReturned(call, toReturn, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -886,11 +932,11 @@ private module Stage1 implements StageSig {
|
|||||||
additional predicate viableParamArgNodeCandFwd1(
|
additional predicate viableParamArgNodeCandFwd1(
|
||||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||||
) {
|
) {
|
||||||
viableParamArgEx(call, p, arg) and
|
fwdFlowIn(call, arg, _, p, config)
|
||||||
fwdFlow(arg, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate revFlowIn(
|
private predicate revFlowIn(
|
||||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -1223,7 +1269,16 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail);
|
Ap apCons(TypedContent tc, Ap tail);
|
||||||
|
|
||||||
Content getHeadContent(Ap ap);
|
/**
|
||||||
|
* An approximation of `Content` that corresponds to the precision level of
|
||||||
|
* `Ap`, such that the mappings from both `Ap` and `Content` to this type
|
||||||
|
* are functional.
|
||||||
|
*/
|
||||||
|
class ApHeadContent;
|
||||||
|
|
||||||
|
ApHeadContent getHeadContent(Ap ap);
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c);
|
||||||
|
|
||||||
class ApOption;
|
class ApOption;
|
||||||
|
|
||||||
@@ -1471,34 +1526,32 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ApNonNil instanceof Ap {
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
ApNonNil() { not this instanceof ApNil }
|
private predicate readStepCand(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
string toString() { result = "" }
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowRead0(
|
|
||||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
|
||||||
Configuration config
|
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
PrevStage::readStepCand(node1, _, _, config)
|
apc = projectToHeadContent(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, c]
|
bindingset[node1, apc]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
private predicate hasHeadContent(Ap ap, Content c) { getHeadContent(ap) = c }
|
private predicate readStepCand0(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
|
) {
|
||||||
|
readStepCand(node1, apc, c, node2, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
exists(ApHeadContent apc |
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
hasHeadContent(ap, c)
|
apc = getHeadContent(ap) and
|
||||||
|
readStepCand0(node1, apc, c, node2, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -2072,8 +2125,12 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Unit;
|
||||||
|
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
Content getHeadContent(Ap ap) { exists(result) and ap = true }
|
ApHeadContent getHeadContent(Ap ap) { exists(result) and ap = true }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { any() }
|
||||||
|
|
||||||
class ApOption = BooleanOption;
|
class ApOption = BooleanOption;
|
||||||
|
|
||||||
@@ -2337,8 +2394,12 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = ContentApprox;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
predicate projectToHeadContent = getContentApprox/1;
|
||||||
|
|
||||||
class ApOption = ApproxAccessPathFrontOption;
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2413,8 +2474,12 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathFrontOption;
|
class ApOption = AccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2743,8 +2808,12 @@ private module Stage5Param implements MkStage<Stage4>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathApproxOption;
|
class ApOption = AccessPathApproxOption;
|
||||||
|
|
||||||
|
|||||||
@@ -667,23 +667,78 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(NodeEx arg |
|
fwdFlowIn(_, _, _, node, config) and
|
||||||
fwdFlow(arg, _, config) and
|
cc = true
|
||||||
viableParamArgEx(_, node, arg) and
|
|
||||||
cc = true and
|
|
||||||
not fullBarrier(node, config)
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(DataFlowCall call |
|
fwdFlowOut(_, node, false, config) and
|
||||||
fwdFlowOut(call, node, false, config) and
|
|
||||||
cc = false
|
cc = false
|
||||||
or
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
fwdFlowOutFromArg(call, node, config) and
|
fwdFlowOutFromArg(call, node, config) and
|
||||||
fwdFlowIsEntered(call, cc, config)
|
fwdFlowIsEntered(call, cc, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowIn(
|
||||||
|
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||||
|
) {
|
||||||
|
// call context cannot help reduce virtual dispatch
|
||||||
|
fwdFlow(arg, cc, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
not fullBarrier(p, config) and
|
||||||
|
(
|
||||||
|
cc = false
|
||||||
|
or
|
||||||
|
cc = true and
|
||||||
|
not reducedViableImplInCallContext(call, _, _)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// call context may help reduce virtual dispatch
|
||||||
|
exists(DataFlowCallable target |
|
||||||
|
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||||
|
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||||
|
cc = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||||
|
fwdFlowIn(call, _, cc, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||||
|
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(arg, true, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
reducedViableImplInCallContext(call, _, _) and
|
||||||
|
target = p.getEnclosingCallable() and
|
||||||
|
not fullBarrier(p, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||||
|
* restricted to those `call`s for which a context might make a difference,
|
||||||
|
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||||
|
DataFlowCall call, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCall ctx |
|
||||||
|
fwdFlowIsEntered(ctx, _, config) and
|
||||||
|
result = viableImplInCallContextExt(call, ctx)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -726,7 +781,8 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
fwdFlowReturnPosition(pos, cc, config) and
|
fwdFlowReturnPosition(pos, cc, config) and
|
||||||
@@ -740,17 +796,6 @@ private module Stage1 implements StageSig {
|
|||||||
fwdFlowOut(call, out, true, config)
|
fwdFlowOut(call, out, true, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
|
||||||
*/
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
|
||||||
exists(ArgNodeEx arg |
|
|
||||||
fwdFlow(arg, cc, config) and
|
|
||||||
viableParamArgEx(call, _, arg)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||||
exists(NodeEx node1 |
|
exists(NodeEx node1 |
|
||||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||||
@@ -817,20 +862,21 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(DataFlowCall call |
|
revFlowIn(_, node, false, config) and
|
||||||
revFlowIn(call, node, false, config) and
|
|
||||||
toReturn = false
|
toReturn = false
|
||||||
or
|
or
|
||||||
revFlowInToReturn(call, node, config) and
|
|
||||||
revFlowIsReturned(call, toReturn, config)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
revFlowOut(pos, config) and
|
revFlowOut(pos, config) and
|
||||||
node.(RetNodeEx).getReturnPosition() = pos and
|
node.(RetNodeEx).getReturnPosition() = pos and
|
||||||
toReturn = true
|
toReturn = true
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
|
revFlowInToReturn(call, node, config) and
|
||||||
|
revFlowIsReturned(call, toReturn, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -886,11 +932,11 @@ private module Stage1 implements StageSig {
|
|||||||
additional predicate viableParamArgNodeCandFwd1(
|
additional predicate viableParamArgNodeCandFwd1(
|
||||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||||
) {
|
) {
|
||||||
viableParamArgEx(call, p, arg) and
|
fwdFlowIn(call, arg, _, p, config)
|
||||||
fwdFlow(arg, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate revFlowIn(
|
private predicate revFlowIn(
|
||||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -1223,7 +1269,16 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail);
|
Ap apCons(TypedContent tc, Ap tail);
|
||||||
|
|
||||||
Content getHeadContent(Ap ap);
|
/**
|
||||||
|
* An approximation of `Content` that corresponds to the precision level of
|
||||||
|
* `Ap`, such that the mappings from both `Ap` and `Content` to this type
|
||||||
|
* are functional.
|
||||||
|
*/
|
||||||
|
class ApHeadContent;
|
||||||
|
|
||||||
|
ApHeadContent getHeadContent(Ap ap);
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c);
|
||||||
|
|
||||||
class ApOption;
|
class ApOption;
|
||||||
|
|
||||||
@@ -1471,34 +1526,32 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ApNonNil instanceof Ap {
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
ApNonNil() { not this instanceof ApNil }
|
private predicate readStepCand(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
string toString() { result = "" }
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowRead0(
|
|
||||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
|
||||||
Configuration config
|
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
PrevStage::readStepCand(node1, _, _, config)
|
apc = projectToHeadContent(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, c]
|
bindingset[node1, apc]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
private predicate hasHeadContent(Ap ap, Content c) { getHeadContent(ap) = c }
|
private predicate readStepCand0(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
|
) {
|
||||||
|
readStepCand(node1, apc, c, node2, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
exists(ApHeadContent apc |
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
hasHeadContent(ap, c)
|
apc = getHeadContent(ap) and
|
||||||
|
readStepCand0(node1, apc, c, node2, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -2072,8 +2125,12 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Unit;
|
||||||
|
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
Content getHeadContent(Ap ap) { exists(result) and ap = true }
|
ApHeadContent getHeadContent(Ap ap) { exists(result) and ap = true }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { any() }
|
||||||
|
|
||||||
class ApOption = BooleanOption;
|
class ApOption = BooleanOption;
|
||||||
|
|
||||||
@@ -2337,8 +2394,12 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = ContentApprox;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
predicate projectToHeadContent = getContentApprox/1;
|
||||||
|
|
||||||
class ApOption = ApproxAccessPathFrontOption;
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2413,8 +2474,12 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathFrontOption;
|
class ApOption = AccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2743,8 +2808,12 @@ private module Stage5Param implements MkStage<Stage4>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathApproxOption;
|
class ApOption = AccessPathApproxOption;
|
||||||
|
|
||||||
|
|||||||
@@ -667,23 +667,78 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(NodeEx arg |
|
fwdFlowIn(_, _, _, node, config) and
|
||||||
fwdFlow(arg, _, config) and
|
cc = true
|
||||||
viableParamArgEx(_, node, arg) and
|
|
||||||
cc = true and
|
|
||||||
not fullBarrier(node, config)
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(DataFlowCall call |
|
fwdFlowOut(_, node, false, config) and
|
||||||
fwdFlowOut(call, node, false, config) and
|
|
||||||
cc = false
|
cc = false
|
||||||
or
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
fwdFlowOutFromArg(call, node, config) and
|
fwdFlowOutFromArg(call, node, config) and
|
||||||
fwdFlowIsEntered(call, cc, config)
|
fwdFlowIsEntered(call, cc, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowIn(
|
||||||
|
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||||
|
) {
|
||||||
|
// call context cannot help reduce virtual dispatch
|
||||||
|
fwdFlow(arg, cc, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
not fullBarrier(p, config) and
|
||||||
|
(
|
||||||
|
cc = false
|
||||||
|
or
|
||||||
|
cc = true and
|
||||||
|
not reducedViableImplInCallContext(call, _, _)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// call context may help reduce virtual dispatch
|
||||||
|
exists(DataFlowCallable target |
|
||||||
|
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||||
|
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||||
|
cc = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||||
|
fwdFlowIn(call, _, cc, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||||
|
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(arg, true, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
reducedViableImplInCallContext(call, _, _) and
|
||||||
|
target = p.getEnclosingCallable() and
|
||||||
|
not fullBarrier(p, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||||
|
* restricted to those `call`s for which a context might make a difference,
|
||||||
|
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||||
|
DataFlowCall call, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCall ctx |
|
||||||
|
fwdFlowIsEntered(ctx, _, config) and
|
||||||
|
result = viableImplInCallContextExt(call, ctx)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -726,7 +781,8 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
fwdFlowReturnPosition(pos, cc, config) and
|
fwdFlowReturnPosition(pos, cc, config) and
|
||||||
@@ -740,17 +796,6 @@ private module Stage1 implements StageSig {
|
|||||||
fwdFlowOut(call, out, true, config)
|
fwdFlowOut(call, out, true, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
|
||||||
*/
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
|
||||||
exists(ArgNodeEx arg |
|
|
||||||
fwdFlow(arg, cc, config) and
|
|
||||||
viableParamArgEx(call, _, arg)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||||
exists(NodeEx node1 |
|
exists(NodeEx node1 |
|
||||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||||
@@ -817,20 +862,21 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(DataFlowCall call |
|
revFlowIn(_, node, false, config) and
|
||||||
revFlowIn(call, node, false, config) and
|
|
||||||
toReturn = false
|
toReturn = false
|
||||||
or
|
or
|
||||||
revFlowInToReturn(call, node, config) and
|
|
||||||
revFlowIsReturned(call, toReturn, config)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
revFlowOut(pos, config) and
|
revFlowOut(pos, config) and
|
||||||
node.(RetNodeEx).getReturnPosition() = pos and
|
node.(RetNodeEx).getReturnPosition() = pos and
|
||||||
toReturn = true
|
toReturn = true
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
|
revFlowInToReturn(call, node, config) and
|
||||||
|
revFlowIsReturned(call, toReturn, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -886,11 +932,11 @@ private module Stage1 implements StageSig {
|
|||||||
additional predicate viableParamArgNodeCandFwd1(
|
additional predicate viableParamArgNodeCandFwd1(
|
||||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||||
) {
|
) {
|
||||||
viableParamArgEx(call, p, arg) and
|
fwdFlowIn(call, arg, _, p, config)
|
||||||
fwdFlow(arg, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate revFlowIn(
|
private predicate revFlowIn(
|
||||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -1223,7 +1269,16 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail);
|
Ap apCons(TypedContent tc, Ap tail);
|
||||||
|
|
||||||
Content getHeadContent(Ap ap);
|
/**
|
||||||
|
* An approximation of `Content` that corresponds to the precision level of
|
||||||
|
* `Ap`, such that the mappings from both `Ap` and `Content` to this type
|
||||||
|
* are functional.
|
||||||
|
*/
|
||||||
|
class ApHeadContent;
|
||||||
|
|
||||||
|
ApHeadContent getHeadContent(Ap ap);
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c);
|
||||||
|
|
||||||
class ApOption;
|
class ApOption;
|
||||||
|
|
||||||
@@ -1471,34 +1526,32 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ApNonNil instanceof Ap {
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
ApNonNil() { not this instanceof ApNil }
|
private predicate readStepCand(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
string toString() { result = "" }
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowRead0(
|
|
||||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
|
||||||
Configuration config
|
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
PrevStage::readStepCand(node1, _, _, config)
|
apc = projectToHeadContent(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, c]
|
bindingset[node1, apc]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
private predicate hasHeadContent(Ap ap, Content c) { getHeadContent(ap) = c }
|
private predicate readStepCand0(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
|
) {
|
||||||
|
readStepCand(node1, apc, c, node2, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
exists(ApHeadContent apc |
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
hasHeadContent(ap, c)
|
apc = getHeadContent(ap) and
|
||||||
|
readStepCand0(node1, apc, c, node2, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -2072,8 +2125,12 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Unit;
|
||||||
|
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
Content getHeadContent(Ap ap) { exists(result) and ap = true }
|
ApHeadContent getHeadContent(Ap ap) { exists(result) and ap = true }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { any() }
|
||||||
|
|
||||||
class ApOption = BooleanOption;
|
class ApOption = BooleanOption;
|
||||||
|
|
||||||
@@ -2337,8 +2394,12 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = ContentApprox;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
predicate projectToHeadContent = getContentApprox/1;
|
||||||
|
|
||||||
class ApOption = ApproxAccessPathFrontOption;
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2413,8 +2474,12 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathFrontOption;
|
class ApOption = AccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2743,8 +2808,12 @@ private module Stage5Param implements MkStage<Stage4>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathApproxOption;
|
class ApOption = AccessPathApproxOption;
|
||||||
|
|
||||||
|
|||||||
@@ -707,8 +707,8 @@ private module Cached {
|
|||||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||||
* restricted to those `call`s for which a context might make a difference.
|
* restricted to those `call`s for which a context might make a difference.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
cached
|
||||||
private DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) {
|
DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) {
|
||||||
result = viableImplInCallContext(call, ctx) and
|
result = viableImplInCallContext(call, ctx) and
|
||||||
result = viableCallable(call)
|
result = viableCallable(call)
|
||||||
or
|
or
|
||||||
@@ -1391,6 +1391,9 @@ class TypedContentApprox extends MkTypedContentApprox {
|
|||||||
/** Gets a typed content approximated by this value. */
|
/** Gets a typed content approximated by this value. */
|
||||||
TypedContent getATypedContent() { result = getATypedContent(this) }
|
TypedContent getATypedContent() { result = getATypedContent(this) }
|
||||||
|
|
||||||
|
/** Gets the content. */
|
||||||
|
ContentApprox getContent() { result = c }
|
||||||
|
|
||||||
/** Gets the container type. */
|
/** Gets the container type. */
|
||||||
DataFlowType getContainerType() { result = t }
|
DataFlowType getContainerType() { result = t }
|
||||||
|
|
||||||
@@ -1408,6 +1411,8 @@ abstract class ApproxAccessPathFront extends TApproxAccessPathFront {
|
|||||||
|
|
||||||
abstract boolean toBoolNonEmpty();
|
abstract boolean toBoolNonEmpty();
|
||||||
|
|
||||||
|
TypedContentApprox getHead() { this = TApproxFrontHead(result) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
TypedContent getAHead() {
|
TypedContent getAHead() {
|
||||||
exists(TypedContentApprox cont |
|
exists(TypedContentApprox cont |
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/cpp-all
|
name: codeql/cpp-all
|
||||||
version: 0.5.2
|
version: 0.5.4-dev
|
||||||
groups: cpp
|
groups: cpp
|
||||||
dbscheme: semmlecode.cpp.dbscheme
|
dbscheme: semmlecode.cpp.dbscheme
|
||||||
extractor: cpp
|
extractor: cpp
|
||||||
|
|||||||
@@ -667,23 +667,78 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(NodeEx arg |
|
fwdFlowIn(_, _, _, node, config) and
|
||||||
fwdFlow(arg, _, config) and
|
cc = true
|
||||||
viableParamArgEx(_, node, arg) and
|
|
||||||
cc = true and
|
|
||||||
not fullBarrier(node, config)
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(DataFlowCall call |
|
fwdFlowOut(_, node, false, config) and
|
||||||
fwdFlowOut(call, node, false, config) and
|
|
||||||
cc = false
|
cc = false
|
||||||
or
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
fwdFlowOutFromArg(call, node, config) and
|
fwdFlowOutFromArg(call, node, config) and
|
||||||
fwdFlowIsEntered(call, cc, config)
|
fwdFlowIsEntered(call, cc, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowIn(
|
||||||
|
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||||
|
) {
|
||||||
|
// call context cannot help reduce virtual dispatch
|
||||||
|
fwdFlow(arg, cc, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
not fullBarrier(p, config) and
|
||||||
|
(
|
||||||
|
cc = false
|
||||||
|
or
|
||||||
|
cc = true and
|
||||||
|
not reducedViableImplInCallContext(call, _, _)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// call context may help reduce virtual dispatch
|
||||||
|
exists(DataFlowCallable target |
|
||||||
|
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||||
|
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||||
|
cc = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||||
|
fwdFlowIn(call, _, cc, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||||
|
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(arg, true, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
reducedViableImplInCallContext(call, _, _) and
|
||||||
|
target = p.getEnclosingCallable() and
|
||||||
|
not fullBarrier(p, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||||
|
* restricted to those `call`s for which a context might make a difference,
|
||||||
|
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||||
|
DataFlowCall call, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCall ctx |
|
||||||
|
fwdFlowIsEntered(ctx, _, config) and
|
||||||
|
result = viableImplInCallContextExt(call, ctx)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -726,7 +781,8 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
fwdFlowReturnPosition(pos, cc, config) and
|
fwdFlowReturnPosition(pos, cc, config) and
|
||||||
@@ -740,17 +796,6 @@ private module Stage1 implements StageSig {
|
|||||||
fwdFlowOut(call, out, true, config)
|
fwdFlowOut(call, out, true, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
|
||||||
*/
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
|
||||||
exists(ArgNodeEx arg |
|
|
||||||
fwdFlow(arg, cc, config) and
|
|
||||||
viableParamArgEx(call, _, arg)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||||
exists(NodeEx node1 |
|
exists(NodeEx node1 |
|
||||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||||
@@ -817,20 +862,21 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(DataFlowCall call |
|
revFlowIn(_, node, false, config) and
|
||||||
revFlowIn(call, node, false, config) and
|
|
||||||
toReturn = false
|
toReturn = false
|
||||||
or
|
or
|
||||||
revFlowInToReturn(call, node, config) and
|
|
||||||
revFlowIsReturned(call, toReturn, config)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
revFlowOut(pos, config) and
|
revFlowOut(pos, config) and
|
||||||
node.(RetNodeEx).getReturnPosition() = pos and
|
node.(RetNodeEx).getReturnPosition() = pos and
|
||||||
toReturn = true
|
toReturn = true
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
|
revFlowInToReturn(call, node, config) and
|
||||||
|
revFlowIsReturned(call, toReturn, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -886,11 +932,11 @@ private module Stage1 implements StageSig {
|
|||||||
additional predicate viableParamArgNodeCandFwd1(
|
additional predicate viableParamArgNodeCandFwd1(
|
||||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||||
) {
|
) {
|
||||||
viableParamArgEx(call, p, arg) and
|
fwdFlowIn(call, arg, _, p, config)
|
||||||
fwdFlow(arg, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate revFlowIn(
|
private predicate revFlowIn(
|
||||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -1223,7 +1269,16 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail);
|
Ap apCons(TypedContent tc, Ap tail);
|
||||||
|
|
||||||
Content getHeadContent(Ap ap);
|
/**
|
||||||
|
* An approximation of `Content` that corresponds to the precision level of
|
||||||
|
* `Ap`, such that the mappings from both `Ap` and `Content` to this type
|
||||||
|
* are functional.
|
||||||
|
*/
|
||||||
|
class ApHeadContent;
|
||||||
|
|
||||||
|
ApHeadContent getHeadContent(Ap ap);
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c);
|
||||||
|
|
||||||
class ApOption;
|
class ApOption;
|
||||||
|
|
||||||
@@ -1471,34 +1526,32 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ApNonNil instanceof Ap {
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
ApNonNil() { not this instanceof ApNil }
|
private predicate readStepCand(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
string toString() { result = "" }
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowRead0(
|
|
||||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
|
||||||
Configuration config
|
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
PrevStage::readStepCand(node1, _, _, config)
|
apc = projectToHeadContent(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, c]
|
bindingset[node1, apc]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
private predicate hasHeadContent(Ap ap, Content c) { getHeadContent(ap) = c }
|
private predicate readStepCand0(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
|
) {
|
||||||
|
readStepCand(node1, apc, c, node2, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
exists(ApHeadContent apc |
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
hasHeadContent(ap, c)
|
apc = getHeadContent(ap) and
|
||||||
|
readStepCand0(node1, apc, c, node2, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -2072,8 +2125,12 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Unit;
|
||||||
|
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
Content getHeadContent(Ap ap) { exists(result) and ap = true }
|
ApHeadContent getHeadContent(Ap ap) { exists(result) and ap = true }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { any() }
|
||||||
|
|
||||||
class ApOption = BooleanOption;
|
class ApOption = BooleanOption;
|
||||||
|
|
||||||
@@ -2337,8 +2394,12 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = ContentApprox;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
predicate projectToHeadContent = getContentApprox/1;
|
||||||
|
|
||||||
class ApOption = ApproxAccessPathFrontOption;
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2413,8 +2474,12 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathFrontOption;
|
class ApOption = AccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2743,8 +2808,12 @@ private module Stage5Param implements MkStage<Stage4>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathApproxOption;
|
class ApOption = AccessPathApproxOption;
|
||||||
|
|
||||||
|
|||||||
@@ -667,23 +667,78 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(NodeEx arg |
|
fwdFlowIn(_, _, _, node, config) and
|
||||||
fwdFlow(arg, _, config) and
|
cc = true
|
||||||
viableParamArgEx(_, node, arg) and
|
|
||||||
cc = true and
|
|
||||||
not fullBarrier(node, config)
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(DataFlowCall call |
|
fwdFlowOut(_, node, false, config) and
|
||||||
fwdFlowOut(call, node, false, config) and
|
|
||||||
cc = false
|
cc = false
|
||||||
or
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
fwdFlowOutFromArg(call, node, config) and
|
fwdFlowOutFromArg(call, node, config) and
|
||||||
fwdFlowIsEntered(call, cc, config)
|
fwdFlowIsEntered(call, cc, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowIn(
|
||||||
|
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||||
|
) {
|
||||||
|
// call context cannot help reduce virtual dispatch
|
||||||
|
fwdFlow(arg, cc, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
not fullBarrier(p, config) and
|
||||||
|
(
|
||||||
|
cc = false
|
||||||
|
or
|
||||||
|
cc = true and
|
||||||
|
not reducedViableImplInCallContext(call, _, _)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// call context may help reduce virtual dispatch
|
||||||
|
exists(DataFlowCallable target |
|
||||||
|
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||||
|
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||||
|
cc = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||||
|
fwdFlowIn(call, _, cc, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||||
|
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(arg, true, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
reducedViableImplInCallContext(call, _, _) and
|
||||||
|
target = p.getEnclosingCallable() and
|
||||||
|
not fullBarrier(p, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||||
|
* restricted to those `call`s for which a context might make a difference,
|
||||||
|
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||||
|
DataFlowCall call, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCall ctx |
|
||||||
|
fwdFlowIsEntered(ctx, _, config) and
|
||||||
|
result = viableImplInCallContextExt(call, ctx)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -726,7 +781,8 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
fwdFlowReturnPosition(pos, cc, config) and
|
fwdFlowReturnPosition(pos, cc, config) and
|
||||||
@@ -740,17 +796,6 @@ private module Stage1 implements StageSig {
|
|||||||
fwdFlowOut(call, out, true, config)
|
fwdFlowOut(call, out, true, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
|
||||||
*/
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
|
||||||
exists(ArgNodeEx arg |
|
|
||||||
fwdFlow(arg, cc, config) and
|
|
||||||
viableParamArgEx(call, _, arg)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||||
exists(NodeEx node1 |
|
exists(NodeEx node1 |
|
||||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||||
@@ -817,20 +862,21 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(DataFlowCall call |
|
revFlowIn(_, node, false, config) and
|
||||||
revFlowIn(call, node, false, config) and
|
|
||||||
toReturn = false
|
toReturn = false
|
||||||
or
|
or
|
||||||
revFlowInToReturn(call, node, config) and
|
|
||||||
revFlowIsReturned(call, toReturn, config)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
revFlowOut(pos, config) and
|
revFlowOut(pos, config) and
|
||||||
node.(RetNodeEx).getReturnPosition() = pos and
|
node.(RetNodeEx).getReturnPosition() = pos and
|
||||||
toReturn = true
|
toReturn = true
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
|
revFlowInToReturn(call, node, config) and
|
||||||
|
revFlowIsReturned(call, toReturn, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -886,11 +932,11 @@ private module Stage1 implements StageSig {
|
|||||||
additional predicate viableParamArgNodeCandFwd1(
|
additional predicate viableParamArgNodeCandFwd1(
|
||||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||||
) {
|
) {
|
||||||
viableParamArgEx(call, p, arg) and
|
fwdFlowIn(call, arg, _, p, config)
|
||||||
fwdFlow(arg, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate revFlowIn(
|
private predicate revFlowIn(
|
||||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -1223,7 +1269,16 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail);
|
Ap apCons(TypedContent tc, Ap tail);
|
||||||
|
|
||||||
Content getHeadContent(Ap ap);
|
/**
|
||||||
|
* An approximation of `Content` that corresponds to the precision level of
|
||||||
|
* `Ap`, such that the mappings from both `Ap` and `Content` to this type
|
||||||
|
* are functional.
|
||||||
|
*/
|
||||||
|
class ApHeadContent;
|
||||||
|
|
||||||
|
ApHeadContent getHeadContent(Ap ap);
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c);
|
||||||
|
|
||||||
class ApOption;
|
class ApOption;
|
||||||
|
|
||||||
@@ -1471,34 +1526,32 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ApNonNil instanceof Ap {
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
ApNonNil() { not this instanceof ApNil }
|
private predicate readStepCand(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
string toString() { result = "" }
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowRead0(
|
|
||||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
|
||||||
Configuration config
|
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
PrevStage::readStepCand(node1, _, _, config)
|
apc = projectToHeadContent(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, c]
|
bindingset[node1, apc]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
private predicate hasHeadContent(Ap ap, Content c) { getHeadContent(ap) = c }
|
private predicate readStepCand0(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
|
) {
|
||||||
|
readStepCand(node1, apc, c, node2, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
exists(ApHeadContent apc |
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
hasHeadContent(ap, c)
|
apc = getHeadContent(ap) and
|
||||||
|
readStepCand0(node1, apc, c, node2, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -2072,8 +2125,12 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Unit;
|
||||||
|
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
Content getHeadContent(Ap ap) { exists(result) and ap = true }
|
ApHeadContent getHeadContent(Ap ap) { exists(result) and ap = true }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { any() }
|
||||||
|
|
||||||
class ApOption = BooleanOption;
|
class ApOption = BooleanOption;
|
||||||
|
|
||||||
@@ -2337,8 +2394,12 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = ContentApprox;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
predicate projectToHeadContent = getContentApprox/1;
|
||||||
|
|
||||||
class ApOption = ApproxAccessPathFrontOption;
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2413,8 +2474,12 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathFrontOption;
|
class ApOption = AccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2743,8 +2808,12 @@ private module Stage5Param implements MkStage<Stage4>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathApproxOption;
|
class ApOption = AccessPathApproxOption;
|
||||||
|
|
||||||
|
|||||||
@@ -667,23 +667,78 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(NodeEx arg |
|
fwdFlowIn(_, _, _, node, config) and
|
||||||
fwdFlow(arg, _, config) and
|
cc = true
|
||||||
viableParamArgEx(_, node, arg) and
|
|
||||||
cc = true and
|
|
||||||
not fullBarrier(node, config)
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(DataFlowCall call |
|
fwdFlowOut(_, node, false, config) and
|
||||||
fwdFlowOut(call, node, false, config) and
|
|
||||||
cc = false
|
cc = false
|
||||||
or
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
fwdFlowOutFromArg(call, node, config) and
|
fwdFlowOutFromArg(call, node, config) and
|
||||||
fwdFlowIsEntered(call, cc, config)
|
fwdFlowIsEntered(call, cc, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowIn(
|
||||||
|
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||||
|
) {
|
||||||
|
// call context cannot help reduce virtual dispatch
|
||||||
|
fwdFlow(arg, cc, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
not fullBarrier(p, config) and
|
||||||
|
(
|
||||||
|
cc = false
|
||||||
|
or
|
||||||
|
cc = true and
|
||||||
|
not reducedViableImplInCallContext(call, _, _)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// call context may help reduce virtual dispatch
|
||||||
|
exists(DataFlowCallable target |
|
||||||
|
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||||
|
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||||
|
cc = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||||
|
fwdFlowIn(call, _, cc, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||||
|
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(arg, true, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
reducedViableImplInCallContext(call, _, _) and
|
||||||
|
target = p.getEnclosingCallable() and
|
||||||
|
not fullBarrier(p, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||||
|
* restricted to those `call`s for which a context might make a difference,
|
||||||
|
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||||
|
DataFlowCall call, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCall ctx |
|
||||||
|
fwdFlowIsEntered(ctx, _, config) and
|
||||||
|
result = viableImplInCallContextExt(call, ctx)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -726,7 +781,8 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
fwdFlowReturnPosition(pos, cc, config) and
|
fwdFlowReturnPosition(pos, cc, config) and
|
||||||
@@ -740,17 +796,6 @@ private module Stage1 implements StageSig {
|
|||||||
fwdFlowOut(call, out, true, config)
|
fwdFlowOut(call, out, true, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
|
||||||
*/
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
|
||||||
exists(ArgNodeEx arg |
|
|
||||||
fwdFlow(arg, cc, config) and
|
|
||||||
viableParamArgEx(call, _, arg)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||||
exists(NodeEx node1 |
|
exists(NodeEx node1 |
|
||||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||||
@@ -817,20 +862,21 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(DataFlowCall call |
|
revFlowIn(_, node, false, config) and
|
||||||
revFlowIn(call, node, false, config) and
|
|
||||||
toReturn = false
|
toReturn = false
|
||||||
or
|
or
|
||||||
revFlowInToReturn(call, node, config) and
|
|
||||||
revFlowIsReturned(call, toReturn, config)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
revFlowOut(pos, config) and
|
revFlowOut(pos, config) and
|
||||||
node.(RetNodeEx).getReturnPosition() = pos and
|
node.(RetNodeEx).getReturnPosition() = pos and
|
||||||
toReturn = true
|
toReturn = true
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
|
revFlowInToReturn(call, node, config) and
|
||||||
|
revFlowIsReturned(call, toReturn, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -886,11 +932,11 @@ private module Stage1 implements StageSig {
|
|||||||
additional predicate viableParamArgNodeCandFwd1(
|
additional predicate viableParamArgNodeCandFwd1(
|
||||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||||
) {
|
) {
|
||||||
viableParamArgEx(call, p, arg) and
|
fwdFlowIn(call, arg, _, p, config)
|
||||||
fwdFlow(arg, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate revFlowIn(
|
private predicate revFlowIn(
|
||||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -1223,7 +1269,16 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail);
|
Ap apCons(TypedContent tc, Ap tail);
|
||||||
|
|
||||||
Content getHeadContent(Ap ap);
|
/**
|
||||||
|
* An approximation of `Content` that corresponds to the precision level of
|
||||||
|
* `Ap`, such that the mappings from both `Ap` and `Content` to this type
|
||||||
|
* are functional.
|
||||||
|
*/
|
||||||
|
class ApHeadContent;
|
||||||
|
|
||||||
|
ApHeadContent getHeadContent(Ap ap);
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c);
|
||||||
|
|
||||||
class ApOption;
|
class ApOption;
|
||||||
|
|
||||||
@@ -1471,34 +1526,32 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ApNonNil instanceof Ap {
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
ApNonNil() { not this instanceof ApNil }
|
private predicate readStepCand(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
string toString() { result = "" }
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowRead0(
|
|
||||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
|
||||||
Configuration config
|
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
PrevStage::readStepCand(node1, _, _, config)
|
apc = projectToHeadContent(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, c]
|
bindingset[node1, apc]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
private predicate hasHeadContent(Ap ap, Content c) { getHeadContent(ap) = c }
|
private predicate readStepCand0(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
|
) {
|
||||||
|
readStepCand(node1, apc, c, node2, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
exists(ApHeadContent apc |
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
hasHeadContent(ap, c)
|
apc = getHeadContent(ap) and
|
||||||
|
readStepCand0(node1, apc, c, node2, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -2072,8 +2125,12 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Unit;
|
||||||
|
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
Content getHeadContent(Ap ap) { exists(result) and ap = true }
|
ApHeadContent getHeadContent(Ap ap) { exists(result) and ap = true }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { any() }
|
||||||
|
|
||||||
class ApOption = BooleanOption;
|
class ApOption = BooleanOption;
|
||||||
|
|
||||||
@@ -2337,8 +2394,12 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = ContentApprox;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
predicate projectToHeadContent = getContentApprox/1;
|
||||||
|
|
||||||
class ApOption = ApproxAccessPathFrontOption;
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2413,8 +2474,12 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathFrontOption;
|
class ApOption = AccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2743,8 +2808,12 @@ private module Stage5Param implements MkStage<Stage4>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathApproxOption;
|
class ApOption = AccessPathApproxOption;
|
||||||
|
|
||||||
|
|||||||
@@ -667,23 +667,78 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(NodeEx arg |
|
fwdFlowIn(_, _, _, node, config) and
|
||||||
fwdFlow(arg, _, config) and
|
cc = true
|
||||||
viableParamArgEx(_, node, arg) and
|
|
||||||
cc = true and
|
|
||||||
not fullBarrier(node, config)
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(DataFlowCall call |
|
fwdFlowOut(_, node, false, config) and
|
||||||
fwdFlowOut(call, node, false, config) and
|
|
||||||
cc = false
|
cc = false
|
||||||
or
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
fwdFlowOutFromArg(call, node, config) and
|
fwdFlowOutFromArg(call, node, config) and
|
||||||
fwdFlowIsEntered(call, cc, config)
|
fwdFlowIsEntered(call, cc, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowIn(
|
||||||
|
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||||
|
) {
|
||||||
|
// call context cannot help reduce virtual dispatch
|
||||||
|
fwdFlow(arg, cc, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
not fullBarrier(p, config) and
|
||||||
|
(
|
||||||
|
cc = false
|
||||||
|
or
|
||||||
|
cc = true and
|
||||||
|
not reducedViableImplInCallContext(call, _, _)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// call context may help reduce virtual dispatch
|
||||||
|
exists(DataFlowCallable target |
|
||||||
|
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||||
|
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||||
|
cc = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||||
|
fwdFlowIn(call, _, cc, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||||
|
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(arg, true, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
reducedViableImplInCallContext(call, _, _) and
|
||||||
|
target = p.getEnclosingCallable() and
|
||||||
|
not fullBarrier(p, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||||
|
* restricted to those `call`s for which a context might make a difference,
|
||||||
|
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||||
|
DataFlowCall call, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCall ctx |
|
||||||
|
fwdFlowIsEntered(ctx, _, config) and
|
||||||
|
result = viableImplInCallContextExt(call, ctx)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -726,7 +781,8 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
fwdFlowReturnPosition(pos, cc, config) and
|
fwdFlowReturnPosition(pos, cc, config) and
|
||||||
@@ -740,17 +796,6 @@ private module Stage1 implements StageSig {
|
|||||||
fwdFlowOut(call, out, true, config)
|
fwdFlowOut(call, out, true, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
|
||||||
*/
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
|
||||||
exists(ArgNodeEx arg |
|
|
||||||
fwdFlow(arg, cc, config) and
|
|
||||||
viableParamArgEx(call, _, arg)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||||
exists(NodeEx node1 |
|
exists(NodeEx node1 |
|
||||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||||
@@ -817,20 +862,21 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(DataFlowCall call |
|
revFlowIn(_, node, false, config) and
|
||||||
revFlowIn(call, node, false, config) and
|
|
||||||
toReturn = false
|
toReturn = false
|
||||||
or
|
or
|
||||||
revFlowInToReturn(call, node, config) and
|
|
||||||
revFlowIsReturned(call, toReturn, config)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
revFlowOut(pos, config) and
|
revFlowOut(pos, config) and
|
||||||
node.(RetNodeEx).getReturnPosition() = pos and
|
node.(RetNodeEx).getReturnPosition() = pos and
|
||||||
toReturn = true
|
toReturn = true
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
|
revFlowInToReturn(call, node, config) and
|
||||||
|
revFlowIsReturned(call, toReturn, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -886,11 +932,11 @@ private module Stage1 implements StageSig {
|
|||||||
additional predicate viableParamArgNodeCandFwd1(
|
additional predicate viableParamArgNodeCandFwd1(
|
||||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||||
) {
|
) {
|
||||||
viableParamArgEx(call, p, arg) and
|
fwdFlowIn(call, arg, _, p, config)
|
||||||
fwdFlow(arg, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate revFlowIn(
|
private predicate revFlowIn(
|
||||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -1223,7 +1269,16 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail);
|
Ap apCons(TypedContent tc, Ap tail);
|
||||||
|
|
||||||
Content getHeadContent(Ap ap);
|
/**
|
||||||
|
* An approximation of `Content` that corresponds to the precision level of
|
||||||
|
* `Ap`, such that the mappings from both `Ap` and `Content` to this type
|
||||||
|
* are functional.
|
||||||
|
*/
|
||||||
|
class ApHeadContent;
|
||||||
|
|
||||||
|
ApHeadContent getHeadContent(Ap ap);
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c);
|
||||||
|
|
||||||
class ApOption;
|
class ApOption;
|
||||||
|
|
||||||
@@ -1471,34 +1526,32 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ApNonNil instanceof Ap {
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
ApNonNil() { not this instanceof ApNil }
|
private predicate readStepCand(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
string toString() { result = "" }
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowRead0(
|
|
||||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
|
||||||
Configuration config
|
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
PrevStage::readStepCand(node1, _, _, config)
|
apc = projectToHeadContent(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, c]
|
bindingset[node1, apc]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
private predicate hasHeadContent(Ap ap, Content c) { getHeadContent(ap) = c }
|
private predicate readStepCand0(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
|
) {
|
||||||
|
readStepCand(node1, apc, c, node2, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
exists(ApHeadContent apc |
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
hasHeadContent(ap, c)
|
apc = getHeadContent(ap) and
|
||||||
|
readStepCand0(node1, apc, c, node2, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -2072,8 +2125,12 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Unit;
|
||||||
|
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
Content getHeadContent(Ap ap) { exists(result) and ap = true }
|
ApHeadContent getHeadContent(Ap ap) { exists(result) and ap = true }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { any() }
|
||||||
|
|
||||||
class ApOption = BooleanOption;
|
class ApOption = BooleanOption;
|
||||||
|
|
||||||
@@ -2337,8 +2394,12 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = ContentApprox;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
predicate projectToHeadContent = getContentApprox/1;
|
||||||
|
|
||||||
class ApOption = ApproxAccessPathFrontOption;
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2413,8 +2474,12 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathFrontOption;
|
class ApOption = AccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2743,8 +2808,12 @@ private module Stage5Param implements MkStage<Stage4>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathApproxOption;
|
class ApOption = AccessPathApproxOption;
|
||||||
|
|
||||||
|
|||||||
@@ -707,8 +707,8 @@ private module Cached {
|
|||||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||||
* restricted to those `call`s for which a context might make a difference.
|
* restricted to those `call`s for which a context might make a difference.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
cached
|
||||||
private DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) {
|
DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) {
|
||||||
result = viableImplInCallContext(call, ctx) and
|
result = viableImplInCallContext(call, ctx) and
|
||||||
result = viableCallable(call)
|
result = viableCallable(call)
|
||||||
or
|
or
|
||||||
@@ -1391,6 +1391,9 @@ class TypedContentApprox extends MkTypedContentApprox {
|
|||||||
/** Gets a typed content approximated by this value. */
|
/** Gets a typed content approximated by this value. */
|
||||||
TypedContent getATypedContent() { result = getATypedContent(this) }
|
TypedContent getATypedContent() { result = getATypedContent(this) }
|
||||||
|
|
||||||
|
/** Gets the content. */
|
||||||
|
ContentApprox getContent() { result = c }
|
||||||
|
|
||||||
/** Gets the container type. */
|
/** Gets the container type. */
|
||||||
DataFlowType getContainerType() { result = t }
|
DataFlowType getContainerType() { result = t }
|
||||||
|
|
||||||
@@ -1408,6 +1411,8 @@ abstract class ApproxAccessPathFront extends TApproxAccessPathFront {
|
|||||||
|
|
||||||
abstract boolean toBoolNonEmpty();
|
abstract boolean toBoolNonEmpty();
|
||||||
|
|
||||||
|
TypedContentApprox getHead() { this = TApproxFrontHead(result) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
TypedContent getAHead() {
|
TypedContent getAHead() {
|
||||||
exists(TypedContentApprox cont |
|
exists(TypedContentApprox cont |
|
||||||
|
|||||||
@@ -667,23 +667,78 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(NodeEx arg |
|
fwdFlowIn(_, _, _, node, config) and
|
||||||
fwdFlow(arg, _, config) and
|
cc = true
|
||||||
viableParamArgEx(_, node, arg) and
|
|
||||||
cc = true and
|
|
||||||
not fullBarrier(node, config)
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(DataFlowCall call |
|
fwdFlowOut(_, node, false, config) and
|
||||||
fwdFlowOut(call, node, false, config) and
|
|
||||||
cc = false
|
cc = false
|
||||||
or
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
fwdFlowOutFromArg(call, node, config) and
|
fwdFlowOutFromArg(call, node, config) and
|
||||||
fwdFlowIsEntered(call, cc, config)
|
fwdFlowIsEntered(call, cc, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowIn(
|
||||||
|
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||||
|
) {
|
||||||
|
// call context cannot help reduce virtual dispatch
|
||||||
|
fwdFlow(arg, cc, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
not fullBarrier(p, config) and
|
||||||
|
(
|
||||||
|
cc = false
|
||||||
|
or
|
||||||
|
cc = true and
|
||||||
|
not reducedViableImplInCallContext(call, _, _)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// call context may help reduce virtual dispatch
|
||||||
|
exists(DataFlowCallable target |
|
||||||
|
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||||
|
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||||
|
cc = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||||
|
fwdFlowIn(call, _, cc, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||||
|
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(arg, true, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
reducedViableImplInCallContext(call, _, _) and
|
||||||
|
target = p.getEnclosingCallable() and
|
||||||
|
not fullBarrier(p, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||||
|
* restricted to those `call`s for which a context might make a difference,
|
||||||
|
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||||
|
DataFlowCall call, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCall ctx |
|
||||||
|
fwdFlowIsEntered(ctx, _, config) and
|
||||||
|
result = viableImplInCallContextExt(call, ctx)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -726,7 +781,8 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
fwdFlowReturnPosition(pos, cc, config) and
|
fwdFlowReturnPosition(pos, cc, config) and
|
||||||
@@ -740,17 +796,6 @@ private module Stage1 implements StageSig {
|
|||||||
fwdFlowOut(call, out, true, config)
|
fwdFlowOut(call, out, true, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
|
||||||
*/
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
|
||||||
exists(ArgNodeEx arg |
|
|
||||||
fwdFlow(arg, cc, config) and
|
|
||||||
viableParamArgEx(call, _, arg)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||||
exists(NodeEx node1 |
|
exists(NodeEx node1 |
|
||||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||||
@@ -817,20 +862,21 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(DataFlowCall call |
|
revFlowIn(_, node, false, config) and
|
||||||
revFlowIn(call, node, false, config) and
|
|
||||||
toReturn = false
|
toReturn = false
|
||||||
or
|
or
|
||||||
revFlowInToReturn(call, node, config) and
|
|
||||||
revFlowIsReturned(call, toReturn, config)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
revFlowOut(pos, config) and
|
revFlowOut(pos, config) and
|
||||||
node.(RetNodeEx).getReturnPosition() = pos and
|
node.(RetNodeEx).getReturnPosition() = pos and
|
||||||
toReturn = true
|
toReturn = true
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
|
revFlowInToReturn(call, node, config) and
|
||||||
|
revFlowIsReturned(call, toReturn, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -886,11 +932,11 @@ private module Stage1 implements StageSig {
|
|||||||
additional predicate viableParamArgNodeCandFwd1(
|
additional predicate viableParamArgNodeCandFwd1(
|
||||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||||
) {
|
) {
|
||||||
viableParamArgEx(call, p, arg) and
|
fwdFlowIn(call, arg, _, p, config)
|
||||||
fwdFlow(arg, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate revFlowIn(
|
private predicate revFlowIn(
|
||||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -1223,7 +1269,16 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail);
|
Ap apCons(TypedContent tc, Ap tail);
|
||||||
|
|
||||||
Content getHeadContent(Ap ap);
|
/**
|
||||||
|
* An approximation of `Content` that corresponds to the precision level of
|
||||||
|
* `Ap`, such that the mappings from both `Ap` and `Content` to this type
|
||||||
|
* are functional.
|
||||||
|
*/
|
||||||
|
class ApHeadContent;
|
||||||
|
|
||||||
|
ApHeadContent getHeadContent(Ap ap);
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c);
|
||||||
|
|
||||||
class ApOption;
|
class ApOption;
|
||||||
|
|
||||||
@@ -1471,34 +1526,32 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ApNonNil instanceof Ap {
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
ApNonNil() { not this instanceof ApNil }
|
private predicate readStepCand(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
string toString() { result = "" }
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowRead0(
|
|
||||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
|
||||||
Configuration config
|
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
PrevStage::readStepCand(node1, _, _, config)
|
apc = projectToHeadContent(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, c]
|
bindingset[node1, apc]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
private predicate hasHeadContent(Ap ap, Content c) { getHeadContent(ap) = c }
|
private predicate readStepCand0(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
|
) {
|
||||||
|
readStepCand(node1, apc, c, node2, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
exists(ApHeadContent apc |
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
hasHeadContent(ap, c)
|
apc = getHeadContent(ap) and
|
||||||
|
readStepCand0(node1, apc, c, node2, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -2072,8 +2125,12 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Unit;
|
||||||
|
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
Content getHeadContent(Ap ap) { exists(result) and ap = true }
|
ApHeadContent getHeadContent(Ap ap) { exists(result) and ap = true }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { any() }
|
||||||
|
|
||||||
class ApOption = BooleanOption;
|
class ApOption = BooleanOption;
|
||||||
|
|
||||||
@@ -2337,8 +2394,12 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = ContentApprox;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
predicate projectToHeadContent = getContentApprox/1;
|
||||||
|
|
||||||
class ApOption = ApproxAccessPathFrontOption;
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2413,8 +2474,12 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathFrontOption;
|
class ApOption = AccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2743,8 +2808,12 @@ private module Stage5Param implements MkStage<Stage4>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathApproxOption;
|
class ApOption = AccessPathApproxOption;
|
||||||
|
|
||||||
|
|||||||
@@ -667,23 +667,78 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(NodeEx arg |
|
fwdFlowIn(_, _, _, node, config) and
|
||||||
fwdFlow(arg, _, config) and
|
cc = true
|
||||||
viableParamArgEx(_, node, arg) and
|
|
||||||
cc = true and
|
|
||||||
not fullBarrier(node, config)
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(DataFlowCall call |
|
fwdFlowOut(_, node, false, config) and
|
||||||
fwdFlowOut(call, node, false, config) and
|
|
||||||
cc = false
|
cc = false
|
||||||
or
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
fwdFlowOutFromArg(call, node, config) and
|
fwdFlowOutFromArg(call, node, config) and
|
||||||
fwdFlowIsEntered(call, cc, config)
|
fwdFlowIsEntered(call, cc, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowIn(
|
||||||
|
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||||
|
) {
|
||||||
|
// call context cannot help reduce virtual dispatch
|
||||||
|
fwdFlow(arg, cc, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
not fullBarrier(p, config) and
|
||||||
|
(
|
||||||
|
cc = false
|
||||||
|
or
|
||||||
|
cc = true and
|
||||||
|
not reducedViableImplInCallContext(call, _, _)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// call context may help reduce virtual dispatch
|
||||||
|
exists(DataFlowCallable target |
|
||||||
|
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||||
|
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||||
|
cc = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||||
|
fwdFlowIn(call, _, cc, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||||
|
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(arg, true, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
reducedViableImplInCallContext(call, _, _) and
|
||||||
|
target = p.getEnclosingCallable() and
|
||||||
|
not fullBarrier(p, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||||
|
* restricted to those `call`s for which a context might make a difference,
|
||||||
|
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||||
|
DataFlowCall call, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCall ctx |
|
||||||
|
fwdFlowIsEntered(ctx, _, config) and
|
||||||
|
result = viableImplInCallContextExt(call, ctx)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -726,7 +781,8 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
fwdFlowReturnPosition(pos, cc, config) and
|
fwdFlowReturnPosition(pos, cc, config) and
|
||||||
@@ -740,17 +796,6 @@ private module Stage1 implements StageSig {
|
|||||||
fwdFlowOut(call, out, true, config)
|
fwdFlowOut(call, out, true, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
|
||||||
*/
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
|
||||||
exists(ArgNodeEx arg |
|
|
||||||
fwdFlow(arg, cc, config) and
|
|
||||||
viableParamArgEx(call, _, arg)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||||
exists(NodeEx node1 |
|
exists(NodeEx node1 |
|
||||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||||
@@ -817,20 +862,21 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(DataFlowCall call |
|
revFlowIn(_, node, false, config) and
|
||||||
revFlowIn(call, node, false, config) and
|
|
||||||
toReturn = false
|
toReturn = false
|
||||||
or
|
or
|
||||||
revFlowInToReturn(call, node, config) and
|
|
||||||
revFlowIsReturned(call, toReturn, config)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
revFlowOut(pos, config) and
|
revFlowOut(pos, config) and
|
||||||
node.(RetNodeEx).getReturnPosition() = pos and
|
node.(RetNodeEx).getReturnPosition() = pos and
|
||||||
toReturn = true
|
toReturn = true
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
|
revFlowInToReturn(call, node, config) and
|
||||||
|
revFlowIsReturned(call, toReturn, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -886,11 +932,11 @@ private module Stage1 implements StageSig {
|
|||||||
additional predicate viableParamArgNodeCandFwd1(
|
additional predicate viableParamArgNodeCandFwd1(
|
||||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||||
) {
|
) {
|
||||||
viableParamArgEx(call, p, arg) and
|
fwdFlowIn(call, arg, _, p, config)
|
||||||
fwdFlow(arg, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate revFlowIn(
|
private predicate revFlowIn(
|
||||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -1223,7 +1269,16 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail);
|
Ap apCons(TypedContent tc, Ap tail);
|
||||||
|
|
||||||
Content getHeadContent(Ap ap);
|
/**
|
||||||
|
* An approximation of `Content` that corresponds to the precision level of
|
||||||
|
* `Ap`, such that the mappings from both `Ap` and `Content` to this type
|
||||||
|
* are functional.
|
||||||
|
*/
|
||||||
|
class ApHeadContent;
|
||||||
|
|
||||||
|
ApHeadContent getHeadContent(Ap ap);
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c);
|
||||||
|
|
||||||
class ApOption;
|
class ApOption;
|
||||||
|
|
||||||
@@ -1471,34 +1526,32 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ApNonNil instanceof Ap {
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
ApNonNil() { not this instanceof ApNil }
|
private predicate readStepCand(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
string toString() { result = "" }
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowRead0(
|
|
||||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
|
||||||
Configuration config
|
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
PrevStage::readStepCand(node1, _, _, config)
|
apc = projectToHeadContent(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, c]
|
bindingset[node1, apc]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
private predicate hasHeadContent(Ap ap, Content c) { getHeadContent(ap) = c }
|
private predicate readStepCand0(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
|
) {
|
||||||
|
readStepCand(node1, apc, c, node2, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
exists(ApHeadContent apc |
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
hasHeadContent(ap, c)
|
apc = getHeadContent(ap) and
|
||||||
|
readStepCand0(node1, apc, c, node2, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -2072,8 +2125,12 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Unit;
|
||||||
|
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
Content getHeadContent(Ap ap) { exists(result) and ap = true }
|
ApHeadContent getHeadContent(Ap ap) { exists(result) and ap = true }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { any() }
|
||||||
|
|
||||||
class ApOption = BooleanOption;
|
class ApOption = BooleanOption;
|
||||||
|
|
||||||
@@ -2337,8 +2394,12 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = ContentApprox;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
predicate projectToHeadContent = getContentApprox/1;
|
||||||
|
|
||||||
class ApOption = ApproxAccessPathFrontOption;
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2413,8 +2474,12 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathFrontOption;
|
class ApOption = AccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2743,8 +2808,12 @@ private module Stage5Param implements MkStage<Stage4>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathApproxOption;
|
class ApOption = AccessPathApproxOption;
|
||||||
|
|
||||||
|
|||||||
@@ -667,23 +667,78 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(NodeEx arg |
|
fwdFlowIn(_, _, _, node, config) and
|
||||||
fwdFlow(arg, _, config) and
|
cc = true
|
||||||
viableParamArgEx(_, node, arg) and
|
|
||||||
cc = true and
|
|
||||||
not fullBarrier(node, config)
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(DataFlowCall call |
|
fwdFlowOut(_, node, false, config) and
|
||||||
fwdFlowOut(call, node, false, config) and
|
|
||||||
cc = false
|
cc = false
|
||||||
or
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
fwdFlowOutFromArg(call, node, config) and
|
fwdFlowOutFromArg(call, node, config) and
|
||||||
fwdFlowIsEntered(call, cc, config)
|
fwdFlowIsEntered(call, cc, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowIn(
|
||||||
|
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||||
|
) {
|
||||||
|
// call context cannot help reduce virtual dispatch
|
||||||
|
fwdFlow(arg, cc, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
not fullBarrier(p, config) and
|
||||||
|
(
|
||||||
|
cc = false
|
||||||
|
or
|
||||||
|
cc = true and
|
||||||
|
not reducedViableImplInCallContext(call, _, _)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// call context may help reduce virtual dispatch
|
||||||
|
exists(DataFlowCallable target |
|
||||||
|
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||||
|
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||||
|
cc = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||||
|
fwdFlowIn(call, _, cc, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||||
|
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(arg, true, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
reducedViableImplInCallContext(call, _, _) and
|
||||||
|
target = p.getEnclosingCallable() and
|
||||||
|
not fullBarrier(p, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||||
|
* restricted to those `call`s for which a context might make a difference,
|
||||||
|
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||||
|
DataFlowCall call, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCall ctx |
|
||||||
|
fwdFlowIsEntered(ctx, _, config) and
|
||||||
|
result = viableImplInCallContextExt(call, ctx)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -726,7 +781,8 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
fwdFlowReturnPosition(pos, cc, config) and
|
fwdFlowReturnPosition(pos, cc, config) and
|
||||||
@@ -740,17 +796,6 @@ private module Stage1 implements StageSig {
|
|||||||
fwdFlowOut(call, out, true, config)
|
fwdFlowOut(call, out, true, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
|
||||||
*/
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
|
||||||
exists(ArgNodeEx arg |
|
|
||||||
fwdFlow(arg, cc, config) and
|
|
||||||
viableParamArgEx(call, _, arg)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||||
exists(NodeEx node1 |
|
exists(NodeEx node1 |
|
||||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||||
@@ -817,20 +862,21 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(DataFlowCall call |
|
revFlowIn(_, node, false, config) and
|
||||||
revFlowIn(call, node, false, config) and
|
|
||||||
toReturn = false
|
toReturn = false
|
||||||
or
|
or
|
||||||
revFlowInToReturn(call, node, config) and
|
|
||||||
revFlowIsReturned(call, toReturn, config)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
revFlowOut(pos, config) and
|
revFlowOut(pos, config) and
|
||||||
node.(RetNodeEx).getReturnPosition() = pos and
|
node.(RetNodeEx).getReturnPosition() = pos and
|
||||||
toReturn = true
|
toReturn = true
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
|
revFlowInToReturn(call, node, config) and
|
||||||
|
revFlowIsReturned(call, toReturn, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -886,11 +932,11 @@ private module Stage1 implements StageSig {
|
|||||||
additional predicate viableParamArgNodeCandFwd1(
|
additional predicate viableParamArgNodeCandFwd1(
|
||||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||||
) {
|
) {
|
||||||
viableParamArgEx(call, p, arg) and
|
fwdFlowIn(call, arg, _, p, config)
|
||||||
fwdFlow(arg, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate revFlowIn(
|
private predicate revFlowIn(
|
||||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -1223,7 +1269,16 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail);
|
Ap apCons(TypedContent tc, Ap tail);
|
||||||
|
|
||||||
Content getHeadContent(Ap ap);
|
/**
|
||||||
|
* An approximation of `Content` that corresponds to the precision level of
|
||||||
|
* `Ap`, such that the mappings from both `Ap` and `Content` to this type
|
||||||
|
* are functional.
|
||||||
|
*/
|
||||||
|
class ApHeadContent;
|
||||||
|
|
||||||
|
ApHeadContent getHeadContent(Ap ap);
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c);
|
||||||
|
|
||||||
class ApOption;
|
class ApOption;
|
||||||
|
|
||||||
@@ -1471,34 +1526,32 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ApNonNil instanceof Ap {
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
ApNonNil() { not this instanceof ApNil }
|
private predicate readStepCand(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
string toString() { result = "" }
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowRead0(
|
|
||||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
|
||||||
Configuration config
|
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
PrevStage::readStepCand(node1, _, _, config)
|
apc = projectToHeadContent(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, c]
|
bindingset[node1, apc]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
private predicate hasHeadContent(Ap ap, Content c) { getHeadContent(ap) = c }
|
private predicate readStepCand0(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
|
) {
|
||||||
|
readStepCand(node1, apc, c, node2, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
exists(ApHeadContent apc |
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
hasHeadContent(ap, c)
|
apc = getHeadContent(ap) and
|
||||||
|
readStepCand0(node1, apc, c, node2, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -2072,8 +2125,12 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Unit;
|
||||||
|
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
Content getHeadContent(Ap ap) { exists(result) and ap = true }
|
ApHeadContent getHeadContent(Ap ap) { exists(result) and ap = true }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { any() }
|
||||||
|
|
||||||
class ApOption = BooleanOption;
|
class ApOption = BooleanOption;
|
||||||
|
|
||||||
@@ -2337,8 +2394,12 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = ContentApprox;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
predicate projectToHeadContent = getContentApprox/1;
|
||||||
|
|
||||||
class ApOption = ApproxAccessPathFrontOption;
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2413,8 +2474,12 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathFrontOption;
|
class ApOption = AccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2743,8 +2808,12 @@ private module Stage5Param implements MkStage<Stage4>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathApproxOption;
|
class ApOption = AccessPathApproxOption;
|
||||||
|
|
||||||
|
|||||||
@@ -667,23 +667,78 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(NodeEx arg |
|
fwdFlowIn(_, _, _, node, config) and
|
||||||
fwdFlow(arg, _, config) and
|
cc = true
|
||||||
viableParamArgEx(_, node, arg) and
|
|
||||||
cc = true and
|
|
||||||
not fullBarrier(node, config)
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(DataFlowCall call |
|
fwdFlowOut(_, node, false, config) and
|
||||||
fwdFlowOut(call, node, false, config) and
|
|
||||||
cc = false
|
cc = false
|
||||||
or
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
fwdFlowOutFromArg(call, node, config) and
|
fwdFlowOutFromArg(call, node, config) and
|
||||||
fwdFlowIsEntered(call, cc, config)
|
fwdFlowIsEntered(call, cc, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowIn(
|
||||||
|
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||||
|
) {
|
||||||
|
// call context cannot help reduce virtual dispatch
|
||||||
|
fwdFlow(arg, cc, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
not fullBarrier(p, config) and
|
||||||
|
(
|
||||||
|
cc = false
|
||||||
|
or
|
||||||
|
cc = true and
|
||||||
|
not reducedViableImplInCallContext(call, _, _)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// call context may help reduce virtual dispatch
|
||||||
|
exists(DataFlowCallable target |
|
||||||
|
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||||
|
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||||
|
cc = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||||
|
fwdFlowIn(call, _, cc, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||||
|
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(arg, true, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
reducedViableImplInCallContext(call, _, _) and
|
||||||
|
target = p.getEnclosingCallable() and
|
||||||
|
not fullBarrier(p, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||||
|
* restricted to those `call`s for which a context might make a difference,
|
||||||
|
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||||
|
DataFlowCall call, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCall ctx |
|
||||||
|
fwdFlowIsEntered(ctx, _, config) and
|
||||||
|
result = viableImplInCallContextExt(call, ctx)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -726,7 +781,8 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
fwdFlowReturnPosition(pos, cc, config) and
|
fwdFlowReturnPosition(pos, cc, config) and
|
||||||
@@ -740,17 +796,6 @@ private module Stage1 implements StageSig {
|
|||||||
fwdFlowOut(call, out, true, config)
|
fwdFlowOut(call, out, true, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
|
||||||
*/
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
|
||||||
exists(ArgNodeEx arg |
|
|
||||||
fwdFlow(arg, cc, config) and
|
|
||||||
viableParamArgEx(call, _, arg)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||||
exists(NodeEx node1 |
|
exists(NodeEx node1 |
|
||||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||||
@@ -817,20 +862,21 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(DataFlowCall call |
|
revFlowIn(_, node, false, config) and
|
||||||
revFlowIn(call, node, false, config) and
|
|
||||||
toReturn = false
|
toReturn = false
|
||||||
or
|
or
|
||||||
revFlowInToReturn(call, node, config) and
|
|
||||||
revFlowIsReturned(call, toReturn, config)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
revFlowOut(pos, config) and
|
revFlowOut(pos, config) and
|
||||||
node.(RetNodeEx).getReturnPosition() = pos and
|
node.(RetNodeEx).getReturnPosition() = pos and
|
||||||
toReturn = true
|
toReturn = true
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
|
revFlowInToReturn(call, node, config) and
|
||||||
|
revFlowIsReturned(call, toReturn, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -886,11 +932,11 @@ private module Stage1 implements StageSig {
|
|||||||
additional predicate viableParamArgNodeCandFwd1(
|
additional predicate viableParamArgNodeCandFwd1(
|
||||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||||
) {
|
) {
|
||||||
viableParamArgEx(call, p, arg) and
|
fwdFlowIn(call, arg, _, p, config)
|
||||||
fwdFlow(arg, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate revFlowIn(
|
private predicate revFlowIn(
|
||||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -1223,7 +1269,16 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail);
|
Ap apCons(TypedContent tc, Ap tail);
|
||||||
|
|
||||||
Content getHeadContent(Ap ap);
|
/**
|
||||||
|
* An approximation of `Content` that corresponds to the precision level of
|
||||||
|
* `Ap`, such that the mappings from both `Ap` and `Content` to this type
|
||||||
|
* are functional.
|
||||||
|
*/
|
||||||
|
class ApHeadContent;
|
||||||
|
|
||||||
|
ApHeadContent getHeadContent(Ap ap);
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c);
|
||||||
|
|
||||||
class ApOption;
|
class ApOption;
|
||||||
|
|
||||||
@@ -1471,34 +1526,32 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ApNonNil instanceof Ap {
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
ApNonNil() { not this instanceof ApNil }
|
private predicate readStepCand(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
string toString() { result = "" }
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowRead0(
|
|
||||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
|
||||||
Configuration config
|
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
PrevStage::readStepCand(node1, _, _, config)
|
apc = projectToHeadContent(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, c]
|
bindingset[node1, apc]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
private predicate hasHeadContent(Ap ap, Content c) { getHeadContent(ap) = c }
|
private predicate readStepCand0(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
|
) {
|
||||||
|
readStepCand(node1, apc, c, node2, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
exists(ApHeadContent apc |
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
hasHeadContent(ap, c)
|
apc = getHeadContent(ap) and
|
||||||
|
readStepCand0(node1, apc, c, node2, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -2072,8 +2125,12 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Unit;
|
||||||
|
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
Content getHeadContent(Ap ap) { exists(result) and ap = true }
|
ApHeadContent getHeadContent(Ap ap) { exists(result) and ap = true }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { any() }
|
||||||
|
|
||||||
class ApOption = BooleanOption;
|
class ApOption = BooleanOption;
|
||||||
|
|
||||||
@@ -2337,8 +2394,12 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = ContentApprox;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
predicate projectToHeadContent = getContentApprox/1;
|
||||||
|
|
||||||
class ApOption = ApproxAccessPathFrontOption;
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2413,8 +2474,12 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathFrontOption;
|
class ApOption = AccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2743,8 +2808,12 @@ private module Stage5Param implements MkStage<Stage4>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathApproxOption;
|
class ApOption = AccessPathApproxOption;
|
||||||
|
|
||||||
|
|||||||
@@ -667,23 +667,78 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(NodeEx arg |
|
fwdFlowIn(_, _, _, node, config) and
|
||||||
fwdFlow(arg, _, config) and
|
cc = true
|
||||||
viableParamArgEx(_, node, arg) and
|
|
||||||
cc = true and
|
|
||||||
not fullBarrier(node, config)
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(DataFlowCall call |
|
fwdFlowOut(_, node, false, config) and
|
||||||
fwdFlowOut(call, node, false, config) and
|
|
||||||
cc = false
|
cc = false
|
||||||
or
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
fwdFlowOutFromArg(call, node, config) and
|
fwdFlowOutFromArg(call, node, config) and
|
||||||
fwdFlowIsEntered(call, cc, config)
|
fwdFlowIsEntered(call, cc, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowIn(
|
||||||
|
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||||
|
) {
|
||||||
|
// call context cannot help reduce virtual dispatch
|
||||||
|
fwdFlow(arg, cc, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
not fullBarrier(p, config) and
|
||||||
|
(
|
||||||
|
cc = false
|
||||||
|
or
|
||||||
|
cc = true and
|
||||||
|
not reducedViableImplInCallContext(call, _, _)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// call context may help reduce virtual dispatch
|
||||||
|
exists(DataFlowCallable target |
|
||||||
|
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||||
|
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||||
|
cc = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||||
|
fwdFlowIn(call, _, cc, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||||
|
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(arg, true, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
reducedViableImplInCallContext(call, _, _) and
|
||||||
|
target = p.getEnclosingCallable() and
|
||||||
|
not fullBarrier(p, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||||
|
* restricted to those `call`s for which a context might make a difference,
|
||||||
|
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||||
|
DataFlowCall call, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCall ctx |
|
||||||
|
fwdFlowIsEntered(ctx, _, config) and
|
||||||
|
result = viableImplInCallContextExt(call, ctx)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -726,7 +781,8 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
fwdFlowReturnPosition(pos, cc, config) and
|
fwdFlowReturnPosition(pos, cc, config) and
|
||||||
@@ -740,17 +796,6 @@ private module Stage1 implements StageSig {
|
|||||||
fwdFlowOut(call, out, true, config)
|
fwdFlowOut(call, out, true, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
|
||||||
*/
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
|
||||||
exists(ArgNodeEx arg |
|
|
||||||
fwdFlow(arg, cc, config) and
|
|
||||||
viableParamArgEx(call, _, arg)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||||
exists(NodeEx node1 |
|
exists(NodeEx node1 |
|
||||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||||
@@ -817,20 +862,21 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(DataFlowCall call |
|
revFlowIn(_, node, false, config) and
|
||||||
revFlowIn(call, node, false, config) and
|
|
||||||
toReturn = false
|
toReturn = false
|
||||||
or
|
or
|
||||||
revFlowInToReturn(call, node, config) and
|
|
||||||
revFlowIsReturned(call, toReturn, config)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
revFlowOut(pos, config) and
|
revFlowOut(pos, config) and
|
||||||
node.(RetNodeEx).getReturnPosition() = pos and
|
node.(RetNodeEx).getReturnPosition() = pos and
|
||||||
toReturn = true
|
toReturn = true
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
|
revFlowInToReturn(call, node, config) and
|
||||||
|
revFlowIsReturned(call, toReturn, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -886,11 +932,11 @@ private module Stage1 implements StageSig {
|
|||||||
additional predicate viableParamArgNodeCandFwd1(
|
additional predicate viableParamArgNodeCandFwd1(
|
||||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||||
) {
|
) {
|
||||||
viableParamArgEx(call, p, arg) and
|
fwdFlowIn(call, arg, _, p, config)
|
||||||
fwdFlow(arg, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate revFlowIn(
|
private predicate revFlowIn(
|
||||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -1223,7 +1269,16 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail);
|
Ap apCons(TypedContent tc, Ap tail);
|
||||||
|
|
||||||
Content getHeadContent(Ap ap);
|
/**
|
||||||
|
* An approximation of `Content` that corresponds to the precision level of
|
||||||
|
* `Ap`, such that the mappings from both `Ap` and `Content` to this type
|
||||||
|
* are functional.
|
||||||
|
*/
|
||||||
|
class ApHeadContent;
|
||||||
|
|
||||||
|
ApHeadContent getHeadContent(Ap ap);
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c);
|
||||||
|
|
||||||
class ApOption;
|
class ApOption;
|
||||||
|
|
||||||
@@ -1471,34 +1526,32 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ApNonNil instanceof Ap {
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
ApNonNil() { not this instanceof ApNil }
|
private predicate readStepCand(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
string toString() { result = "" }
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowRead0(
|
|
||||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
|
||||||
Configuration config
|
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
PrevStage::readStepCand(node1, _, _, config)
|
apc = projectToHeadContent(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, c]
|
bindingset[node1, apc]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
private predicate hasHeadContent(Ap ap, Content c) { getHeadContent(ap) = c }
|
private predicate readStepCand0(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
|
) {
|
||||||
|
readStepCand(node1, apc, c, node2, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
exists(ApHeadContent apc |
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
hasHeadContent(ap, c)
|
apc = getHeadContent(ap) and
|
||||||
|
readStepCand0(node1, apc, c, node2, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -2072,8 +2125,12 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Unit;
|
||||||
|
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
Content getHeadContent(Ap ap) { exists(result) and ap = true }
|
ApHeadContent getHeadContent(Ap ap) { exists(result) and ap = true }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { any() }
|
||||||
|
|
||||||
class ApOption = BooleanOption;
|
class ApOption = BooleanOption;
|
||||||
|
|
||||||
@@ -2337,8 +2394,12 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = ContentApprox;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
predicate projectToHeadContent = getContentApprox/1;
|
||||||
|
|
||||||
class ApOption = ApproxAccessPathFrontOption;
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2413,8 +2474,12 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathFrontOption;
|
class ApOption = AccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2743,8 +2808,12 @@ private module Stage5Param implements MkStage<Stage4>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathApproxOption;
|
class ApOption = AccessPathApproxOption;
|
||||||
|
|
||||||
|
|||||||
@@ -707,8 +707,8 @@ private module Cached {
|
|||||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||||
* restricted to those `call`s for which a context might make a difference.
|
* restricted to those `call`s for which a context might make a difference.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
cached
|
||||||
private DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) {
|
DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) {
|
||||||
result = viableImplInCallContext(call, ctx) and
|
result = viableImplInCallContext(call, ctx) and
|
||||||
result = viableCallable(call)
|
result = viableCallable(call)
|
||||||
or
|
or
|
||||||
@@ -1391,6 +1391,9 @@ class TypedContentApprox extends MkTypedContentApprox {
|
|||||||
/** Gets a typed content approximated by this value. */
|
/** Gets a typed content approximated by this value. */
|
||||||
TypedContent getATypedContent() { result = getATypedContent(this) }
|
TypedContent getATypedContent() { result = getATypedContent(this) }
|
||||||
|
|
||||||
|
/** Gets the content. */
|
||||||
|
ContentApprox getContent() { result = c }
|
||||||
|
|
||||||
/** Gets the container type. */
|
/** Gets the container type. */
|
||||||
DataFlowType getContainerType() { result = t }
|
DataFlowType getContainerType() { result = t }
|
||||||
|
|
||||||
@@ -1408,6 +1411,8 @@ abstract class ApproxAccessPathFront extends TApproxAccessPathFront {
|
|||||||
|
|
||||||
abstract boolean toBoolNonEmpty();
|
abstract boolean toBoolNonEmpty();
|
||||||
|
|
||||||
|
TypedContentApprox getHead() { this = TApproxFrontHead(result) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
TypedContent getAHead() {
|
TypedContent getAHead() {
|
||||||
exists(TypedContentApprox cont |
|
exists(TypedContentApprox cont |
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ predicate isInsecureEncryption(string name) { name.regexpMatch(getInsecureAlgori
|
|||||||
*/
|
*/
|
||||||
bindingset[name]
|
bindingset[name]
|
||||||
predicate isEncryptionAdditionalEvidence(string name) {
|
predicate isEncryptionAdditionalEvidence(string name) {
|
||||||
name.toUpperCase().matches("%" + ["CRYPT", "CODE", "CODING", "CBC", "KEY", "CIPHER", "MAC"] + "%")
|
name.regexpMatch("(?i).*(crypt|code|coding|cbc|key|cipher|mac).*")
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ import cpp
|
|||||||
*/
|
*/
|
||||||
bindingset[s]
|
bindingset[s]
|
||||||
private predicate suspicious(string s) {
|
private predicate suspicious(string s) {
|
||||||
s.regexpMatch(".*(password|passwd|accountid|account.?key|accnt.?key|license.?key|trusted).*") and
|
s.regexpMatch("(?i).*(password|passwd|accountid|account.?key|accnt.?key|license.?key|trusted).*") and
|
||||||
not s.matches(["%hash%", "%crypt%", "%file%", "%path%", "%invalid%"])
|
not s.regexpMatch("(?i).*(hash|crypt|file|path|invalid).*")
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -23,7 +23,7 @@ private predicate suspicious(string s) {
|
|||||||
*/
|
*/
|
||||||
class SensitiveVariable extends Variable {
|
class SensitiveVariable extends Variable {
|
||||||
SensitiveVariable() {
|
SensitiveVariable() {
|
||||||
suspicious(this.getName().toLowerCase()) and
|
suspicious(this.getName()) and
|
||||||
not this.getUnspecifiedType() instanceof IntegralType
|
not this.getUnspecifiedType() instanceof IntegralType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -33,7 +33,7 @@ class SensitiveVariable extends Variable {
|
|||||||
*/
|
*/
|
||||||
class SensitiveFunction extends Function {
|
class SensitiveFunction extends Function {
|
||||||
SensitiveFunction() {
|
SensitiveFunction() {
|
||||||
suspicious(this.getName().toLowerCase()) and
|
suspicious(this.getName()) and
|
||||||
not this.getUnspecifiedType() instanceof IntegralType
|
not this.getUnspecifiedType() instanceof IntegralType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
## 0.5.3
|
||||||
|
|
||||||
|
No user-facing changes.
|
||||||
|
|
||||||
## 0.5.2
|
## 0.5.2
|
||||||
|
|
||||||
No user-facing changes.
|
No user-facing changes.
|
||||||
|
|||||||
3
cpp/ql/src/change-notes/released/0.5.3.md
Normal file
3
cpp/ql/src/change-notes/released/0.5.3.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
## 0.5.3
|
||||||
|
|
||||||
|
No user-facing changes.
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
---
|
---
|
||||||
lastReleaseVersion: 0.5.2
|
lastReleaseVersion: 0.5.3
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
...
|
||||||
|
char buf[256];
|
||||||
|
X509_NAME_oneline(X509_get_subject_name(peer),buf,sizeof(buf)); // GOOD
|
||||||
|
...
|
||||||
|
char buf[256];
|
||||||
|
X509_NAME_oneline(X509_get_subject_name(peer),buf,1024); // BAD
|
||||||
|
...
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<!DOCTYPE qhelp PUBLIC
|
||||||
|
"-//Semmle//qhelp//EN"
|
||||||
|
"qhelp.dtd">
|
||||||
|
<qhelp>
|
||||||
|
<overview>
|
||||||
|
<p>Using a size argument that is larger than the buffer size will result in an out-of-bounds memory access and possibly overflow. You need to limit the value of the length argument.</p>
|
||||||
|
|
||||||
|
</overview>
|
||||||
|
|
||||||
|
<example>
|
||||||
|
<p>The following example shows the use of a function with and without an error in the size argument.</p>
|
||||||
|
<sample src="BufferAccessWithIncorrectLengthValue.cpp" />
|
||||||
|
|
||||||
|
</example>
|
||||||
|
<references>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
CERT Coding Standard:
|
||||||
|
<a href="https://wiki.sei.cmu.edu/confluence/display/c/ARR38-C.+Guarantee+that+library+functions+do+not+form+invalid+pointers">ARR38-C. Guarantee that library functions do not form invalid pointers - SEI CERT C Coding Standard - Confluence</a>.
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</references>
|
||||||
|
</qhelp>
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/**
|
||||||
|
* @name Buffer access with incorrect length value
|
||||||
|
* @description Incorrect use of the length argument in some functions will result in out-of-memory accesses.
|
||||||
|
* @kind problem
|
||||||
|
* @id cpp/buffer-access-with-incorrect-length-value
|
||||||
|
* @problem.severity warning
|
||||||
|
* @precision medium
|
||||||
|
* @tags correctness
|
||||||
|
* security
|
||||||
|
* experimental
|
||||||
|
* external/cwe/cwe-805
|
||||||
|
*/
|
||||||
|
|
||||||
|
import cpp
|
||||||
|
|
||||||
|
/** Holds for a function `f`, which has an argument at index `bpos` that points to a buffer and an argument at index `spos` that points to a size. */
|
||||||
|
predicate numberArgument(Function f, int bpos, int spos) {
|
||||||
|
f.hasGlobalOrStdName([
|
||||||
|
"X509_NAME_oneline", "SSL_CIPHER_description", "SSL_get_shared_ciphers",
|
||||||
|
"SSL_export_keying_material_early", "SSL_export_keying_material", "SSL_set_alpn_protos",
|
||||||
|
"SSL_CTX_set_alpn_protos", "SSL_read", "SSL_read_ex", "SSL_read_early_data",
|
||||||
|
"SSL_bytes_to_cipher_list", "SSL_write", "SSL_SESSION_set1_master_key",
|
||||||
|
"SSL_CTX_set_session_id_context", "BIO_gets", "BIO_read", "BIO_read_ex", "BIO_write",
|
||||||
|
"BIO_write_ex", "BIO_ctrl", "BN_bn2binpad", "BN_signed_bn2bin", "BN_signed_bn2lebin",
|
||||||
|
"EVP_PKEY_get_default_digest_name", "EVP_DigestUpdate", "EVP_PKEY_CTX_set1_tls1_prf_secret",
|
||||||
|
"EVP_KDF_derive", "EVP_CIPHER_CTX_get_updated_iv", "EVP_PKEY_get_group_name", "EVP_MAC_init",
|
||||||
|
"write", "read", "send", "sendto", "recv", "recvfrom", "strerror_r"
|
||||||
|
]) and
|
||||||
|
bpos = 1 and
|
||||||
|
spos = 2
|
||||||
|
or
|
||||||
|
f.hasGlobalOrStdName(["X509_NAME_get_text_by_NID", "EVP_PKEY_get_utf8_string_param"]) and
|
||||||
|
bpos = 2 and
|
||||||
|
spos = 3
|
||||||
|
or
|
||||||
|
f.hasGlobalOrStdName([
|
||||||
|
"BIO_snprintf", "BN_signed_lebin2bn", "BIO_new_mem_buf", "BN_lebin2bn", "BN_bin2bn",
|
||||||
|
"EVP_read_pw_string", "EVP_read_pw_string", "strftime", "strnlen", "fgets", "snprintf",
|
||||||
|
"vsnprintf"
|
||||||
|
]) and
|
||||||
|
bpos = 0 and
|
||||||
|
spos = 1
|
||||||
|
or
|
||||||
|
f.hasGlobalOrStdName(["AES_ige_encrypt", "memchr"]) and bpos = 0 and spos = 2
|
||||||
|
or
|
||||||
|
f.hasGlobalOrStdName("EVP_MAC_final") and bpos = 1 and spos = 3
|
||||||
|
or
|
||||||
|
f.hasGlobalOrStdName("OBJ_obj2txt") and bpos = 2 and spos = 1
|
||||||
|
or
|
||||||
|
f.hasGlobalOrStdName("EVP_CIPHER_CTX_ctrl") and bpos = 3 and spos = 2
|
||||||
|
or
|
||||||
|
f.hasGlobalOrStdName(["EVP_PKEY_get_octet_string_param", "getnameinfo"]) and bpos = 2 and spos = 3
|
||||||
|
or
|
||||||
|
f.hasGlobalOrStdName([
|
||||||
|
"EVP_DecryptUpdate", "EVP_EncryptUpdate", "EVP_PKEY_encrypt", "EVP_PKEY_sign",
|
||||||
|
"EVP_CipherUpdate"
|
||||||
|
]) and
|
||||||
|
bpos = 3 and
|
||||||
|
spos = 4
|
||||||
|
or
|
||||||
|
f.hasGlobalOrStdName("getnameinfo") and bpos = 4 and spos = 5
|
||||||
|
}
|
||||||
|
|
||||||
|
from FunctionCall fc
|
||||||
|
where
|
||||||
|
exists(ArrayType array, int bufArgPos, int sizeArgPos |
|
||||||
|
numberArgument(fc.getTarget(), bufArgPos, sizeArgPos) and
|
||||||
|
fc.getArgument(pragma[only_bind_into](sizeArgPos)).getValue().toInt() > array.getByteSize() and
|
||||||
|
fc.getArgument(pragma[only_bind_into](bufArgPos))
|
||||||
|
.(VariableAccess)
|
||||||
|
.getTarget()
|
||||||
|
.getADeclarationEntry()
|
||||||
|
.getType() = array
|
||||||
|
)
|
||||||
|
select fc,
|
||||||
|
"Access beyond the bounds of the allocated memory is possible, the size argument used is greater than the size of the buffer."
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/cpp-queries
|
name: codeql/cpp-queries
|
||||||
version: 0.5.2
|
version: 0.5.4-dev
|
||||||
groups:
|
groups:
|
||||||
- cpp
|
- cpp
|
||||||
- queries
|
- queries
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
| test.cpp:27:5:27:21 | call to X509_NAME_oneline | Access beyond the bounds of the allocated memory is possible, the size argument used is greater than the size of the buffer. |
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
experimental/Security/CWE/CWE-805/BufferAccessWithIncorrectLengthValue.ql
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
struct X509_NAME {};
|
||||||
|
struct SSL {};
|
||||||
|
struct X509 {};
|
||||||
|
|
||||||
|
char * X509_NAME_oneline(X509_NAME *a,char *buf,int size);
|
||||||
|
X509 *SSL_get_peer_certificate(const SSL *ssl);
|
||||||
|
X509_NAME *X509_get_subject_name(const X509 *x);
|
||||||
|
char *strcasestr(char *a, char *b);
|
||||||
|
|
||||||
|
bool goodTest1(SSL *ssl,char *text)
|
||||||
|
{
|
||||||
|
X509 *peer;
|
||||||
|
char buf[256];
|
||||||
|
if( peer = SSL_get_peer_certificate(ssl))
|
||||||
|
{
|
||||||
|
X509_NAME_oneline(X509_get_subject_name(peer),buf,sizeof(buf)); // GOOD
|
||||||
|
if((char*)strcasestr(buf,text)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool badTest1(SSL *ssl,char *text)
|
||||||
|
{
|
||||||
|
X509 *peer;
|
||||||
|
char buf[256];
|
||||||
|
if( peer = SSL_get_peer_certificate(ssl))
|
||||||
|
{
|
||||||
|
X509_NAME_oneline(X509_get_subject_name(peer),buf,1024); // BAD
|
||||||
|
if((char*)strcasestr(buf,text)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
@@ -145,6 +145,14 @@ namespace Semmle.Autobuild.CSharp.Tests
|
|||||||
|
|
||||||
bool IBuildActions.IsWindows() => IsWindows;
|
bool IBuildActions.IsWindows() => IsWindows;
|
||||||
|
|
||||||
|
public bool IsMacOs { get; set; }
|
||||||
|
|
||||||
|
bool IBuildActions.IsMacOs() => IsMacOs;
|
||||||
|
|
||||||
|
public bool IsArm { get; set; }
|
||||||
|
|
||||||
|
bool IBuildActions.IsArm() => IsArm;
|
||||||
|
|
||||||
public string PathCombine(params string[] parts)
|
public string PathCombine(params string[] parts)
|
||||||
{
|
{
|
||||||
return string.Join(IsWindows ? '\\' : '/', parts.Where(p => !string.IsNullOrWhiteSpace(p)));
|
return string.Join(IsWindows ? '\\' : '/', parts.Where(p => !string.IsNullOrWhiteSpace(p)));
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using System.Xml;
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Semmle.Autobuild.Shared
|
namespace Semmle.Autobuild.Shared
|
||||||
{
|
{
|
||||||
@@ -98,6 +99,18 @@ namespace Semmle.Autobuild.Shared
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
bool IsWindows();
|
bool IsWindows();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether we are running on macOS.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if we are running on macOS.</returns>
|
||||||
|
bool IsMacOs();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether we are running on arm.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if we are running on arm.</returns>
|
||||||
|
bool IsArm();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Combine path segments, Path.Combine().
|
/// Combine path segments, Path.Combine().
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -203,6 +216,12 @@ namespace Semmle.Autobuild.Shared
|
|||||||
|
|
||||||
bool IBuildActions.IsWindows() => Win32.IsWindows();
|
bool IBuildActions.IsWindows() => Win32.IsWindows();
|
||||||
|
|
||||||
|
bool IBuildActions.IsMacOs() => RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
|
||||||
|
|
||||||
|
bool IBuildActions.IsArm() =>
|
||||||
|
RuntimeInformation.ProcessArchitecture == Architecture.Arm64 ||
|
||||||
|
RuntimeInformation.ProcessArchitecture == Architecture.Arm;
|
||||||
|
|
||||||
string IBuildActions.PathCombine(params string[] parts) => Path.Combine(parts);
|
string IBuildActions.PathCombine(params string[] parts) => Path.Combine(parts);
|
||||||
|
|
||||||
void IBuildActions.WriteAllText(string filename, string contents) => File.WriteAllText(filename, contents);
|
void IBuildActions.WriteAllText(string filename, string contents) => File.WriteAllText(filename, contents);
|
||||||
|
|||||||
@@ -1,18 +1,36 @@
|
|||||||
using Semmle.Util.Logging;
|
using Semmle.Util.Logging;
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Semmle.Autobuild.Shared
|
namespace Semmle.Autobuild.Shared
|
||||||
{
|
{
|
||||||
|
internal static class MsBuildCommandExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Appends a call to msbuild.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cmdBuilder"></param>
|
||||||
|
/// <param name="builder"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static CommandBuilder MsBuildCommand(this CommandBuilder cmdBuilder, IAutobuilder<AutobuildOptionsShared> builder)
|
||||||
|
{
|
||||||
|
var isArmMac = builder.Actions.IsMacOs() && builder.Actions.IsArm();
|
||||||
|
|
||||||
|
// mono doesn't ship with `msbuild` on Arm-based Macs, but we can fall back to
|
||||||
|
// msbuild that ships with `dotnet` which can be invoked with `dotnet msbuild`
|
||||||
|
// perhaps we should do this on all platforms?
|
||||||
|
return isArmMac ?
|
||||||
|
cmdBuilder.RunCommand("dotnet").Argument("msbuild") :
|
||||||
|
cmdBuilder.RunCommand("msbuild");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A build rule using msbuild.
|
/// A build rule using msbuild.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MsBuildRule : IBuildRule<AutobuildOptionsShared>
|
public class MsBuildRule : IBuildRule<AutobuildOptionsShared>
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// The name of the msbuild command.
|
|
||||||
/// </summary>
|
|
||||||
private const string msBuild = "msbuild";
|
|
||||||
|
|
||||||
public BuildScript Analyse(IAutobuilder<AutobuildOptionsShared> builder, bool auto)
|
public BuildScript Analyse(IAutobuilder<AutobuildOptionsShared> builder, bool auto)
|
||||||
{
|
{
|
||||||
if (!builder.ProjectsOrSolutionsToBuild.Any())
|
if (!builder.ProjectsOrSolutionsToBuild.Any())
|
||||||
@@ -57,7 +75,7 @@ namespace Semmle.Autobuild.Shared
|
|||||||
Script;
|
Script;
|
||||||
var nugetRestore = GetNugetRestoreScript();
|
var nugetRestore = GetNugetRestoreScript();
|
||||||
var msbuildRestoreCommand = new CommandBuilder(builder.Actions).
|
var msbuildRestoreCommand = new CommandBuilder(builder.Actions).
|
||||||
RunCommand(msBuild).
|
MsBuildCommand(builder).
|
||||||
Argument("/t:restore").
|
Argument("/t:restore").
|
||||||
QuoteArgument(projectOrSolution.FullPath);
|
QuoteArgument(projectOrSolution.FullPath);
|
||||||
|
|
||||||
@@ -95,7 +113,7 @@ namespace Semmle.Autobuild.Shared
|
|||||||
command.RunCommand("set Platform=&& type NUL", quoteExe: false);
|
command.RunCommand("set Platform=&& type NUL", quoteExe: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
command.RunCommand(msBuild);
|
command.MsBuildCommand(builder);
|
||||||
command.QuoteArgument(projectOrSolution.FullPath);
|
command.QuoteArgument(projectOrSolution.FullPath);
|
||||||
|
|
||||||
var target = builder.Options.MsBuildTarget ?? "rebuild";
|
var target = builder.Options.MsBuildTarget ?? "rebuild";
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
|||||||
|
description: Remove a relation for scoped annotations.
|
||||||
|
compatibility: backwards
|
||||||
|
scoped_annotation.rel: delete
|
||||||
@@ -106,36 +106,6 @@ namespace Semmle.BuildAnalyser
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to load the reference from the GAC.
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var loadedAssembly = System.Reflection.Assembly.ReflectionOnlyLoad(id);
|
|
||||||
|
|
||||||
if (loadedAssembly is not null)
|
|
||||||
{
|
|
||||||
// The assembly was somewhere we haven't indexed before.
|
|
||||||
// Add this assembly to our index so that subsequent lookups are faster.
|
|
||||||
|
|
||||||
result = AssemblyInfo.MakeFromAssembly(loadedAssembly);
|
|
||||||
assemblyInfoById[id] = result;
|
|
||||||
assemblyInfoByFileName[loadedAssembly.Location] = result;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (FileNotFoundException)
|
|
||||||
{
|
|
||||||
// A suitable assembly could not be found
|
|
||||||
}
|
|
||||||
catch (FileLoadException)
|
|
||||||
{
|
|
||||||
// The assembly cannot be loaded for some reason
|
|
||||||
// e.g. The name is malformed.
|
|
||||||
}
|
|
||||||
catch (PlatformNotSupportedException)
|
|
||||||
{
|
|
||||||
// .NET Core does not have a GAC.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback position - locate the assembly by its lower-case name only.
|
// Fallback position - locate the assembly by its lower-case name only.
|
||||||
var asmName = assemblyName.ToLowerInvariant();
|
var asmName = assemblyName.ToLowerInvariant();
|
||||||
|
|
||||||
|
|||||||
@@ -59,6 +59,19 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void PopulateScopedKind(TextWriter trapFile, ScopedKind kind)
|
||||||
|
{
|
||||||
|
switch (kind)
|
||||||
|
{
|
||||||
|
case ScopedKind.ScopedRef:
|
||||||
|
trapFile.scoped_annotation(this, Kinds.ScopedAnnotation.ScopedRef);
|
||||||
|
break;
|
||||||
|
case ScopedKind.ScopedValue:
|
||||||
|
trapFile.scoped_annotation(this, Kinds.ScopedAnnotation.ScopedValue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void ExtractCompilerGenerated(TextWriter trapFile)
|
protected void ExtractCompilerGenerated(TextWriter trapFile)
|
||||||
{
|
{
|
||||||
if (Symbol.IsImplicitlyDeclared)
|
if (Symbol.IsImplicitlyDeclared)
|
||||||
|
|||||||
@@ -33,7 +33,8 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||||||
PopulateRefKind(trapFile, Symbol.RefKind);
|
PopulateRefKind(trapFile, Symbol.RefKind);
|
||||||
|
|
||||||
var unboundFieldKey = Field.Create(Context, Symbol.OriginalDefinition);
|
var unboundFieldKey = Field.Create(Context, Symbol.OriginalDefinition);
|
||||||
trapFile.fields(this, (Symbol.IsConst ? 2 : 1), Symbol.Name, ContainingType, Type.TypeRef, unboundFieldKey);
|
var kind = Symbol.IsConst ? VariableKind.Const : VariableKind.None;
|
||||||
|
trapFile.fields(this, kind, Symbol.Name, ContainingType, Type.TypeRef, unboundFieldKey);
|
||||||
|
|
||||||
PopulateModifiers(trapFile);
|
PopulateModifiers(trapFile);
|
||||||
|
|
||||||
|
|||||||
@@ -23,17 +23,23 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||||||
public void PopulateManual(Expression parent, bool isVar)
|
public void PopulateManual(Expression parent, bool isVar)
|
||||||
{
|
{
|
||||||
var trapFile = Context.TrapWriter.Writer;
|
var trapFile = Context.TrapWriter.Writer;
|
||||||
var (kind, type) = Symbol is ILocalSymbol l
|
var @var = isVar ? 1 : 0;
|
||||||
? (l.IsRef ? 3 : l.IsConst ? 2 : 1, l.GetAnnotatedType())
|
|
||||||
: (1, parent.Type);
|
|
||||||
trapFile.localvars(this, kind, Symbol.Name, isVar ? 1 : 0, Type.Create(Context, type).TypeRef, parent);
|
|
||||||
|
|
||||||
if (Symbol is ILocalSymbol local)
|
if (Symbol is ILocalSymbol local)
|
||||||
{
|
{
|
||||||
|
var kind = local.IsRef ? Kinds.VariableKind.Ref : local.IsConst ? Kinds.VariableKind.Const : Kinds.VariableKind.None;
|
||||||
|
var type = local.GetAnnotatedType();
|
||||||
|
trapFile.localvars(this, kind, Symbol.Name, @var, Type.Create(Context, type).TypeRef, parent);
|
||||||
|
|
||||||
PopulateNullability(trapFile, local.GetAnnotatedType());
|
PopulateNullability(trapFile, local.GetAnnotatedType());
|
||||||
|
PopulateScopedKind(trapFile, local.ScopedKind);
|
||||||
if (local.IsRef)
|
if (local.IsRef)
|
||||||
trapFile.type_annotation(this, Kinds.TypeAnnotation.Ref);
|
trapFile.type_annotation(this, Kinds.TypeAnnotation.Ref);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
trapFile.localvars(this, Kinds.VariableKind.None, Symbol.Name, @var, Type.Create(Context, parent.Type).TypeRef, parent);
|
||||||
|
}
|
||||||
|
|
||||||
trapFile.localvar_location(this, Location);
|
trapFile.localvar_location(this, Location);
|
||||||
|
|
||||||
|
|||||||
@@ -65,6 +65,15 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||||||
trapFile.has_modifiers(target, Modifier.Create(cx, modifier));
|
trapFile.has_modifiers(target, Modifier.Create(cx, modifier));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void ExtractFieldModifiers(Context cx, TextWriter trapFile, IEntity key, IFieldSymbol symbol)
|
||||||
|
{
|
||||||
|
if (symbol.IsReadOnly)
|
||||||
|
HasModifier(cx, trapFile, key, Modifiers.Readonly);
|
||||||
|
|
||||||
|
if (symbol.IsRequired)
|
||||||
|
HasModifier(cx, trapFile, key, Modifiers.Required);
|
||||||
|
}
|
||||||
|
|
||||||
private static void ExtractNamedTypeModifiers(Context cx, TextWriter trapFile, IEntity key, ISymbol symbol)
|
private static void ExtractNamedTypeModifiers(Context cx, TextWriter trapFile, IEntity key, ISymbol symbol)
|
||||||
{
|
{
|
||||||
if (symbol.Kind != SymbolKind.NamedType)
|
if (symbol.Kind != SymbolKind.NamedType)
|
||||||
@@ -106,8 +115,11 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||||||
if (symbol.IsVirtual)
|
if (symbol.IsVirtual)
|
||||||
HasModifier(cx, trapFile, key, Modifiers.Virtual);
|
HasModifier(cx, trapFile, key, Modifiers.Virtual);
|
||||||
|
|
||||||
if (symbol.Kind == SymbolKind.Field && ((IFieldSymbol)symbol).IsReadOnly)
|
if (symbol is IFieldSymbol field)
|
||||||
HasModifier(cx, trapFile, key, Modifiers.Readonly);
|
ExtractFieldModifiers(cx, trapFile, key, field);
|
||||||
|
|
||||||
|
if (symbol.Kind == SymbolKind.Property && ((IPropertySymbol)symbol).IsRequired)
|
||||||
|
HasModifier(cx, trapFile, key, Modifiers.Required);
|
||||||
|
|
||||||
if (symbol.IsOverride)
|
if (symbol.IsOverride)
|
||||||
HasModifier(cx, trapFile, key, Modifiers.Override);
|
HasModifier(cx, trapFile, key, Modifiers.Override);
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ internal static class Modifiers
|
|||||||
public const string Public = "public";
|
public const string Public = "public";
|
||||||
public const string Readonly = "readonly";
|
public const string Readonly = "readonly";
|
||||||
public const string Record = "record";
|
public const string Record = "record";
|
||||||
|
public const string Required = "required";
|
||||||
public const string Ref = "ref";
|
public const string Ref = "ref";
|
||||||
public const string Sealed = "sealed";
|
public const string Sealed = "sealed";
|
||||||
public const string Static = "static";
|
public const string Static = "static";
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||||||
PopulateAttributes();
|
PopulateAttributes();
|
||||||
PopulateNullability(trapFile, Symbol.GetAnnotatedType());
|
PopulateNullability(trapFile, Symbol.GetAnnotatedType());
|
||||||
PopulateRefKind(trapFile, Symbol.RefKind);
|
PopulateRefKind(trapFile, Symbol.RefKind);
|
||||||
|
PopulateScopedKind(trapFile, Symbol.ScopedKind);
|
||||||
|
|
||||||
if (Symbol.Name != Original.Symbol.Name)
|
if (Symbol.Name != Original.Symbol.Name)
|
||||||
Context.ModelError(Symbol, "Inconsistent parameter declaration");
|
Context.ModelError(Symbol, "Inconsistent parameter declaration");
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Semmle.Extraction.Kinds;
|
||||||
|
|
||||||
|
public enum ScopedAnnotation
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
ScopedRef = 1,
|
||||||
|
ScopedValue = 2
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Semmle.Extraction.Kinds;
|
||||||
|
|
||||||
|
public enum VariableKind
|
||||||
|
{
|
||||||
|
None = 1,
|
||||||
|
Const = 2,
|
||||||
|
Ref = 3
|
||||||
|
}
|
||||||
@@ -191,8 +191,8 @@ namespace Semmle.Extraction.CSharp
|
|||||||
internal static void field_location(this TextWriter trapFile, Field field, Location location) =>
|
internal static void field_location(this TextWriter trapFile, Field field, Location location) =>
|
||||||
trapFile.WriteTuple("field_location", field, location);
|
trapFile.WriteTuple("field_location", field, location);
|
||||||
|
|
||||||
internal static void fields(this TextWriter trapFile, Field field, int @const, string name, Type declaringType, Type fieldType, Field unboundKey) =>
|
internal static void fields(this TextWriter trapFile, Field field, VariableKind kind, string name, Type declaringType, Type fieldType, Field unboundKey) =>
|
||||||
trapFile.WriteTuple("fields", field, @const, name, declaringType, fieldType, unboundKey);
|
trapFile.WriteTuple("fields", field, (int)kind, name, declaringType, fieldType, unboundKey);
|
||||||
|
|
||||||
internal static void general_type_parameter_constraints(this TextWriter trapFile, TypeParameterConstraints constraints, int hasKind) =>
|
internal static void general_type_parameter_constraints(this TextWriter trapFile, TypeParameterConstraints constraints, int hasKind) =>
|
||||||
trapFile.WriteTuple("general_type_parameter_constraints", constraints, hasKind);
|
trapFile.WriteTuple("general_type_parameter_constraints", constraints, hasKind);
|
||||||
@@ -227,8 +227,8 @@ namespace Semmle.Extraction.CSharp
|
|||||||
internal static void localvar_location(this TextWriter trapFile, LocalVariable var, Location location) =>
|
internal static void localvar_location(this TextWriter trapFile, LocalVariable var, Location location) =>
|
||||||
trapFile.WriteTuple("localvar_location", var, location);
|
trapFile.WriteTuple("localvar_location", var, location);
|
||||||
|
|
||||||
internal static void localvars(this TextWriter trapFile, LocalVariable key, int @const, string name, int @var, Type type, Expression expr) =>
|
internal static void localvars(this TextWriter trapFile, LocalVariable key, VariableKind kind, string name, int @var, Type type, Expression expr) =>
|
||||||
trapFile.WriteTuple("localvars", key, @const, name, @var, type, expr);
|
trapFile.WriteTuple("localvars", key, (int)kind, name, @var, type, expr);
|
||||||
|
|
||||||
public static void metadata_handle(this TextWriter trapFile, IEntity entity, Location assembly, int handleValue) =>
|
public static void metadata_handle(this TextWriter trapFile, IEntity entity, Location assembly, int handleValue) =>
|
||||||
trapFile.WriteTuple("metadata_handle", entity, assembly, handleValue);
|
trapFile.WriteTuple("metadata_handle", entity, assembly, handleValue);
|
||||||
@@ -462,5 +462,8 @@ namespace Semmle.Extraction.CSharp
|
|||||||
|
|
||||||
internal static void file_extraction_mode(this System.IO.TextWriter trapFile, Entities.File file, ExtractorMode mode) =>
|
internal static void file_extraction_mode(this System.IO.TextWriter trapFile, Entities.File file, ExtractorMode mode) =>
|
||||||
trapFile.WriteTuple("file_extraction_mode", file, mode);
|
trapFile.WriteTuple("file_extraction_mode", file, mode);
|
||||||
|
|
||||||
|
internal static void scoped_annotation(this TextWriter trapFile, IEntity element, ScopedAnnotation @scoped) =>
|
||||||
|
trapFile.WriteTuple("scoped_annotation", element, (int)@scoped);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -223,7 +223,7 @@ namespace Semmle.Extraction
|
|||||||
{
|
{
|
||||||
FileUtils.MoveOrReplace(tmpSrcFile, dest);
|
FileUtils.MoveOrReplace(tmpSrcFile, dest);
|
||||||
}
|
}
|
||||||
catch (IOException ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// If this happened, it was probably because the same file was compiled multiple times.
|
// If this happened, it was probably because the same file was compiled multiple times.
|
||||||
// In any case, this is not a fatal error.
|
// In any case, this is not a fatal error.
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
## 1.4.3
|
||||||
|
|
||||||
|
No user-facing changes.
|
||||||
|
|
||||||
## 1.4.2
|
## 1.4.2
|
||||||
|
|
||||||
No user-facing changes.
|
No user-facing changes.
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
## 1.4.3
|
||||||
|
|
||||||
|
No user-facing changes.
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
---
|
---
|
||||||
lastReleaseVersion: 1.4.2
|
lastReleaseVersion: 1.4.3
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/csharp-solorigate-all
|
name: codeql/csharp-solorigate-all
|
||||||
version: 1.4.2
|
version: 1.4.4-dev
|
||||||
groups:
|
groups:
|
||||||
- csharp
|
- csharp
|
||||||
- solorigate
|
- solorigate
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
## 1.4.3
|
||||||
|
|
||||||
|
No user-facing changes.
|
||||||
|
|
||||||
## 1.4.2
|
## 1.4.2
|
||||||
|
|
||||||
No user-facing changes.
|
No user-facing changes.
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
## 1.4.3
|
||||||
|
|
||||||
|
No user-facing changes.
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
---
|
---
|
||||||
lastReleaseVersion: 1.4.2
|
lastReleaseVersion: 1.4.3
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/csharp-solorigate-queries
|
name: codeql/csharp-solorigate-queries
|
||||||
version: 1.4.2
|
version: 1.4.4-dev
|
||||||
groups:
|
groups:
|
||||||
- csharp
|
- csharp
|
||||||
- solorigate
|
- solorigate
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import os
|
import os
|
||||||
from create_database_utils import *
|
from create_database_utils import *
|
||||||
|
|
||||||
run_codeql_database_create(['dotnet publish'], test_db="default-db", db=None, lang="csharp")
|
artifacts = 'bin/Temp'
|
||||||
|
run_codeql_database_create([f"dotnet publish -o {artifacts}"], test_db="default-db", db=None, lang="csharp")
|
||||||
|
|
||||||
## Check that the publish folder is created.
|
## Check that the publish folder is created.
|
||||||
if not os.path.isdir("bin/Debug/net7.0/publish/"):
|
if not os.path.isdir(artifacts):
|
||||||
raise Exception("The publish artifact folder was not created.")
|
raise Exception("The publish artifact folder was not created.")
|
||||||
|
|||||||
13
csharp/ql/integration-tests/all-platforms/msbuild/Program.cs
Normal file
13
csharp/ql/integration-tests/all-platforms/msbuild/Program.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Test
|
||||||
|
{
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
public static int Main(string[] args)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Hello world!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net4.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
from create_database_utils import *
|
||||||
|
|
||||||
|
# force CodeQL to use MSBuild by setting `LGTM_INDEX_MSBUILD_TARGET`
|
||||||
|
run_codeql_database_create([], test_db="default-db", db=None, lang="csharp", extra_env={ 'LGTM_INDEX_MSBUILD_TARGET': 'Build' })
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
## 0.5.3
|
||||||
|
|
||||||
|
### Minor Analysis Improvements
|
||||||
|
|
||||||
|
* C# 11: Added extractor support for the `scoped` modifier annotation on parameters and local variables.
|
||||||
|
|
||||||
## 0.5.2
|
## 0.5.2
|
||||||
|
|
||||||
### Major Analysis Improvements
|
### Major Analysis Improvements
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: minorAnalysis
|
||||||
|
---
|
||||||
|
* C# 11: Added library support for `checked` operators.
|
||||||
4
csharp/ql/lib/change-notes/2023-02-16-requiredmembers.md
Normal file
4
csharp/ql/lib/change-notes/2023-02-16-requiredmembers.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: minorAnalysis
|
||||||
|
---
|
||||||
|
* C# 11: Added extractor support for `required` fields and properties.
|
||||||
5
csharp/ql/lib/change-notes/released/0.5.3.md
Normal file
5
csharp/ql/lib/change-notes/released/0.5.3.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
## 0.5.3
|
||||||
|
|
||||||
|
### Minor Analysis Improvements
|
||||||
|
|
||||||
|
* C# 11: Added extractor support for the `scoped` modifier annotation on parameters and local variables.
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
---
|
---
|
||||||
lastReleaseVersion: 0.5.2
|
lastReleaseVersion: 0.5.3
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/csharp-all
|
name: codeql/csharp-all
|
||||||
version: 0.5.2
|
version: 0.5.4-dev
|
||||||
groups: csharp
|
groups: csharp
|
||||||
dbscheme: semmlecode.csharp.dbscheme
|
dbscheme: semmlecode.csharp.dbscheme
|
||||||
extractor: csharp
|
extractor: csharp
|
||||||
|
|||||||
@@ -435,8 +435,12 @@ class Destructor extends DotNet::Destructor, Callable, Member, Attributable, @de
|
|||||||
* (`BinaryOperator`), or a conversion operator (`ConversionOperator`).
|
* (`BinaryOperator`), or a conversion operator (`ConversionOperator`).
|
||||||
*/
|
*/
|
||||||
class Operator extends Callable, Member, Attributable, @operator {
|
class Operator extends Callable, Member, Attributable, @operator {
|
||||||
/** Gets the assembly name of this operator. */
|
/**
|
||||||
string getAssemblyName() { operators(this, result, _, _, _, _) }
|
* DEPRECATED: use `getFunctionName()` instead.
|
||||||
|
*
|
||||||
|
* Gets the assembly name of this operator.
|
||||||
|
*/
|
||||||
|
deprecated string getAssemblyName() { result = this.getFunctionName() }
|
||||||
|
|
||||||
override string getName() { operators(this, _, result, _, _, _) }
|
override string getName() { operators(this, _, result, _, _, _) }
|
||||||
|
|
||||||
@@ -445,7 +449,7 @@ class Operator extends Callable, Member, Attributable, @operator {
|
|||||||
/**
|
/**
|
||||||
* Gets the metadata name of the operator, such as `op_implicit` or `op_RightShift`.
|
* Gets the metadata name of the operator, such as `op_implicit` or `op_RightShift`.
|
||||||
*/
|
*/
|
||||||
string getFunctionName() { none() }
|
string getFunctionName() { operators(this, result, _, _, _, _) }
|
||||||
|
|
||||||
override ValueOrRefType getDeclaringType() { operators(this, _, _, result, _, _) }
|
override ValueOrRefType getDeclaringType() { operators(this, _, _, result, _, _) }
|
||||||
|
|
||||||
@@ -481,10 +485,11 @@ class RecordCloneMethod extends Method, DotNet::RecordCloneCallable {
|
|||||||
* A user-defined unary operator - an operator taking one operand.
|
* A user-defined unary operator - an operator taking one operand.
|
||||||
*
|
*
|
||||||
* Either a plus operator (`PlusOperator`), minus operator (`MinusOperator`),
|
* Either a plus operator (`PlusOperator`), minus operator (`MinusOperator`),
|
||||||
* not operator (`NotOperator`), complement operator (`ComplementOperator`),
|
* checked minus operator (`CheckedMinusOperator`), not operator (`NotOperator`),
|
||||||
* true operator (`TrueOperator`), false operator (`FalseOperator`),
|
* complement operator (`ComplementOperator`), true operator (`TrueOperator`),
|
||||||
* increment operator (`IncrementOperator`), or decrement operator
|
* false operator (`FalseOperator`), increment operator (`IncrementOperator`),
|
||||||
* (`DecrementOperator`).
|
* checked increment operator (`CheckedIncrementOperator`), decrement operator
|
||||||
|
* (`DecrementOperator`) or checked decrement operator (`CheckedDecrementOperator`).
|
||||||
*/
|
*/
|
||||||
class UnaryOperator extends Operator {
|
class UnaryOperator extends Operator {
|
||||||
UnaryOperator() {
|
UnaryOperator() {
|
||||||
@@ -505,8 +510,6 @@ class UnaryOperator extends Operator {
|
|||||||
class PlusOperator extends UnaryOperator {
|
class PlusOperator extends UnaryOperator {
|
||||||
PlusOperator() { this.getName() = "+" }
|
PlusOperator() { this.getName() = "+" }
|
||||||
|
|
||||||
override string getFunctionName() { result = "op_UnaryPlus" }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "PlusOperator" }
|
override string getAPrimaryQlClass() { result = "PlusOperator" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -522,11 +525,24 @@ class PlusOperator extends UnaryOperator {
|
|||||||
class MinusOperator extends UnaryOperator {
|
class MinusOperator extends UnaryOperator {
|
||||||
MinusOperator() { this.getName() = "-" }
|
MinusOperator() { this.getName() = "-" }
|
||||||
|
|
||||||
override string getFunctionName() { result = "op_UnaryNegation" }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "MinusOperator" }
|
override string getAPrimaryQlClass() { result = "MinusOperator" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A user-defined checked minus operator (`-`), for example
|
||||||
|
*
|
||||||
|
* ```csharp
|
||||||
|
* public static Widget operator checked -(Widget w) {
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
class CheckedMinusOperator extends UnaryOperator {
|
||||||
|
CheckedMinusOperator() { this.getName() = "checked -" }
|
||||||
|
|
||||||
|
override string getAPrimaryQlClass() { result = "CheckedMinusOperator" }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A user-defined not operator (`!`), for example
|
* A user-defined not operator (`!`), for example
|
||||||
*
|
*
|
||||||
@@ -539,8 +555,6 @@ class MinusOperator extends UnaryOperator {
|
|||||||
class NotOperator extends UnaryOperator {
|
class NotOperator extends UnaryOperator {
|
||||||
NotOperator() { this.getName() = "!" }
|
NotOperator() { this.getName() = "!" }
|
||||||
|
|
||||||
override string getFunctionName() { result = "op_LogicalNot" }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "NotOperator" }
|
override string getAPrimaryQlClass() { result = "NotOperator" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -556,8 +570,6 @@ class NotOperator extends UnaryOperator {
|
|||||||
class ComplementOperator extends UnaryOperator {
|
class ComplementOperator extends UnaryOperator {
|
||||||
ComplementOperator() { this.getName() = "~" }
|
ComplementOperator() { this.getName() = "~" }
|
||||||
|
|
||||||
override string getFunctionName() { result = "op_OnesComplement" }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "ComplementOperator" }
|
override string getAPrimaryQlClass() { result = "ComplementOperator" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -573,11 +585,24 @@ class ComplementOperator extends UnaryOperator {
|
|||||||
class IncrementOperator extends UnaryOperator {
|
class IncrementOperator extends UnaryOperator {
|
||||||
IncrementOperator() { this.getName() = "++" }
|
IncrementOperator() { this.getName() = "++" }
|
||||||
|
|
||||||
override string getFunctionName() { result = "op_Increment" }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "IncrementOperator" }
|
override string getAPrimaryQlClass() { result = "IncrementOperator" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A user-defined checked increment operator (`++`), for example
|
||||||
|
*
|
||||||
|
* ```csharp
|
||||||
|
* public static Widget operator checked ++(Widget w) {
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
class CheckedIncrementOperator extends UnaryOperator {
|
||||||
|
CheckedIncrementOperator() { this.getName() = "checked ++" }
|
||||||
|
|
||||||
|
override string getAPrimaryQlClass() { result = "CheckedIncrementOperator" }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A user-defined decrement operator (`--`), for example
|
* A user-defined decrement operator (`--`), for example
|
||||||
*
|
*
|
||||||
@@ -590,11 +615,24 @@ class IncrementOperator extends UnaryOperator {
|
|||||||
class DecrementOperator extends UnaryOperator {
|
class DecrementOperator extends UnaryOperator {
|
||||||
DecrementOperator() { this.getName() = "--" }
|
DecrementOperator() { this.getName() = "--" }
|
||||||
|
|
||||||
override string getFunctionName() { result = "op_Decrement" }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "DecrementOperator" }
|
override string getAPrimaryQlClass() { result = "DecrementOperator" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A user-defined checked decrement operator (`--`), for example
|
||||||
|
*
|
||||||
|
* ```csharp
|
||||||
|
* public static Widget operator checked --(Widget w) {
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
class CheckedDecrementOperator extends UnaryOperator {
|
||||||
|
CheckedDecrementOperator() { this.getName() = "checked --" }
|
||||||
|
|
||||||
|
override string getAPrimaryQlClass() { result = "CheckedDecrementOperator" }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A user-defined false operator (`false`), for example
|
* A user-defined false operator (`false`), for example
|
||||||
*
|
*
|
||||||
@@ -607,8 +645,6 @@ class DecrementOperator extends UnaryOperator {
|
|||||||
class FalseOperator extends UnaryOperator {
|
class FalseOperator extends UnaryOperator {
|
||||||
FalseOperator() { this.getName() = "false" }
|
FalseOperator() { this.getName() = "false" }
|
||||||
|
|
||||||
override string getFunctionName() { result = "op_False" }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "FalseOperator" }
|
override string getAPrimaryQlClass() { result = "FalseOperator" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -624,17 +660,18 @@ class FalseOperator extends UnaryOperator {
|
|||||||
class TrueOperator extends UnaryOperator {
|
class TrueOperator extends UnaryOperator {
|
||||||
TrueOperator() { this.getName() = "true" }
|
TrueOperator() { this.getName() = "true" }
|
||||||
|
|
||||||
override string getFunctionName() { result = "op_True" }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "TrueOperator" }
|
override string getAPrimaryQlClass() { result = "TrueOperator" }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A user-defined binary operator.
|
* A user-defined binary operator.
|
||||||
*
|
*
|
||||||
* Either an addition operator (`AddOperator`), a subtraction operator
|
* Either an addition operator (`AddOperator`), a checked addition operator
|
||||||
* (`SubOperator`), a multiplication operator (`MulOperator`), a division
|
* (`CheckedAddOperator`) a subtraction operator (`SubOperator`), a checked
|
||||||
* operator (`DivOperator`), a remainder operator (`RemOperator`), an and
|
* substraction operator (`CheckedSubOperator`), a multiplication operator
|
||||||
|
* (`MulOperator`), a checked multiplication operator (`CheckedMulOperator`),
|
||||||
|
* a division operator (`DivOperator`), a checked division operator
|
||||||
|
* (`CheckedDivOperator`), a remainder operator (`RemOperator`), an and
|
||||||
* operator (`AndOperator`), an or operator (`OrOperator`), an xor
|
* operator (`AndOperator`), an or operator (`OrOperator`), an xor
|
||||||
* operator (`XorOperator`), a left shift operator (`LeftShiftOperator`),
|
* operator (`XorOperator`), a left shift operator (`LeftShiftOperator`),
|
||||||
* a right shift operator (`RightShiftOperator`), an unsigned right shift
|
* a right shift operator (`RightShiftOperator`), an unsigned right shift
|
||||||
@@ -659,11 +696,24 @@ class BinaryOperator extends Operator {
|
|||||||
class AddOperator extends BinaryOperator {
|
class AddOperator extends BinaryOperator {
|
||||||
AddOperator() { this.getName() = "+" }
|
AddOperator() { this.getName() = "+" }
|
||||||
|
|
||||||
override string getFunctionName() { result = "op_Addition" }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "AddOperator" }
|
override string getAPrimaryQlClass() { result = "AddOperator" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A user-defined checked addition operator (`+`), for example
|
||||||
|
*
|
||||||
|
* ```csharp
|
||||||
|
* public static Widget operator checked +(Widget lhs, Widget rhs) {
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
class CheckedAddOperator extends BinaryOperator {
|
||||||
|
CheckedAddOperator() { this.getName() = "checked +" }
|
||||||
|
|
||||||
|
override string getAPrimaryQlClass() { result = "CheckedAddOperator" }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A user-defined subtraction operator (`-`), for example
|
* A user-defined subtraction operator (`-`), for example
|
||||||
*
|
*
|
||||||
@@ -676,11 +726,24 @@ class AddOperator extends BinaryOperator {
|
|||||||
class SubOperator extends BinaryOperator {
|
class SubOperator extends BinaryOperator {
|
||||||
SubOperator() { this.getName() = "-" }
|
SubOperator() { this.getName() = "-" }
|
||||||
|
|
||||||
override string getFunctionName() { result = "op_Subtraction" }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "SubOperator" }
|
override string getAPrimaryQlClass() { result = "SubOperator" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A user-defined checked subtraction operator (`-`), for example
|
||||||
|
*
|
||||||
|
* ```csharp
|
||||||
|
* public static Widget operator checked -(Widget lhs, Widget rhs) {
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
class CheckedSubOperator extends BinaryOperator {
|
||||||
|
CheckedSubOperator() { this.getName() = "checked -" }
|
||||||
|
|
||||||
|
override string getAPrimaryQlClass() { result = "CheckedSubOperator" }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A user-defined multiplication operator (`*`), for example
|
* A user-defined multiplication operator (`*`), for example
|
||||||
*
|
*
|
||||||
@@ -693,11 +756,24 @@ class SubOperator extends BinaryOperator {
|
|||||||
class MulOperator extends BinaryOperator {
|
class MulOperator extends BinaryOperator {
|
||||||
MulOperator() { this.getName() = "*" }
|
MulOperator() { this.getName() = "*" }
|
||||||
|
|
||||||
override string getFunctionName() { result = "op_Multiply" }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "MulOperator" }
|
override string getAPrimaryQlClass() { result = "MulOperator" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A user-defined checked multiplication operator (`*`), for example
|
||||||
|
*
|
||||||
|
* ```csharp
|
||||||
|
* public static Widget operator checked *(Widget lhs, Widget rhs) {
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
class CheckedMulOperator extends BinaryOperator {
|
||||||
|
CheckedMulOperator() { this.getName() = "checked *" }
|
||||||
|
|
||||||
|
override string getAPrimaryQlClass() { result = "CheckedMulOperator" }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A user-defined division operator (`/`), for example
|
* A user-defined division operator (`/`), for example
|
||||||
*
|
*
|
||||||
@@ -710,11 +786,24 @@ class MulOperator extends BinaryOperator {
|
|||||||
class DivOperator extends BinaryOperator {
|
class DivOperator extends BinaryOperator {
|
||||||
DivOperator() { this.getName() = "/" }
|
DivOperator() { this.getName() = "/" }
|
||||||
|
|
||||||
override string getFunctionName() { result = "op_Division" }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "DivOperator" }
|
override string getAPrimaryQlClass() { result = "DivOperator" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A user-defined checked division operator (`/`), for example
|
||||||
|
*
|
||||||
|
* ```csharp
|
||||||
|
* public static Widget operator checked /(Widget lhs, Widget rhs) {
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
class CheckedDivOperator extends BinaryOperator {
|
||||||
|
CheckedDivOperator() { this.getName() = "checked /" }
|
||||||
|
|
||||||
|
override string getAPrimaryQlClass() { result = "CheckedDivOperator" }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A user-defined remainder operator (`%`), for example
|
* A user-defined remainder operator (`%`), for example
|
||||||
*
|
*
|
||||||
@@ -727,8 +816,6 @@ class DivOperator extends BinaryOperator {
|
|||||||
class RemOperator extends BinaryOperator {
|
class RemOperator extends BinaryOperator {
|
||||||
RemOperator() { this.getName() = "%" }
|
RemOperator() { this.getName() = "%" }
|
||||||
|
|
||||||
override string getFunctionName() { result = "op_Modulus" }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "RemOperator" }
|
override string getAPrimaryQlClass() { result = "RemOperator" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -744,8 +831,6 @@ class RemOperator extends BinaryOperator {
|
|||||||
class AndOperator extends BinaryOperator {
|
class AndOperator extends BinaryOperator {
|
||||||
AndOperator() { this.getName() = "&" }
|
AndOperator() { this.getName() = "&" }
|
||||||
|
|
||||||
override string getFunctionName() { result = "op_BitwiseAnd" }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "AndOperator" }
|
override string getAPrimaryQlClass() { result = "AndOperator" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -761,8 +846,6 @@ class AndOperator extends BinaryOperator {
|
|||||||
class OrOperator extends BinaryOperator {
|
class OrOperator extends BinaryOperator {
|
||||||
OrOperator() { this.getName() = "|" }
|
OrOperator() { this.getName() = "|" }
|
||||||
|
|
||||||
override string getFunctionName() { result = "op_BitwiseOr" }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "OrOperator" }
|
override string getAPrimaryQlClass() { result = "OrOperator" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -778,8 +861,6 @@ class OrOperator extends BinaryOperator {
|
|||||||
class XorOperator extends BinaryOperator {
|
class XorOperator extends BinaryOperator {
|
||||||
XorOperator() { this.getName() = "^" }
|
XorOperator() { this.getName() = "^" }
|
||||||
|
|
||||||
override string getFunctionName() { result = "op_ExclusiveOr" }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "XorOperator" }
|
override string getAPrimaryQlClass() { result = "XorOperator" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -795,8 +876,6 @@ class XorOperator extends BinaryOperator {
|
|||||||
class LeftShiftOperator extends BinaryOperator {
|
class LeftShiftOperator extends BinaryOperator {
|
||||||
LeftShiftOperator() { this.getName() = "<<" }
|
LeftShiftOperator() { this.getName() = "<<" }
|
||||||
|
|
||||||
override string getFunctionName() { result = "op_LeftShift" }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "LeftShiftOperator" }
|
override string getAPrimaryQlClass() { result = "LeftShiftOperator" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -815,8 +894,6 @@ deprecated class LShiftOperator = LeftShiftOperator;
|
|||||||
class RightShiftOperator extends BinaryOperator {
|
class RightShiftOperator extends BinaryOperator {
|
||||||
RightShiftOperator() { this.getName() = ">>" }
|
RightShiftOperator() { this.getName() = ">>" }
|
||||||
|
|
||||||
override string getFunctionName() { result = "op_RightShift" }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "RightShiftOperator" }
|
override string getAPrimaryQlClass() { result = "RightShiftOperator" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -835,8 +912,6 @@ deprecated class RShiftOperator = RightShiftOperator;
|
|||||||
class UnsignedRightShiftOperator extends BinaryOperator {
|
class UnsignedRightShiftOperator extends BinaryOperator {
|
||||||
UnsignedRightShiftOperator() { this.getName() = ">>>" }
|
UnsignedRightShiftOperator() { this.getName() = ">>>" }
|
||||||
|
|
||||||
override string getFunctionName() { result = "op_UnsignedRightShift" }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "UnsignedRightShiftOperator" }
|
override string getAPrimaryQlClass() { result = "UnsignedRightShiftOperator" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -852,8 +927,6 @@ class UnsignedRightShiftOperator extends BinaryOperator {
|
|||||||
class EQOperator extends BinaryOperator {
|
class EQOperator extends BinaryOperator {
|
||||||
EQOperator() { this.getName() = "==" }
|
EQOperator() { this.getName() = "==" }
|
||||||
|
|
||||||
override string getFunctionName() { result = "op_Equality" }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "EQOperator" }
|
override string getAPrimaryQlClass() { result = "EQOperator" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -869,8 +942,6 @@ class EQOperator extends BinaryOperator {
|
|||||||
class NEOperator extends BinaryOperator {
|
class NEOperator extends BinaryOperator {
|
||||||
NEOperator() { this.getName() = "!=" }
|
NEOperator() { this.getName() = "!=" }
|
||||||
|
|
||||||
override string getFunctionName() { result = "op_Inequality" }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "NEOperator" }
|
override string getAPrimaryQlClass() { result = "NEOperator" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -886,8 +957,6 @@ class NEOperator extends BinaryOperator {
|
|||||||
class LTOperator extends BinaryOperator {
|
class LTOperator extends BinaryOperator {
|
||||||
LTOperator() { this.getName() = "<" }
|
LTOperator() { this.getName() = "<" }
|
||||||
|
|
||||||
override string getFunctionName() { result = "op_LessThan" }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "LTOperator" }
|
override string getAPrimaryQlClass() { result = "LTOperator" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -903,8 +972,6 @@ class LTOperator extends BinaryOperator {
|
|||||||
class GTOperator extends BinaryOperator {
|
class GTOperator extends BinaryOperator {
|
||||||
GTOperator() { this.getName() = ">" }
|
GTOperator() { this.getName() = ">" }
|
||||||
|
|
||||||
override string getFunctionName() { result = "op_GreaterThan" }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "GTOperator" }
|
override string getAPrimaryQlClass() { result = "GTOperator" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -920,8 +987,6 @@ class GTOperator extends BinaryOperator {
|
|||||||
class LEOperator extends BinaryOperator {
|
class LEOperator extends BinaryOperator {
|
||||||
LEOperator() { this.getName() = "<=" }
|
LEOperator() { this.getName() = "<=" }
|
||||||
|
|
||||||
override string getFunctionName() { result = "op_LessThanOrEqual" }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "LEOperator" }
|
override string getAPrimaryQlClass() { result = "LEOperator" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -937,8 +1002,6 @@ class LEOperator extends BinaryOperator {
|
|||||||
class GEOperator extends BinaryOperator {
|
class GEOperator extends BinaryOperator {
|
||||||
GEOperator() { this.getName() = ">=" }
|
GEOperator() { this.getName() = ">=" }
|
||||||
|
|
||||||
override string getFunctionName() { result = "op_GreaterThanOrEqual" }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "GEOperator" }
|
override string getAPrimaryQlClass() { result = "GEOperator" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -954,7 +1017,8 @@ class GEOperator extends BinaryOperator {
|
|||||||
class ConversionOperator extends Operator {
|
class ConversionOperator extends Operator {
|
||||||
ConversionOperator() {
|
ConversionOperator() {
|
||||||
this.getName() = "implicit conversion" or
|
this.getName() = "implicit conversion" or
|
||||||
this.getName() = "explicit conversion"
|
this.getName() = "explicit conversion" or
|
||||||
|
this.getName() = "checked explicit conversion"
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the source type of the conversion. */
|
/** Gets the source type of the conversion. */
|
||||||
@@ -976,8 +1040,6 @@ class ConversionOperator extends Operator {
|
|||||||
class ImplicitConversionOperator extends ConversionOperator {
|
class ImplicitConversionOperator extends ConversionOperator {
|
||||||
ImplicitConversionOperator() { this.getName() = "implicit conversion" }
|
ImplicitConversionOperator() { this.getName() = "implicit conversion" }
|
||||||
|
|
||||||
override string getFunctionName() { result = "op_Implicit" }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "ImplicitConversionOperator" }
|
override string getAPrimaryQlClass() { result = "ImplicitConversionOperator" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -993,11 +1055,24 @@ class ImplicitConversionOperator extends ConversionOperator {
|
|||||||
class ExplicitConversionOperator extends ConversionOperator {
|
class ExplicitConversionOperator extends ConversionOperator {
|
||||||
ExplicitConversionOperator() { this.getName() = "explicit conversion" }
|
ExplicitConversionOperator() { this.getName() = "explicit conversion" }
|
||||||
|
|
||||||
override string getFunctionName() { result = "op_Explicit" }
|
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "ExplicitConversionOperator" }
|
override string getAPrimaryQlClass() { result = "ExplicitConversionOperator" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A user-defined checked explicit conversion operator, for example
|
||||||
|
*
|
||||||
|
* ```csharp
|
||||||
|
* public static explicit operator checked int(BigInteger i) {
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
class CheckedExplicitConversionOperator extends ConversionOperator {
|
||||||
|
CheckedExplicitConversionOperator() { this.getName() = "checked explicit conversion" }
|
||||||
|
|
||||||
|
override string getAPrimaryQlClass() { result = "CheckedExplicitConversionOperator" }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A local function, defined within the scope of another callable.
|
* A local function, defined within the scope of another callable.
|
||||||
* For example, `Fac` on lines 2--4 in
|
* For example, `Fac` on lines 2--4 in
|
||||||
|
|||||||
@@ -90,6 +90,9 @@ class Modifiable extends Declaration, @modifiable {
|
|||||||
/** Holds if this declaration is `const`. */
|
/** Holds if this declaration is `const`. */
|
||||||
predicate isConst() { this.hasModifier("const") }
|
predicate isConst() { this.hasModifier("const") }
|
||||||
|
|
||||||
|
/** Holds if this declaration has the modifier `required`. */
|
||||||
|
predicate isRequired() { this.hasModifier("required") }
|
||||||
|
|
||||||
/** Holds if this declaration is `unsafe`. */
|
/** Holds if this declaration is `unsafe`. */
|
||||||
predicate isUnsafe() {
|
predicate isUnsafe() {
|
||||||
this.hasModifier("unsafe") or
|
this.hasModifier("unsafe") or
|
||||||
@@ -178,6 +181,8 @@ class Member extends DotNet::Member, Modifiable, @member {
|
|||||||
override predicate isAbstract() { Modifiable.super.isAbstract() }
|
override predicate isAbstract() { Modifiable.super.isAbstract() }
|
||||||
|
|
||||||
override predicate isStatic() { Modifiable.super.isStatic() }
|
override predicate isStatic() { Modifiable.super.isStatic() }
|
||||||
|
|
||||||
|
override predicate isRequired() { Modifiable.super.isRequired() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TOverridable = @virtualizable or @callable_accessor;
|
private class TOverridable = @virtualizable or @callable_accessor;
|
||||||
|
|||||||
@@ -71,6 +71,11 @@ class LocalScopeVariable extends Variable, @local_scope_variable {
|
|||||||
*/
|
*/
|
||||||
predicate isRef() { none() }
|
predicate isRef() { none() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if this local variable or parameter is `scoped`.
|
||||||
|
*/
|
||||||
|
predicate isScoped() { scoped_annotation(this, _) }
|
||||||
|
|
||||||
override predicate hasQualifiedName(string qualifier, string name) { none() }
|
override predicate hasQualifiedName(string qualifier, string name) { none() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -667,23 +667,78 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(NodeEx arg |
|
fwdFlowIn(_, _, _, node, config) and
|
||||||
fwdFlow(arg, _, config) and
|
cc = true
|
||||||
viableParamArgEx(_, node, arg) and
|
|
||||||
cc = true and
|
|
||||||
not fullBarrier(node, config)
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(DataFlowCall call |
|
fwdFlowOut(_, node, false, config) and
|
||||||
fwdFlowOut(call, node, false, config) and
|
|
||||||
cc = false
|
cc = false
|
||||||
or
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
fwdFlowOutFromArg(call, node, config) and
|
fwdFlowOutFromArg(call, node, config) and
|
||||||
fwdFlowIsEntered(call, cc, config)
|
fwdFlowIsEntered(call, cc, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowIn(
|
||||||
|
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||||
|
) {
|
||||||
|
// call context cannot help reduce virtual dispatch
|
||||||
|
fwdFlow(arg, cc, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
not fullBarrier(p, config) and
|
||||||
|
(
|
||||||
|
cc = false
|
||||||
|
or
|
||||||
|
cc = true and
|
||||||
|
not reducedViableImplInCallContext(call, _, _)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// call context may help reduce virtual dispatch
|
||||||
|
exists(DataFlowCallable target |
|
||||||
|
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||||
|
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||||
|
cc = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||||
|
fwdFlowIn(call, _, cc, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||||
|
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(arg, true, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
reducedViableImplInCallContext(call, _, _) and
|
||||||
|
target = p.getEnclosingCallable() and
|
||||||
|
not fullBarrier(p, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||||
|
* restricted to those `call`s for which a context might make a difference,
|
||||||
|
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||||
|
DataFlowCall call, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCall ctx |
|
||||||
|
fwdFlowIsEntered(ctx, _, config) and
|
||||||
|
result = viableImplInCallContextExt(call, ctx)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -726,7 +781,8 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
fwdFlowReturnPosition(pos, cc, config) and
|
fwdFlowReturnPosition(pos, cc, config) and
|
||||||
@@ -740,17 +796,6 @@ private module Stage1 implements StageSig {
|
|||||||
fwdFlowOut(call, out, true, config)
|
fwdFlowOut(call, out, true, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
|
||||||
*/
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
|
||||||
exists(ArgNodeEx arg |
|
|
||||||
fwdFlow(arg, cc, config) and
|
|
||||||
viableParamArgEx(call, _, arg)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||||
exists(NodeEx node1 |
|
exists(NodeEx node1 |
|
||||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||||
@@ -817,20 +862,21 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(DataFlowCall call |
|
revFlowIn(_, node, false, config) and
|
||||||
revFlowIn(call, node, false, config) and
|
|
||||||
toReturn = false
|
toReturn = false
|
||||||
or
|
or
|
||||||
revFlowInToReturn(call, node, config) and
|
|
||||||
revFlowIsReturned(call, toReturn, config)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
revFlowOut(pos, config) and
|
revFlowOut(pos, config) and
|
||||||
node.(RetNodeEx).getReturnPosition() = pos and
|
node.(RetNodeEx).getReturnPosition() = pos and
|
||||||
toReturn = true
|
toReturn = true
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
|
revFlowInToReturn(call, node, config) and
|
||||||
|
revFlowIsReturned(call, toReturn, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -886,11 +932,11 @@ private module Stage1 implements StageSig {
|
|||||||
additional predicate viableParamArgNodeCandFwd1(
|
additional predicate viableParamArgNodeCandFwd1(
|
||||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||||
) {
|
) {
|
||||||
viableParamArgEx(call, p, arg) and
|
fwdFlowIn(call, arg, _, p, config)
|
||||||
fwdFlow(arg, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate revFlowIn(
|
private predicate revFlowIn(
|
||||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -1223,7 +1269,16 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail);
|
Ap apCons(TypedContent tc, Ap tail);
|
||||||
|
|
||||||
Content getHeadContent(Ap ap);
|
/**
|
||||||
|
* An approximation of `Content` that corresponds to the precision level of
|
||||||
|
* `Ap`, such that the mappings from both `Ap` and `Content` to this type
|
||||||
|
* are functional.
|
||||||
|
*/
|
||||||
|
class ApHeadContent;
|
||||||
|
|
||||||
|
ApHeadContent getHeadContent(Ap ap);
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c);
|
||||||
|
|
||||||
class ApOption;
|
class ApOption;
|
||||||
|
|
||||||
@@ -1471,34 +1526,32 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ApNonNil instanceof Ap {
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
ApNonNil() { not this instanceof ApNil }
|
private predicate readStepCand(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
string toString() { result = "" }
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowRead0(
|
|
||||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
|
||||||
Configuration config
|
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
PrevStage::readStepCand(node1, _, _, config)
|
apc = projectToHeadContent(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, c]
|
bindingset[node1, apc]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
private predicate hasHeadContent(Ap ap, Content c) { getHeadContent(ap) = c }
|
private predicate readStepCand0(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
|
) {
|
||||||
|
readStepCand(node1, apc, c, node2, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
exists(ApHeadContent apc |
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
hasHeadContent(ap, c)
|
apc = getHeadContent(ap) and
|
||||||
|
readStepCand0(node1, apc, c, node2, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -2072,8 +2125,12 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Unit;
|
||||||
|
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
Content getHeadContent(Ap ap) { exists(result) and ap = true }
|
ApHeadContent getHeadContent(Ap ap) { exists(result) and ap = true }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { any() }
|
||||||
|
|
||||||
class ApOption = BooleanOption;
|
class ApOption = BooleanOption;
|
||||||
|
|
||||||
@@ -2337,8 +2394,12 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = ContentApprox;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
predicate projectToHeadContent = getContentApprox/1;
|
||||||
|
|
||||||
class ApOption = ApproxAccessPathFrontOption;
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2413,8 +2474,12 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathFrontOption;
|
class ApOption = AccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2743,8 +2808,12 @@ private module Stage5Param implements MkStage<Stage4>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathApproxOption;
|
class ApOption = AccessPathApproxOption;
|
||||||
|
|
||||||
|
|||||||
@@ -667,23 +667,78 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(NodeEx arg |
|
fwdFlowIn(_, _, _, node, config) and
|
||||||
fwdFlow(arg, _, config) and
|
cc = true
|
||||||
viableParamArgEx(_, node, arg) and
|
|
||||||
cc = true and
|
|
||||||
not fullBarrier(node, config)
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(DataFlowCall call |
|
fwdFlowOut(_, node, false, config) and
|
||||||
fwdFlowOut(call, node, false, config) and
|
|
||||||
cc = false
|
cc = false
|
||||||
or
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
fwdFlowOutFromArg(call, node, config) and
|
fwdFlowOutFromArg(call, node, config) and
|
||||||
fwdFlowIsEntered(call, cc, config)
|
fwdFlowIsEntered(call, cc, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowIn(
|
||||||
|
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||||
|
) {
|
||||||
|
// call context cannot help reduce virtual dispatch
|
||||||
|
fwdFlow(arg, cc, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
not fullBarrier(p, config) and
|
||||||
|
(
|
||||||
|
cc = false
|
||||||
|
or
|
||||||
|
cc = true and
|
||||||
|
not reducedViableImplInCallContext(call, _, _)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// call context may help reduce virtual dispatch
|
||||||
|
exists(DataFlowCallable target |
|
||||||
|
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||||
|
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||||
|
cc = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||||
|
fwdFlowIn(call, _, cc, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||||
|
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(arg, true, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
reducedViableImplInCallContext(call, _, _) and
|
||||||
|
target = p.getEnclosingCallable() and
|
||||||
|
not fullBarrier(p, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||||
|
* restricted to those `call`s for which a context might make a difference,
|
||||||
|
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||||
|
DataFlowCall call, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCall ctx |
|
||||||
|
fwdFlowIsEntered(ctx, _, config) and
|
||||||
|
result = viableImplInCallContextExt(call, ctx)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -726,7 +781,8 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
fwdFlowReturnPosition(pos, cc, config) and
|
fwdFlowReturnPosition(pos, cc, config) and
|
||||||
@@ -740,17 +796,6 @@ private module Stage1 implements StageSig {
|
|||||||
fwdFlowOut(call, out, true, config)
|
fwdFlowOut(call, out, true, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
|
||||||
*/
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
|
||||||
exists(ArgNodeEx arg |
|
|
||||||
fwdFlow(arg, cc, config) and
|
|
||||||
viableParamArgEx(call, _, arg)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||||
exists(NodeEx node1 |
|
exists(NodeEx node1 |
|
||||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||||
@@ -817,20 +862,21 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(DataFlowCall call |
|
revFlowIn(_, node, false, config) and
|
||||||
revFlowIn(call, node, false, config) and
|
|
||||||
toReturn = false
|
toReturn = false
|
||||||
or
|
or
|
||||||
revFlowInToReturn(call, node, config) and
|
|
||||||
revFlowIsReturned(call, toReturn, config)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
revFlowOut(pos, config) and
|
revFlowOut(pos, config) and
|
||||||
node.(RetNodeEx).getReturnPosition() = pos and
|
node.(RetNodeEx).getReturnPosition() = pos and
|
||||||
toReturn = true
|
toReturn = true
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
|
revFlowInToReturn(call, node, config) and
|
||||||
|
revFlowIsReturned(call, toReturn, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -886,11 +932,11 @@ private module Stage1 implements StageSig {
|
|||||||
additional predicate viableParamArgNodeCandFwd1(
|
additional predicate viableParamArgNodeCandFwd1(
|
||||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||||
) {
|
) {
|
||||||
viableParamArgEx(call, p, arg) and
|
fwdFlowIn(call, arg, _, p, config)
|
||||||
fwdFlow(arg, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate revFlowIn(
|
private predicate revFlowIn(
|
||||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -1223,7 +1269,16 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail);
|
Ap apCons(TypedContent tc, Ap tail);
|
||||||
|
|
||||||
Content getHeadContent(Ap ap);
|
/**
|
||||||
|
* An approximation of `Content` that corresponds to the precision level of
|
||||||
|
* `Ap`, such that the mappings from both `Ap` and `Content` to this type
|
||||||
|
* are functional.
|
||||||
|
*/
|
||||||
|
class ApHeadContent;
|
||||||
|
|
||||||
|
ApHeadContent getHeadContent(Ap ap);
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c);
|
||||||
|
|
||||||
class ApOption;
|
class ApOption;
|
||||||
|
|
||||||
@@ -1471,34 +1526,32 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ApNonNil instanceof Ap {
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
ApNonNil() { not this instanceof ApNil }
|
private predicate readStepCand(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
string toString() { result = "" }
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowRead0(
|
|
||||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
|
||||||
Configuration config
|
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
PrevStage::readStepCand(node1, _, _, config)
|
apc = projectToHeadContent(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, c]
|
bindingset[node1, apc]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
private predicate hasHeadContent(Ap ap, Content c) { getHeadContent(ap) = c }
|
private predicate readStepCand0(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
|
) {
|
||||||
|
readStepCand(node1, apc, c, node2, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
exists(ApHeadContent apc |
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
hasHeadContent(ap, c)
|
apc = getHeadContent(ap) and
|
||||||
|
readStepCand0(node1, apc, c, node2, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -2072,8 +2125,12 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Unit;
|
||||||
|
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
Content getHeadContent(Ap ap) { exists(result) and ap = true }
|
ApHeadContent getHeadContent(Ap ap) { exists(result) and ap = true }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { any() }
|
||||||
|
|
||||||
class ApOption = BooleanOption;
|
class ApOption = BooleanOption;
|
||||||
|
|
||||||
@@ -2337,8 +2394,12 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = ContentApprox;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
predicate projectToHeadContent = getContentApprox/1;
|
||||||
|
|
||||||
class ApOption = ApproxAccessPathFrontOption;
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2413,8 +2474,12 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathFrontOption;
|
class ApOption = AccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2743,8 +2808,12 @@ private module Stage5Param implements MkStage<Stage4>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathApproxOption;
|
class ApOption = AccessPathApproxOption;
|
||||||
|
|
||||||
|
|||||||
@@ -667,23 +667,78 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(NodeEx arg |
|
fwdFlowIn(_, _, _, node, config) and
|
||||||
fwdFlow(arg, _, config) and
|
cc = true
|
||||||
viableParamArgEx(_, node, arg) and
|
|
||||||
cc = true and
|
|
||||||
not fullBarrier(node, config)
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(DataFlowCall call |
|
fwdFlowOut(_, node, false, config) and
|
||||||
fwdFlowOut(call, node, false, config) and
|
|
||||||
cc = false
|
cc = false
|
||||||
or
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
fwdFlowOutFromArg(call, node, config) and
|
fwdFlowOutFromArg(call, node, config) and
|
||||||
fwdFlowIsEntered(call, cc, config)
|
fwdFlowIsEntered(call, cc, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowIn(
|
||||||
|
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||||
|
) {
|
||||||
|
// call context cannot help reduce virtual dispatch
|
||||||
|
fwdFlow(arg, cc, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
not fullBarrier(p, config) and
|
||||||
|
(
|
||||||
|
cc = false
|
||||||
|
or
|
||||||
|
cc = true and
|
||||||
|
not reducedViableImplInCallContext(call, _, _)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// call context may help reduce virtual dispatch
|
||||||
|
exists(DataFlowCallable target |
|
||||||
|
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||||
|
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||||
|
cc = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||||
|
fwdFlowIn(call, _, cc, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||||
|
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(arg, true, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
reducedViableImplInCallContext(call, _, _) and
|
||||||
|
target = p.getEnclosingCallable() and
|
||||||
|
not fullBarrier(p, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||||
|
* restricted to those `call`s for which a context might make a difference,
|
||||||
|
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||||
|
DataFlowCall call, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCall ctx |
|
||||||
|
fwdFlowIsEntered(ctx, _, config) and
|
||||||
|
result = viableImplInCallContextExt(call, ctx)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -726,7 +781,8 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
fwdFlowReturnPosition(pos, cc, config) and
|
fwdFlowReturnPosition(pos, cc, config) and
|
||||||
@@ -740,17 +796,6 @@ private module Stage1 implements StageSig {
|
|||||||
fwdFlowOut(call, out, true, config)
|
fwdFlowOut(call, out, true, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
|
||||||
*/
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
|
||||||
exists(ArgNodeEx arg |
|
|
||||||
fwdFlow(arg, cc, config) and
|
|
||||||
viableParamArgEx(call, _, arg)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||||
exists(NodeEx node1 |
|
exists(NodeEx node1 |
|
||||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||||
@@ -817,20 +862,21 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(DataFlowCall call |
|
revFlowIn(_, node, false, config) and
|
||||||
revFlowIn(call, node, false, config) and
|
|
||||||
toReturn = false
|
toReturn = false
|
||||||
or
|
or
|
||||||
revFlowInToReturn(call, node, config) and
|
|
||||||
revFlowIsReturned(call, toReturn, config)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
revFlowOut(pos, config) and
|
revFlowOut(pos, config) and
|
||||||
node.(RetNodeEx).getReturnPosition() = pos and
|
node.(RetNodeEx).getReturnPosition() = pos and
|
||||||
toReturn = true
|
toReturn = true
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
|
revFlowInToReturn(call, node, config) and
|
||||||
|
revFlowIsReturned(call, toReturn, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -886,11 +932,11 @@ private module Stage1 implements StageSig {
|
|||||||
additional predicate viableParamArgNodeCandFwd1(
|
additional predicate viableParamArgNodeCandFwd1(
|
||||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||||
) {
|
) {
|
||||||
viableParamArgEx(call, p, arg) and
|
fwdFlowIn(call, arg, _, p, config)
|
||||||
fwdFlow(arg, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate revFlowIn(
|
private predicate revFlowIn(
|
||||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -1223,7 +1269,16 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail);
|
Ap apCons(TypedContent tc, Ap tail);
|
||||||
|
|
||||||
Content getHeadContent(Ap ap);
|
/**
|
||||||
|
* An approximation of `Content` that corresponds to the precision level of
|
||||||
|
* `Ap`, such that the mappings from both `Ap` and `Content` to this type
|
||||||
|
* are functional.
|
||||||
|
*/
|
||||||
|
class ApHeadContent;
|
||||||
|
|
||||||
|
ApHeadContent getHeadContent(Ap ap);
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c);
|
||||||
|
|
||||||
class ApOption;
|
class ApOption;
|
||||||
|
|
||||||
@@ -1471,34 +1526,32 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ApNonNil instanceof Ap {
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
ApNonNil() { not this instanceof ApNil }
|
private predicate readStepCand(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
string toString() { result = "" }
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowRead0(
|
|
||||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
|
||||||
Configuration config
|
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
PrevStage::readStepCand(node1, _, _, config)
|
apc = projectToHeadContent(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, c]
|
bindingset[node1, apc]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
private predicate hasHeadContent(Ap ap, Content c) { getHeadContent(ap) = c }
|
private predicate readStepCand0(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
|
) {
|
||||||
|
readStepCand(node1, apc, c, node2, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
exists(ApHeadContent apc |
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
hasHeadContent(ap, c)
|
apc = getHeadContent(ap) and
|
||||||
|
readStepCand0(node1, apc, c, node2, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -2072,8 +2125,12 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Unit;
|
||||||
|
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
Content getHeadContent(Ap ap) { exists(result) and ap = true }
|
ApHeadContent getHeadContent(Ap ap) { exists(result) and ap = true }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { any() }
|
||||||
|
|
||||||
class ApOption = BooleanOption;
|
class ApOption = BooleanOption;
|
||||||
|
|
||||||
@@ -2337,8 +2394,12 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = ContentApprox;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
predicate projectToHeadContent = getContentApprox/1;
|
||||||
|
|
||||||
class ApOption = ApproxAccessPathFrontOption;
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2413,8 +2474,12 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathFrontOption;
|
class ApOption = AccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2743,8 +2808,12 @@ private module Stage5Param implements MkStage<Stage4>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathApproxOption;
|
class ApOption = AccessPathApproxOption;
|
||||||
|
|
||||||
|
|||||||
@@ -667,23 +667,78 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(NodeEx arg |
|
fwdFlowIn(_, _, _, node, config) and
|
||||||
fwdFlow(arg, _, config) and
|
cc = true
|
||||||
viableParamArgEx(_, node, arg) and
|
|
||||||
cc = true and
|
|
||||||
not fullBarrier(node, config)
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(DataFlowCall call |
|
fwdFlowOut(_, node, false, config) and
|
||||||
fwdFlowOut(call, node, false, config) and
|
|
||||||
cc = false
|
cc = false
|
||||||
or
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
fwdFlowOutFromArg(call, node, config) and
|
fwdFlowOutFromArg(call, node, config) and
|
||||||
fwdFlowIsEntered(call, cc, config)
|
fwdFlowIsEntered(call, cc, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowIn(
|
||||||
|
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||||
|
) {
|
||||||
|
// call context cannot help reduce virtual dispatch
|
||||||
|
fwdFlow(arg, cc, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
not fullBarrier(p, config) and
|
||||||
|
(
|
||||||
|
cc = false
|
||||||
|
or
|
||||||
|
cc = true and
|
||||||
|
not reducedViableImplInCallContext(call, _, _)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// call context may help reduce virtual dispatch
|
||||||
|
exists(DataFlowCallable target |
|
||||||
|
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||||
|
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||||
|
cc = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||||
|
fwdFlowIn(call, _, cc, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||||
|
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(arg, true, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
reducedViableImplInCallContext(call, _, _) and
|
||||||
|
target = p.getEnclosingCallable() and
|
||||||
|
not fullBarrier(p, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||||
|
* restricted to those `call`s for which a context might make a difference,
|
||||||
|
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||||
|
DataFlowCall call, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCall ctx |
|
||||||
|
fwdFlowIsEntered(ctx, _, config) and
|
||||||
|
result = viableImplInCallContextExt(call, ctx)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -726,7 +781,8 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
fwdFlowReturnPosition(pos, cc, config) and
|
fwdFlowReturnPosition(pos, cc, config) and
|
||||||
@@ -740,17 +796,6 @@ private module Stage1 implements StageSig {
|
|||||||
fwdFlowOut(call, out, true, config)
|
fwdFlowOut(call, out, true, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
|
||||||
*/
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
|
||||||
exists(ArgNodeEx arg |
|
|
||||||
fwdFlow(arg, cc, config) and
|
|
||||||
viableParamArgEx(call, _, arg)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||||
exists(NodeEx node1 |
|
exists(NodeEx node1 |
|
||||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||||
@@ -817,20 +862,21 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(DataFlowCall call |
|
revFlowIn(_, node, false, config) and
|
||||||
revFlowIn(call, node, false, config) and
|
|
||||||
toReturn = false
|
toReturn = false
|
||||||
or
|
or
|
||||||
revFlowInToReturn(call, node, config) and
|
|
||||||
revFlowIsReturned(call, toReturn, config)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
revFlowOut(pos, config) and
|
revFlowOut(pos, config) and
|
||||||
node.(RetNodeEx).getReturnPosition() = pos and
|
node.(RetNodeEx).getReturnPosition() = pos and
|
||||||
toReturn = true
|
toReturn = true
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
|
revFlowInToReturn(call, node, config) and
|
||||||
|
revFlowIsReturned(call, toReturn, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -886,11 +932,11 @@ private module Stage1 implements StageSig {
|
|||||||
additional predicate viableParamArgNodeCandFwd1(
|
additional predicate viableParamArgNodeCandFwd1(
|
||||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||||
) {
|
) {
|
||||||
viableParamArgEx(call, p, arg) and
|
fwdFlowIn(call, arg, _, p, config)
|
||||||
fwdFlow(arg, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate revFlowIn(
|
private predicate revFlowIn(
|
||||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -1223,7 +1269,16 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail);
|
Ap apCons(TypedContent tc, Ap tail);
|
||||||
|
|
||||||
Content getHeadContent(Ap ap);
|
/**
|
||||||
|
* An approximation of `Content` that corresponds to the precision level of
|
||||||
|
* `Ap`, such that the mappings from both `Ap` and `Content` to this type
|
||||||
|
* are functional.
|
||||||
|
*/
|
||||||
|
class ApHeadContent;
|
||||||
|
|
||||||
|
ApHeadContent getHeadContent(Ap ap);
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c);
|
||||||
|
|
||||||
class ApOption;
|
class ApOption;
|
||||||
|
|
||||||
@@ -1471,34 +1526,32 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ApNonNil instanceof Ap {
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
ApNonNil() { not this instanceof ApNil }
|
private predicate readStepCand(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
string toString() { result = "" }
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowRead0(
|
|
||||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
|
||||||
Configuration config
|
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
PrevStage::readStepCand(node1, _, _, config)
|
apc = projectToHeadContent(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, c]
|
bindingset[node1, apc]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
private predicate hasHeadContent(Ap ap, Content c) { getHeadContent(ap) = c }
|
private predicate readStepCand0(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
|
) {
|
||||||
|
readStepCand(node1, apc, c, node2, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
exists(ApHeadContent apc |
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
hasHeadContent(ap, c)
|
apc = getHeadContent(ap) and
|
||||||
|
readStepCand0(node1, apc, c, node2, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -2072,8 +2125,12 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Unit;
|
||||||
|
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
Content getHeadContent(Ap ap) { exists(result) and ap = true }
|
ApHeadContent getHeadContent(Ap ap) { exists(result) and ap = true }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { any() }
|
||||||
|
|
||||||
class ApOption = BooleanOption;
|
class ApOption = BooleanOption;
|
||||||
|
|
||||||
@@ -2337,8 +2394,12 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = ContentApprox;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
predicate projectToHeadContent = getContentApprox/1;
|
||||||
|
|
||||||
class ApOption = ApproxAccessPathFrontOption;
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2413,8 +2474,12 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathFrontOption;
|
class ApOption = AccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2743,8 +2808,12 @@ private module Stage5Param implements MkStage<Stage4>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathApproxOption;
|
class ApOption = AccessPathApproxOption;
|
||||||
|
|
||||||
|
|||||||
@@ -667,23 +667,78 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(NodeEx arg |
|
fwdFlowIn(_, _, _, node, config) and
|
||||||
fwdFlow(arg, _, config) and
|
cc = true
|
||||||
viableParamArgEx(_, node, arg) and
|
|
||||||
cc = true and
|
|
||||||
not fullBarrier(node, config)
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(DataFlowCall call |
|
fwdFlowOut(_, node, false, config) and
|
||||||
fwdFlowOut(call, node, false, config) and
|
|
||||||
cc = false
|
cc = false
|
||||||
or
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
fwdFlowOutFromArg(call, node, config) and
|
fwdFlowOutFromArg(call, node, config) and
|
||||||
fwdFlowIsEntered(call, cc, config)
|
fwdFlowIsEntered(call, cc, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowIn(
|
||||||
|
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||||
|
) {
|
||||||
|
// call context cannot help reduce virtual dispatch
|
||||||
|
fwdFlow(arg, cc, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
not fullBarrier(p, config) and
|
||||||
|
(
|
||||||
|
cc = false
|
||||||
|
or
|
||||||
|
cc = true and
|
||||||
|
not reducedViableImplInCallContext(call, _, _)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// call context may help reduce virtual dispatch
|
||||||
|
exists(DataFlowCallable target |
|
||||||
|
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||||
|
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||||
|
cc = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||||
|
fwdFlowIn(call, _, cc, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||||
|
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(arg, true, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
reducedViableImplInCallContext(call, _, _) and
|
||||||
|
target = p.getEnclosingCallable() and
|
||||||
|
not fullBarrier(p, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||||
|
* restricted to those `call`s for which a context might make a difference,
|
||||||
|
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||||
|
DataFlowCall call, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCall ctx |
|
||||||
|
fwdFlowIsEntered(ctx, _, config) and
|
||||||
|
result = viableImplInCallContextExt(call, ctx)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -726,7 +781,8 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
fwdFlowReturnPosition(pos, cc, config) and
|
fwdFlowReturnPosition(pos, cc, config) and
|
||||||
@@ -740,17 +796,6 @@ private module Stage1 implements StageSig {
|
|||||||
fwdFlowOut(call, out, true, config)
|
fwdFlowOut(call, out, true, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
|
||||||
*/
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
|
||||||
exists(ArgNodeEx arg |
|
|
||||||
fwdFlow(arg, cc, config) and
|
|
||||||
viableParamArgEx(call, _, arg)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||||
exists(NodeEx node1 |
|
exists(NodeEx node1 |
|
||||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||||
@@ -817,20 +862,21 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(DataFlowCall call |
|
revFlowIn(_, node, false, config) and
|
||||||
revFlowIn(call, node, false, config) and
|
|
||||||
toReturn = false
|
toReturn = false
|
||||||
or
|
or
|
||||||
revFlowInToReturn(call, node, config) and
|
|
||||||
revFlowIsReturned(call, toReturn, config)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
revFlowOut(pos, config) and
|
revFlowOut(pos, config) and
|
||||||
node.(RetNodeEx).getReturnPosition() = pos and
|
node.(RetNodeEx).getReturnPosition() = pos and
|
||||||
toReturn = true
|
toReturn = true
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
|
revFlowInToReturn(call, node, config) and
|
||||||
|
revFlowIsReturned(call, toReturn, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -886,11 +932,11 @@ private module Stage1 implements StageSig {
|
|||||||
additional predicate viableParamArgNodeCandFwd1(
|
additional predicate viableParamArgNodeCandFwd1(
|
||||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||||
) {
|
) {
|
||||||
viableParamArgEx(call, p, arg) and
|
fwdFlowIn(call, arg, _, p, config)
|
||||||
fwdFlow(arg, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate revFlowIn(
|
private predicate revFlowIn(
|
||||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -1223,7 +1269,16 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail);
|
Ap apCons(TypedContent tc, Ap tail);
|
||||||
|
|
||||||
Content getHeadContent(Ap ap);
|
/**
|
||||||
|
* An approximation of `Content` that corresponds to the precision level of
|
||||||
|
* `Ap`, such that the mappings from both `Ap` and `Content` to this type
|
||||||
|
* are functional.
|
||||||
|
*/
|
||||||
|
class ApHeadContent;
|
||||||
|
|
||||||
|
ApHeadContent getHeadContent(Ap ap);
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c);
|
||||||
|
|
||||||
class ApOption;
|
class ApOption;
|
||||||
|
|
||||||
@@ -1471,34 +1526,32 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ApNonNil instanceof Ap {
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
ApNonNil() { not this instanceof ApNil }
|
private predicate readStepCand(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
string toString() { result = "" }
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowRead0(
|
|
||||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
|
||||||
Configuration config
|
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
PrevStage::readStepCand(node1, _, _, config)
|
apc = projectToHeadContent(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, c]
|
bindingset[node1, apc]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
private predicate hasHeadContent(Ap ap, Content c) { getHeadContent(ap) = c }
|
private predicate readStepCand0(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
|
) {
|
||||||
|
readStepCand(node1, apc, c, node2, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
exists(ApHeadContent apc |
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
hasHeadContent(ap, c)
|
apc = getHeadContent(ap) and
|
||||||
|
readStepCand0(node1, apc, c, node2, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -2072,8 +2125,12 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Unit;
|
||||||
|
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
Content getHeadContent(Ap ap) { exists(result) and ap = true }
|
ApHeadContent getHeadContent(Ap ap) { exists(result) and ap = true }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { any() }
|
||||||
|
|
||||||
class ApOption = BooleanOption;
|
class ApOption = BooleanOption;
|
||||||
|
|
||||||
@@ -2337,8 +2394,12 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = ContentApprox;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
predicate projectToHeadContent = getContentApprox/1;
|
||||||
|
|
||||||
class ApOption = ApproxAccessPathFrontOption;
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2413,8 +2474,12 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathFrontOption;
|
class ApOption = AccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2743,8 +2808,12 @@ private module Stage5Param implements MkStage<Stage4>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathApproxOption;
|
class ApOption = AccessPathApproxOption;
|
||||||
|
|
||||||
|
|||||||
@@ -707,8 +707,8 @@ private module Cached {
|
|||||||
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||||
* restricted to those `call`s for which a context might make a difference.
|
* restricted to those `call`s for which a context might make a difference.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
cached
|
||||||
private DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) {
|
DataFlowCallable viableImplInCallContextExt(DataFlowCall call, DataFlowCall ctx) {
|
||||||
result = viableImplInCallContext(call, ctx) and
|
result = viableImplInCallContext(call, ctx) and
|
||||||
result = viableCallable(call)
|
result = viableCallable(call)
|
||||||
or
|
or
|
||||||
@@ -1391,6 +1391,9 @@ class TypedContentApprox extends MkTypedContentApprox {
|
|||||||
/** Gets a typed content approximated by this value. */
|
/** Gets a typed content approximated by this value. */
|
||||||
TypedContent getATypedContent() { result = getATypedContent(this) }
|
TypedContent getATypedContent() { result = getATypedContent(this) }
|
||||||
|
|
||||||
|
/** Gets the content. */
|
||||||
|
ContentApprox getContent() { result = c }
|
||||||
|
|
||||||
/** Gets the container type. */
|
/** Gets the container type. */
|
||||||
DataFlowType getContainerType() { result = t }
|
DataFlowType getContainerType() { result = t }
|
||||||
|
|
||||||
@@ -1408,6 +1411,8 @@ abstract class ApproxAccessPathFront extends TApproxAccessPathFront {
|
|||||||
|
|
||||||
abstract boolean toBoolNonEmpty();
|
abstract boolean toBoolNonEmpty();
|
||||||
|
|
||||||
|
TypedContentApprox getHead() { this = TApproxFrontHead(result) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
TypedContent getAHead() {
|
TypedContent getAHead() {
|
||||||
exists(TypedContentApprox cont |
|
exists(TypedContentApprox cont |
|
||||||
|
|||||||
@@ -667,23 +667,78 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(NodeEx arg |
|
fwdFlowIn(_, _, _, node, config) and
|
||||||
fwdFlow(arg, _, config) and
|
cc = true
|
||||||
viableParamArgEx(_, node, arg) and
|
|
||||||
cc = true and
|
|
||||||
not fullBarrier(node, config)
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(DataFlowCall call |
|
fwdFlowOut(_, node, false, config) and
|
||||||
fwdFlowOut(call, node, false, config) and
|
|
||||||
cc = false
|
cc = false
|
||||||
or
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
fwdFlowOutFromArg(call, node, config) and
|
fwdFlowOutFromArg(call, node, config) and
|
||||||
fwdFlowIsEntered(call, cc, config)
|
fwdFlowIsEntered(call, cc, config)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
|
private predicate fwdFlowIn(
|
||||||
|
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
|
||||||
|
) {
|
||||||
|
// call context cannot help reduce virtual dispatch
|
||||||
|
fwdFlow(arg, cc, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
not fullBarrier(p, config) and
|
||||||
|
(
|
||||||
|
cc = false
|
||||||
|
or
|
||||||
|
cc = true and
|
||||||
|
not reducedViableImplInCallContext(call, _, _)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// call context may help reduce virtual dispatch
|
||||||
|
exists(DataFlowCallable target |
|
||||||
|
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
|
||||||
|
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
|
||||||
|
cc = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
||||||
|
fwdFlowIn(call, _, cc, _, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate fwdFlowInReducedViableImplInSomeCallContext(
|
||||||
|
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
|
||||||
|
) {
|
||||||
|
fwdFlow(arg, true, config) and
|
||||||
|
viableParamArgEx(call, p, arg) and
|
||||||
|
reducedViableImplInCallContext(call, _, _) and
|
||||||
|
target = p.getEnclosingCallable() and
|
||||||
|
not fullBarrier(p, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a viable dispatch target of `call` in the context `ctx`. This is
|
||||||
|
* restricted to those `call`s for which a context might make a difference,
|
||||||
|
* and to `ctx`s that are reachable in `fwdFlow`.
|
||||||
|
*/
|
||||||
|
pragma[nomagic]
|
||||||
|
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
|
||||||
|
DataFlowCall call, Configuration config
|
||||||
|
) {
|
||||||
|
exists(DataFlowCall ctx |
|
||||||
|
fwdFlowIsEntered(ctx, _, config) and
|
||||||
|
result = viableImplInCallContextExt(call, ctx)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -726,7 +781,8 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
fwdFlowReturnPosition(pos, cc, config) and
|
fwdFlowReturnPosition(pos, cc, config) and
|
||||||
@@ -740,17 +796,6 @@ private module Stage1 implements StageSig {
|
|||||||
fwdFlowOut(call, out, true, config)
|
fwdFlowOut(call, out, true, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
|
|
||||||
*/
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
|
|
||||||
exists(ArgNodeEx arg |
|
|
||||||
fwdFlow(arg, cc, config) and
|
|
||||||
viableParamArgEx(call, _, arg)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
|
||||||
exists(NodeEx node1 |
|
exists(NodeEx node1 |
|
||||||
additionalLocalStateStep(node1, state1, _, state2, config) or
|
additionalLocalStateStep(node1, state1, _, state2, config) or
|
||||||
@@ -817,20 +862,21 @@ private module Stage1 implements StageSig {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
// flow into a callable
|
// flow into a callable
|
||||||
exists(DataFlowCall call |
|
revFlowIn(_, node, false, config) and
|
||||||
revFlowIn(call, node, false, config) and
|
|
||||||
toReturn = false
|
toReturn = false
|
||||||
or
|
or
|
||||||
revFlowInToReturn(call, node, config) and
|
|
||||||
revFlowIsReturned(call, toReturn, config)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// flow out of a callable
|
// flow out of a callable
|
||||||
exists(ReturnPosition pos |
|
exists(ReturnPosition pos |
|
||||||
revFlowOut(pos, config) and
|
revFlowOut(pos, config) and
|
||||||
node.(RetNodeEx).getReturnPosition() = pos and
|
node.(RetNodeEx).getReturnPosition() = pos and
|
||||||
toReturn = true
|
toReturn = true
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
// flow through a callable
|
||||||
|
exists(DataFlowCall call |
|
||||||
|
revFlowInToReturn(call, node, config) and
|
||||||
|
revFlowIsReturned(call, toReturn, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -886,11 +932,11 @@ private module Stage1 implements StageSig {
|
|||||||
additional predicate viableParamArgNodeCandFwd1(
|
additional predicate viableParamArgNodeCandFwd1(
|
||||||
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
|
||||||
) {
|
) {
|
||||||
viableParamArgEx(call, p, arg) and
|
fwdFlowIn(call, arg, _, p, config)
|
||||||
fwdFlow(arg, config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
// inline to reduce the number of iterations
|
||||||
|
pragma[inline]
|
||||||
private predicate revFlowIn(
|
private predicate revFlowIn(
|
||||||
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
|
||||||
) {
|
) {
|
||||||
@@ -1223,7 +1269,16 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail);
|
Ap apCons(TypedContent tc, Ap tail);
|
||||||
|
|
||||||
Content getHeadContent(Ap ap);
|
/**
|
||||||
|
* An approximation of `Content` that corresponds to the precision level of
|
||||||
|
* `Ap`, such that the mappings from both `Ap` and `Content` to this type
|
||||||
|
* are functional.
|
||||||
|
*/
|
||||||
|
class ApHeadContent;
|
||||||
|
|
||||||
|
ApHeadContent getHeadContent(Ap ap);
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c);
|
||||||
|
|
||||||
class ApOption;
|
class ApOption;
|
||||||
|
|
||||||
@@ -1471,34 +1526,32 @@ private module MkStage<StageSig PrevStage> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ApNonNil instanceof Ap {
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
ApNonNil() { not this instanceof ApNil }
|
private predicate readStepCand(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
string toString() { result = "" }
|
|
||||||
}
|
|
||||||
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate fwdFlowRead0(
|
|
||||||
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
|
|
||||||
Configuration config
|
|
||||||
) {
|
) {
|
||||||
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
PrevStage::readStepCand(node1, c, node2, config) and
|
||||||
PrevStage::readStepCand(node1, _, _, config)
|
apc = projectToHeadContent(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[ap, c]
|
bindingset[node1, apc]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
private predicate hasHeadContent(Ap ap, Content c) { getHeadContent(ap) = c }
|
private predicate readStepCand0(
|
||||||
|
NodeEx node1, ApHeadContent apc, Content c, NodeEx node2, Configuration config
|
||||||
|
) {
|
||||||
|
readStepCand(node1, apc, c, node2, config)
|
||||||
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate fwdFlowRead(
|
private predicate fwdFlowRead(
|
||||||
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
|
||||||
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
|
||||||
) {
|
) {
|
||||||
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
|
exists(ApHeadContent apc |
|
||||||
PrevStage::readStepCand(node1, c, node2, config) and
|
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
|
||||||
hasHeadContent(ap, c)
|
apc = getHeadContent(ap) and
|
||||||
|
readStepCand0(node1, apc, c, node2, config)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -2072,8 +2125,12 @@ private module Stage2Param implements MkStage<Stage1>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = true and exists(tc) and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Unit;
|
||||||
|
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
Content getHeadContent(Ap ap) { exists(result) and ap = true }
|
ApHeadContent getHeadContent(Ap ap) { exists(result) and ap = true }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { any() }
|
||||||
|
|
||||||
class ApOption = BooleanOption;
|
class ApOption = BooleanOption;
|
||||||
|
|
||||||
@@ -2337,8 +2394,12 @@ private module Stage3Param implements MkStage<Stage2>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getAHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = ContentApprox;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getAHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
predicate projectToHeadContent = getContentApprox/1;
|
||||||
|
|
||||||
class ApOption = ApproxAccessPathFrontOption;
|
class ApOption = ApproxAccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2413,8 +2474,12 @@ private module Stage4Param implements MkStage<Stage3>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result.getHead() = tc and exists(tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathFrontOption;
|
class ApOption = AccessPathFrontOption;
|
||||||
|
|
||||||
@@ -2743,8 +2808,12 @@ private module Stage5Param implements MkStage<Stage4>::StageParam {
|
|||||||
bindingset[tc, tail]
|
bindingset[tc, tail]
|
||||||
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
Ap apCons(TypedContent tc, Ap tail) { result = push(tc, tail) }
|
||||||
|
|
||||||
|
class ApHeadContent = Content;
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
Content getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
ApHeadContent getHeadContent(Ap ap) { result = ap.getHead().getContent() }
|
||||||
|
|
||||||
|
ApHeadContent projectToHeadContent(Content c) { result = c }
|
||||||
|
|
||||||
class ApOption = AccessPathApproxOption;
|
class ApOption = AccessPathApproxOption;
|
||||||
|
|
||||||
|
|||||||
@@ -80,6 +80,9 @@ class Member extends Declaration, @dotnet_member {
|
|||||||
/** Holds if this member is `static`. */
|
/** Holds if this member is `static`. */
|
||||||
predicate isStatic() { none() }
|
predicate isStatic() { none() }
|
||||||
|
|
||||||
|
/** Holds if this member is declared `required`. */
|
||||||
|
predicate isRequired() { none() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if this member has name `name` and is defined in type `type`
|
* Holds if this member has name `name` and is defined in type `type`
|
||||||
* with namespace `namespace`.
|
* with namespace `namespace`.
|
||||||
|
|||||||
@@ -878,6 +878,13 @@ param_location(
|
|||||||
int id: @parameter ref,
|
int id: @parameter ref,
|
||||||
int loc: @location ref);
|
int loc: @location ref);
|
||||||
|
|
||||||
|
@has_scoped_annotation = @local_scope_variable
|
||||||
|
|
||||||
|
scoped_annotation(
|
||||||
|
int id: @has_scoped_annotation ref,
|
||||||
|
int kind: int ref // scoped ref = 1, scoped value = 2
|
||||||
|
);
|
||||||
|
|
||||||
/** STATEMENTS **/
|
/** STATEMENTS **/
|
||||||
|
|
||||||
@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent;
|
@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent;
|
||||||
|
|||||||
@@ -26228,6 +26228,59 @@
|
|||||||
</dep>
|
</dep>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</relation>
|
</relation>
|
||||||
|
<relation>
|
||||||
|
<name>scoped_annotation</name>
|
||||||
|
<cardinality>43498</cardinality>
|
||||||
|
<columnsizes>
|
||||||
|
<e>
|
||||||
|
<k>id</k>
|
||||||
|
<v>43498</v>
|
||||||
|
</e>
|
||||||
|
<e>
|
||||||
|
<k>kind</k>
|
||||||
|
<v>18</v>
|
||||||
|
</e>
|
||||||
|
</columnsizes>
|
||||||
|
<dependencies>
|
||||||
|
<dep>
|
||||||
|
<src>id</src>
|
||||||
|
<trg>kind</trg>
|
||||||
|
<val>
|
||||||
|
<hist>
|
||||||
|
<budget>12</budget>
|
||||||
|
<bs>
|
||||||
|
<b>
|
||||||
|
<a>1</a>
|
||||||
|
<b>2</b>
|
||||||
|
<v>43498</v>
|
||||||
|
</b>
|
||||||
|
</bs>
|
||||||
|
</hist>
|
||||||
|
</val>
|
||||||
|
</dep>
|
||||||
|
<dep>
|
||||||
|
<src>kind</src>
|
||||||
|
<trg>id</trg>
|
||||||
|
<val>
|
||||||
|
<hist>
|
||||||
|
<budget>12</budget>
|
||||||
|
<bs>
|
||||||
|
<b>
|
||||||
|
<a>11</a>
|
||||||
|
<b>12</b>
|
||||||
|
<v>9</v>
|
||||||
|
</b>
|
||||||
|
<b>
|
||||||
|
<a>4599</a>
|
||||||
|
<b>4600</b>
|
||||||
|
<v>9</v>
|
||||||
|
</b>
|
||||||
|
</bs>
|
||||||
|
</hist>
|
||||||
|
</val>
|
||||||
|
</dep>
|
||||||
|
</dependencies>
|
||||||
|
</relation>
|
||||||
<relation>
|
<relation>
|
||||||
<name>statements</name>
|
<name>statements</name>
|
||||||
<cardinality>2458000</cardinality>
|
<cardinality>2458000</cardinality>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
|||||||
|
description: Add a relation for scoped annotations.
|
||||||
|
compatibility: backwards
|
||||||
@@ -1,3 +1,7 @@
|
|||||||
|
## 0.5.3
|
||||||
|
|
||||||
|
No user-facing changes.
|
||||||
|
|
||||||
## 0.5.2
|
## 0.5.2
|
||||||
|
|
||||||
No user-facing changes.
|
No user-facing changes.
|
||||||
|
|||||||
@@ -11,17 +11,19 @@ private import semmle.code.csharp.dataflow.internal.DataFlowDispatch as DataFlow
|
|||||||
private import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate
|
private import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate
|
||||||
private import semmle.code.csharp.security.dataflow.flowsources.Remote
|
private import semmle.code.csharp.security.dataflow.flowsources.Remote
|
||||||
|
|
||||||
/**
|
pragma[nomagic]
|
||||||
* A test library.
|
private predicate isTestNamespace(Namespace ns) {
|
||||||
*/
|
ns.getFullName()
|
||||||
class TestLibrary extends RefType {
|
|
||||||
TestLibrary() {
|
|
||||||
this.getNamespace()
|
|
||||||
.getFullName()
|
|
||||||
.matches([
|
.matches([
|
||||||
"NUnit.Framework%", "Xunit%", "Microsoft.VisualStudio.TestTools.UnitTesting%", "Moq%"
|
"NUnit.Framework%", "Xunit%", "Microsoft.VisualStudio.TestTools.UnitTesting%", "Moq%"
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A test library.
|
||||||
|
*/
|
||||||
|
class TestLibrary extends RefType {
|
||||||
|
TestLibrary() { isTestNamespace(this.getNamespace()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if the given callable is not worth supporting. */
|
/** Holds if the given callable is not worth supporting. */
|
||||||
@@ -85,6 +87,7 @@ class ExternalApi extends DotNet::Callable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if this API has a supported summary. */
|
/** Holds if this API has a supported summary. */
|
||||||
|
pragma[nomagic]
|
||||||
predicate hasSummary() {
|
predicate hasSummary() {
|
||||||
this instanceof SummarizedCallable
|
this instanceof SummarizedCallable
|
||||||
or
|
or
|
||||||
@@ -92,11 +95,13 @@ class ExternalApi extends DotNet::Callable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if this API is a known source. */
|
/** Holds if this API is a known source. */
|
||||||
|
pragma[nomagic]
|
||||||
predicate isSource() {
|
predicate isSource() {
|
||||||
this.getAnOutput() instanceof RemoteFlowSource or sourceNode(this.getAnOutput(), _)
|
this.getAnOutput() instanceof RemoteFlowSource or sourceNode(this.getAnOutput(), _)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if this API is a known sink. */
|
/** Holds if this API is a known sink. */
|
||||||
|
pragma[nomagic]
|
||||||
predicate isSink() { sinkNode(this.getAnInput(), _) }
|
predicate isSink() { sinkNode(this.getAnInput(), _) }
|
||||||
|
|
||||||
/** Holds if this API is supported by existing CodeQL libraries, that is, it is either a recognized source or sink or has a flow summary. */
|
/** Holds if this API is supported by existing CodeQL libraries, that is, it is either a recognized source or sink or has a flow summary. */
|
||||||
|
|||||||
3
csharp/ql/src/change-notes/released/0.5.3.md
Normal file
3
csharp/ql/src/change-notes/released/0.5.3.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
## 0.5.3
|
||||||
|
|
||||||
|
No user-facing changes.
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
---
|
---
|
||||||
lastReleaseVersion: 0.5.2
|
lastReleaseVersion: 0.5.3
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: codeql/csharp-queries
|
name: codeql/csharp-queries
|
||||||
version: 0.5.2
|
version: 0.5.4-dev
|
||||||
groups:
|
groups:
|
||||||
- csharp
|
- csharp
|
||||||
- queries
|
- queries
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user