mirror of
https://github.com/github/codeql.git
synced 2026-05-26 09:01:22 +02:00
Compare commits
724 Commits
idrissrio/
...
copilot/cr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3396021a6c | ||
|
|
5a65282241 | ||
|
|
79499c240a | ||
|
|
267a46d01b | ||
|
|
341059d2d0 | ||
|
|
3c3c58b0a9 | ||
|
|
9bf1072a01 | ||
|
|
a5f23ade8c | ||
|
|
017b6f2e44 | ||
|
|
6a6bb5ebf9 | ||
|
|
b631138b63 | ||
|
|
093d36ebe6 | ||
|
|
c7349740f0 | ||
|
|
efa797a21d | ||
|
|
77d4f5a2dc | ||
|
|
edf88b34da | ||
|
|
0215ea3ee3 | ||
|
|
35ac66d3aa | ||
|
|
219fe03637 | ||
|
|
dbb8bb86ba | ||
|
|
afb2243984 | ||
|
|
a7e426d89f | ||
|
|
fde51e0c29 | ||
|
|
69ed88bccd | ||
|
|
97e1c96200 | ||
|
|
46ba1f9160 | ||
|
|
5d74ad5bc6 | ||
|
|
4013f00b19 | ||
|
|
e0e5319b11 | ||
|
|
d8007a85e6 | ||
|
|
512e27187e | ||
|
|
f2bad1e6e1 | ||
|
|
c5360ba46c | ||
|
|
be9c1d074f | ||
|
|
097681e705 | ||
|
|
63e8061917 | ||
|
|
8bbb0ec954 | ||
|
|
d81b9aa5fd | ||
|
|
fd7093e74d | ||
|
|
a6de855549 | ||
|
|
3b9eba2afc | ||
|
|
84bef5d4bc | ||
|
|
2340369e2d | ||
|
|
70c1b58492 | ||
|
|
f3dc0412b5 | ||
|
|
a3e9aed00a | ||
|
|
e96ba4806b | ||
|
|
76346eccd8 | ||
|
|
feb45e5731 | ||
|
|
66ca10c338 | ||
|
|
fa61f6f3df | ||
|
|
0561a63003 | ||
|
|
ff41917147 | ||
|
|
838f3b90e7 | ||
|
|
3c36a9e308 | ||
|
|
eb81743fb5 | ||
|
|
d9ef9f82e1 | ||
|
|
92a719092a | ||
|
|
ffa5110522 | ||
|
|
c9fa7fa283 | ||
|
|
8ef4be49aa | ||
|
|
e6996ea29a | ||
|
|
579c871b69 | ||
|
|
63c71b418c | ||
|
|
3e7a966c0d | ||
|
|
926725a87f | ||
|
|
9bf4262dbb | ||
|
|
c82f75604a | ||
|
|
ea77c0d86c | ||
|
|
ec1d034ee0 | ||
|
|
37a8fc85eb | ||
|
|
b5bf1c578c | ||
|
|
f3898329d6 | ||
|
|
acd6f4156b | ||
|
|
e22d3a1074 | ||
|
|
212374b94b | ||
|
|
aa7a730041 | ||
|
|
1c5afb2306 | ||
|
|
5b30e945ef | ||
|
|
2b3111441d | ||
|
|
99a4fe4828 | ||
|
|
aa28c94562 | ||
|
|
501485b9f6 | ||
|
|
db491fc985 | ||
|
|
1950fd33db | ||
|
|
91b6801db1 | ||
|
|
ea30f02271 | ||
|
|
f41c30e335 | ||
|
|
ddebdad9e1 | ||
|
|
f8f8991d36 | ||
|
|
3c129fcd23 | ||
|
|
6001c735ff | ||
|
|
5a97348e78 | ||
|
|
0eccd902c2 | ||
|
|
45eb14975a | ||
|
|
badfa1a5c5 | ||
|
|
b475f14575 | ||
|
|
d4ba2d68f9 | ||
|
|
05a77a2005 | ||
|
|
ef345a3279 | ||
|
|
2357ef07cc | ||
|
|
088913d925 | ||
|
|
83155df1f7 | ||
|
|
b7992ed8cd | ||
|
|
219ea28217 | ||
|
|
fbf40ef02a | ||
|
|
370c5157f1 | ||
|
|
2782d90d0f | ||
|
|
ad5ab9f270 | ||
|
|
4474e252fe | ||
|
|
18d2f586b3 | ||
|
|
189c16095d | ||
|
|
a604a68fe9 | ||
|
|
4e2a93df55 | ||
|
|
6a904eddd4 | ||
|
|
fe032a5834 | ||
|
|
cfd4be6b4e | ||
|
|
93a28cbfaf | ||
|
|
13ce515aab | ||
|
|
8807217e49 | ||
|
|
daefd5988e | ||
|
|
d9ea78bfb8 | ||
|
|
f02abb3e93 | ||
|
|
a2f45f1b5b | ||
|
|
bb5bfda14b | ||
|
|
e152f08468 | ||
|
|
16cd3a8bc0 | ||
|
|
7d30e3ca5e | ||
|
|
319e3d1ba4 | ||
|
|
8380474acd | ||
|
|
a3d15dbaa3 | ||
|
|
ec7e6e8e03 | ||
|
|
4e63b83fd3 | ||
|
|
ea1fc43732 | ||
|
|
13959ab91e | ||
|
|
df7379c0d2 | ||
|
|
7795badd18 | ||
|
|
e695477f4f | ||
|
|
627654cff9 | ||
|
|
f2cc0da936 | ||
|
|
bd0d69ffca | ||
|
|
97ed67e284 | ||
|
|
db33dadb8e | ||
|
|
1139059d77 | ||
|
|
92f26027e1 | ||
|
|
85875c2879 | ||
|
|
17e6fd2fe9 | ||
|
|
5d75b255a8 | ||
|
|
26e8701ae3 | ||
|
|
cdb41588a9 | ||
|
|
1eccb8ea93 | ||
|
|
66611323e2 | ||
|
|
d804fc5168 | ||
|
|
f223c957ba | ||
|
|
86bd0c0dc3 | ||
|
|
6e0c5615fe | ||
|
|
edde4149aa | ||
|
|
87478d016a | ||
|
|
09d74a3b3e | ||
|
|
271a759490 | ||
|
|
b9595d985e | ||
|
|
ab94524328 | ||
|
|
155e21e729 | ||
|
|
d440b5fa85 | ||
|
|
47895b3334 | ||
|
|
71fb6bf915 | ||
|
|
c673bd9151 | ||
|
|
0f2de46648 | ||
|
|
f0f58dacb3 | ||
|
|
4a3b86c652 | ||
|
|
600f585a31 | ||
|
|
062fbf2b3c | ||
|
|
4280d35bf3 | ||
|
|
11a726d1b4 | ||
|
|
ec0b90f4b4 | ||
|
|
96a06bed8d | ||
|
|
f2dc585751 | ||
|
|
478f56b82f | ||
|
|
89e5a9bd72 | ||
|
|
cfbae50845 | ||
|
|
78f855d7e3 | ||
|
|
75ffb5fc4c | ||
|
|
75fea4245a | ||
|
|
5c108e5c12 | ||
|
|
53e886380c | ||
|
|
97f7a26e11 | ||
|
|
9b9c9304c7 | ||
|
|
c4f8748a42 | ||
|
|
5523b5e25f | ||
|
|
4e4d0555c0 | ||
|
|
1213369d75 | ||
|
|
ccc318106e | ||
|
|
4d0c72eafe | ||
|
|
15a2575949 | ||
|
|
968856ed96 | ||
|
|
5b5dc9c708 | ||
|
|
42e41c57d4 | ||
|
|
e0ab5ce49b | ||
|
|
f0e665d08c | ||
|
|
de9b1adf63 | ||
|
|
018674cfde | ||
|
|
266130b5cf | ||
|
|
8769059ce5 | ||
|
|
6bfb1e1fae | ||
|
|
f107235db2 | ||
|
|
06a8fd0e4a | ||
|
|
113565ba76 | ||
|
|
ae5ab9c67c | ||
|
|
884c61604e | ||
|
|
c5e1f0ccc9 | ||
|
|
3e2f6e571f | ||
|
|
ea9e4b3409 | ||
|
|
d36350aca4 | ||
|
|
0947323e78 | ||
|
|
15af6c1b20 | ||
|
|
f9869daa91 | ||
|
|
61d809b41a | ||
|
|
197ee9b9a6 | ||
|
|
7df44f9418 | ||
|
|
7351e82c92 | ||
|
|
8488039fb9 | ||
|
|
7de476aeb0 | ||
|
|
a255b4f50f | ||
|
|
003b539287 | ||
|
|
03a54bfbf9 | ||
|
|
d3fcc2a6cc | ||
|
|
e8427a59f5 | ||
|
|
e9511560b7 | ||
|
|
6b7f339287 | ||
|
|
0151e8427c | ||
|
|
e14b4f1c5c | ||
|
|
365bae1f9c | ||
|
|
79ac95d8a8 | ||
|
|
8719072519 | ||
|
|
af0bfe0981 | ||
|
|
d546b85163 | ||
|
|
2969feef89 | ||
|
|
9773775a08 | ||
|
|
532e1feacc | ||
|
|
7d7bbf2a50 | ||
|
|
0e543a9843 | ||
|
|
a83c53ec9a | ||
|
|
94121f19ca | ||
|
|
2b8e719034 | ||
|
|
bdbbd45909 | ||
|
|
0d0711f2a7 | ||
|
|
d4873dd35e | ||
|
|
f7317b6a2b | ||
|
|
352b3711f6 | ||
|
|
eb37c413f2 | ||
|
|
106a9d479f | ||
|
|
d84e0e262d | ||
|
|
8b0dd7b866 | ||
|
|
b798bc2c8f | ||
|
|
a72cf56a05 | ||
|
|
4d9c0e0c26 | ||
|
|
a6ee1df567 | ||
|
|
581679d27d | ||
|
|
fc8b7c04cf | ||
|
|
ccd28ff66a | ||
|
|
a844d60174 | ||
|
|
6ac8c4f544 | ||
|
|
e0eb653dcc | ||
|
|
fb2799bd47 | ||
|
|
12b9999289 | ||
|
|
7871cd74f6 | ||
|
|
1e9dcea88b | ||
|
|
6fbdb2c52b | ||
|
|
48e3724299 | ||
|
|
0c9931ff8a | ||
|
|
48d7d9cedb | ||
|
|
4a97a449fc | ||
|
|
2e987343dd | ||
|
|
723a896b99 | ||
|
|
ada9c452f0 | ||
|
|
99de5d4238 | ||
|
|
12bd709219 | ||
|
|
a935d97190 | ||
|
|
480ae619e6 | ||
|
|
8947f7afd8 | ||
|
|
9228304294 | ||
|
|
8eed18a8ff | ||
|
|
fdbd49a843 | ||
|
|
15fde872b5 | ||
|
|
1dba99f47d | ||
|
|
27638c7029 | ||
|
|
a5905a6f20 | ||
|
|
ca41ae0d1a | ||
|
|
38219f6ebb | ||
|
|
b08e4e1dba | ||
|
|
07099f17d6 | ||
|
|
e8de8433f4 | ||
|
|
20fea3955e | ||
|
|
a684943bb7 | ||
|
|
a0099d64c8 | ||
|
|
dfe451128e | ||
|
|
fd5c5b5635 | ||
|
|
97a02ed903 | ||
|
|
6e8f43ce2e | ||
|
|
6dfbd4e062 | ||
|
|
e11363280a | ||
|
|
6b6d8862b0 | ||
|
|
1d6b8c5120 | ||
|
|
05d681fe19 | ||
|
|
a2339305e5 | ||
|
|
f577e973bc | ||
|
|
df35f9f98b | ||
|
|
24f3d9ede0 | ||
|
|
3d4785f29f | ||
|
|
1357de90ec | ||
|
|
d7250a8abe | ||
|
|
116f5a253c | ||
|
|
22b55f3d6f | ||
|
|
93d417049c | ||
|
|
1bff7a3eb8 | ||
|
|
eb7f1989c7 | ||
|
|
de5470a85c | ||
|
|
b3681f7a0c | ||
|
|
6294c3b3b8 | ||
|
|
4aee99f0eb | ||
|
|
5df695bec9 | ||
|
|
1fa183ee2a | ||
|
|
d4bb92b038 | ||
|
|
3e4f42f8a3 | ||
|
|
fc429c1757 | ||
|
|
1d7a39a093 | ||
|
|
a1eaf42cbf | ||
|
|
fa73cd5d5c | ||
|
|
6760390d75 | ||
|
|
60295662b7 | ||
|
|
ea0d1bf262 | ||
|
|
0106072b88 | ||
|
|
779fd757a3 | ||
|
|
0b31ca4348 | ||
|
|
60b8213fdd | ||
|
|
004ebd386c | ||
|
|
9efe112026 | ||
|
|
5cf281a1b6 | ||
|
|
61dc1d673e | ||
|
|
0676ba1c07 | ||
|
|
1072d6a7b7 | ||
|
|
ceb3b21e0f | ||
|
|
c811fae876 | ||
|
|
549dcb31be | ||
|
|
05f9b4124d | ||
|
|
b8f9dd9de5 | ||
|
|
a8e93e7fa0 | ||
|
|
744ade6720 | ||
|
|
c877487e11 | ||
|
|
5151df456c | ||
|
|
8aa839f4c0 | ||
|
|
1a35a05ccc | ||
|
|
bd94ceddd9 | ||
|
|
3dc465f167 | ||
|
|
61e8f91404 | ||
|
|
e587541e55 | ||
|
|
8a051d7e57 | ||
|
|
fa27eaabef | ||
|
|
d3541b87d6 | ||
|
|
c3f0967e9b | ||
|
|
3aa21242cd | ||
|
|
94e3d86f6a | ||
|
|
31895c04f8 | ||
|
|
e299cccb6e | ||
|
|
4efbc6ea9b | ||
|
|
366ebcad83 | ||
|
|
b34777e67f | ||
|
|
b5898c5a30 | ||
|
|
cd62cdadff | ||
|
|
73194a5e86 | ||
|
|
26a1f4888a | ||
|
|
c29bac2bc1 | ||
|
|
43c6e7d250 | ||
|
|
9289ac2838 | ||
|
|
eec4739497 | ||
|
|
2b78a7b256 | ||
|
|
fb67f93a86 | ||
|
|
304cd12fff | ||
|
|
987b10ab3e | ||
|
|
72f5109ec2 | ||
|
|
248932db7a | ||
|
|
306d7d1b5d | ||
|
|
7ea96c43ec | ||
|
|
bd71db87be | ||
|
|
c46c662b72 | ||
|
|
df0f2f8ce4 | ||
|
|
51ebec9164 | ||
|
|
fd7b123ee3 | ||
|
|
79cbf2f1cf | ||
|
|
d0681c6ffb | ||
|
|
032c7ea034 | ||
|
|
da527ffc19 | ||
|
|
ef04f927fb | ||
|
|
7742a5667f | ||
|
|
cf73d96c9d | ||
|
|
597be6a1c0 | ||
|
|
94f1d94a2b | ||
|
|
9fc95f5171 | ||
|
|
924bb92d91 | ||
|
|
60e58f8219 | ||
|
|
6c0c1d558e | ||
|
|
146fc7a8c0 | ||
|
|
91c731f68d | ||
|
|
c4192b670b | ||
|
|
53b8f2abb1 | ||
|
|
178fbf9600 | ||
|
|
6da3a4557e | ||
|
|
31840902cd | ||
|
|
4b240ebf8a | ||
|
|
a5e6f6daf9 | ||
|
|
7d2b40c657 | ||
|
|
5ccd61ac97 | ||
|
|
bfbb2eef6c | ||
|
|
84be8517bb | ||
|
|
149f3ed5b6 | ||
|
|
47a9f87d9b | ||
|
|
6f609a5ed6 | ||
|
|
05a50ad21a | ||
|
|
16ddb5658f | ||
|
|
d6b71a346e | ||
|
|
8f8f4c2d52 | ||
|
|
90befa0c00 | ||
|
|
ca4c988e97 | ||
|
|
2e0f244376 | ||
|
|
c7099584b4 | ||
|
|
3c161f9c93 | ||
|
|
1fefa989d7 | ||
|
|
953ff9f0d0 | ||
|
|
106254b220 | ||
|
|
c3a1eb181e | ||
|
|
d93f4850df | ||
|
|
97c0267614 | ||
|
|
113f3e880b | ||
|
|
edb2ed8df2 | ||
|
|
5bdf550317 | ||
|
|
c539c2f4fd | ||
|
|
bfe26c1989 | ||
|
|
d0999e3abd | ||
|
|
d1811bc1fe | ||
|
|
febc82dc19 | ||
|
|
4a7395b017 | ||
|
|
9bbbbefd34 | ||
|
|
36e4efe77e | ||
|
|
f5a38b4701 | ||
|
|
b39732ba02 | ||
|
|
dfe6ed2171 | ||
|
|
c64a6762d0 | ||
|
|
f7231f40eb | ||
|
|
a53218c2ce | ||
|
|
d1eb9ab5d2 | ||
|
|
e2ad1f6511 | ||
|
|
bf02e478fd | ||
|
|
4d4e7a1b5c | ||
|
|
7d17454a3b | ||
|
|
3e5c2ddeaf | ||
|
|
5f970d9f2f | ||
|
|
218585b52a | ||
|
|
a945f15987 | ||
|
|
5c53677051 | ||
|
|
2dc91a56eb | ||
|
|
6dd6bddff3 | ||
|
|
a4dd4f91d4 | ||
|
|
90a16cfaee | ||
|
|
a27d20dbcd | ||
|
|
76ed386246 | ||
|
|
fea07ebfcb | ||
|
|
9596b7b921 | ||
|
|
b14ece72be | ||
|
|
9f5b8141f0 | ||
|
|
6a8204d28c | ||
|
|
1ee5728311 | ||
|
|
a22fd39230 | ||
|
|
fa3fba4a00 | ||
|
|
44eeee5757 | ||
|
|
e6dbd525c3 | ||
|
|
522e4d64de | ||
|
|
bed1ec8981 | ||
|
|
6c67475352 | ||
|
|
287a8717a8 | ||
|
|
9ed22610a3 | ||
|
|
36c3084435 | ||
|
|
37af38eed5 | ||
|
|
89e9a253eb | ||
|
|
40b908494c | ||
|
|
000d8244c4 | ||
|
|
2fa71f0c17 | ||
|
|
2b10c8aef3 | ||
|
|
0ac1bc4c57 | ||
|
|
cfa62ae434 | ||
|
|
766dc94444 | ||
|
|
542d4631d7 | ||
|
|
f01d5840b0 | ||
|
|
936c4cc79f | ||
|
|
e1bddd9365 | ||
|
|
22e9c212d6 | ||
|
|
26ef33212d | ||
|
|
700543b30b | ||
|
|
22e9b42808 | ||
|
|
50ed0af9da | ||
|
|
e00e3a87ff | ||
|
|
8955fd0bf4 | ||
|
|
9f9c353806 | ||
|
|
4bb110beb8 | ||
|
|
a91cf6b7cb | ||
|
|
9f8ed710e2 | ||
|
|
f60d759a65 | ||
|
|
e4871fc519 | ||
|
|
00acff293a | ||
|
|
49f24ca8ec | ||
|
|
564a3bd444 | ||
|
|
ece85854cd | ||
|
|
c15ad31b07 | ||
|
|
5116b0c1e5 | ||
|
|
37261b2f5c | ||
|
|
b38c3268fb | ||
|
|
ca90de2bed | ||
|
|
f8ed810a44 | ||
|
|
10a2824b82 | ||
|
|
f881d368f0 | ||
|
|
d1c63603ee | ||
|
|
578efeaaa3 | ||
|
|
4d6fb873ab | ||
|
|
39218f5e6b | ||
|
|
d33375cd16 | ||
|
|
25b836b1b5 | ||
|
|
f2d3bc03aa | ||
|
|
55e5bc4970 | ||
|
|
518fb44a92 | ||
|
|
5634395a32 | ||
|
|
eee4014e94 | ||
|
|
a033057d90 | ||
|
|
624ee1898a | ||
|
|
0cd5366034 | ||
|
|
78c262ca63 | ||
|
|
c3ac20267a | ||
|
|
e172cb3f7a | ||
|
|
677949e409 | ||
|
|
fe10fb37e9 | ||
|
|
ba3fc0a769 | ||
|
|
6611978368 | ||
|
|
16539b4667 | ||
|
|
23bab81855 | ||
|
|
df54459552 | ||
|
|
85ae4045c5 | ||
|
|
6235edaa21 | ||
|
|
9a5128f915 | ||
|
|
c5f6820b5d | ||
|
|
5ad42f8bcc | ||
|
|
bee1718469 | ||
|
|
98b51149da | ||
|
|
8e36316ebf | ||
|
|
3e914f7ff1 | ||
|
|
42d2de848d | ||
|
|
b5e3168032 | ||
|
|
109d802607 | ||
|
|
71e8730c63 | ||
|
|
eff9f99f44 | ||
|
|
d9fea156f6 | ||
|
|
bcdbd6e283 | ||
|
|
fe94b3b68b | ||
|
|
90401b3ad3 | ||
|
|
1796bc0abb | ||
|
|
36cc20989c | ||
|
|
2b806ad6fd | ||
|
|
a534d26449 | ||
|
|
ca18179bd2 | ||
|
|
d9feadcfec | ||
|
|
95d4a541bc | ||
|
|
6c171c804f | ||
|
|
d0bd8459a1 | ||
|
|
1c43ceae95 | ||
|
|
a5aeadd31d | ||
|
|
5bf2d9442e | ||
|
|
c40d784a4d | ||
|
|
bf6568b928 | ||
|
|
79ad064a93 | ||
|
|
552976d057 | ||
|
|
353cd31ce6 | ||
|
|
08174d7ec9 | ||
|
|
f6c302b68c | ||
|
|
4f11913ee5 | ||
|
|
42f6e6a19c | ||
|
|
97f19d03ad | ||
|
|
97ddab0724 | ||
|
|
27e19813be | ||
|
|
88adb05d4b | ||
|
|
265922d2e5 | ||
|
|
7db97799c1 | ||
|
|
08b72d0a86 | ||
|
|
46a2a249f9 | ||
|
|
b8ba905253 | ||
|
|
9912aaaf1a | ||
|
|
48db24d184 | ||
|
|
8459eec239 | ||
|
|
c5179e40c6 | ||
|
|
38830ddc5c | ||
|
|
d5827b5cca | ||
|
|
6c355a1bf8 | ||
|
|
e550d4937c | ||
|
|
62a6b5985d | ||
|
|
2c05624088 | ||
|
|
ac1987f264 | ||
|
|
d57a42a7f7 | ||
|
|
32aaac27ec | ||
|
|
2dc7576232 | ||
|
|
05a487ec3b | ||
|
|
c0a5c63e8e | ||
|
|
5adc9f8ff0 | ||
|
|
02e4a8b6f7 | ||
|
|
bd3e4d3d7e | ||
|
|
4b6a53b577 | ||
|
|
6cbe000d51 | ||
|
|
c040daab9c | ||
|
|
849823eff6 | ||
|
|
e831c80a23 | ||
|
|
5e02a86542 | ||
|
|
b9f36f37b6 | ||
|
|
9a4a6cfcb8 | ||
|
|
edfdc9812f | ||
|
|
ab505e3281 | ||
|
|
8c27437628 | ||
|
|
12ee93042b | ||
|
|
bac356c9a1 | ||
|
|
68c1a3d389 | ||
|
|
2764d697d2 | ||
|
|
c62d95ac9d | ||
|
|
05bef12ddd | ||
|
|
1df3adf021 | ||
|
|
025f73301b | ||
|
|
e26c199426 | ||
|
|
1203da1b66 | ||
|
|
f79bd3f4cf | ||
|
|
476df7de73 | ||
|
|
29e01748b7 | ||
|
|
11003e685d | ||
|
|
9de5f5c72b | ||
|
|
e4daeec2ca | ||
|
|
81977f11a1 | ||
|
|
32fe12a6dd | ||
|
|
d40071321a | ||
|
|
97f7dcb04a | ||
|
|
83adf793e4 | ||
|
|
0a88425170 | ||
|
|
cd73dcfb04 | ||
|
|
52dc58172d | ||
|
|
544931f73f | ||
|
|
2d02908e7f | ||
|
|
4fcf3fbff8 | ||
|
|
6f40ac15b4 | ||
|
|
55ea55a44f | ||
|
|
36fa0a22f9 | ||
|
|
60bb9a9b06 | ||
|
|
c68cd58f70 | ||
|
|
dca10f8740 | ||
|
|
3f08ff88a4 | ||
|
|
5e6e64b2b7 | ||
|
|
4973523404 | ||
|
|
62fb38d834 | ||
|
|
571f21ba49 | ||
|
|
2d61fc5309 | ||
|
|
8e39ed079e | ||
|
|
389cd5d648 | ||
|
|
092d25451f | ||
|
|
32b86eca50 | ||
|
|
40a58135c2 | ||
|
|
7ef96e3f3c | ||
|
|
5531ef9bc1 | ||
|
|
cbc2dbc14d | ||
|
|
208cf716dc | ||
|
|
d72d8b63ed | ||
|
|
1791c1f1f9 | ||
|
|
d5c4a19efa | ||
|
|
6fbf727309 | ||
|
|
e00390d23a | ||
|
|
d079671ec8 | ||
|
|
cbbc057dd3 | ||
|
|
9fc2a54712 | ||
|
|
d0e30d19c4 | ||
|
|
8de37fec17 | ||
|
|
e712e62f14 | ||
|
|
30b30d65c8 | ||
|
|
6d67e419ff | ||
|
|
29930fa6bf | ||
|
|
a57c6cde30 | ||
|
|
b16f1d3778 | ||
|
|
73d06f26cb | ||
|
|
7ddfa80399 | ||
|
|
99b498b891 | ||
|
|
95afe615b5 | ||
|
|
8b03608a4f | ||
|
|
0567864a83 | ||
|
|
18576838d4 | ||
|
|
8aa1bff9a5 | ||
|
|
958c798c3f | ||
|
|
fb6175d10b | ||
|
|
3f718123a6 | ||
|
|
6113d4be9e | ||
|
|
7fccc23dbe | ||
|
|
ac5a74448f | ||
|
|
30ce4069c7 | ||
|
|
4543c66d26 | ||
|
|
2f29c905c3 | ||
|
|
e1cf0a15ed | ||
|
|
52c510bfea | ||
|
|
b2f878229d | ||
|
|
3dd6b3fb69 | ||
|
|
c316d51d41 | ||
|
|
2cb0e81da0 | ||
|
|
aae5333325 | ||
|
|
fa59a8ae24 | ||
|
|
4526afc29f | ||
|
|
5bfeede364 | ||
|
|
330505c524 | ||
|
|
01cc19cffc | ||
|
|
26b8a394b3 | ||
|
|
a660eaba95 | ||
|
|
acddb2c272 | ||
|
|
d790c6df57 | ||
|
|
fab96d9539 | ||
|
|
5ca9ff2082 | ||
|
|
341f553866 | ||
|
|
704e2966cb | ||
|
|
d27d4fdb27 | ||
|
|
47fac883b8 |
4
.bazelrc
4
.bazelrc
@@ -11,6 +11,8 @@ build --compilation_mode opt
|
||||
common --override_module=semmle_code=%workspace%/misc/bazel/semmle_code_stub
|
||||
|
||||
build --repo_env=CC=clang --repo_env=CXX=clang++
|
||||
# Disable Android SDK auto-detection (we don't use it, and rules_android has Bazel 9 compatibility issues)
|
||||
build --repo_env=ANDROID_HOME=
|
||||
|
||||
# print test output, like sembuild does.
|
||||
# Set to `errors` if this is too verbose.
|
||||
@@ -34,7 +36,7 @@ common --@rules_dotnet//dotnet/settings:strict_deps=false
|
||||
common --@rules_rust//rust/toolchain/channel=nightly
|
||||
|
||||
# Reduce this eventually to empty, once we've fixed all our usages of java, and https://github.com/bazel-contrib/rules_go/issues/4193 is fixed
|
||||
common --incompatible_autoload_externally="+@rules_java,+@rules_shell"
|
||||
common --incompatible_autoload_externally="+@rules_cc,+@rules_java,+@rules_shell"
|
||||
|
||||
build --java_language_version=17
|
||||
build --tool_java_language_version=17
|
||||
|
||||
@@ -1 +1 @@
|
||||
8.4.2
|
||||
9.0.0
|
||||
|
||||
77
MODULE.bazel
77
MODULE.bazel
@@ -15,21 +15,23 @@ local_path_override(
|
||||
# see https://registry.bazel.build/ for a list of available packages
|
||||
|
||||
bazel_dep(name = "platforms", version = "1.0.0")
|
||||
bazel_dep(name = "rules_go", version = "0.56.1")
|
||||
bazel_dep(name = "rules_cc", version = "0.2.16")
|
||||
bazel_dep(name = "rules_go", version = "0.59.0")
|
||||
bazel_dep(name = "rules_java", version = "9.0.3")
|
||||
bazel_dep(name = "rules_pkg", version = "1.0.1")
|
||||
bazel_dep(name = "rules_nodejs", version = "6.2.0-codeql.1")
|
||||
bazel_dep(name = "rules_python", version = "0.40.0")
|
||||
bazel_dep(name = "rules_shell", version = "0.5.0")
|
||||
bazel_dep(name = "rules_nodejs", version = "6.7.3")
|
||||
bazel_dep(name = "rules_python", version = "1.9.0")
|
||||
bazel_dep(name = "rules_shell", version = "0.6.1")
|
||||
bazel_dep(name = "bazel_skylib", version = "1.8.1")
|
||||
bazel_dep(name = "abseil-cpp", version = "20240116.1", repo_name = "absl")
|
||||
bazel_dep(name = "abseil-cpp", version = "20260107.1", repo_name = "absl")
|
||||
bazel_dep(name = "nlohmann_json", version = "3.11.3", repo_name = "json")
|
||||
bazel_dep(name = "fmt", version = "12.1.0-codeql.1")
|
||||
bazel_dep(name = "rules_kotlin", version = "2.2.0-codeql.1")
|
||||
bazel_dep(name = "gazelle", version = "0.40.0")
|
||||
bazel_dep(name = "rules_kotlin", version = "2.2.2-codeql.1")
|
||||
bazel_dep(name = "gazelle", version = "0.47.0")
|
||||
bazel_dep(name = "rules_dotnet", version = "0.21.5-codeql.1")
|
||||
bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
|
||||
bazel_dep(name = "rules_rust", version = "0.66.0")
|
||||
bazel_dep(name = "zstd", version = "1.5.5.bcr.1")
|
||||
bazel_dep(name = "googletest", version = "1.17.0.bcr.2")
|
||||
bazel_dep(name = "rules_rust", version = "0.68.1.codeql.1")
|
||||
bazel_dep(name = "zstd", version = "1.5.7.bcr.1")
|
||||
|
||||
bazel_dep(name = "buildifier_prebuilt", version = "6.4.0", dev_dependency = True)
|
||||
|
||||
@@ -41,7 +43,7 @@ RUST_EDITION = "2024"
|
||||
# a nightly toolchain is required to enable experimental_use_cc_common_link, which we require internally
|
||||
# we prefer to run the same version as internally, even if experimental_use_cc_common_link is not really
|
||||
# required in this repo
|
||||
RUST_VERSION = "nightly/2025-08-01"
|
||||
RUST_VERSION = "nightly/2026-01-22"
|
||||
|
||||
rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
|
||||
rust.toolchain(
|
||||
@@ -53,26 +55,26 @@ rust.toolchain(
|
||||
],
|
||||
# generated by buildutils-internal/scripts/fill-rust-sha256s.py (internal repo)
|
||||
sha256s = {
|
||||
"2025-08-01/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz": "9bbeaf5d3fc7247d31463a9083aa251c995cc50662c8219e7a2254d76a72a9a4",
|
||||
"2025-08-01/rustc-nightly-x86_64-apple-darwin.tar.xz": "c9ea539a8eff0d5d162701f99f9e1aabe14dd0dfb420d62362817a5d09219de7",
|
||||
"2025-08-01/rustc-nightly-aarch64-apple-darwin.tar.xz": "ae83feebbc39cfd982e4ecc8297731fe79c185173aee138467b334c5404b3773",
|
||||
"2025-08-01/rustc-nightly-x86_64-pc-windows-msvc.tar.xz": "9f170c30d802a349be60cf52ec46260802093cb1013ad667fc0d528b7b10152f",
|
||||
"2025-08-01/clippy-nightly-x86_64-unknown-linux-gnu.tar.xz": "9ae5f3cd8f557c4f6df522597c69d14398cf604cfaed2b83e767c4b77a7eaaf6",
|
||||
"2025-08-01/clippy-nightly-x86_64-apple-darwin.tar.xz": "983cb9ee0b6b968188e04ab2d33743d54764b2681ce565e1b3f2b9135c696a3e",
|
||||
"2025-08-01/clippy-nightly-aarch64-apple-darwin.tar.xz": "ed2219dbc49d088225e1b7c5c4390fa295066e071fddaa2714018f6bb39ddbf0",
|
||||
"2025-08-01/clippy-nightly-x86_64-pc-windows-msvc.tar.xz": "911f40ab5cbdd686f40e00965271fe47c4805513a308ed01f30eafb25b448a50",
|
||||
"2025-08-01/cargo-nightly-x86_64-unknown-linux-gnu.tar.xz": "106463c284e48e4904c717471eeec2be5cc83a9d2cae8d6e948b52438cad2e69",
|
||||
"2025-08-01/cargo-nightly-x86_64-apple-darwin.tar.xz": "6ad35c40efc41a8c531ea43235058347b6902d98a9693bf0aed7fc16d5590cef",
|
||||
"2025-08-01/cargo-nightly-aarch64-apple-darwin.tar.xz": "dd28c365e9d298abc3154c797720ad36a0058f131265c9978b4c8e4e37012c8a",
|
||||
"2025-08-01/cargo-nightly-x86_64-pc-windows-msvc.tar.xz": "7b431286e12d6b3834b038f078389a00cac73f351e8c3152b2504a3c06420b3b",
|
||||
"2025-08-01/llvm-tools-nightly-x86_64-unknown-linux-gnu.tar.xz": "e342e305d7927cc288d386983b2bc253cfad3776b113386e903d0b302648ef47",
|
||||
"2025-08-01/llvm-tools-nightly-x86_64-apple-darwin.tar.xz": "e44dd3506524d85c37b3a54bcc91d01378fd2c590b2db5c5974d12f05c1b84d1",
|
||||
"2025-08-01/llvm-tools-nightly-aarch64-apple-darwin.tar.xz": "0c1b5f46dd81be4a9227b10283a0fcaa39c14fea7e81aea6fd6d9887ff6cdc41",
|
||||
"2025-08-01/llvm-tools-nightly-x86_64-pc-windows-msvc.tar.xz": "423e5fd11406adccbc31b8456ceb7375ce055cdf45e90d2c3babeb2d7f58383f",
|
||||
"2025-08-01/rust-std-nightly-x86_64-unknown-linux-gnu.tar.xz": "3c0ceb46a252647a1d4c7116d9ccae684fa5e42aaf3296419febd2c962c3b41d",
|
||||
"2025-08-01/rust-std-nightly-x86_64-apple-darwin.tar.xz": "3be416003cab10f767390a753d1d16ae4d26c7421c03c98992cf1943e5b0efe8",
|
||||
"2025-08-01/rust-std-nightly-aarch64-apple-darwin.tar.xz": "4046ac0ef951cb056b5028a399124f60999fa37792eab69d008d8d7965f389b4",
|
||||
"2025-08-01/rust-std-nightly-x86_64-pc-windows-msvc.tar.xz": "191ed9d8603c3a4fe5a7bbbc2feb72049078dae2df3d3b7d5dedf3abbf823e6e",
|
||||
"2026-01-22/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz": "88db619323cc1321630d124efa51ed02fabc5e020f08cfa0eda2c0ac1afbe69a",
|
||||
"2026-01-22/rustc-nightly-x86_64-apple-darwin.tar.xz": "08484da3fa38db56f93629aeabdc0ae9ff8ed9704c0792d35259cbc849b3f54c",
|
||||
"2026-01-22/rustc-nightly-aarch64-apple-darwin.tar.xz": "a39c0b21b7058e364ea1bd43144e42e4bf1efade036b2e82455f2afce194ee81",
|
||||
"2026-01-22/rustc-nightly-x86_64-pc-windows-msvc.tar.xz": "d00248ee9850dbb6932b2578e32ff74fc7c429854c1aa071066ca31b65385a3b",
|
||||
"2026-01-22/clippy-nightly-x86_64-unknown-linux-gnu.tar.xz": "70656a0ce994ffff16d5a35a7b170a0acd41e9bb54a589c96ed45bf97b094a4d",
|
||||
"2026-01-22/clippy-nightly-x86_64-apple-darwin.tar.xz": "fe242519fa961522734733009705aec3c2d9a20cc57291f2aa614e5e6262c88f",
|
||||
"2026-01-22/clippy-nightly-aarch64-apple-darwin.tar.xz": "38bb226363ec97c9722edf966cd58774a683e19fd2ff2a6030094445d51e06f9",
|
||||
"2026-01-22/clippy-nightly-x86_64-pc-windows-msvc.tar.xz": "6da9b4470beea67abfebf046f141eee0d2a8db7c7a9e4e2294478734fd477228",
|
||||
"2026-01-22/cargo-nightly-x86_64-unknown-linux-gnu.tar.xz": "99004e9d10c43a01499642f53bb3184d41137a95d65bfb217098840a9e79e892",
|
||||
"2026-01-22/cargo-nightly-x86_64-apple-darwin.tar.xz": "6e021394cf8d8400ac6cfdfcef24e4d74f988e91eb8028b36de3a64ce3502990",
|
||||
"2026-01-22/cargo-nightly-aarch64-apple-darwin.tar.xz": "4b2494cb69ab64132cddbc411a38ea9f1105e54d6f986e43168d54f79510c673",
|
||||
"2026-01-22/cargo-nightly-x86_64-pc-windows-msvc.tar.xz": "c36613cf57407212d10d37b76e49a60ff42336e953cdff9e177283f530a83fc1",
|
||||
"2026-01-22/llvm-tools-nightly-x86_64-unknown-linux-gnu.tar.xz": "0b123c5027dbd833aae6845ffe9bd07d309bf798746a7176aadaea68fbcbd05d",
|
||||
"2026-01-22/llvm-tools-nightly-x86_64-apple-darwin.tar.xz": "a47864491ad5619158c950ab7570fb6e487d5117338585c27334d45824b406d8",
|
||||
"2026-01-22/llvm-tools-nightly-aarch64-apple-darwin.tar.xz": "db9bc826d6e2e7e914505d50157682e516ceb90357e83d77abddc32c2d962f41",
|
||||
"2026-01-22/llvm-tools-nightly-x86_64-pc-windows-msvc.tar.xz": "ffaa406932b2fe62e01dad61cf4ed34860a5d2a6f9306ca340d79e630d930039",
|
||||
"2026-01-22/rust-std-nightly-x86_64-unknown-linux-gnu.tar.xz": "e9c0d5e06e18a4b509391b3088f29293e310cdc8ccc865be8fa3f09733326925",
|
||||
"2026-01-22/rust-std-nightly-x86_64-apple-darwin.tar.xz": "25d75995cee679a4828ca9fe48c5a31a67c3b0846018440ef912e5a6208f53f6",
|
||||
"2026-01-22/rust-std-nightly-aarch64-apple-darwin.tar.xz": "e4132bf3f2eed4684c86756a02315bcf481c23e675e3e25630fc604c9cb4594c",
|
||||
"2026-01-22/rust-std-nightly-x86_64-pc-windows-msvc.tar.xz": "961bb535ef95ae8a5fa4e224cb94aff190f155c45a9bcf7a53e184b024aa41b1",
|
||||
},
|
||||
versions = [RUST_VERSION],
|
||||
)
|
||||
@@ -188,6 +190,15 @@ pip.parse(
|
||||
)
|
||||
use_repo(pip, "codegen_deps")
|
||||
|
||||
python = use_extension("@rules_python//python/extensions:python.bzl", "python")
|
||||
python.toolchain(
|
||||
is_default = True,
|
||||
python_version = "3.12",
|
||||
)
|
||||
use_repo(python, "python_3_12", "python_versions")
|
||||
|
||||
register_toolchains("@python_versions//3.12:all")
|
||||
|
||||
swift_deps = use_extension("//swift/third_party:load.bzl", "swift_deps")
|
||||
|
||||
# following list can be kept in sync with `bazel mod tidy`
|
||||
@@ -254,11 +265,11 @@ use_repo(
|
||||
)
|
||||
|
||||
go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")
|
||||
go_sdk.download(version = "1.25.0")
|
||||
go_sdk.download(version = "1.26.0")
|
||||
|
||||
go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps")
|
||||
go_deps.from_file(go_mod = "//go/extractor:go.mod")
|
||||
use_repo(go_deps, "org_golang_x_mod", "org_golang_x_tools")
|
||||
use_repo(go_deps, "com_github_stretchr_testify", "org_golang_x_mod", "org_golang_x_tools")
|
||||
|
||||
ripunzip_archive = use_repo_rule("//misc/ripunzip:ripunzip.bzl", "ripunzip_archive")
|
||||
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
## 0.4.29
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.28
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.27
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
3
actions/ql/lib/change-notes/released/0.4.28.md
Normal file
3
actions/ql/lib/change-notes/released/0.4.28.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.4.28
|
||||
|
||||
No user-facing changes.
|
||||
3
actions/ql/lib/change-notes/released/0.4.29.md
Normal file
3
actions/ql/lib/change-notes/released/0.4.29.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.4.29
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.4.27
|
||||
lastReleaseVersion: 0.4.29
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/actions-all
|
||||
version: 0.4.27
|
||||
version: 0.4.30-dev
|
||||
library: true
|
||||
warnOnImplicitThis: true
|
||||
dependencies:
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
## 0.6.21
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.20
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.19
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
3
actions/ql/src/change-notes/released/0.6.20.md
Normal file
3
actions/ql/src/change-notes/released/0.6.20.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.6.20
|
||||
|
||||
No user-facing changes.
|
||||
3
actions/ql/src/change-notes/released/0.6.21.md
Normal file
3
actions/ql/src/change-notes/released/0.6.21.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.6.21
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.6.19
|
||||
lastReleaseVersion: 0.6.21
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/actions-queries
|
||||
version: 0.6.19
|
||||
version: 0.6.22-dev
|
||||
library: false
|
||||
warnOnImplicitThis: true
|
||||
groups: [actions, queries]
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
class Element extends @element {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Trap extends @trap {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Tag extends @tag {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from Element e, Trap trap
|
||||
where
|
||||
in_trap_or_tag(e, trap)
|
||||
or
|
||||
exists(Tag tag |
|
||||
in_trap_or_tag(e, tag) and
|
||||
trap_uses_tag(trap, tag)
|
||||
)
|
||||
select e, trap
|
||||
2545
cpp/downgrades/770002bb02322e04fa25345838ce6e82af285a0b/old.dbscheme
Normal file
2545
cpp/downgrades/770002bb02322e04fa25345838ce6e82af285a0b/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,13 @@
|
||||
class SourceFile extends @source_file {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Trap extends @trap {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from SourceFile source_file, string name, Trap trap
|
||||
where
|
||||
source_file_uses_trap(source_file, trap) and
|
||||
source_file_name(source_file, name)
|
||||
select name, trap
|
||||
@@ -0,0 +1,8 @@
|
||||
description: Add source_file_name
|
||||
compatibility: backwards
|
||||
source_file_uses_trap.rel: run source_file_uses_trap.ql
|
||||
source_file_name.rel: delete
|
||||
tag_name.rel: delete
|
||||
trap_uses_tag.rel: delete
|
||||
in_trap.rel: run in_trap.ql
|
||||
in_trap_or_tag.rel: delete
|
||||
2517
cpp/downgrades/7e7c2f55670f8123d514cf542ccb1938118ac561/old.dbscheme
Normal file
2517
cpp/downgrades/7e7c2f55670f8123d514cf542ccb1938118ac561/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
description: Add trap_filename, source_file_uses_trap and in_trap relations
|
||||
compatibility: full
|
||||
trap_filename.rel: delete
|
||||
source_file_uses_trap.rel: delete
|
||||
in_trap.rel: delete
|
||||
@@ -1,3 +1,24 @@
|
||||
## 8.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* CodeQL version 2.24.2 accidentally introduced a syntactical breaking change to `BarrierGuard<...>::getAnIndirectBarrierNode` and `InstructionBarrierGuard<...>::getAnIndirectBarrierNode`. These breaking changes have now been reverted so that the original code compiles again.
|
||||
* `MustFlow`, the inter-procedural must-flow data flow analysis library, has been re-worked to use parameterized modules. Like in the case of data flow and taint tracking, instead of extending the `MustFlowConfiguration` class, the user should now implement a module with the `MustFlow::ConfigSig` signature, and instantiate the `MustFlow::Global` parameterized module with the implemented module.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Refactored the "Year field changed using an arithmetic operation without checking for leap year" query (`cpp/leap-year/unchecked-after-arithmetic-year-modification`) to address large numbers of false positive results.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* The `allowInterproceduralFlow` predicate of must-flow data flow configurations now correctly handles direct recursion.
|
||||
|
||||
## 7.1.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Added remote flow source models for the `winhttp.h` windows header and the Azure SDK core library for C/C++.
|
||||
|
||||
## 7.1.0
|
||||
|
||||
### New Features
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Inline expectations test comments, which are of the form `// $ tag` or `// $ tag=value`, are now parsed more strictly and will not be recognized if there isn't a space after the `$` symbol.
|
||||
5
cpp/ql/lib/change-notes/released/7.1.1.md
Normal file
5
cpp/ql/lib/change-notes/released/7.1.1.md
Normal file
@@ -0,0 +1,5 @@
|
||||
## 7.1.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Added remote flow source models for the `winhttp.h` windows header and the Azure SDK core library for C/C++.
|
||||
14
cpp/ql/lib/change-notes/released/8.0.0.md
Normal file
14
cpp/ql/lib/change-notes/released/8.0.0.md
Normal file
@@ -0,0 +1,14 @@
|
||||
## 8.0.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* CodeQL version 2.24.2 accidentally introduced a syntactical breaking change to `BarrierGuard<...>::getAnIndirectBarrierNode` and `InstructionBarrierGuard<...>::getAnIndirectBarrierNode`. These breaking changes have now been reverted so that the original code compiles again.
|
||||
* `MustFlow`, the inter-procedural must-flow data flow analysis library, has been re-worked to use parameterized modules. Like in the case of data flow and taint tracking, instead of extending the `MustFlowConfiguration` class, the user should now implement a module with the `MustFlow::ConfigSig` signature, and instantiate the `MustFlow::Global` parameterized module with the implemented module.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Refactored the "Year field changed using an arithmetic operation without checking for leap year" query (`cpp/leap-year/unchecked-after-arithmetic-year-modification`) to address large numbers of false positive results.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* The `allowInterproceduralFlow` predicate of must-flow data flow configurations now correctly handles direct recursion.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 7.1.0
|
||||
lastReleaseVersion: 8.0.0
|
||||
|
||||
@@ -24,6 +24,13 @@ extensions:
|
||||
- ["", "", False, "MapViewOfFileNuma2", "", "", "ReturnValue[*]", "local", "manual"]
|
||||
# ntifs.h
|
||||
- ["", "", False, "NtReadFile", "", "", "Argument[*5]", "local", "manual"]
|
||||
# winhttp.h
|
||||
- ["", "", False, "WinHttpReadData", "", "", "Argument[*1]", "remote", "manual"]
|
||||
- ["", "", False, "WinHttpReadDataEx", "", "", "Argument[*1]", "remote", "manual"]
|
||||
- ["", "", False, "WinHttpQueryHeaders", "", "", "Argument[*3]", "remote", "manual"]
|
||||
- ["", "", False, "WinHttpQueryHeadersEx", "", "", "Argument[*5]", "remote", "manual"]
|
||||
- ["", "", False, "WinHttpQueryHeadersEx", "", "", "Argument[*6]", "remote", "manual"]
|
||||
- ["", "", False, "WinHttpQueryHeadersEx", "", "", "Argument[**8]", "remote", "manual"]
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: summaryModel
|
||||
@@ -46,4 +53,6 @@ extensions:
|
||||
- ["", "", False, "RtlMoveMemory", "", "", "Argument[*@1]", "Argument[*@0]", "value", "manual"]
|
||||
- ["", "", False, "RtlMoveVolatileMemory", "", "", "Argument[*@1]", "Argument[*@0]", "value", "manual"]
|
||||
# winternl.h
|
||||
- ["", "", False, "RtlInitUnicodeString", "", "", "Argument[*1]", "Argument[*0].Field[*Buffer]", "value", "manual"]
|
||||
- ["", "", False, "RtlInitUnicodeString", "", "", "Argument[*1]", "Argument[*0].Field[*Buffer]", "value", "manual"]
|
||||
# winhttp.h
|
||||
- ["", "", False, "WinHttpCrackUrl", "", "", "Argument[*0]", "Argument[*3]", "taint", "manual"]
|
||||
41
cpp/ql/lib/ext/azure.core.model.yml
Normal file
41
cpp/ql/lib/ext/azure.core.model.yml
Normal file
@@ -0,0 +1,41 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: sourceModel
|
||||
data: # namespace, type, subtypes, name, signature, ext, output, kind, provenance
|
||||
- ["Azure::Core::Http", "RawResponse", True, "GetHeaders", "", "", "ReturnValue[*]", "remote", "manual"]
|
||||
- ["Azure::Core::Http", "RawResponse", True, "GetBody", "", "", "ReturnValue[*]", "remote", "manual"]
|
||||
- ["Azure::Core::Http", "RawResponse", True, "ExtractBodyStream", "", "", "ReturnValue[*]", "remote", "manual"]
|
||||
- ["Azure::Core::Http", "Request", True, "GetHeaders", "", "", "ReturnValue", "remote", "manual"]
|
||||
- ["Azure::Core::Http", "Request", True, "GetHeader", "", "", "ReturnValue", "remote", "manual"]
|
||||
- ["Azure::Core::Http", "Request", True, "GetBodyStream", "", "", "ReturnValue[*]", "remote", "manual"]
|
||||
|
||||
- addsTo:
|
||||
pack: codeql/cpp-all
|
||||
extensible: summaryModel
|
||||
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
|
||||
- ["Azure::Core", "Url", True, "Url", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "SetScheme", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "SetHost", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "SetPort", "", "", "Argument[0]", "Argument[-1]", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "SetPath", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "SetQueryParameters", "", "", "Argument[0]", "Argument[-1]", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "AppendPath", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "AppendQueryParameter", "", "", "Argument[*1]", "Argument[-1]", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "GetHost", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "GetPath", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "GetPort", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "GetQueryParameters", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "GetScheme", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "GetRelativeUrl", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "GetAbsoluteUrl", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "Decode", "", "", "Argument[*0]", "ReturnValue", "taint", "manual"]
|
||||
- ["Azure::Core", "Url", True, "Encode", "", "", "Argument[*0]", "ReturnValue", "taint", "manual"]
|
||||
- ["Azure::Core::IO", "BodyStream", True, "Read", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"]
|
||||
- ["Azure::Core::IO", "BodyStream", True, "ReadToCount", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"]
|
||||
- ["Azure::Core::IO", "BodyStream", True, "ReadToEnd", "", "", "Argument[-1]", "ReturnValue.Element", "taint", "manual"]
|
||||
- ["Azure", "Nullable", True, "Nullable", "", "", "Argument[0]", "Argument[-1]", "taint", "manual"]
|
||||
- ["Azure", "Nullable", True, "operator=", "", "", "Argument[*0]", "Argument[-1]", "value", "manual"]
|
||||
- ["Azure", "Nullable", True, "Value", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
|
||||
- ["Azure", "Nullable", True, "operator->", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
|
||||
- ["Azure", "Nullable", True, "operator*", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 7.1.0
|
||||
version: 8.0.1-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -14,7 +14,9 @@ class PackedTimeType extends Type {
|
||||
}
|
||||
}
|
||||
|
||||
private predicate timeType(string typeName) { typeName = ["_SYSTEMTIME", "SYSTEMTIME", "tm"] }
|
||||
private predicate timeType(string typeName) {
|
||||
typeName = ["_SYSTEMTIME", "SYSTEMTIME", "tm", "TIME_FIELDS", "_TIME_FIELDS", "PTIME_FIELDS"]
|
||||
}
|
||||
|
||||
/**
|
||||
* A type that is used to represent times and dates in an 'unpacked' form, that is,
|
||||
@@ -95,3 +97,24 @@ class StructTmMonthFieldAccess extends MonthFieldAccess {
|
||||
class StructTmYearFieldAccess extends YearFieldAccess {
|
||||
StructTmYearFieldAccess() { this.getTarget().getName() = "tm_year" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `DayFieldAccess` for the `TIME_FIELDS` struct.
|
||||
*/
|
||||
class TimeFieldsDayFieldAccess extends DayFieldAccess {
|
||||
TimeFieldsDayFieldAccess() { this.getTarget().getName() = "Day" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `MonthFieldAccess` for the `TIME_FIELDS` struct.
|
||||
*/
|
||||
class TimeFieldsMonthFieldAccess extends MonthFieldAccess {
|
||||
TimeFieldsMonthFieldAccess() { this.getTarget().getName() = "Month" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `YearFieldAccess` for the `TIME_FIELDS` struct.
|
||||
*/
|
||||
class TimeFieldsYearFieldAccess extends YearFieldAccess {
|
||||
TimeFieldsYearFieldAccess() { this.getTarget().getName() = "Year" }
|
||||
}
|
||||
|
||||
@@ -1663,7 +1663,7 @@ private module Cached {
|
||||
private predicate compares_ge(
|
||||
ValueNumber test, Operand left, Operand right, int k, boolean isGe, GuardValue value
|
||||
) {
|
||||
exists(int onemk | k = 1 - onemk | compares_lt(test, right, left, onemk, isGe, value))
|
||||
compares_lt(test, right, left, 1 - k, isGe, value)
|
||||
}
|
||||
|
||||
/** Rearrange various simple comparisons into `left < right + k` form. */
|
||||
|
||||
@@ -353,12 +353,26 @@ module CsvValidation {
|
||||
)
|
||||
}
|
||||
|
||||
private string getIncorrectConstructorSummaryOutput() {
|
||||
exists(string namespace, string type, string name, string output |
|
||||
type = name or
|
||||
type = name + "<" + any(string s)
|
||||
|
|
||||
summaryModel(namespace, type, _, name, _, _, _, output, _, _, _) and
|
||||
output.matches("ReturnValue%") and
|
||||
result =
|
||||
"Constructor model for " + namespace + "." + type +
|
||||
" should use `Argument[this]` in the output, not `ReturnValue`."
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if some row in a CSV-based flow model appears to contain typos. */
|
||||
query predicate invalidModelRow(string msg) {
|
||||
msg =
|
||||
[
|
||||
getInvalidModelSignature(), getInvalidModelInput(), getInvalidModelOutput(),
|
||||
getInvalidModelSubtype(), getInvalidModelColumnCount(), KindVal::getInvalidModelKind()
|
||||
getInvalidModelSubtype(), getInvalidModelColumnCount(), KindVal::getInvalidModelKind(),
|
||||
getIncorrectConstructorSummaryOutput()
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -555,6 +569,7 @@ private Locatable getSupportedFunctionTemplateArgument(Function templateFunction
|
||||
* Normalize the `n`'th parameter of `f` by replacing template names
|
||||
* with `func:N` (where `N` is the index of the template).
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private string getTypeNameWithoutFunctionTemplates(Function f, int n, int remaining) {
|
||||
exists(Function templateFunction |
|
||||
templateFunction = getFullyTemplatedFunction(f) and
|
||||
|
||||
@@ -201,7 +201,7 @@ module SourceSinkInterpretationInput implements
|
||||
string toString() {
|
||||
result = this.asElement().toString()
|
||||
or
|
||||
result = this.asNode().toString()
|
||||
result = this.asNode().toStringImpl()
|
||||
or
|
||||
result = this.asCall().toString()
|
||||
}
|
||||
|
||||
@@ -34,6 +34,38 @@ private string getSingleLocationFilePath(@element e) {
|
||||
macroinvocations(e, _, loc, _)
|
||||
or
|
||||
preprocdirects(e, _, loc)
|
||||
or
|
||||
diagnostics(e, _, _, _, _, loc)
|
||||
or
|
||||
usings(e, _, loc, _)
|
||||
or
|
||||
static_asserts(e, _, _, loc, _)
|
||||
or
|
||||
derivations(e, _, _, _, loc)
|
||||
or
|
||||
frienddecls(e, _, _, loc)
|
||||
or
|
||||
comments(e, _, loc)
|
||||
or
|
||||
exprs(e, _, loc)
|
||||
or
|
||||
stmts(e, _, loc)
|
||||
or
|
||||
initialisers(e, _, _, loc)
|
||||
or
|
||||
attributes(e, _, _, _, loc)
|
||||
or
|
||||
attribute_args(e, _, _, _, loc)
|
||||
or
|
||||
namequalifiers(e, _, _, loc)
|
||||
or
|
||||
enumconstants(e, _, _, _, _, loc)
|
||||
or
|
||||
type_mentions(e, _, loc, _)
|
||||
or
|
||||
lambda_capture(e, _, _, _, _, _, loc)
|
||||
or
|
||||
concept_templates(e, _, loc)
|
||||
|
|
||||
result = getLocationFilePath(loc)
|
||||
)
|
||||
@@ -64,17 +96,27 @@ private string getMultiLocationFilePath(@element e) {
|
||||
overlay[local]
|
||||
private predicate isBase() { not isOverlay() }
|
||||
|
||||
/**
|
||||
* Holds if `path` was extracted in the overlay database.
|
||||
*/
|
||||
overlay[local]
|
||||
private predicate overlayHasFile(string path) {
|
||||
isOverlay() and
|
||||
files(_, path) and
|
||||
path != ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Discards an element from the base variant if:
|
||||
* - It has a single location in a changed file, or
|
||||
* - All of its locations are in changed files.
|
||||
* - It has a single location in a file extracted in the overlay, or
|
||||
* - All of its locations are in files extracted in the overlay.
|
||||
*/
|
||||
overlay[discard_entity]
|
||||
private predicate discardElement(@element e) {
|
||||
isBase() and
|
||||
(
|
||||
overlayChangedFiles(getSingleLocationFilePath(e))
|
||||
overlayHasFile(getSingleLocationFilePath(e))
|
||||
or
|
||||
forex(string path | path = getMultiLocationFilePath(e) | overlayChangedFiles(path))
|
||||
forex(string path | path = getMultiLocationFilePath(e) | overlayHasFile(path))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8,81 +8,143 @@ private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
|
||||
/**
|
||||
* A configuration of a data flow analysis that performs must-flow analysis. This is different
|
||||
* from `DataFlow.qll` which performs may-flow analysis (i.e., it finds paths where the source _may_
|
||||
* flow to the sink).
|
||||
*
|
||||
* Like in `DataFlow.qll`, each use of the `MustFlow.qll` library must define its own unique extension
|
||||
* of this abstract class. To create a configuration, extend this class with a subclass whose
|
||||
* characteristic predicate is a unique singleton string and override `isSource`, `isSink` (and
|
||||
* `isAdditionalFlowStep` if additional steps are required).
|
||||
* Provides an inter-procedural must-flow data flow analysis.
|
||||
*/
|
||||
abstract class MustFlowConfiguration extends string {
|
||||
bindingset[this]
|
||||
MustFlowConfiguration() { any() }
|
||||
|
||||
module MustFlow {
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source.
|
||||
* An input configuration of a data flow analysis that performs must-flow analysis. This is different
|
||||
* from `DataFlow.qll` which performs may-flow analysis (i.e., it finds paths where the source _may_
|
||||
* flow to the sink).
|
||||
*/
|
||||
abstract predicate isSource(Instruction source);
|
||||
signature module ConfigSig {
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source.
|
||||
*/
|
||||
predicate isSource(Instruction source);
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink.
|
||||
*/
|
||||
abstract predicate isSink(Operand sink);
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink.
|
||||
*/
|
||||
predicate isSink(Operand sink);
|
||||
|
||||
/**
|
||||
* Holds if data flow through `instr` is prohibited.
|
||||
*/
|
||||
predicate isBarrier(Instruction instr) { none() }
|
||||
/**
|
||||
* Holds if data flow through `instr` is prohibited.
|
||||
*/
|
||||
default predicate isBarrier(Instruction instr) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Operand node1, Instruction node2) { none() }
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
*/
|
||||
default predicate isAdditionalFlowStep(Operand node1, Instruction node2) { none() }
|
||||
|
||||
/** Holds if this configuration allows flow from arguments to parameters. */
|
||||
predicate allowInterproceduralFlow() { any() }
|
||||
|
||||
/**
|
||||
* Holds if data must flow from `source` to `sink` for this configuration.
|
||||
*
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
final predicate hasFlowPath(MustFlowPathNode source, MustFlowPathSink sink) {
|
||||
this.isSource(source.getInstruction()) and
|
||||
source.getASuccessor*() = sink
|
||||
/** Holds if this configuration allows flow from arguments to parameters. */
|
||||
default predicate allowInterproceduralFlow() { any() }
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if `node` flows from a source. */
|
||||
pragma[nomagic]
|
||||
private predicate flowsFromSource(Instruction node, MustFlowConfiguration config) {
|
||||
not config.isBarrier(node) and
|
||||
(
|
||||
config.isSource(node)
|
||||
or
|
||||
exists(Instruction mid |
|
||||
step(mid, node, config) and
|
||||
flowsFromSource(mid, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Constructs a global must-flow computation.
|
||||
*/
|
||||
module Global<ConfigSig Config> {
|
||||
import Config
|
||||
|
||||
/** Holds if `node` flows to a sink. */
|
||||
pragma[nomagic]
|
||||
private predicate flowsToSink(Instruction node, MustFlowConfiguration config) {
|
||||
flowsFromSource(node, pragma[only_bind_into](config)) and
|
||||
(
|
||||
config.isSink(node.getAUse())
|
||||
or
|
||||
exists(Instruction mid |
|
||||
step(node, mid, config) and
|
||||
flowsToSink(mid, pragma[only_bind_into](config))
|
||||
)
|
||||
)
|
||||
/**
|
||||
* Holds if data must flow from `source` to `sink`.
|
||||
*
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate flowPath(PathNode source, PathSink sink) {
|
||||
isSource(source.getInstruction()) and
|
||||
source.getASuccessor*() = sink
|
||||
}
|
||||
|
||||
/** Holds if `node` flows from a source. */
|
||||
pragma[nomagic]
|
||||
private predicate flowsFromSource(Instruction node) {
|
||||
not isBarrier(node) and
|
||||
(
|
||||
isSource(node)
|
||||
or
|
||||
exists(Instruction mid |
|
||||
step(mid, node) and
|
||||
flowsFromSource(mid)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `node` flows to a sink. */
|
||||
pragma[nomagic]
|
||||
private predicate flowsToSink(Instruction node) {
|
||||
flowsFromSource(node) and
|
||||
(
|
||||
isSink(node.getAUse())
|
||||
or
|
||||
exists(Instruction mid |
|
||||
step(node, mid) and
|
||||
flowsToSink(mid)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `nodeFrom` flows to `nodeTo`. */
|
||||
private predicate step(Instruction nodeFrom, Instruction nodeTo) {
|
||||
Cached::localStep(nodeFrom, nodeTo)
|
||||
or
|
||||
allowInterproceduralFlow() and
|
||||
Cached::flowThroughCallable(nodeFrom, nodeTo)
|
||||
or
|
||||
isAdditionalFlowStep(nodeFrom.getAUse(), nodeTo)
|
||||
}
|
||||
|
||||
private newtype TLocalPathNode =
|
||||
MkLocalPathNode(Instruction n) {
|
||||
flowsToSink(n) and
|
||||
(
|
||||
isSource(n)
|
||||
or
|
||||
exists(PathNode mid | step(mid.getInstruction(), n))
|
||||
)
|
||||
}
|
||||
|
||||
/** A `Node` that is in a path from a source to a sink. */
|
||||
class PathNode extends TLocalPathNode {
|
||||
Instruction n;
|
||||
|
||||
PathNode() { this = MkLocalPathNode(n) }
|
||||
|
||||
/** Gets the underlying node. */
|
||||
Instruction getInstruction() { result = n }
|
||||
|
||||
/** Gets a textual representation of this node. */
|
||||
string toString() { result = n.getAst().toString() }
|
||||
|
||||
/** Gets the location of this element. */
|
||||
Location getLocation() { result = n.getLocation() }
|
||||
|
||||
/** Gets a successor node, if any. */
|
||||
PathNode getASuccessor() { step(this.getInstruction(), result.getInstruction()) }
|
||||
}
|
||||
|
||||
private class PathSink extends PathNode {
|
||||
PathSink() { isSink(this.getInstruction().getAUse()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||
*/
|
||||
module PathGraph {
|
||||
private predicate reach(PathNode n) { n instanceof PathSink or reach(n.getASuccessor()) }
|
||||
|
||||
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||
query predicate edges(PathNode a, PathNode b) { a.getASuccessor() = b and reach(b) }
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -102,7 +164,7 @@ private module Cached {
|
||||
not f.isVirtual() and
|
||||
call.getPositionalArgument(n) = instr and
|
||||
f = call.getStaticCallTarget() and
|
||||
getEnclosingNonVirtualFunctionInitializeParameter(init, f) and
|
||||
isEnclosingNonVirtualFunctionInitializeParameter(init, f) and
|
||||
init.getParameter().getIndex() = pragma[only_bind_into](pragma[only_bind_out](n))
|
||||
}
|
||||
|
||||
@@ -111,7 +173,7 @@ private module Cached {
|
||||
* corresponding initialization instruction that receives the value of `instr` in `f`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate getPositionalArgumentInitParam(
|
||||
private predicate isPositionalArgumentInitParam(
|
||||
CallInstruction call, Instruction instr, InitializeParameterInstruction init, Function f
|
||||
) {
|
||||
exists(int n |
|
||||
@@ -126,18 +188,18 @@ private module Cached {
|
||||
* `instr` in `f`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate getThisArgumentInitParam(
|
||||
private predicate isThisArgumentInitParam(
|
||||
CallInstruction call, Instruction instr, InitializeParameterInstruction init, Function f
|
||||
) {
|
||||
not f.isVirtual() and
|
||||
call.getStaticCallTarget() = f and
|
||||
getEnclosingNonVirtualFunctionInitializeParameter(init, f) and
|
||||
isEnclosingNonVirtualFunctionInitializeParameter(init, f) and
|
||||
call.getThisArgument() = instr and
|
||||
init.getIRVariable() instanceof IRThisVariable
|
||||
}
|
||||
|
||||
/** Holds if `f` is the enclosing non-virtual function of `init`. */
|
||||
private predicate getEnclosingNonVirtualFunctionInitializeParameter(
|
||||
private predicate isEnclosingNonVirtualFunctionInitializeParameter(
|
||||
InitializeParameterInstruction init, Function f
|
||||
) {
|
||||
not f.isVirtual() and
|
||||
@@ -145,7 +207,7 @@ private module Cached {
|
||||
}
|
||||
|
||||
/** Holds if `f` is the enclosing non-virtual function of `init`. */
|
||||
private predicate getEnclosingNonVirtualFunctionInitializeIndirection(
|
||||
private predicate isEnclosingNonVirtualFunctionInitializeIndirection(
|
||||
InitializeIndirectionInstruction init, Function f
|
||||
) {
|
||||
not f.isVirtual() and
|
||||
@@ -153,15 +215,16 @@ private module Cached {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` is an argument (or argument indirection) to a call, and
|
||||
* `succ` is the corresponding initialization instruction in the call target.
|
||||
* Holds if `argument` is an argument (or argument indirection) to a call, and
|
||||
* `parameter` is the corresponding initialization instruction in the call target.
|
||||
*/
|
||||
private predicate flowThroughCallable(Instruction argument, Instruction parameter) {
|
||||
cached
|
||||
predicate flowThroughCallable(Instruction argument, Instruction parameter) {
|
||||
// Flow from an argument to a parameter
|
||||
exists(CallInstruction call, InitializeParameterInstruction init | init = parameter |
|
||||
getPositionalArgumentInitParam(call, argument, init, call.getStaticCallTarget())
|
||||
isPositionalArgumentInitParam(call, argument, init, call.getStaticCallTarget())
|
||||
or
|
||||
getThisArgumentInitParam(call, argument, init, call.getStaticCallTarget())
|
||||
isThisArgumentInitParam(call, argument, init, call.getStaticCallTarget())
|
||||
)
|
||||
or
|
||||
// Flow from argument indirection to parameter indirection
|
||||
@@ -170,7 +233,7 @@ private module Cached {
|
||||
|
|
||||
init = parameter and
|
||||
read.getPrimaryInstruction() = call and
|
||||
getEnclosingNonVirtualFunctionInitializeIndirection(init, call.getStaticCallTarget())
|
||||
isEnclosingNonVirtualFunctionInitializeIndirection(init, call.getStaticCallTarget())
|
||||
|
|
||||
exists(int n |
|
||||
read.getSideEffectOperand().getAnyDef() = argument and
|
||||
@@ -205,92 +268,10 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
predicate step(Instruction nodeFrom, Instruction nodeTo) {
|
||||
predicate localStep(Instruction nodeFrom, Instruction nodeTo) {
|
||||
exists(Operand mid |
|
||||
instructionToOperandStep(nodeFrom, mid) and
|
||||
operandToInstructionStep(mid, nodeTo)
|
||||
)
|
||||
or
|
||||
flowThroughCallable(nodeFrom, nodeTo)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the enclosing callable of `n`. Unlike `n.getEnclosingCallable()`, this
|
||||
* predicate ensures that joins go from `n` to the result instead of the other
|
||||
* way around.
|
||||
*/
|
||||
pragma[inline]
|
||||
private IRFunction getEnclosingCallable(Instruction n) {
|
||||
pragma[only_bind_into](result) = pragma[only_bind_out](n).getEnclosingIRFunction()
|
||||
}
|
||||
|
||||
/** Holds if `nodeFrom` flows to `nodeTo`. */
|
||||
private predicate step(Instruction nodeFrom, Instruction nodeTo, MustFlowConfiguration config) {
|
||||
exists(config) and
|
||||
Cached::step(pragma[only_bind_into](nodeFrom), pragma[only_bind_into](nodeTo)) and
|
||||
(
|
||||
config.allowInterproceduralFlow()
|
||||
or
|
||||
getEnclosingCallable(nodeFrom) = getEnclosingCallable(nodeTo)
|
||||
)
|
||||
or
|
||||
config.isAdditionalFlowStep(nodeFrom.getAUse(), nodeTo)
|
||||
}
|
||||
|
||||
private newtype TLocalPathNode =
|
||||
MkLocalPathNode(Instruction n, MustFlowConfiguration config) {
|
||||
flowsToSink(n, config) and
|
||||
(
|
||||
config.isSource(n)
|
||||
or
|
||||
exists(MustFlowPathNode mid | step(mid.getInstruction(), n, config))
|
||||
)
|
||||
}
|
||||
|
||||
/** A `Node` that is in a path from a source to a sink. */
|
||||
class MustFlowPathNode extends TLocalPathNode {
|
||||
Instruction n;
|
||||
|
||||
MustFlowPathNode() { this = MkLocalPathNode(n, _) }
|
||||
|
||||
/** Gets the underlying node. */
|
||||
Instruction getInstruction() { result = n }
|
||||
|
||||
/** Gets a textual representation of this node. */
|
||||
string toString() { result = n.getAst().toString() }
|
||||
|
||||
/** Gets the location of this element. */
|
||||
Location getLocation() { result = n.getLocation() }
|
||||
|
||||
/** Gets a successor node, if any. */
|
||||
MustFlowPathNode getASuccessor() {
|
||||
step(this.getInstruction(), result.getInstruction(), this.getConfiguration())
|
||||
}
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
MustFlowConfiguration getConfiguration() { this = MkLocalPathNode(_, result) }
|
||||
}
|
||||
|
||||
private class MustFlowPathSink extends MustFlowPathNode {
|
||||
MustFlowPathSink() { this.getConfiguration().isSink(this.getInstruction().getAUse()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||
*/
|
||||
module PathGraph {
|
||||
private predicate reach(MustFlowPathNode n) {
|
||||
n instanceof MustFlowPathSink or reach(n.getASuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||
query predicate edges(MustFlowPathNode a, MustFlowPathNode b) {
|
||||
a.getASuccessor() = b and reach(b)
|
||||
}
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(MustFlowPathNode n, string key, string val) {
|
||||
reach(n) and key = "semmle.label" and val = n.toString()
|
||||
}
|
||||
}
|
||||
|
||||
1823
cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll
Normal file
1823
cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
private import cpp as Cpp
|
||||
private import DataFlowUtil
|
||||
private import DataFlowNodes
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import DataFlowDispatch
|
||||
private import semmle.code.cpp.ir.internal.IRCppLanguage
|
||||
@@ -16,28 +17,42 @@ private import semmle.code.cpp.dataflow.ExternalFlow as External
|
||||
cached
|
||||
private module Cached {
|
||||
cached
|
||||
module Nodes0 {
|
||||
cached
|
||||
newtype TIRDataFlowNode0 =
|
||||
TInstructionNode0(Instruction i) {
|
||||
not Ssa::ignoreInstruction(i) and
|
||||
not exists(Operand op |
|
||||
not Ssa::ignoreOperand(op) and i = Ssa::getIRRepresentationOfOperand(op)
|
||||
) and
|
||||
// We exclude `void`-typed instructions because they cannot contain data.
|
||||
// However, if the instruction is a glvalue, and their type is `void`, then the result
|
||||
// type of the instruction is really `void*`, and thus we still want to have a dataflow
|
||||
// node for it.
|
||||
(not i.getResultType() instanceof VoidType or i.isGLValue())
|
||||
} or
|
||||
TMultipleUseOperandNode0(Operand op) {
|
||||
not Ssa::ignoreOperand(op) and not exists(Ssa::getIRRepresentationOfOperand(op))
|
||||
} or
|
||||
TSingleUseOperandNode0(Operand op) {
|
||||
not Ssa::ignoreOperand(op) and exists(Ssa::getIRRepresentationOfOperand(op))
|
||||
}
|
||||
newtype TIRDataFlowNode0 =
|
||||
TInstructionNode0(Instruction i) {
|
||||
not Ssa::ignoreInstruction(i) and
|
||||
not exists(Operand op |
|
||||
not Ssa::ignoreOperand(op) and i = Ssa::getIRRepresentationOfOperand(op)
|
||||
) and
|
||||
// We exclude `void`-typed instructions because they cannot contain data.
|
||||
// However, if the instruction is a glvalue, and their type is `void`, then the result
|
||||
// type of the instruction is really `void*`, and thus we still want to have a dataflow
|
||||
// node for it.
|
||||
(not i.getResultType() instanceof VoidType or i.isGLValue())
|
||||
} or
|
||||
TMultipleUseOperandNode0(Operand op) {
|
||||
not Ssa::ignoreOperand(op) and not exists(Ssa::getIRRepresentationOfOperand(op))
|
||||
} or
|
||||
TSingleUseOperandNode0(Operand op) {
|
||||
not Ssa::ignoreOperand(op) and exists(Ssa::getIRRepresentationOfOperand(op))
|
||||
}
|
||||
|
||||
cached
|
||||
string toStringCached(Node n) {
|
||||
result = toExprString(n)
|
||||
or
|
||||
not exists(toExprString(n)) and
|
||||
result = n.toStringImpl()
|
||||
}
|
||||
|
||||
cached
|
||||
Location getLocationCached(Node n) { result = n.getLocationImpl() }
|
||||
|
||||
cached
|
||||
newtype TContentApprox =
|
||||
TFieldApproxContent(string s) { fieldHasApproxName(_, s) } or
|
||||
TUnionApproxContent(string s) { unionHasApproxName(_, s) } or
|
||||
TElementApproxContent()
|
||||
|
||||
/**
|
||||
* Gets an additional term that is added to the `join` and `branch` computations to reflect
|
||||
* an additional forward or backwards branching factor that is not taken into account
|
||||
@@ -59,38 +74,174 @@ private module Cached {
|
||||
result = countNumberOfBranchesUsingParameter(switch, p)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import Cached
|
||||
private import Nodes0
|
||||
cached
|
||||
newtype TDataFlowCallable =
|
||||
TSourceCallable(Cpp::Declaration decl) or
|
||||
TSummarizedCallable(FlowSummaryImpl::Public::SummarizedCallable c)
|
||||
|
||||
/**
|
||||
* A module for calculating the number of stars (i.e., `*`s) needed for various
|
||||
* dataflow node `toString` predicates.
|
||||
*/
|
||||
module NodeStars {
|
||||
private int getNumberOfIndirections(Node n) {
|
||||
result = n.(RawIndirectOperand).getIndirectionIndex()
|
||||
cached
|
||||
newtype TDataFlowCall =
|
||||
TNormalCall(CallInstruction call) or
|
||||
TSummaryCall(
|
||||
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
|
||||
) {
|
||||
FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` in a way that loses the
|
||||
* calling context. For example, this would happen with flow through a
|
||||
* global or static variable.
|
||||
*/
|
||||
cached
|
||||
predicate jumpStep(Node n1, Node n2) {
|
||||
exists(GlobalLikeVariable v |
|
||||
exists(Ssa::GlobalUse globalUse |
|
||||
v = globalUse.getVariable() and
|
||||
n1.(FinalGlobalValue).getGlobalUse() = globalUse
|
||||
|
|
||||
globalUse.getIndirection() = getMinIndirectionForGlobalUse(globalUse) and
|
||||
v = n2.asVariable()
|
||||
or
|
||||
v = n2.asIndirectVariable(globalUse.getIndirection())
|
||||
)
|
||||
or
|
||||
exists(Ssa::GlobalDef globalDef |
|
||||
v = globalDef.getVariable() and
|
||||
n2.(InitialGlobalValue).getGlobalDef() = globalDef
|
||||
|
|
||||
globalDef.getIndirection() = getMinIndirectionForGlobalDef(globalDef) and
|
||||
v = n1.asVariable()
|
||||
or
|
||||
v = n1.asIndirectVariable(globalDef.getIndirection())
|
||||
)
|
||||
)
|
||||
or
|
||||
result = n.(RawIndirectInstruction).getIndirectionIndex()
|
||||
or
|
||||
result = n.(VariableNode).getIndirectionIndex()
|
||||
or
|
||||
result = n.(PostUpdateNodeImpl).getIndirectionIndex()
|
||||
or
|
||||
result = n.(FinalParameterNode).getIndirectionIndex()
|
||||
or
|
||||
result = n.(BodyLessParameterNodeImpl).getIndirectionIndex()
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryJumpStep(n1.(FlowSummaryNode).getSummaryNode(),
|
||||
n2.(FlowSummaryNode).getSummaryNode())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of stars (i.e., `*`s) needed to produce the `toString`
|
||||
* output for `n`.
|
||||
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
|
||||
* Thus, `node2` references an object with a field `f` that contains the
|
||||
* value of `node1`.
|
||||
*
|
||||
* The boolean `certain` is true if the destination address does not involve
|
||||
* any pointer arithmetic, and false otherwise.
|
||||
*/
|
||||
string stars(Node n) { result = repeatStars(getNumberOfIndirections(n)) }
|
||||
cached
|
||||
predicate storeStepImpl(Node node1, Content c, Node node2, boolean certain) {
|
||||
exists(
|
||||
PostFieldUpdateNode postFieldUpdate, int indirectionIndex1, int numberOfLoads,
|
||||
StoreInstruction store, FieldContent fc
|
||||
|
|
||||
postFieldUpdate = node2 and
|
||||
fc = c and
|
||||
nodeHasInstruction(node1, pragma[only_bind_into](store),
|
||||
pragma[only_bind_into](indirectionIndex1)) and
|
||||
postFieldUpdate.getIndirectionIndex() = 1 and
|
||||
numberOfLoadsFromOperand(postFieldUpdate.getFieldAddress(),
|
||||
store.getDestinationAddressOperand(), numberOfLoads, certain) and
|
||||
fc.getAField() = postFieldUpdate.getUpdatedField() and
|
||||
getIndirectionIndexLate(fc) = 1 + indirectionIndex1 + numberOfLoads
|
||||
)
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), c,
|
||||
node2.(FlowSummaryNode).getSummaryNode()) and
|
||||
certain = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
|
||||
* Thus, `node2` references an object with a field `f` that contains the
|
||||
* value of `node1`.
|
||||
*/
|
||||
cached
|
||||
predicate storeStep(Node node1, ContentSet c, Node node2) { storeStepImpl(node1, c, node2, _) }
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via a read of `f`.
|
||||
* Thus, `node1` references an object with a field `f` whose value ends up in
|
||||
* `node2`.
|
||||
*/
|
||||
cached
|
||||
predicate readStep(Node node1, ContentSet c, Node node2) {
|
||||
exists(
|
||||
FieldAddress fa1, Operand operand, int numberOfLoads, int indirectionIndex2, FieldContent fc
|
||||
|
|
||||
fc = c and
|
||||
nodeHasOperand(node2, operand, indirectionIndex2) and
|
||||
// The `1` here matches the `node2.getIndirectionIndex() = 1` conjunct
|
||||
// in `storeStep`.
|
||||
nodeHasOperand(node1, fa1.getObjectAddressOperand(), 1) and
|
||||
numberOfLoadsFromOperand(fa1, operand, numberOfLoads, _) and
|
||||
fc.getAField() = fa1.getField() and
|
||||
getIndirectionIndexLate(fc) = indirectionIndex2 + numberOfLoads
|
||||
)
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), c,
|
||||
node2.(FlowSummaryNode).getSummaryNode())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if values stored inside content `c` are cleared at node `n`.
|
||||
*/
|
||||
cached
|
||||
predicate clearsContent(Node n, ContentSet c) {
|
||||
n =
|
||||
any(PostUpdateNode pun, Content d |
|
||||
d.impliesClearOf(c) and storeStepImpl(_, d, pun, true)
|
||||
|
|
||||
pun
|
||||
).getPreUpdateNode() and
|
||||
(
|
||||
not exists(Operand op, Cpp::Operation p |
|
||||
n.(IndirectOperand).hasOperandAndIndirectionIndex(op, _) and
|
||||
(
|
||||
p instanceof Cpp::AssignPointerAddExpr or
|
||||
p instanceof Cpp::AssignPointerSubExpr or
|
||||
p instanceof Cpp::CrementOperation
|
||||
)
|
||||
|
|
||||
p.getAnOperand() = op.getUse().getAst()
|
||||
)
|
||||
or
|
||||
forex(PostUpdateNode pun, Content d |
|
||||
pragma[only_bind_into](d).impliesClearOf(pragma[only_bind_into](c)) and
|
||||
storeStepImpl(_, d, pun, true) and
|
||||
pun.getPreUpdateNode() = n
|
||||
|
|
||||
c.(Content).getIndirectionIndex() = d.getIndirectionIndex()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import NodeStars
|
||||
import Cached
|
||||
|
||||
private int getNumberOfIndirections(Node n) {
|
||||
result = n.(RawIndirectOperand).getIndirectionIndex()
|
||||
or
|
||||
result = n.(RawIndirectInstruction).getIndirectionIndex()
|
||||
or
|
||||
result = n.(VariableNode).getIndirectionIndex()
|
||||
or
|
||||
result = n.(PostUpdateNodeImpl).getIndirectionIndex()
|
||||
or
|
||||
result = n.(FinalParameterNode).getIndirectionIndex()
|
||||
or
|
||||
result = n.(BodyLessParameterNodeImpl).getIndirectionIndex()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of stars (i.e., `*`s) needed to produce the `toString`
|
||||
* output for `n`.
|
||||
*/
|
||||
string stars(Node n) { result = repeatStars(getNumberOfIndirections(n)) }
|
||||
|
||||
/**
|
||||
* A cut-down `DataFlow::Node` class that does not depend on the output of SSA.
|
||||
@@ -828,85 +979,10 @@ private int getMinIndirectionForGlobalDef(Ssa::GlobalDef def) {
|
||||
result = getMinIndirectionsForType(def.getUnspecifiedType())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` in a way that loses the
|
||||
* calling context. For example, this would happen with flow through a
|
||||
* global or static variable.
|
||||
*/
|
||||
predicate jumpStep(Node n1, Node n2) {
|
||||
exists(GlobalLikeVariable v |
|
||||
exists(Ssa::GlobalUse globalUse |
|
||||
v = globalUse.getVariable() and
|
||||
n1.(FinalGlobalValue).getGlobalUse() = globalUse
|
||||
|
|
||||
globalUse.getIndirection() = getMinIndirectionForGlobalUse(globalUse) and
|
||||
v = n2.asVariable()
|
||||
or
|
||||
v = n2.asIndirectVariable(globalUse.getIndirection())
|
||||
)
|
||||
or
|
||||
exists(Ssa::GlobalDef globalDef |
|
||||
v = globalDef.getVariable() and
|
||||
n2.(InitialGlobalValue).getGlobalDef() = globalDef
|
||||
|
|
||||
globalDef.getIndirection() = getMinIndirectionForGlobalDef(globalDef) and
|
||||
v = n1.asVariable()
|
||||
or
|
||||
v = n1.asIndirectVariable(globalDef.getIndirection())
|
||||
)
|
||||
)
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryJumpStep(n1.(FlowSummaryNode).getSummaryNode(),
|
||||
n2.(FlowSummaryNode).getSummaryNode())
|
||||
}
|
||||
|
||||
bindingset[c]
|
||||
pragma[inline_late]
|
||||
private int getIndirectionIndexLate(Content c) { result = c.getIndirectionIndex() }
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
|
||||
* Thus, `node2` references an object with a field `f` that contains the
|
||||
* value of `node1`.
|
||||
*
|
||||
* The boolean `certain` is true if the destination address does not involve
|
||||
* any pointer arithmetic, and false otherwise. This has to do with whether a
|
||||
* store step can be used to clear a field (see `clearsContent`).
|
||||
*/
|
||||
predicate storeStepImpl(Node node1, Content c, Node node2, boolean certain) {
|
||||
exists(
|
||||
PostFieldUpdateNode postFieldUpdate, int indirectionIndex1, int numberOfLoads,
|
||||
StoreInstruction store, FieldContent fc
|
||||
|
|
||||
postFieldUpdate = node2 and
|
||||
fc = c and
|
||||
nodeHasInstruction(node1, pragma[only_bind_into](store),
|
||||
pragma[only_bind_into](indirectionIndex1)) and
|
||||
postFieldUpdate.getIndirectionIndex() = 1 and
|
||||
numberOfLoadsFromOperand(postFieldUpdate.getFieldAddress(),
|
||||
store.getDestinationAddressOperand(), numberOfLoads, certain) and
|
||||
fc.getAField() = postFieldUpdate.getUpdatedField() and
|
||||
getIndirectionIndexLate(fc) = 1 + indirectionIndex1 + numberOfLoads
|
||||
)
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), c,
|
||||
node2.(FlowSummaryNode).getSummaryNode()) and
|
||||
certain = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
|
||||
* Thus, `node2` references an object with a field `f` that contains the
|
||||
* value of `node1`.
|
||||
*/
|
||||
predicate storeStep(Node node1, ContentSet c, Node node2) { storeStepImpl(node1, c, node2, _) }
|
||||
|
||||
/**
|
||||
* Holds if `operandFrom` flows to `operandTo` using a sequence of conversion-like
|
||||
* operations and exactly `n` `LoadInstruction` operations.
|
||||
*/
|
||||
private predicate numberOfLoadsFromOperandRec(
|
||||
Operand operandFrom, Operand operandTo, int ind, boolean certain
|
||||
) {
|
||||
@@ -957,63 +1033,6 @@ predicate nodeHasInstruction(Node node, Instruction instr, int indirectionIndex)
|
||||
hasInstructionAndIndex(node, instr, indirectionIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via a read of `f`.
|
||||
* Thus, `node1` references an object with a field `f` whose value ends up in
|
||||
* `node2`.
|
||||
*/
|
||||
predicate readStep(Node node1, ContentSet c, Node node2) {
|
||||
exists(
|
||||
FieldAddress fa1, Operand operand, int numberOfLoads, int indirectionIndex2, FieldContent fc
|
||||
|
|
||||
fc = c and
|
||||
nodeHasOperand(node2, operand, indirectionIndex2) and
|
||||
// The `1` here matches the `node2.getIndirectionIndex() = 1` conjunct
|
||||
// in `storeStep`.
|
||||
nodeHasOperand(node1, fa1.getObjectAddressOperand(), 1) and
|
||||
numberOfLoadsFromOperand(fa1, operand, numberOfLoads, _) and
|
||||
fc.getAField() = fa1.getField() and
|
||||
getIndirectionIndexLate(fc) = indirectionIndex2 + numberOfLoads
|
||||
)
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), c,
|
||||
node2.(FlowSummaryNode).getSummaryNode())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if values stored inside content `c` are cleared at node `n`.
|
||||
*/
|
||||
predicate clearsContent(Node n, ContentSet c) {
|
||||
n =
|
||||
any(PostUpdateNode pun, Content d | d.impliesClearOf(c) and storeStepImpl(_, d, pun, true) | pun)
|
||||
.getPreUpdateNode() and
|
||||
(
|
||||
// The crement operations and pointer addition and subtraction self-assign. We do not
|
||||
// want to clear the contents if it is indirectly pointed at by any of these operations,
|
||||
// as part of the contents might still be accessible afterwards. If there is no such
|
||||
// indirection clearing the contents is safe.
|
||||
not exists(Operand op, Cpp::Operation p |
|
||||
n.(IndirectOperand).hasOperandAndIndirectionIndex(op, _) and
|
||||
(
|
||||
p instanceof Cpp::AssignPointerAddExpr or
|
||||
p instanceof Cpp::AssignPointerSubExpr or
|
||||
p instanceof Cpp::CrementOperation
|
||||
)
|
||||
|
|
||||
p.getAnOperand() = op.getUse().getAst()
|
||||
)
|
||||
or
|
||||
forex(PostUpdateNode pun, Content d |
|
||||
pragma[only_bind_into](d).impliesClearOf(pragma[only_bind_into](c)) and
|
||||
storeStepImpl(_, d, pun, true) and
|
||||
pun.getPreUpdateNode() = n
|
||||
|
|
||||
c.(Content).getIndirectionIndex() = d.getIndirectionIndex()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the value that is being tracked is expected to be stored inside content `c`
|
||||
* at node `n`.
|
||||
@@ -1046,11 +1065,6 @@ class CastNode extends Node {
|
||||
CastNode() { none() } // stub implementation
|
||||
}
|
||||
|
||||
cached
|
||||
private newtype TDataFlowCallable =
|
||||
TSourceCallable(Cpp::Declaration decl) or
|
||||
TSummarizedCallable(FlowSummaryImpl::Public::SummarizedCallable c)
|
||||
|
||||
/**
|
||||
* A callable, which may be:
|
||||
* - a function (that may contain code)
|
||||
@@ -1134,15 +1148,6 @@ class DataFlowType extends TypeFinal {
|
||||
string toString() { result = "" }
|
||||
}
|
||||
|
||||
cached
|
||||
private newtype TDataFlowCall =
|
||||
TNormalCall(CallInstruction call) or
|
||||
TSummaryCall(
|
||||
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
|
||||
) {
|
||||
FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
|
||||
}
|
||||
|
||||
private predicate summarizedCallableIsManual(SummarizedCallable sc) {
|
||||
sc.asSummarizedCallable().hasManualModel()
|
||||
}
|
||||
@@ -1523,12 +1528,6 @@ private predicate fieldHasApproxName(Field f, string s) {
|
||||
|
||||
private predicate unionHasApproxName(Cpp::Union u, string s) { s = u.getName().charAt(0) }
|
||||
|
||||
cached
|
||||
private newtype TContentApprox =
|
||||
TFieldApproxContent(string s) { fieldHasApproxName(_, s) } or
|
||||
TUnionApproxContent(string s) { unionHasApproxName(_, s) } or
|
||||
TElementApproxContent()
|
||||
|
||||
/** An approximated `Content`. */
|
||||
class ContentApprox extends TContentApprox {
|
||||
string toString() { none() } // overridden in subclasses
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,8 +6,8 @@ private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import DataFlowUtil
|
||||
private import DataFlowPrivate
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedExpr
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.InstructionTag
|
||||
private import DataFlowNodes
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
@@ -73,17 +73,9 @@ private module Cached {
|
||||
// a result for `getConvertedResultExpression`. We remap this here so that
|
||||
// this `ConvertInstruction` maps to the result of the expression that
|
||||
// represents the extent.
|
||||
exists(TranslatedNonConstantAllocationSize tas |
|
||||
result = tas.getExtent().getExpr() and
|
||||
instr = tas.getInstruction(AllocationExtentConvertTag())
|
||||
)
|
||||
result = IRConstruction::Raw::getAllocationExtentConvertExpr(instr)
|
||||
or
|
||||
// There's no instruction that returns `ParenthesisExpr`, but some queries
|
||||
// expect this
|
||||
exists(TranslatedTransparentConversion ttc |
|
||||
result = ttc.getExpr().(ParenthesisExpr) and
|
||||
instr = ttc.getResult()
|
||||
)
|
||||
result = IRConstruction::Raw::getTransparentConversionParenthesisExpr(instr)
|
||||
or
|
||||
// Certain expressions generate `CopyValueInstruction`s only when they
|
||||
// are needed. Examples of this include crement operations and compound
|
||||
@@ -112,10 +104,10 @@ private module Cached {
|
||||
// needed, and in that case the only value that will propagate forward in
|
||||
// the program is the value that's been updated. So in those cases we just
|
||||
// use the result of `node.asDefinition()` as the result of `node.asExpr()`.
|
||||
exists(TranslatedCoreExpr tco |
|
||||
tco.getInstruction(_) = instr and
|
||||
tco.producesExprResult() and
|
||||
result = asDefinitionImpl0(instr)
|
||||
exists(StoreInstruction store |
|
||||
store = instr and
|
||||
IRConstruction::Raw::instructionProducesExprResult(store) and
|
||||
result = asDefinitionImpl0(store)
|
||||
)
|
||||
or
|
||||
// IR construction breaks an array aggregate literal `{1, 2, 3}` into a
|
||||
@@ -145,18 +137,9 @@ private module Cached {
|
||||
// For an expression such as `i += 2` we pretend that the generated
|
||||
// `StoreInstruction` contains the result of the expression even though
|
||||
// this isn't totally aligned with the C/C++ standard.
|
||||
exists(TranslatedAssignOperation tao |
|
||||
store = tao.getInstruction(AssignmentStoreTag()) and
|
||||
result = tao.getExpr()
|
||||
)
|
||||
result = IRConstruction::Raw::getAssignOperationStoreExpr(store)
|
||||
or
|
||||
// Similarly for `i++` and `++i` we pretend that the generated
|
||||
// `StoreInstruction` contains the result of the expression even though
|
||||
// this isn't totally aligned with the C/C++ standard.
|
||||
exists(TranslatedCrementOperation tco |
|
||||
store = tco.getInstruction(CrementStoreTag()) and
|
||||
result = tco.getExpr()
|
||||
)
|
||||
result = IRConstruction::Raw::getCrementOperationStoreExpr(store)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -166,11 +149,7 @@ private module Cached {
|
||||
*/
|
||||
private predicate excludeAsDefinitionResult(StoreInstruction store) {
|
||||
// Exclude the store to the temporary generated by a ternary expression.
|
||||
exists(TranslatedConditionalExpr tce |
|
||||
store = tce.getInstruction(ConditionValueFalseStoreTag())
|
||||
or
|
||||
store = tce.getInstruction(ConditionValueTrueStoreTag())
|
||||
)
|
||||
IRConstruction::Raw::isConditionalExprTempStore(store)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs
|
||||
private import DataFlowUtil
|
||||
private import DataFlowNodes
|
||||
private import DataFlowPrivate
|
||||
private import SsaImpl as Ssa
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes
|
||||
private import PrintIRUtilities
|
||||
|
||||
/** A property provider for local IR dataflow store steps. */
|
||||
|
||||
@@ -2,6 +2,7 @@ private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes
|
||||
private import SsaImpl as Ssa
|
||||
private import PrintIRUtilities
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes
|
||||
|
||||
private Instruction getInstruction(Node n, string stars) {
|
||||
result = [n.asInstruction(), n.(RawIndirectInstruction).getInstruction()] and
|
||||
|
||||
@@ -10,8 +10,9 @@ private import semmle.code.cpp.models.interfaces.PartialFlow as PartialFlow
|
||||
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs as FIO
|
||||
private import semmle.code.cpp.ir.internal.IRCppLanguage
|
||||
private import semmle.code.cpp.ir.dataflow.internal.ModelUtil
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.TranslatedInitialization
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
|
||||
private import DataFlowPrivate
|
||||
private import DataFlowNodes
|
||||
import SsaImplCommon
|
||||
|
||||
private module SourceVariables {
|
||||
@@ -438,10 +439,7 @@ private predicate sourceVariableHasBaseAndIndex(SourceVariable v, BaseSourceVari
|
||||
* initialize `v`.
|
||||
*/
|
||||
private Instruction getInitializationTargetAddress(IRVariable v) {
|
||||
exists(TranslatedVariableInitialization init |
|
||||
init.getIRVariable() = v and
|
||||
result = init.getTargetAddress()
|
||||
)
|
||||
result = IRConstruction::Raw::getInitializationTargetAddress(v)
|
||||
}
|
||||
|
||||
/** An initial definition of an SSA variable address. */
|
||||
|
||||
@@ -4,47 +4,12 @@ import semmle.code.cpp.ir.internal.IRCppLanguage
|
||||
private import semmle.code.cpp.ir.implementation.raw.internal.SideEffects as SideEffects
|
||||
private import DataFlowImplCommon as DataFlowImplCommon
|
||||
private import DataFlowUtil
|
||||
private import DataFlowNodes
|
||||
private import semmle.code.cpp.models.interfaces.PointerWrapper
|
||||
private import DataFlowPrivate
|
||||
private import TypeFlow
|
||||
private import semmle.code.cpp.ir.ValueNumbering
|
||||
|
||||
/**
|
||||
* Holds if `operand` is an operand that is not used by the dataflow library.
|
||||
* Ignored operands are not recognized as uses by SSA, and they don't have a
|
||||
* corresponding `(Indirect)OperandNode`.
|
||||
*/
|
||||
predicate ignoreOperand(Operand operand) {
|
||||
operand = any(Instruction instr | ignoreInstruction(instr)).getAnOperand() or
|
||||
operand = any(Instruction instr | ignoreInstruction(instr)).getAUse() or
|
||||
operand instanceof MemoryOperand
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` is an instruction that is not used by the dataflow library.
|
||||
* Ignored instructions are not recognized as reads/writes by SSA, and they
|
||||
* don't have a corresponding `(Indirect)InstructionNode`.
|
||||
*/
|
||||
predicate ignoreInstruction(Instruction instr) {
|
||||
DataFlowImplCommon::forceCachingInSameStage() and
|
||||
(
|
||||
instr instanceof CallSideEffectInstruction or
|
||||
instr instanceof CallReadSideEffectInstruction or
|
||||
instr instanceof ExitFunctionInstruction or
|
||||
instr instanceof EnterFunctionInstruction or
|
||||
instr instanceof WriteSideEffectInstruction or
|
||||
instr instanceof PhiInstruction or
|
||||
instr instanceof ReadSideEffectInstruction or
|
||||
instr instanceof ChiInstruction or
|
||||
instr instanceof InitializeIndirectionInstruction or
|
||||
instr instanceof AliasedDefinitionInstruction or
|
||||
instr instanceof AliasedUseInstruction or
|
||||
instr instanceof InitializeNonLocalInstruction or
|
||||
instr instanceof ReturnIndirectionInstruction or
|
||||
instr instanceof UninitializedGroupInstruction
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the C++ type of `this` in the member function `f`.
|
||||
* The result is a glvalue if `isGLValue` is true, and
|
||||
@@ -55,26 +20,6 @@ private CppType getThisType(Cpp::MemberFunction f, boolean isGLValue) {
|
||||
result.hasType(f.getTypeOfThis(), isGLValue)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the C++ type of the instruction `i`.
|
||||
*
|
||||
* This is equivalent to `i.getResultLanguageType()` with the exception
|
||||
* of instructions that directly references a `this` IRVariable. In this
|
||||
* case, `i.getResultLanguageType()` gives an unknown type, whereas the
|
||||
* predicate gives the expected type (i.e., a potentially cv-qualified
|
||||
* type `A*` where `A` is the declaring type of the member function that
|
||||
* contains `i`).
|
||||
*/
|
||||
cached
|
||||
CppType getResultLanguageType(Instruction i) {
|
||||
if i.(VariableAddressInstruction).getIRVariable() instanceof IRThisVariable
|
||||
then
|
||||
if i.isGLValue()
|
||||
then result = getThisType(i.getEnclosingFunction(), true)
|
||||
else result = getThisType(i.getEnclosingFunction(), false)
|
||||
else result = i.getResultLanguageType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the C++ type of the operand `operand`.
|
||||
* This is equivalent to the type of the operand's defining instruction.
|
||||
@@ -347,10 +292,6 @@ predicate isWrite(Node0Impl value, Operand address, boolean certain) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate isAdditionalConversionFlow(Operand opFrom, Instruction instrTo) {
|
||||
any(Indirection ind).isAdditionalConversionFlow(opFrom, instrTo)
|
||||
}
|
||||
|
||||
newtype TBaseSourceVariable =
|
||||
// Each IR variable gets its own source variable
|
||||
TBaseIRVariable(IRVariable var) or
|
||||
@@ -572,6 +513,69 @@ private class BaseCallInstruction extends BaseSourceVariableInstruction, CallIns
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
/**
|
||||
* Holds if `operand` is an operand that is not used by the dataflow library.
|
||||
* Ignored operands are not recognized as uses by SSA, and they don't have a
|
||||
* corresponding `(Indirect)OperandNode`.
|
||||
*/
|
||||
cached
|
||||
predicate ignoreOperand(Operand operand) {
|
||||
operand = any(Instruction instr | ignoreInstruction(instr)).getAnOperand() or
|
||||
operand = any(Instruction instr | ignoreInstruction(instr)).getAUse() or
|
||||
operand instanceof MemoryOperand
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` is an instruction that is not used by the dataflow library.
|
||||
* Ignored instructions are not recognized as reads/writes by SSA, and they
|
||||
* don't have a corresponding `(Indirect)InstructionNode`.
|
||||
*/
|
||||
cached
|
||||
predicate ignoreInstruction(Instruction instr) {
|
||||
DataFlowImplCommon::forceCachingInSameStage() and
|
||||
(
|
||||
instr instanceof CallSideEffectInstruction or
|
||||
instr instanceof CallReadSideEffectInstruction or
|
||||
instr instanceof ExitFunctionInstruction or
|
||||
instr instanceof EnterFunctionInstruction or
|
||||
instr instanceof WriteSideEffectInstruction or
|
||||
instr instanceof PhiInstruction or
|
||||
instr instanceof ReadSideEffectInstruction or
|
||||
instr instanceof ChiInstruction or
|
||||
instr instanceof InitializeIndirectionInstruction or
|
||||
instr instanceof AliasedDefinitionInstruction or
|
||||
instr instanceof AliasedUseInstruction or
|
||||
instr instanceof InitializeNonLocalInstruction or
|
||||
instr instanceof ReturnIndirectionInstruction or
|
||||
instr instanceof UninitializedGroupInstruction
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate isAdditionalConversionFlow(Operand opFrom, Instruction instrTo) {
|
||||
any(Indirection ind).isAdditionalConversionFlow(opFrom, instrTo)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the C++ type of the instruction `i`.
|
||||
*
|
||||
* This is equivalent to `i.getResultLanguageType()` with the exception
|
||||
* of instructions that directly references a `this` IRVariable. In this
|
||||
* case, `i.getResultLanguageType()` gives an unknown type, whereas the
|
||||
* predicate gives the expected type (i.e., a potentially cv-qualified
|
||||
* type `A*` where `A` is the declaring type of the member function that
|
||||
* contains `i`).
|
||||
*/
|
||||
cached
|
||||
CppType getResultLanguageType(Instruction i) {
|
||||
if i.(VariableAddressInstruction).getIRVariable() instanceof IRThisVariable
|
||||
then
|
||||
if i.isGLValue()
|
||||
then result = getThisType(i.getEnclosingFunction(), true)
|
||||
else result = getThisType(i.getEnclosingFunction(), false)
|
||||
else result = i.getResultLanguageType()
|
||||
}
|
||||
|
||||
/** Holds if `op` is the only use of its defining instruction, and that op is used in a conversation */
|
||||
private predicate isConversion(Operand op) {
|
||||
exists(Instruction def, Operand use |
|
||||
|
||||
@@ -5,64 +5,81 @@ private import semmle.code.cpp.models.interfaces.DataFlow
|
||||
private import semmle.code.cpp.models.interfaces.SideEffect
|
||||
private import DataFlowUtil
|
||||
private import DataFlowPrivate
|
||||
private import DataFlowNodes
|
||||
private import SsaImpl as Ssa
|
||||
private import semmle.code.cpp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
|
||||
private import semmle.code.cpp.ir.dataflow.FlowSteps
|
||||
|
||||
/**
|
||||
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
|
||||
* (intra-procedural) step. This relation is only used for local taint flow
|
||||
* (for example `TaintTracking::localTaint(source, sink)`) so it may contain
|
||||
* special cases that should only apply to local taint flow.
|
||||
*/
|
||||
predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
// dataflow step
|
||||
DataFlow::localFlowStep(nodeFrom, nodeTo)
|
||||
or
|
||||
// taint flow step
|
||||
localAdditionalTaintStep(nodeFrom, nodeTo, _)
|
||||
or
|
||||
// models-as-data summarized flow for local data flow (i.e. special case for flow
|
||||
// through calls to modeled functions, without relying on global dataflow to join
|
||||
// the dots).
|
||||
FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(nodeFrom, nodeTo, _)
|
||||
cached
|
||||
private module Cached {
|
||||
private import DataFlowImplCommon as DataFlowImplCommon
|
||||
|
||||
/**
|
||||
* This predicate exists to collapse the `cached` predicates in this module with the
|
||||
* `cached` predicates in other C/C++ dataflow files, which is then collapsed
|
||||
* with the `cached` predicates in `DataFlowImplCommon.qll`.
|
||||
*/
|
||||
cached
|
||||
predicate forceCachingInSameStage() { DataFlowImplCommon::forceCachingInSameStage() }
|
||||
|
||||
/**
|
||||
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
|
||||
* (intra-procedural) step. This relation is only used for local taint flow
|
||||
* (for example `TaintTracking::localTaint(source, sink)`) so it may contain
|
||||
* special cases that should only apply to local taint flow.
|
||||
*/
|
||||
cached
|
||||
predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
// dataflow step
|
||||
DataFlow::localFlowStep(nodeFrom, nodeTo)
|
||||
or
|
||||
// taint flow step
|
||||
localAdditionalTaintStep(nodeFrom, nodeTo, _)
|
||||
or
|
||||
// models-as-data summarized flow for local data flow (i.e. special case for flow
|
||||
// through calls to modeled functions, without relying on global dataflow to join
|
||||
// the dots).
|
||||
FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(nodeFrom, nodeTo, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint can flow in one local step from `nodeFrom` to `nodeTo` excluding
|
||||
* local data flow steps. That is, `nodeFrom` and `nodeTo` are likely to represent
|
||||
* different objects.
|
||||
*/
|
||||
cached
|
||||
predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, string model) {
|
||||
operandToInstructionTaintStep(nodeFrom.asOperand(), nodeTo.asInstruction()) and
|
||||
model = ""
|
||||
or
|
||||
modeledTaintStep(nodeFrom, nodeTo, model)
|
||||
or
|
||||
// Flow from (the indirection of) an operand of a pointer arithmetic instruction to the
|
||||
// indirection of the pointer arithmetic instruction. This provides flow from `source`
|
||||
// in `x[source]` to the result of the associated load instruction.
|
||||
exists(PointerArithmeticInstruction pai, int indirectionIndex |
|
||||
nodeHasOperand(nodeFrom, pai.getAnOperand(), pragma[only_bind_into](indirectionIndex)) and
|
||||
hasInstructionAndIndex(nodeTo, pai, indirectionIndex + 1)
|
||||
) and
|
||||
model = ""
|
||||
or
|
||||
any(Ssa::Indirection ind).isAdditionalTaintStep(nodeFrom, nodeTo) and
|
||||
model = ""
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
|
||||
nodeTo.(FlowSummaryNode).getSummaryNode(), false, model)
|
||||
or
|
||||
// object->field conflation for content that is a `TaintInheritingContent`.
|
||||
exists(DataFlow::ContentSet f |
|
||||
readStep(nodeFrom, f, nodeTo) and
|
||||
f.getAReadContent() instanceof TaintInheritingContent
|
||||
) and
|
||||
model = ""
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint can flow in one local step from `nodeFrom` to `nodeTo` excluding
|
||||
* local data flow steps. That is, `nodeFrom` and `nodeTo` are likely to represent
|
||||
* different objects.
|
||||
*/
|
||||
cached
|
||||
predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, string model) {
|
||||
operandToInstructionTaintStep(nodeFrom.asOperand(), nodeTo.asInstruction()) and
|
||||
model = ""
|
||||
or
|
||||
modeledTaintStep(nodeFrom, nodeTo, model)
|
||||
or
|
||||
// Flow from (the indirection of) an operand of a pointer arithmetic instruction to the
|
||||
// indirection of the pointer arithmetic instruction. This provides flow from `source`
|
||||
// in `x[source]` to the result of the associated load instruction.
|
||||
exists(PointerArithmeticInstruction pai, int indirectionIndex |
|
||||
nodeHasOperand(nodeFrom, pai.getAnOperand(), pragma[only_bind_into](indirectionIndex)) and
|
||||
hasInstructionAndIndex(nodeTo, pai, indirectionIndex + 1)
|
||||
) and
|
||||
model = ""
|
||||
or
|
||||
any(Ssa::Indirection ind).isAdditionalTaintStep(nodeFrom, nodeTo) and
|
||||
model = ""
|
||||
or
|
||||
// models-as-data summarized flow
|
||||
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
|
||||
nodeTo.(FlowSummaryNode).getSummaryNode(), false, model)
|
||||
or
|
||||
// object->field conflation for content that is a `TaintInheritingContent`.
|
||||
exists(DataFlow::ContentSet f |
|
||||
readStep(nodeFrom, f, nodeTo) and
|
||||
f.getAReadContent() instanceof TaintInheritingContent
|
||||
) and
|
||||
model = ""
|
||||
}
|
||||
import Cached
|
||||
|
||||
/**
|
||||
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
|
||||
@@ -196,7 +213,7 @@ predicate modeledTaintStep(DataFlow::Node nodeIn, DataFlow::Node nodeOut, string
|
||||
// Taint flow from a pointer argument to an output, when the model specifies flow from the deref
|
||||
// to that output, but the deref is not modeled in the IR for the caller.
|
||||
exists(
|
||||
CallInstruction call, DataFlow::SideEffectOperandNode indirectArgument, Function func,
|
||||
CallInstruction call, SideEffectOperandNode indirectArgument, Function func,
|
||||
FunctionInput modelIn, FunctionOutput modelOut
|
||||
|
|
||||
indirectArgument = callInput(call, modelIn) and
|
||||
|
||||
@@ -15,6 +15,7 @@ private import TranslatedCall
|
||||
private import TranslatedStmt
|
||||
private import TranslatedFunction
|
||||
private import TranslatedGlobalVar
|
||||
private import TranslatedInitialization
|
||||
|
||||
TranslatedElement getInstructionTranslatedElement(Instruction instruction) {
|
||||
instruction = TRawInstruction(result, _)
|
||||
@@ -194,6 +195,89 @@ module Raw {
|
||||
Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
|
||||
result = getInstructionConvertedResultExpression(instruction).getUnconverted()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expression associated with the instruction `instr` that computes
|
||||
* the `Convert` instruction on the extent expression of an allocation.
|
||||
*/
|
||||
cached
|
||||
Expr getAllocationExtentConvertExpr(Instruction instr) {
|
||||
exists(TranslatedNonConstantAllocationSize tas |
|
||||
instr = tas.getInstruction(AllocationExtentConvertTag()) and
|
||||
result = tas.getExtent().getExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `ParenthesisExpr` associated with a transparent conversion
|
||||
* instruction, if any.
|
||||
*/
|
||||
cached
|
||||
ParenthesisExpr getTransparentConversionParenthesisExpr(Instruction instr) {
|
||||
exists(TranslatedTransparentConversion ttc |
|
||||
result = ttc.getExpr() and
|
||||
instr = ttc.getResult()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` belongs to a `TranslatedCoreExpr` that produces an
|
||||
* expression result. This indicates that the instruction represents a
|
||||
* definition whose result should be mapped back to the expression.
|
||||
*/
|
||||
cached
|
||||
predicate instructionProducesExprResult(Instruction instr) {
|
||||
exists(TranslatedCoreExpr tco |
|
||||
tco.getInstruction(_) = instr and
|
||||
tco.producesExprResult()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expression associated with a `StoreInstruction` generated
|
||||
* by an `TranslatedAssignOperation`.
|
||||
*/
|
||||
cached
|
||||
Expr getAssignOperationStoreExpr(StoreInstruction store) {
|
||||
exists(TranslatedAssignOperation tao |
|
||||
store = tao.getInstruction(AssignmentStoreTag()) and
|
||||
result = tao.getExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expression associated with a `StoreInstruction` generated
|
||||
* by an `TranslatedCrementOperation`.
|
||||
*/
|
||||
cached
|
||||
Expr getCrementOperationStoreExpr(StoreInstruction store) {
|
||||
exists(TranslatedCrementOperation tco |
|
||||
store = tco.getInstruction(CrementStoreTag()) and
|
||||
result = tco.getExpr()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `store` is a `StoreInstruction` that defines the temporary
|
||||
* `IRVariable` generated as part of the translation of a ternary expression.
|
||||
*/
|
||||
cached
|
||||
predicate isConditionalExprTempStore(StoreInstruction store) {
|
||||
exists(TranslatedConditionalExpr tce |
|
||||
store = tce.getInstruction(ConditionValueFalseStoreTag())
|
||||
or
|
||||
store = tce.getInstruction(ConditionValueTrueStoreTag())
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the instruction that computes the address used to initialize `v`. */
|
||||
cached
|
||||
Instruction getInitializationTargetAddress(IRVariable v) {
|
||||
exists(TranslatedVariableInitialization init |
|
||||
init.getIRVariable() = v and
|
||||
result = init.getTargetAddress()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TStageInstruction = TRawInstruction or TRawUnreachedInstruction;
|
||||
|
||||
@@ -62,26 +62,12 @@ private predicate ignoreConstantValue(Operation op) {
|
||||
op instanceof BitwiseXorExpr
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `expr` contains an address-of expression that EDG may have constant-folded.
|
||||
* We don't recurse into `sizeof` or `alignof` since they don't evaluate their operands,
|
||||
* so any address-of inside them doesn't affect actual execution.
|
||||
*/
|
||||
private predicate containsAddressOf(Expr expr) {
|
||||
expr instanceof AddressOfExpr
|
||||
or
|
||||
not expr instanceof SizeofOperator and
|
||||
not expr instanceof AlignofOperator and
|
||||
containsAddressOf(expr.getAChild())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `expr` is a constant of a type that can be replaced directly with
|
||||
* its value in the IR. This does not include address constants as we have no
|
||||
* means to express those as QL values.
|
||||
*/
|
||||
predicate isIRConstant(Expr expr) {
|
||||
not containsAddressOf(expr) and
|
||||
exists(expr.getValue()) and
|
||||
// We avoid constant folding certain operations since it's often useful to
|
||||
// mark one of those as a source in dataflow, and if the operation is
|
||||
|
||||
@@ -390,7 +390,7 @@ class TranslatedDeclStmt extends TranslatedStmt {
|
||||
|
||||
override TranslatedElement getLastChild() { result = this.getChild(this.getChildCount() - 1) }
|
||||
|
||||
private int getChildCount() { result = count(this.getDeclarationEntry(_)) }
|
||||
private int getChildCount() { result = count(int i | exists(this.getDeclarationEntry(i))) }
|
||||
|
||||
IRDeclarationEntry getIRDeclarationEntry(int index) {
|
||||
result.hasIndex(index) and
|
||||
|
||||
@@ -57,3 +57,4 @@ private import implementations.CAtlFile
|
||||
private import implementations.CAtlFileMapping
|
||||
private import implementations.CAtlTemporaryFile
|
||||
private import implementations.CRegKey
|
||||
private import implementations.WinHttp
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.dataflow.FlowSteps
|
||||
private import semmle.code.cpp.dataflow.new.DataFlow
|
||||
|
||||
/** The `WINHTTP_HEADER_NAME` class from `winhttp.h`. */
|
||||
class WinHttpHeaderName extends Class {
|
||||
WinHttpHeaderName() { this.hasGlobalName("_WINHTTP_HEADER_NAME") }
|
||||
}
|
||||
|
||||
/** The `WINHTTP_EXTENDED_HEADER` class from `winhttp.h`. */
|
||||
class WinHttpExtendedHeader extends Class {
|
||||
WinHttpExtendedHeader() { this.hasGlobalName("_WINHTTP_EXTENDED_HEADER") }
|
||||
}
|
||||
|
||||
private class WinHttpHeaderNameInheritingContent extends TaintInheritingContent,
|
||||
DataFlow::FieldContent
|
||||
{
|
||||
WinHttpHeaderNameInheritingContent() {
|
||||
this.getIndirectionIndex() = 2 and
|
||||
(
|
||||
this.getAField().getDeclaringType() instanceof WinHttpHeaderName
|
||||
or
|
||||
// The extended header looks like:
|
||||
// struct WINHTTP_EXTENDED_HEADER {
|
||||
// union { [...] };
|
||||
// union { [...] };
|
||||
// };
|
||||
// So the first declaring type is the anonymous unions, and the declaring
|
||||
// type of those anonymous unions is the `WINHTTP_EXTENDED_HEADER` struct.
|
||||
this.getAField().getDeclaringType().getDeclaringType() instanceof WinHttpExtendedHeader
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** The `URL_COMPONENTS` class from `winhttp.h`. */
|
||||
class WinHttpUrlComponents extends Class {
|
||||
WinHttpUrlComponents() { this.hasGlobalName("_WINHTTP_URL_COMPONENTS") }
|
||||
}
|
||||
|
||||
private class WinHttpUrlComponentsInheritingContent extends TaintInheritingContent,
|
||||
DataFlow::FieldContent
|
||||
{
|
||||
WinHttpUrlComponentsInheritingContent() {
|
||||
exists(Field f | f = this.getField() and f.getDeclaringType() instanceof WinHttpUrlComponents |
|
||||
if f.getType().getUnspecifiedType() instanceof PointerType
|
||||
then this.getIndirectionIndex() = 2
|
||||
else this.getIndirectionIndex() = 1
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -404,7 +404,7 @@ predicate cmpWithLinearBound(
|
||||
* For example, if `t` is a signed 32-bit type then holds if `lb` is
|
||||
* `-2^31` and `ub` is `2^31 - 1`.
|
||||
*/
|
||||
private predicate typeBounds(ArithmeticType t, float lb, float ub) {
|
||||
private predicate typeBounds0(ArithmeticType t, float lb, float ub) {
|
||||
exists(IntegralType integralType, float limit |
|
||||
integralType = t and limit = 2.pow(8 * integralType.getSize())
|
||||
|
|
||||
@@ -423,6 +423,42 @@ private predicate typeBounds(ArithmeticType t, float lb, float ub) {
|
||||
t instanceof FloatingPointType and lb = -(1.0 / 0.0) and ub = 1.0 / 0.0
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the underlying type for an enumeration `e`.
|
||||
*
|
||||
* If the enumeration does not have an explicit type we approximate it using
|
||||
* the following rules:
|
||||
* - The result type is always `signed`, and
|
||||
* - if the largest value fits in an `int` the result is `int`. Otherwise, the
|
||||
* result is `long`.
|
||||
*/
|
||||
private IntegralType getUnderlyingTypeForEnum(Enum e) {
|
||||
result = e.getExplicitUnderlyingType()
|
||||
or
|
||||
not e.hasExplicitUnderlyingType() and
|
||||
result.isSigned() and
|
||||
exists(IntType intType |
|
||||
if max(e.getAnEnumConstant().getValue().toFloat()) >= 2.pow(8 * intType.getSize() - 1)
|
||||
then result instanceof LongType
|
||||
else result = intType
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `lb` and `ub` are the lower and upper bounds of the unspecified
|
||||
* type `t`.
|
||||
*
|
||||
* For example, if `t` is a signed 32-bit type then holds if `lb` is
|
||||
* `-2^31` and `ub` is `2^31 - 1`.
|
||||
*
|
||||
* Unlike `typeBounds0`, this predicate also handles `Enum` types.
|
||||
*/
|
||||
private predicate typeBounds(Type t, float lb, float ub) {
|
||||
typeBounds0(t, lb, ub)
|
||||
or
|
||||
typeBounds0(getUnderlyingTypeForEnum(t), lb, ub)
|
||||
}
|
||||
|
||||
private Type stripReference(Type t) {
|
||||
if t instanceof ReferenceType then result = t.(ReferenceType).getBaseType() else result = t
|
||||
}
|
||||
|
||||
@@ -512,8 +512,8 @@ private module BoundsEstimate {
|
||||
*/
|
||||
float getBoundsLimit() {
|
||||
// This limit is arbitrary, but low enough that it prevents timeouts on
|
||||
// specific observed customer databases (and the in the tests).
|
||||
result = 2.0.pow(40)
|
||||
// specific observed customer databases (and in the tests).
|
||||
result = 2.0.pow(29)
|
||||
}
|
||||
|
||||
/** Gets the maximum number of bounds possible for `t` when widening is used. */
|
||||
@@ -552,34 +552,47 @@ private module BoundsEstimate {
|
||||
private float nrOfBoundsPhiGuard(RangeSsaDefinition def, StackVariable v) {
|
||||
// If we have
|
||||
//
|
||||
// if (x < c) { e1 } else { e2 }
|
||||
// e3
|
||||
//
|
||||
// then `{ e1 }` and `{ e2 }` are both guard phi nodes guarded by `x < c`.
|
||||
// The range analysis propagates bounds on `x` into both branches, filtered
|
||||
// by the condition. In this case all lower bounds flow to `{ e1 }` and only
|
||||
// lower bounds that are smaller than `c` flow to `{ e2 }`.
|
||||
//
|
||||
// The largest number of bounds possible for `e3` is the number of bounds on `x` plus
|
||||
// one. This happens when all bounds flow from `x` to `e1` to `e3` and the
|
||||
// bound `c` can flow to `e2` to `e3`.
|
||||
//
|
||||
// We want to optimize our bounds estimate for `e3`, as that is the estimate
|
||||
// that can continue propagating forward. We don't know how the existing
|
||||
// bounds will be split between the different branches. That depends on
|
||||
// whether the range analysis is tracking lower bounds or upper bounds, and
|
||||
// on the meaning of the condition.
|
||||
//
|
||||
// As a heuristic we divide the number of bounds on `x` by 2 to "average"
|
||||
// the effect of the condition and add 1 to account for the bound from the
|
||||
// condition itself. This will approximate estimates inside the branches,
|
||||
// but will give a good estimate after the branches are merged.
|
||||
//
|
||||
// This also handles cases such as this one
|
||||
//
|
||||
// if (x < c) { e1 }
|
||||
// e2
|
||||
// e3
|
||||
//
|
||||
// then `e2` is both a guard phi node (guarded by `x < c`) and a normal
|
||||
// phi node (control is merged after the `if` statement).
|
||||
//
|
||||
// Assume `x` has `n` bounds. Then `n` bounds are propagated to the guard
|
||||
// phi node `{ e1 }` and, since `{ e1 }` is input to `e2` as a normal phi
|
||||
// node, `n` bounds are propagated to `e2`. If we also propagate the `n`
|
||||
// bounds to `e2` as a guard phi node, then we square the number of
|
||||
// bounds.
|
||||
//
|
||||
// However in practice `x < c` is going to cut down the number of bounds:
|
||||
// The tracked bounds can't flow to both branches as that would require
|
||||
// them to simultaneously be greater and smaller than `c`. To approximate
|
||||
// this better, the contribution from a guard phi node that is also a
|
||||
// normal phi node is 1.
|
||||
exists(def.getAPhiInput(v)) and
|
||||
isGuardPhiWithBound(def, v, _) and
|
||||
result = 1
|
||||
or
|
||||
not exists(def.getAPhiInput(v)) and
|
||||
// If there's different `access`es, then they refer to the same variable
|
||||
// with the same lower bounds. Hence adding these guards make no sense (the
|
||||
// implementation will take the union, but they'll be removed by
|
||||
// deduplication). Hence we use `max` as an approximation.
|
||||
result =
|
||||
max(VariableAccess access | isGuardPhiWithBound(def, v, access) | nrOfBoundsExpr(access))
|
||||
// where `e3` is both a guard phi node (guarded by `x < c`) and a normal
|
||||
// phi node (control is merged after the `if` statement). Here half of the
|
||||
// bounds flow into the branch and then to `e3` as a normal phi node and the
|
||||
// "other" half flow from the condition to `e3` as a guard phi node.
|
||||
exists(float varBounds |
|
||||
// If there's different `access`es, then they refer to the same
|
||||
// variable with the same lower bounds. Hence adding these guards makes no
|
||||
// sense (the implementation will take the union, but they'll be removed by
|
||||
// deduplication). Hence we use `max` as an approximation.
|
||||
varBounds =
|
||||
max(VariableAccess access | isGuardPhiWithBound(def, v, access) | nrOfBoundsExpr(access)) and
|
||||
result = (varBounds + 1) / 2
|
||||
)
|
||||
or
|
||||
def.isPhiNode(v) and
|
||||
not isGuardPhiWithBound(def, v, _) and
|
||||
@@ -2180,6 +2193,16 @@ module SimpleRangeAnalysisInternal {
|
||||
|
||||
/** Gets the estimate of the number of bounds for `e`. */
|
||||
float estimateNrOfBounds(Expr e) { result = BoundsEstimate::nrOfBoundsExpr(e) }
|
||||
|
||||
/** Counts the numbers of lower bounds that are computed internally for `e`. */
|
||||
float countNrOfLowerBounds(Expr e) {
|
||||
result = strictcount(float lb | lb = getLowerBoundsImpl(e) | lb)
|
||||
}
|
||||
|
||||
/** Counts the numbers of upper bounds that are computed internally for `e`. */
|
||||
float countNrOfUpperBounds(Expr e) {
|
||||
result = strictcount(float ub | ub = getUpperBoundsImpl(e) | ub)
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides predicates for debugging the simple range analysis library. */
|
||||
@@ -2208,7 +2231,7 @@ private module Debug {
|
||||
*/
|
||||
predicate countGetLowerBoundsImpl(Expr e, int n) {
|
||||
e = getRelevantLocatable() and
|
||||
n = strictcount(float lb | lb = getLowerBoundsImpl(e) | lb)
|
||||
n = SimpleRangeAnalysisInternal::countNrOfLowerBounds(e)
|
||||
}
|
||||
|
||||
float debugNrOfBounds(Expr e) {
|
||||
|
||||
@@ -236,6 +236,62 @@ extractor_version(
|
||||
string frontend_version: string ref
|
||||
)
|
||||
|
||||
/**
|
||||
* Gives the TRAP filename that `trap` is associated with.
|
||||
* For debugging only.
|
||||
*/
|
||||
trap_filename(
|
||||
int trap: @trap,
|
||||
string filename: string ref
|
||||
);
|
||||
|
||||
/**
|
||||
* Gives the tag name for `tag`.
|
||||
* For debugging only.
|
||||
*/
|
||||
tag_name(
|
||||
int tag: @tag,
|
||||
string name: string ref
|
||||
);
|
||||
|
||||
@trap_or_tag = @tag | @trap;
|
||||
|
||||
/**
|
||||
* Gives the name for the source file.
|
||||
*/
|
||||
source_file_name(
|
||||
int sf: @source_file,
|
||||
string name: string ref
|
||||
);
|
||||
|
||||
/**
|
||||
* In `build-mode: none` overlay mode, indicates that `source_file`
|
||||
* (`/path/to/foo.c`) uses the TRAP file `trap_file`; i.e. it is the
|
||||
* TRAP file corresponding to `foo.c`, something it transitively
|
||||
* includes, or a template instantiation it transitively uses.
|
||||
*/
|
||||
source_file_uses_trap(
|
||||
int source_file: @source_file ref,
|
||||
int trap_file: @trap ref
|
||||
);
|
||||
|
||||
/**
|
||||
* In `build-mode: none` overlay mode, indicates that the TRAP file
|
||||
* `trap_file` uses tag `tag`.
|
||||
*/
|
||||
trap_uses_tag(
|
||||
int trap_file: @trap ref,
|
||||
int tag: @tag ref
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds if there is a definition of `element` in TRAP file or tag `t`.
|
||||
*/
|
||||
in_trap_or_tag(
|
||||
int element: @element ref,
|
||||
int t: @trap_or_tag ref
|
||||
);
|
||||
|
||||
pch_uses(
|
||||
int pch: @pch ref,
|
||||
int compilation: @compilation ref,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
class Element extends @element {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Trap extends @trap {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from Element e, Trap trap
|
||||
where in_trap(e, trap)
|
||||
select e, trap
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,22 @@
|
||||
newtype TSourceFile = MkSourceFile(string name) { source_file_uses_trap(name, _) }
|
||||
|
||||
module FreshSourceFile = QlBuiltins::NewEntity<TSourceFile>;
|
||||
|
||||
class SourceFile extends FreshSourceFile::EntityId {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Trap extends @trap {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
query predicate mk_source_file_name(SourceFile source_file, string name) {
|
||||
source_file = FreshSourceFile::map(MkSourceFile(name))
|
||||
}
|
||||
|
||||
query predicate mk_source_file_uses_trap(SourceFile source_file, Trap trap) {
|
||||
exists(string name |
|
||||
source_file_uses_trap(name, trap) and
|
||||
mk_source_file_name(source_file, name)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
description: Add source_file_name
|
||||
compatibility: backwards
|
||||
source_file_uses_trap.rel: run source_files.ql mk_source_file_uses_trap
|
||||
source_file_name.rel: run source_files.ql mk_source_file_name
|
||||
in_trap.rel: delete
|
||||
in_trap_or_tag.rel: run in_trap_or_tag.ql
|
||||
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 trap_filename, source_file_uses_trap and in_trap relations
|
||||
compatibility: full
|
||||
@@ -1,3 +1,11 @@
|
||||
## 1.5.12
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.5.11
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.5.10
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -308,3 +308,37 @@ private module PossibleYearArithmeticOperationCheckConfig implements DataFlow::C
|
||||
|
||||
module PossibleYearArithmeticOperationCheckFlow =
|
||||
TaintTracking::Global<PossibleYearArithmeticOperationCheckConfig>;
|
||||
|
||||
/**
|
||||
* A time conversion function where either
|
||||
* 1) an incorrect leap year date would result in an error that can be checked from the return value or
|
||||
* 2) an incorrect leap year date is auto corrected (no checks required)
|
||||
*/
|
||||
class TimeConversionFunction extends Function {
|
||||
boolean autoLeapYearCorrecting;
|
||||
|
||||
TimeConversionFunction() {
|
||||
autoLeapYearCorrecting = false and
|
||||
(
|
||||
this.getName() =
|
||||
[
|
||||
"FileTimeToSystemTime", "SystemTimeToFileTime", "SystemTimeToTzSpecificLocalTime",
|
||||
"SystemTimeToTzSpecificLocalTimeEx", "TzSpecificLocalTimeToSystemTime",
|
||||
"TzSpecificLocalTimeToSystemTimeEx", "RtlLocalTimeToSystemTime",
|
||||
"RtlTimeToSecondsSince1970", "_mkgmtime", "SetSystemTime", "VarUdateFromDate", "from_tm"
|
||||
]
|
||||
or
|
||||
// Matches all forms of GetDateFormat, e.g. GetDateFormatA/W/Ex
|
||||
this.getName().matches("GetDateFormat%")
|
||||
)
|
||||
or
|
||||
autoLeapYearCorrecting = true and
|
||||
this.getName() =
|
||||
["mktime", "_mktime32", "_mktime64", "SystemTimeToVariantTime", "VariantTimeToSystemTime"]
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the function is expected to auto convert a bad leap year date.
|
||||
*/
|
||||
predicate isAutoLeapYearCorrecting() { autoLeapYearCorrecting = true }
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @name Year field changed using an arithmetic operation without checking for leap year
|
||||
* @description A field that represents a year is being modified by an arithmetic operation, but no proper check for leap years can be detected afterwards.
|
||||
* @kind problem
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @id cpp/leap-year/unchecked-after-arithmetic-year-modification
|
||||
* @precision medium
|
||||
@@ -11,49 +11,844 @@
|
||||
|
||||
import cpp
|
||||
import LeapYear
|
||||
import semmle.code.cpp.controlflow.IRGuards
|
||||
|
||||
from Variable var, LeapYearFieldAccess yfa
|
||||
where
|
||||
exists(VariableAccess va |
|
||||
yfa.getQualifier() = va and
|
||||
var.getAnAccess() = va and
|
||||
// The year is modified with an arithmetic operation. Avoid values that are likely false positives
|
||||
yfa.isModifiedByArithmeticOperationNotForNormalization() and
|
||||
// Avoid false positives
|
||||
not (
|
||||
// If there is a local check for leap year after the modification
|
||||
exists(LeapYearFieldAccess yfacheck |
|
||||
yfacheck.getQualifier() = var.getAnAccess() and
|
||||
yfacheck.isUsedInCorrectLeapYearCheck() and
|
||||
yfacheck.getBasicBlock() = yfa.getBasicBlock().getASuccessor*()
|
||||
)
|
||||
/**
|
||||
* Functions whose operations should never be considered a
|
||||
* source or sink of a dangerous leap year operation.
|
||||
* The general concept is to add conversion functions
|
||||
* that convert one time type to another. Often
|
||||
* other ignorable operation heuristics will filter these,
|
||||
* but some cases, the simplest approach is to simply filter
|
||||
* the function entirely.
|
||||
* Note that flow through these functions should still be allowed
|
||||
* we just cannot start or end flow from an operation to a
|
||||
* year assignment in one of these functions.
|
||||
*/
|
||||
class IgnorableFunction extends Function {
|
||||
IgnorableFunction() {
|
||||
// arithmetic in known time conversion functions may look like dangerous operations
|
||||
// we assume all known time conversion functions are safe.
|
||||
this instanceof TimeConversionFunction
|
||||
or
|
||||
// Helper utility in postgres with string time conversions
|
||||
this.getName() = "DecodeISO8601Interval"
|
||||
or
|
||||
// helper utility for date conversions in qtbase
|
||||
this.getName() = "adjacentDay"
|
||||
or
|
||||
// Windows API function that does timezone conversions
|
||||
this.getName().matches("%SystemTimeToTzSpecificLocalTime%")
|
||||
or
|
||||
// Windows APIs that do time conversions
|
||||
this.getName().matches("%localtime%\\_s%")
|
||||
or
|
||||
// Windows APIs that do time conversions
|
||||
this.getName().matches("%SpecificLocalTimeToSystemTime%")
|
||||
or
|
||||
// postgres function for diffing timestamps, date for leap year
|
||||
// is not applicable.
|
||||
this.getName().toLowerCase().matches("%timestamp%age%")
|
||||
or
|
||||
// Reading byte streams often involves operations of some base, but that's
|
||||
// not a real source of leap year issues.
|
||||
this.getName().toLowerCase().matches("%read%bytes%")
|
||||
or
|
||||
// A postgres function for local time conversions
|
||||
// conversion operations (from one time structure to another) are generally ignorable
|
||||
this.getName() = "localsub"
|
||||
or
|
||||
// Indication of a calendar not applicable to
|
||||
// gregorian leap year, e.g., Hijri, Persian, Hebrew
|
||||
this.getName().toLowerCase().matches("%hijri%")
|
||||
or
|
||||
this.getFile().getBaseName().toLowerCase().matches("%hijri%")
|
||||
or
|
||||
this.getName().toLowerCase().matches("%persian%")
|
||||
or
|
||||
this.getFile().getBaseName().toLowerCase().matches("%persian%")
|
||||
or
|
||||
this.getName().toLowerCase().matches("%hebrew%")
|
||||
or
|
||||
this.getFile().getBaseName().toLowerCase().matches("%hebrew%")
|
||||
or
|
||||
// misc. from string/char converters heuristic
|
||||
this.getName()
|
||||
.toLowerCase()
|
||||
.matches(["%char%to%", "%string%to%", "%from%char%", "%from%string%"])
|
||||
or
|
||||
// boost's gregorian.cpp has year manipulations that are checked in complex ways.
|
||||
// ignore the entire file as a source or sink.
|
||||
this.getFile().getAbsolutePath().toLowerCase().matches("%boost%gregorian.cpp%")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The set of expressions which are ignorable; either because they seem to not be part of a year mutation,
|
||||
* or because they seem to be a conversion pattern of mapping date scalars.
|
||||
*/
|
||||
abstract class IgnorableOperation extends Expr { }
|
||||
|
||||
class IgnorableExprRem extends IgnorableOperation instanceof RemExpr { }
|
||||
|
||||
/**
|
||||
* An operation with 10, 100, 1000, 10000 as an operand is often a sign of conversion
|
||||
* or atoi.
|
||||
*/
|
||||
class IgnorableExpr10MultipleComponent extends IgnorableOperation {
|
||||
IgnorableExpr10MultipleComponent() {
|
||||
this.(Operation).getAnOperand().getValue().toInt() in [10, 100, 1000, 10000]
|
||||
or
|
||||
exists(AssignOperation a | a.getRValue() = this |
|
||||
a.getRValue().getValue().toInt() in [10, 100, 1000, 10000]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An operation involving a sub expression with char literal `48`, ignore as a likely string conversion. For example: `X - '0'`
|
||||
*/
|
||||
class IgnorableExpr48Mapping extends IgnorableOperation {
|
||||
IgnorableExpr48Mapping() {
|
||||
this.(SubExpr).getRightOperand().getValue().toInt() = 48
|
||||
or
|
||||
exists(AssignSubExpr e | e.getRValue() = this | e.getRValue().getValue().toInt() = 48)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A binary or arithmetic operation whereby one of the components is textual or a string.
|
||||
*/
|
||||
class IgnorableCharLiteralArithmetic extends IgnorableOperation {
|
||||
IgnorableCharLiteralArithmetic() {
|
||||
this.(BinaryArithmeticOperation).getAnOperand() instanceof TextLiteral
|
||||
or
|
||||
this instanceof TextLiteral and
|
||||
any(AssignArithmeticOperation arith).getRValue() = this
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constants often used in date conversions (from one date data type to another)
|
||||
* Numerous examples exist, like 1900 or 2000 that convert years from one
|
||||
* representation to another.
|
||||
* Also '0' is sometimes observed as an atoi style conversion.
|
||||
*/
|
||||
bindingset[c]
|
||||
predicate isLikelyConversionConstant(int c) {
|
||||
exists(int i | i = c.abs() |
|
||||
i =
|
||||
[
|
||||
146097, // days in 400-year Gregorian cycle
|
||||
36524, // days in 100-year Gregorian subcycle
|
||||
1461, // days in 4-year cycle (incl. 1 leap)
|
||||
32044, // Fliegel-van Flandern JDN epoch shift
|
||||
1721425, // JDN of 0001-01-01 (Gregorian)
|
||||
1721119, // alt epoch offset
|
||||
2400000, // MJD -> JDN conversion
|
||||
2400001, // alt MJD -> JDN conversion
|
||||
2141, // fixed-point month/day extraction
|
||||
65536, // observed in some conversions
|
||||
7834, // observed in some conversions
|
||||
256, // observed in some conversions
|
||||
292275056, // qdatetime.h Qt Core year range first year constant
|
||||
292278994, // qdatetime.h Qt Core year range last year constant
|
||||
1601, // Windows FILETIME epoch start year
|
||||
1970, // Unix epoch start year
|
||||
70, // Unix epoch start year short form
|
||||
1899, // Observed in uses with 1900 to address off by one scenarios
|
||||
1900, // Used when converting a 2 digit year
|
||||
2000, // Used when converting a 2 digit year
|
||||
1400, // Hijri base year, used when converting a 2 digit year
|
||||
1980, // FAT filesystem epoch start year
|
||||
227013, // constant observed for Hirji year conversion, and Hirji years are not applicable for gregorian leap year
|
||||
10631, // constant observed for Hirji year conversion, and Hirji years are not applicable for gregorian leap year,
|
||||
80, // 1980/01/01 is the start of the epoch on DOS
|
||||
0
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* An `isLikelyConversionConstant` constant indicates conversion that is ignorable, e.g.,
|
||||
* julian to gregorian conversion or conversions from linux time structs
|
||||
* that start at 1900, etc.
|
||||
*/
|
||||
class IgnorableConstantArithmetic extends IgnorableOperation {
|
||||
IgnorableConstantArithmetic() {
|
||||
exists(int i | isLikelyConversionConstant(i) |
|
||||
this.(Operation).getAnOperand().getValue().toInt() = i
|
||||
or
|
||||
// If there is a data flow from the variable that was modified to a function that seems to check for leap year
|
||||
exists(VariableAccess source, ChecksForLeapYearFunctionCall fc |
|
||||
source = var.getAnAccess() and
|
||||
LeapYearCheckFlow::flow(DataFlow::exprNode(source), DataFlow::exprNode(fc.getAnArgument()))
|
||||
)
|
||||
or
|
||||
// If there is a data flow from the field that was modified to a function that seems to check for leap year
|
||||
exists(VariableAccess vacheck, YearFieldAccess yfacheck, ChecksForLeapYearFunctionCall fc |
|
||||
vacheck = var.getAnAccess() and
|
||||
yfacheck.getQualifier() = vacheck and
|
||||
LeapYearCheckFlow::flow(DataFlow::exprNode(yfacheck), DataFlow::exprNode(fc.getAnArgument()))
|
||||
)
|
||||
or
|
||||
// If there is a successor or predecessor that sets the month = 1
|
||||
exists(MonthFieldAccess mfa, AssignExpr ae |
|
||||
mfa.getQualifier() = var.getAnAccess() and
|
||||
mfa.isModified() and
|
||||
(
|
||||
mfa.getBasicBlock() = yfa.getBasicBlock().getASuccessor*() or
|
||||
yfa.getBasicBlock() = mfa.getBasicBlock().getASuccessor+()
|
||||
) and
|
||||
ae = mfa.getEnclosingElement() and
|
||||
ae.getAnOperand().getValue().toInt() = 1
|
||||
exists(AssignArithmeticOperation a | this = a.getRValue() |
|
||||
a.getRValue().getValue().toInt() = i
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// If a unary minus assume it is some sort of conversion
|
||||
class IgnorableUnaryMinus extends IgnorableOperation {
|
||||
IgnorableUnaryMinus() {
|
||||
this instanceof UnaryMinusExpr
|
||||
or
|
||||
this.(Operation).getAnOperand() instanceof UnaryMinusExpr
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An argument to a function is ignorable if the function that is called is an ignored function
|
||||
*/
|
||||
class OperationAsArgToIgnorableFunction extends IgnorableOperation {
|
||||
OperationAsArgToIgnorableFunction() {
|
||||
exists(Call c |
|
||||
c.getAnArgument().getAChild*() = this and
|
||||
c.getTarget() instanceof IgnorableFunction
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A binary operation on two literals means the result is constant/known
|
||||
* and the operation is basically ignorable (it's not a real operation but
|
||||
* probably one visual simplicity what it means).
|
||||
*/
|
||||
class ConstantBinaryArithmeticOperation extends IgnorableOperation, BinaryArithmeticOperation {
|
||||
ConstantBinaryArithmeticOperation() {
|
||||
this.getLeftOperand() instanceof Literal and
|
||||
this.getRightOperand() instanceof Literal
|
||||
}
|
||||
}
|
||||
|
||||
class IgnorableBinaryBitwiseOperation extends IgnorableOperation instanceof BinaryBitwiseOperation {
|
||||
}
|
||||
|
||||
class IgnorableUnaryBitwiseOperation extends IgnorableOperation instanceof UnaryBitwiseOperation { }
|
||||
|
||||
class IgnorableAssignmentBitwiseOperation extends IgnorableOperation instanceof AssignBitwiseOperation
|
||||
{ }
|
||||
|
||||
/**
|
||||
* An arithmetic operation where one of the operands is a pointer or char type, ignore it
|
||||
*/
|
||||
class IgnorablePointerOrCharArithmetic extends IgnorableOperation {
|
||||
IgnorablePointerOrCharArithmetic() {
|
||||
this instanceof BinaryArithmeticOperation and
|
||||
exists(Expr op | op = this.(BinaryArithmeticOperation).getAnOperand() |
|
||||
op.getUnspecifiedType() instanceof PointerType
|
||||
or
|
||||
op.getUnspecifiedType() instanceof CharType
|
||||
or
|
||||
// Operations on calls to functions that accept char or char*
|
||||
op.(Call).getAnArgument().getUnspecifiedType().stripType() instanceof CharType
|
||||
or
|
||||
// Operations on calls to functions named like "strlen", "wcslen", etc
|
||||
// NOTE: workaround for cases where the wchar_t type is not a char, but an unsigned short
|
||||
// unclear if there is a best way to filter cases like these out based on type info.
|
||||
op.(Call).getTarget().getName().matches("%len%")
|
||||
)
|
||||
or
|
||||
exists(AssignArithmeticOperation a | a.getRValue() = this |
|
||||
exists(Expr op | op = a.getAnOperand() |
|
||||
op.getUnspecifiedType() instanceof PointerType
|
||||
or
|
||||
op.getUnspecifiedType() instanceof CharType
|
||||
or
|
||||
// Operations on calls to functions that accept char or char*
|
||||
op.(Call).getAnArgument().getUnspecifiedType().stripType() instanceof CharType
|
||||
)
|
||||
or
|
||||
// Operations on calls to functions named like "strlen", "wcslen", etc
|
||||
// for example `strlen(foo) + bar`
|
||||
this.(BinaryArithmeticOperation).getAnOperand().(Call).getTarget().getName().matches("%len%")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds for an expression that is an add or similar operation that could flow to a Year field.
|
||||
*/
|
||||
predicate isOperationSourceCandidate(Expr e) {
|
||||
not e instanceof IgnorableOperation and
|
||||
exists(Function f |
|
||||
f = e.getEnclosingFunction() and
|
||||
not f instanceof IgnorableFunction
|
||||
) and
|
||||
(
|
||||
e instanceof SubExpr
|
||||
or
|
||||
e instanceof AddExpr
|
||||
or
|
||||
e instanceof CrementOperation
|
||||
or
|
||||
e instanceof AssignSubExpr
|
||||
or
|
||||
e instanceof AssignAddExpr
|
||||
)
|
||||
select yfa,
|
||||
"Field $@ on variable $@ has been modified, but no appropriate check for LeapYear was found.",
|
||||
yfa.getTarget(), yfa.getTarget().toString(), var, var.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow that tracks an ignorable operation (such as a bitwise operation) to an operation source, so we may disqualify it.
|
||||
*/
|
||||
module IgnorableOperationToOperationSourceCandidateConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node n) { n.asExpr() instanceof IgnorableOperation }
|
||||
|
||||
predicate isSink(DataFlow::Node n) { isOperationSourceCandidate(n.asExpr()) }
|
||||
|
||||
// looking for sources and sinks in the same function
|
||||
DataFlow::FlowFeature getAFeature() {
|
||||
result instanceof DataFlow::FeatureEqualSourceSinkCallContext
|
||||
}
|
||||
}
|
||||
|
||||
module IgnorableOperationToOperationSourceCandidateFlow =
|
||||
TaintTracking::Global<IgnorableOperationToOperationSourceCandidateConfig>;
|
||||
|
||||
/**
|
||||
* The set of all expressions which is a candidate expression and also does not flow from to to some ignorable expression (eg. bitwise op)
|
||||
* ```
|
||||
* a = something <<< 2;
|
||||
* myDate.year = a + 1; // invalid
|
||||
* ...
|
||||
* a = someDate.year + 1;
|
||||
* myDate.year = a; // valid
|
||||
* ```
|
||||
*/
|
||||
class OperationSource extends Expr {
|
||||
OperationSource() {
|
||||
isOperationSourceCandidate(this) and
|
||||
// If the candidate came from an ignorable operation, ignore the candidate
|
||||
// NOTE: we cannot easily flow the candidate to an ignorable operation as that can
|
||||
// be tricky in practice, e.g., a mod operation on a year would be part of a leap year check
|
||||
// but a mod operation ending in a year is more indicative of something to ignore (a conversion)
|
||||
not exists(IgnorableOperationToOperationSourceCandidateFlow::PathNode sink |
|
||||
sink.getNode().asExpr() = this and
|
||||
sink.isSink()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class YearFieldAssignmentNode extends DataFlow::Node {
|
||||
YearFieldAccess access;
|
||||
|
||||
YearFieldAssignmentNode() {
|
||||
exists(Function f |
|
||||
f = this.getEnclosingCallable().getUnderlyingCallable() and not f instanceof IgnorableFunction
|
||||
) and
|
||||
(
|
||||
this.asDefinition().(Assignment).getLValue() = access
|
||||
or
|
||||
this.asDefinition().(CrementOperation).getOperand() = access
|
||||
or
|
||||
exists(Call c | c.getAnArgument() = access and this.asDefiningArgument() = access)
|
||||
or
|
||||
exists(Call c, AddressOfExpr aoe |
|
||||
c.getAnArgument() = aoe and
|
||||
aoe.getOperand() = access and
|
||||
this.asDefiningArgument() = aoe
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
YearFieldAccess getYearFieldAccess() { result = access }
|
||||
}
|
||||
|
||||
/**
|
||||
* A DataFlow configuration for identifying flows from an identified source
|
||||
* to the Year field of a date object.
|
||||
*/
|
||||
module OperationToYearAssignmentConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node n) { n.asExpr() instanceof OperationSource }
|
||||
|
||||
predicate isSink(DataFlow::Node n) {
|
||||
n instanceof YearFieldAssignmentNode and
|
||||
not isYearModifiedWithCheck(n) and
|
||||
not isControlledByMonthEqualityCheckNonFebruary(n.asExpr())
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node n) {
|
||||
exists(ArrayExpr arr | arr.getArrayOffset() = n.asExpr())
|
||||
or
|
||||
n.getType().getUnspecifiedType() instanceof PointerType
|
||||
or
|
||||
n.getType().getUnspecifiedType() instanceof CharType
|
||||
or
|
||||
// If a type resembles "string" ignore flow (likely string conversion, currently ignored)
|
||||
n.getType().getUnspecifiedType().stripType().getName().toLowerCase().matches("%string%")
|
||||
or
|
||||
n.asExpr() instanceof IgnorableOperation
|
||||
or
|
||||
// Flowing into variables that indicate likely non-gregorian years are barriers
|
||||
// e.g., names similar to hijri, persian, lunar, chinese, hebrew, etc.
|
||||
exists(Variable v |
|
||||
v.getName()
|
||||
.toLowerCase()
|
||||
.matches(["%hijri%", "%persian%", "%lunar%", "%chinese%", "%hebrew%"]) and
|
||||
v.getAnAccess() = [n.asIndirectExpr(), n.asExpr()]
|
||||
)
|
||||
or
|
||||
isLeapYearCheckSink(n)
|
||||
or
|
||||
// this is a bit of a hack to address cases where a year is normalized and checked, but the
|
||||
// normalized year is never itself assigned to the final year struct
|
||||
// isLeapYear(getCivilYear(year))
|
||||
// struct.year = year
|
||||
// This is assuming a user would have done this all on one line though.
|
||||
// setting a variable for the conversion and passing that separately would be more difficult to track
|
||||
// considering this approach good enough for current observed false positives
|
||||
exists(Expr arg |
|
||||
isLeapYearCheckCall(_, arg) and arg.getAChild*() = [n.asExpr(), n.asIndirectExpr()]
|
||||
)
|
||||
or
|
||||
// If as the flow progresses, the value holding a dangerous operation result
|
||||
// is apparently being passed by address to some function, it is more than likely
|
||||
// intended to be modified, and therefore, the definition is killed.
|
||||
exists(Call c | c.getAnArgument().(AddressOfExpr).getAnOperand() = n.asIndirectExpr())
|
||||
}
|
||||
|
||||
/** Block flow out of an operation source to get the "closest" operation to the sink */
|
||||
predicate isBarrierIn(DataFlow::Node n) { isSource(n) }
|
||||
|
||||
predicate isBarrierOut(DataFlow::Node n) { isSink(n) }
|
||||
}
|
||||
|
||||
module OperationToYearAssignmentFlow = TaintTracking::Global<OperationToYearAssignmentConfig>;
|
||||
|
||||
predicate isLeapYearCheckSink(DataFlow::Node sink) {
|
||||
exists(LeapYearGuardCondition lgc |
|
||||
lgc.checkedYearAccess() = [sink.asExpr(), sink.asIndirectExpr()]
|
||||
)
|
||||
or
|
||||
isLeapYearCheckCall(_, [sink.asExpr(), sink.asIndirectExpr()])
|
||||
}
|
||||
|
||||
predicate yearAssignmentToCheckCommonSteps(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
// flow from a YearFieldAccess to the qualifier
|
||||
node2.asExpr() = node1.asExpr().(YearFieldAccess).getQualifier*()
|
||||
or
|
||||
// getting the 'access' can be tricky at definitions (assignments especially)
|
||||
// as dataflow uses asDefinition not asExpr.
|
||||
// the YearFieldAssignmentNode holds the access in these cases
|
||||
node1.(YearFieldAssignmentNode).getYearFieldAccess().getQualifier() = node2.asExpr()
|
||||
or
|
||||
// flow from a year access qualifier to a year field
|
||||
exists(YearFieldAccess yfa | node2.asExpr() = yfa and node1.asExpr() = yfa.getQualifier())
|
||||
or
|
||||
node1.(YearFieldAssignmentNode).getYearFieldAccess().getQualifier() = node2.asExpr()
|
||||
or
|
||||
// Pass through any intermediate struct
|
||||
exists(Assignment a |
|
||||
a.getRValue() = node1.asExpr() and
|
||||
node2.asExpr() = a.getLValue().(YearFieldAccess).getQualifier*()
|
||||
)
|
||||
or
|
||||
// in cases of t.year = x and the value of x is checked, but the year t.year isn't directly checked
|
||||
// flow from a year assignment node to an RHS if it is an assignment
|
||||
// e.g.,
|
||||
// t.year = x;
|
||||
// isLeapYear(x);
|
||||
// --> at this point there is no flow of t.year to a check, but only its raw value
|
||||
// To detect the flow of 'x' to the isLeapYear check,
|
||||
// flow from t.year to 'x' (at assignment, t.year = x, flow to the RHS to track use-use flow of x)
|
||||
exists(YearFieldAssignmentNode yfan |
|
||||
node1 = yfan and
|
||||
node2.asExpr() = yfan.asDefinition().(Assignment).getRValue()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A flow configuration from a Year field access to some Leap year check or guard
|
||||
*/
|
||||
module YearAssignmentToLeapYearCheckConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof YearFieldAssignmentNode }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { isLeapYearCheckSink(sink) }
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
yearAssignmentToCheckCommonSteps(node1, node2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforcing the check must occur in the same call context as the source,
|
||||
* i.e., do not return from the source function and check in a caller.
|
||||
*/
|
||||
DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSourceCallContext }
|
||||
}
|
||||
|
||||
module YearAssignmentToLeapYearCheckFlow =
|
||||
TaintTracking::Global<YearAssignmentToLeapYearCheckConfig>;
|
||||
|
||||
/** Does there exist a flow from the given YearFieldAccess to a Leap Year check or guard? */
|
||||
predicate isYearModifiedWithCheck(YearFieldAssignmentNode n) {
|
||||
exists(YearAssignmentToLeapYearCheckFlow::PathNode src |
|
||||
src.isSource() and
|
||||
src.getNode() = n
|
||||
)
|
||||
or
|
||||
// If the time flows to a time conversion whose value/result is checked,
|
||||
// assume the leap year is being handled.
|
||||
exists(YearAssignmentToCheckedTimeConversionFlow::PathNode timeQualSrc |
|
||||
timeQualSrc.isSource() and
|
||||
timeQualSrc.getNode() = n
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression which checks the value of a Month field `a->month == 1`.
|
||||
*/
|
||||
class MonthEqualityCheck extends EqualityOperation {
|
||||
MonthEqualityCheck() { this.getAnOperand() instanceof MonthFieldAccess }
|
||||
|
||||
Expr getExprCompared() {
|
||||
exists(Expr e |
|
||||
e = this.getAnOperand() and
|
||||
not e instanceof MonthFieldAccess and
|
||||
result = e
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
final class FinalMonthEqualityCheck = MonthEqualityCheck;
|
||||
|
||||
class MonthEqualityCheckGuard extends GuardCondition, FinalMonthEqualityCheck { }
|
||||
|
||||
/**
|
||||
* Verifies if the expression is guarded by a check on the Month property of a date struct, that is NOT February.
|
||||
*/
|
||||
bindingset[e]
|
||||
pragma[inline_late]
|
||||
predicate isControlledByMonthEqualityCheckNonFebruary(Expr e) {
|
||||
exists(MonthEqualityCheckGuard monthGuard, Expr compared |
|
||||
monthGuard.controls(e.getBasicBlock(), true) and
|
||||
compared = monthGuard.getExprCompared() and
|
||||
not compared.getValue().toInt() = 2
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Flow from a year field access to a time conversion function
|
||||
* that auto converts feb29 in non-leap year, or through a conversion function that doesn't
|
||||
* auto convert to a sanity check guard of the result for error conditions.
|
||||
*/
|
||||
module YearAssignmentToCheckedTimeConversionConfig implements DataFlow::StateConfigSig {
|
||||
// Flow state tracks if flow goes through a known time conversion function
|
||||
// see `TimeConversionFunction`.
|
||||
// A valid check with a time conversion function is either the case:
|
||||
// 1) the year flows into a time conversion function, and the time conversion function's result is checked or
|
||||
// 2) the year flows into a time conversion function that auto corrects for leap year, so no check is necessary.
|
||||
class FlowState = boolean;
|
||||
|
||||
predicate isSource(DataFlow::Node source, FlowState state) {
|
||||
source instanceof YearFieldAssignmentNode and
|
||||
state = false
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink, FlowState state) {
|
||||
// Case 1: Flow through a time conversion function that requires a check,
|
||||
// and we have arrived at a guard, implying the result was checked for possible error, including leap year error.
|
||||
// state = true indicates the flow went through a time conversion function
|
||||
state = true and
|
||||
(
|
||||
exists(IfStmt ifs | ifs.getCondition().getAChild*() = [sink.asExpr(), sink.asIndirectExpr()])
|
||||
or
|
||||
exists(ConditionalExpr ce |
|
||||
ce.getCondition().getAChild*() = [sink.asExpr(), sink.asIndirectExpr()]
|
||||
)
|
||||
or
|
||||
exists(Loop l | l.getCondition().getAChild*() = [sink.asExpr(), sink.asIndirectExpr()])
|
||||
)
|
||||
or
|
||||
// Case 2: Flow through a time conversion function that auto corrects for leap year, so no check is necessary.
|
||||
// state true or false, as flowing through a time conversion function is not necessary in this instance.
|
||||
state in [true, false] and
|
||||
exists(Call c, TimeConversionFunction f |
|
||||
f.isAutoLeapYearCorrecting() and
|
||||
c.getTarget() = f and
|
||||
c.getAnArgument().getAChild*() = [sink.asExpr(), sink.asIndirectExpr()]
|
||||
)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
|
||||
) {
|
||||
state1 in [true, false] and
|
||||
state2 = true and
|
||||
exists(Call c |
|
||||
c.getTarget() instanceof TimeConversionFunction and
|
||||
c.getAnArgument().getAChild*() = [node1.asExpr(), node1.asIndirectExpr()] and
|
||||
node2.asExpr() = c
|
||||
)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
yearAssignmentToCheckCommonSteps(node1, node2)
|
||||
}
|
||||
|
||||
DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSourceCallContext }
|
||||
}
|
||||
|
||||
module YearAssignmentToCheckedTimeConversionFlow =
|
||||
DataFlow::GlobalWithState<YearAssignmentToCheckedTimeConversionConfig>;
|
||||
|
||||
/**
|
||||
* Finds flow from a parameter of a function to a leap year check.
|
||||
* This is necessary to handle for scenarios like this:
|
||||
*
|
||||
* year = DANGEROUS_OP // source
|
||||
* isLeap = isLeapYear(year);
|
||||
* // logic based on isLeap
|
||||
* struct.year = year; // sink
|
||||
*
|
||||
* In this case, we may flow a dangerous op to a year assignment, failing
|
||||
* to barrier the flow through a leap year check, as the leap year check
|
||||
* is nested, and dataflow does not progress down into the check and out.
|
||||
* Instead, the point of this flow is to detect isLeapYear's argument
|
||||
* is checked for leap year, making the isLeapYear call a barrier for
|
||||
* the dangerous flow if we flow through the parameter identified to
|
||||
* be checked.
|
||||
*/
|
||||
module ParameterToLeapYearCheckConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { exists(source.asParameter()) }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(LeapYearGuardCondition lgc |
|
||||
lgc.checkedYearAccess() = [sink.asExpr(), sink.asIndirectExpr()]
|
||||
)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
// flow from a YearFieldAccess to the qualifier
|
||||
node2.asExpr() = node1.asExpr().(YearFieldAccess).getQualifier*()
|
||||
or
|
||||
// flow from a year access qualifier to a year field
|
||||
exists(YearFieldAccess yfa | node2.asExpr() = yfa and node1.asExpr() = yfa.getQualifier())
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforcing the check must occur in the same call context as the source,
|
||||
* i.e., do not return from the source function and check in a caller.
|
||||
*/
|
||||
DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSourceCallContext }
|
||||
}
|
||||
|
||||
// NOTE: I do not believe taint flow is necessary here as we should
|
||||
// be flowing directyly from some parameter to a leap year check.
|
||||
module ParameterToLeapYearCheckFlow = DataFlow::Global<ParameterToLeapYearCheckConfig>;
|
||||
|
||||
predicate isLeapYearCheckCall(Call c, Expr arg) {
|
||||
exists(ParameterToLeapYearCheckFlow::PathNode src, Function f, int i |
|
||||
src.isSource() and
|
||||
f.getParameter(i) = src.getNode().asParameter() and
|
||||
c.getTarget() = f and
|
||||
c.getArgument(i) = arg
|
||||
)
|
||||
}
|
||||
|
||||
class LeapYearGuardCondition extends GuardCondition {
|
||||
Expr yearSinkDiv4;
|
||||
Expr yearSinkDiv100;
|
||||
Expr yearSinkDiv400;
|
||||
|
||||
LeapYearGuardCondition() {
|
||||
exists(
|
||||
LogicalAndExpr andExpr, LogicalOrExpr orExpr, GuardCondition div4Check,
|
||||
GuardCondition div100Check, GuardCondition div400Check, GuardValue gv
|
||||
|
|
||||
// canonical case:
|
||||
// form: `(year % 4 == 0) && (year % 100 != 0 || year % 400 == 0)`
|
||||
// `!((year % 4 == 0) && (year % 100 != 0 || year % 400 == 0))`
|
||||
// `!(year % 4) && (year % 100 || !(year % 400))`
|
||||
// Also accepting `((year & 3) == 0) && (year % 100 != 0 || year % 400 == 0)`
|
||||
// and `(year % 4 == 0) && (year % 100 > 0 || year % 400 == 0)`
|
||||
this = andExpr and
|
||||
andExpr.hasOperands(div4Check, orExpr) and
|
||||
orExpr.hasOperands(div100Check, div400Check) and
|
||||
(
|
||||
// year % 4 == 0
|
||||
exists(RemExpr e |
|
||||
div4Check.comparesEq(e, 0, true, gv) and
|
||||
e.getRightOperand().getValue().toInt() = 4 and
|
||||
yearSinkDiv4 = e.getLeftOperand()
|
||||
)
|
||||
or
|
||||
// year & 3 == 0
|
||||
exists(BitwiseAndExpr e |
|
||||
div4Check.comparesEq(e, 0, true, gv) and
|
||||
e.getRightOperand().getValue().toInt() = 3 and
|
||||
yearSinkDiv4 = e.getLeftOperand()
|
||||
)
|
||||
) and
|
||||
exists(RemExpr e |
|
||||
// year % 100 != 0 or year % 100 > 0
|
||||
(
|
||||
div100Check.comparesEq(e, 0, false, gv) or
|
||||
div100Check.comparesLt(e, 1, false, gv)
|
||||
) and
|
||||
e.getRightOperand().getValue().toInt() = 100 and
|
||||
yearSinkDiv100 = e.getLeftOperand()
|
||||
) and
|
||||
// year % 400 == 0
|
||||
exists(RemExpr e |
|
||||
div400Check.comparesEq(e, 0, true, gv) and
|
||||
e.getRightOperand().getValue().toInt() = 400 and
|
||||
yearSinkDiv400 = e.getLeftOperand()
|
||||
)
|
||||
or
|
||||
// Inverted logic case:
|
||||
// `year % 4 != 0 || (year % 100 == 0 && year % 400 != 0)`
|
||||
// or `year & 3 != 0 || (year % 100 == 0 && year % 400 != 0)`
|
||||
// also accepting `year % 4 > 0 || (year % 100 == 0 && year % 400 > 0)`
|
||||
this = orExpr and
|
||||
orExpr.hasOperands(div4Check, andExpr) and
|
||||
andExpr.hasOperands(div100Check, div400Check) and
|
||||
(
|
||||
// year % 4 != 0 or year % 4 > 0
|
||||
exists(RemExpr e |
|
||||
(
|
||||
div4Check.comparesEq(e, 0, false, gv)
|
||||
or
|
||||
div4Check.comparesLt(e, 1, false, gv)
|
||||
) and
|
||||
e.getRightOperand().getValue().toInt() = 4 and
|
||||
yearSinkDiv4 = e.getLeftOperand()
|
||||
)
|
||||
or
|
||||
// year & 3 != 0
|
||||
exists(BitwiseAndExpr e |
|
||||
div4Check.comparesEq(e, 0, false, gv) and
|
||||
e.getRightOperand().getValue().toInt() = 3 and
|
||||
yearSinkDiv4 = e.getLeftOperand()
|
||||
)
|
||||
) and
|
||||
// year % 100 == 0
|
||||
exists(RemExpr e |
|
||||
div100Check.comparesEq(e, 0, true, gv) and
|
||||
e.getRightOperand().getValue().toInt() = 100 and
|
||||
yearSinkDiv100 = e.getLeftOperand()
|
||||
) and
|
||||
// year % 400 != 0 or year % 400 > 0
|
||||
exists(RemExpr e |
|
||||
(
|
||||
div400Check.comparesEq(e, 0, false, gv)
|
||||
or
|
||||
div400Check.comparesLt(e, 1, false, gv)
|
||||
) and
|
||||
e.getRightOperand().getValue().toInt() = 400 and
|
||||
yearSinkDiv400 = e.getLeftOperand()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
Expr getYearSinkDiv4() { result = yearSinkDiv4 }
|
||||
|
||||
Expr getYearSinkDiv100() { result = yearSinkDiv100 }
|
||||
|
||||
Expr getYearSinkDiv400() { result = yearSinkDiv400 }
|
||||
|
||||
/**
|
||||
* Gets the variable access that is used in all 3 components of the leap year check
|
||||
* e.g., see getYearSinkDiv4/100/400..
|
||||
* If a field access is used, the qualifier and the field access are both returned
|
||||
* in checked condition.
|
||||
* NOTE: if the year is not checked using the same access in all 3 components, no result is returned.
|
||||
* The typical case observed is a consistent variable access is used. If not, this may indicate a bug.
|
||||
* We could check more accurately with a dataflow analysis, but this is likely sufficient for now.
|
||||
*/
|
||||
VariableAccess checkedYearAccess() {
|
||||
exists(Variable var |
|
||||
(
|
||||
this.getYearSinkDiv4().getAChild*() = var.getAnAccess() and
|
||||
this.getYearSinkDiv100().getAChild*() = var.getAnAccess() and
|
||||
this.getYearSinkDiv400().getAChild*() = var.getAnAccess() and
|
||||
result = var.getAnAccess() and
|
||||
(
|
||||
result = this.getYearSinkDiv4().getAChild*() or
|
||||
result = this.getYearSinkDiv100().getAChild*() or
|
||||
result = this.getYearSinkDiv400().getAChild*()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A difficult case to detect is if a year modification is tied to a month or day modification
|
||||
* and the month or day is safe for leap year.
|
||||
* e.g.,
|
||||
* year++;
|
||||
* month = 1;
|
||||
* // alternative: day = 15;
|
||||
* ... values eventually used in the same time struct
|
||||
* If this is even more challenging if the struct the values end up in are not
|
||||
* local (set inter-procedurally).
|
||||
* This configuration looks for constants 1-31 flowing to a month or day assignment.
|
||||
* It is assumed a user of this flow will check if the month/day source and month/day sink
|
||||
* are in the same basic blocks as a year modification source and a year modification sink.
|
||||
* It is also assumed a user will check if the constant source is a value that is ignorable
|
||||
* e.g., if it is 2 and the sink is a month assignment, then it isn't ignorable or
|
||||
* if the value is < 27 and is a day assignment, it is likely ignorable
|
||||
*
|
||||
* Obviously this does not handle all conditions (e.g., the month set in another block).
|
||||
* It is meant to capture the most common cases of false positives.
|
||||
*/
|
||||
module CandidateConstantToDayOrMonthAssignmentConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr().getValue().toInt() in [1 .. 31] and
|
||||
(
|
||||
exists(Assignment a | a.getRValue() = source.asExpr())
|
||||
or
|
||||
exists(Call c | c.getAnArgument() = source.asExpr())
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(Assignment a |
|
||||
(a.getLValue() instanceof MonthFieldAccess or a.getLValue() instanceof DayFieldAccess) and
|
||||
a.getRValue() = sink.asExpr()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: only data flow here (no taint tracking) as we want the exact
|
||||
// constant flowing to the month assignment
|
||||
module CandidateConstantToDayOrMonthAssignmentFlow =
|
||||
DataFlow::Global<CandidateConstantToDayOrMonthAssignmentConfig>;
|
||||
|
||||
/**
|
||||
* Holds if value the assignment `a` resolves to (`dayOrMonthValSrcExpr`) doesn't represent February,
|
||||
* and/or if it represents a day, is a 'safe' day (meaning the 27th or prior).
|
||||
*/
|
||||
bindingset[dayOrMonthValSrcExpr]
|
||||
predicate isSafeValueForAssignmentOfMonthOrDayValue(Assignment a, Expr dayOrMonthValSrcExpr) {
|
||||
a.getLValue() instanceof MonthFieldAccess and
|
||||
dayOrMonthValSrcExpr.getValue().toInt() != 2
|
||||
or
|
||||
a.getLValue() instanceof DayFieldAccess and
|
||||
dayOrMonthValSrcExpr.getValue().toInt() <= 27
|
||||
}
|
||||
|
||||
import OperationToYearAssignmentFlow::PathGraph
|
||||
|
||||
from OperationToYearAssignmentFlow::PathNode src, OperationToYearAssignmentFlow::PathNode sink
|
||||
where
|
||||
OperationToYearAssignmentFlow::flowPath(src, sink) and
|
||||
// Check if a month is set in the same block as the year operation source
|
||||
// and the month value would indicate its set to any other month than february.
|
||||
// Finds if the source year node is in the same block as a source month block
|
||||
// and if the same for the sinks.
|
||||
not exists(DataFlow::Node dayOrMonthValSrc, DataFlow::Node dayOrMonthValSink, Assignment a |
|
||||
CandidateConstantToDayOrMonthAssignmentFlow::flow(dayOrMonthValSrc, dayOrMonthValSink) and
|
||||
a.getRValue() = dayOrMonthValSink.asExpr() and
|
||||
dayOrMonthValSink.getBasicBlock() = sink.getNode().getBasicBlock() and
|
||||
exists(IRBlock dayOrMonthValBB |
|
||||
dayOrMonthValBB = dayOrMonthValSrc.getBasicBlock() and
|
||||
// The source of the day is set in the same block as the source for the year
|
||||
// or the source for the day is set in the same block as the sink for the year
|
||||
dayOrMonthValBB in [
|
||||
src.getNode().getBasicBlock(),
|
||||
sink.getNode().getBasicBlock()
|
||||
]
|
||||
) and
|
||||
isSafeValueForAssignmentOfMonthOrDayValue(a, dayOrMonthValSrc.asExpr())
|
||||
)
|
||||
select sink, src, sink,
|
||||
"Year field has been modified, but no appropriate check for LeapYear was found."
|
||||
|
||||
@@ -44,23 +44,9 @@ class SafeTimeGatheringFunction extends Function {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This list of APIs should check for the return value to detect problems during the conversion.
|
||||
*/
|
||||
class TimeConversionFunction extends Function {
|
||||
TimeConversionFunction() {
|
||||
this.getQualifiedName() =
|
||||
[
|
||||
"FileTimeToSystemTime", "SystemTimeToFileTime", "SystemTimeToTzSpecificLocalTime",
|
||||
"SystemTimeToTzSpecificLocalTimeEx", "TzSpecificLocalTimeToSystemTime",
|
||||
"TzSpecificLocalTimeToSystemTimeEx", "RtlLocalTimeToSystemTime",
|
||||
"RtlTimeToSecondsSince1970", "_mkgmtime"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
from FunctionCall fcall, TimeConversionFunction trf, Variable var
|
||||
where
|
||||
not trf.isAutoLeapYearCorrecting() and
|
||||
fcall = trf.getACallToThisFunction() and
|
||||
fcall instanceof ExprInVoidContext and
|
||||
var.getUnderlyingType() instanceof UnpackedTimeType and
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
|
||||
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes
|
||||
|
||||
/** Gets a loop that contains `e`. */
|
||||
Loop getAnEnclosingLoopOfExpr(Expr e) { result = getAnEnclosingLoopOfStmt(e.getEnclosingStmt()) }
|
||||
@@ -45,9 +46,9 @@ private Expr getExpr(DataFlow::Node node) {
|
||||
or
|
||||
result = node.asOperand().getUse().getAst()
|
||||
or
|
||||
result = node.(DataFlow::RawIndirectInstruction).getInstruction().getAst()
|
||||
result = node.(RawIndirectInstruction).getInstruction().getAst()
|
||||
or
|
||||
result = node.(DataFlow::RawIndirectOperand).getOperand().getUse().getAst()
|
||||
result = node.(RawIndirectOperand).getOperand().getUse().getAst()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -208,7 +209,7 @@ class LoopWithAlloca extends Stmt {
|
||||
this.conditionRequiresInequality(va, _, _) and
|
||||
DataFlow::localFlow(result, DataFlow::exprNode(va)) and
|
||||
// Phi nodes will be preceded by nodes that represent actual definitions
|
||||
not result instanceof DataFlow::SsaSynthNode and
|
||||
not result instanceof SsaSynthNode and
|
||||
// A source is outside the loop if it's not inside the loop
|
||||
not exists(Expr e | e = getExpr(result) | this = getAnEnclosingLoopOfExpr(e))
|
||||
)
|
||||
|
||||
@@ -16,17 +16,15 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.IR
|
||||
import semmle.code.cpp.ir.dataflow.MustFlow
|
||||
import PathGraph
|
||||
import ReturnStackAllocatedMemory::PathGraph
|
||||
|
||||
/** Holds if `f` has a name that we interpret as evidence of intentionally returning the value of the stack pointer. */
|
||||
predicate intentionallyReturnsStackPointer(Function f) {
|
||||
f.getName().toLowerCase().matches(["%stack%", "%sp%"])
|
||||
}
|
||||
|
||||
class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
|
||||
ReturnStackAllocatedMemoryConfig() { this = "ReturnStackAllocatedMemoryConfig" }
|
||||
|
||||
override predicate isSource(Instruction source) {
|
||||
module ReturnStackAllocatedMemoryConfig implements MustFlow::ConfigSig {
|
||||
predicate isSource(Instruction source) {
|
||||
exists(Function func |
|
||||
// Rule out FPs caused by extraction errors.
|
||||
not func.hasErrors() and
|
||||
@@ -50,7 +48,7 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(Operand sink) {
|
||||
predicate isSink(Operand sink) {
|
||||
// Holds if `sink` is a node that represents the `StoreInstruction` that is subsequently used in
|
||||
// a `ReturnValueInstruction`.
|
||||
// We use the `StoreInstruction` instead of the instruction that defines the
|
||||
@@ -72,7 +70,7 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
|
||||
// int* px = id(&x);
|
||||
// }
|
||||
// ```
|
||||
override predicate allowInterproceduralFlow() { none() }
|
||||
predicate allowInterproceduralFlow() { none() }
|
||||
|
||||
/**
|
||||
* This configuration intentionally conflates addresses of fields and their object, and pointer offsets
|
||||
@@ -87,20 +85,22 @@ class ReturnStackAllocatedMemoryConfig extends MustFlowConfiguration {
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
override predicate isAdditionalFlowStep(Operand node1, Instruction node2) {
|
||||
predicate isAdditionalFlowStep(Operand node1, Instruction node2) {
|
||||
node2.(FieldAddressInstruction).getObjectAddressOperand() = node1
|
||||
or
|
||||
node2.(PointerOffsetInstruction).getLeftOperand() = node1
|
||||
}
|
||||
|
||||
override predicate isBarrier(Instruction n) { n.getResultType() instanceof ErroneousType }
|
||||
predicate isBarrier(Instruction n) { n.getResultType() instanceof ErroneousType }
|
||||
}
|
||||
|
||||
module ReturnStackAllocatedMemory = MustFlow::Global<ReturnStackAllocatedMemoryConfig>;
|
||||
|
||||
from
|
||||
MustFlowPathNode source, MustFlowPathNode sink, Instruction instr,
|
||||
ReturnStackAllocatedMemoryConfig conf
|
||||
ReturnStackAllocatedMemory::PathNode source, ReturnStackAllocatedMemory::PathNode sink,
|
||||
Instruction instr
|
||||
where
|
||||
conf.hasFlowPath(pragma[only_bind_into](source), pragma[only_bind_into](sink)) and
|
||||
ReturnStackAllocatedMemory::flowPath(pragma[only_bind_into](source), pragma[only_bind_into](sink)) and
|
||||
source.getInstruction() = instr
|
||||
select sink.getInstruction(), source, sink, "May return stack-allocated memory from $@.",
|
||||
instr.getAst(), instr.getAst().toString()
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.IR
|
||||
import semmle.code.cpp.ir.dataflow.MustFlow
|
||||
import PathGraph
|
||||
import UninitializedLocal::PathGraph
|
||||
|
||||
/**
|
||||
* Auxiliary predicate: Types that don't require initialization
|
||||
@@ -70,25 +70,26 @@ predicate isSinkImpl(Instruction sink, VariableAccess va) {
|
||||
)
|
||||
}
|
||||
|
||||
class MustFlow extends MustFlowConfiguration {
|
||||
MustFlow() { this = "MustFlow" }
|
||||
|
||||
override predicate isSource(Instruction source) {
|
||||
module UninitializedLocalConfig implements MustFlow::ConfigSig {
|
||||
predicate isSource(Instruction source) {
|
||||
source instanceof UninitializedInstruction and
|
||||
exists(Type t | t = source.getResultType() | not allocatedType(t))
|
||||
}
|
||||
|
||||
override predicate isSink(Operand sink) { isSinkImpl(sink.getDef(), _) }
|
||||
predicate isSink(Operand sink) { isSinkImpl(sink.getDef(), _) }
|
||||
|
||||
override predicate allowInterproceduralFlow() { none() }
|
||||
predicate allowInterproceduralFlow() { none() }
|
||||
|
||||
override predicate isBarrier(Instruction instr) { instr instanceof ChiInstruction }
|
||||
predicate isBarrier(Instruction instr) { instr instanceof ChiInstruction }
|
||||
}
|
||||
|
||||
module UninitializedLocal = MustFlow::Global<UninitializedLocalConfig>;
|
||||
|
||||
from
|
||||
VariableAccess va, LocalVariable v, MustFlow conf, MustFlowPathNode source, MustFlowPathNode sink
|
||||
VariableAccess va, LocalVariable v, UninitializedLocal::PathNode source,
|
||||
UninitializedLocal::PathNode sink
|
||||
where
|
||||
conf.hasFlowPath(source, sink) and
|
||||
UninitializedLocal::flowPath(source, sink) and
|
||||
isSinkImpl(sink.getInstruction(), va) and
|
||||
v = va.getTarget()
|
||||
select va, source, sink, "The variable $@ may not be initialized at this access.", v, v.getName()
|
||||
|
||||
@@ -17,16 +17,16 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.IR
|
||||
import semmle.code.cpp.ir.dataflow.MustFlow
|
||||
import PathGraph
|
||||
import UnsafeUseOfThis::PathGraph
|
||||
|
||||
class UnsafeUseOfThisConfig extends MustFlowConfiguration {
|
||||
UnsafeUseOfThisConfig() { this = "UnsafeUseOfThisConfig" }
|
||||
module UnsafeUseOfThisConfig implements MustFlow::ConfigSig {
|
||||
predicate isSource(Instruction source) { isSource(source, _, _) }
|
||||
|
||||
override predicate isSource(Instruction source) { isSource(source, _, _) }
|
||||
|
||||
override predicate isSink(Operand sink) { isSink(sink, _) }
|
||||
predicate isSink(Operand sink) { isSink(sink, _) }
|
||||
}
|
||||
|
||||
module UnsafeUseOfThis = MustFlow::Global<UnsafeUseOfThisConfig>;
|
||||
|
||||
/** Holds if `sink` is a `this` pointer used by the call instruction `call`. */
|
||||
predicate isSink(Operand sink, CallInstruction call) {
|
||||
exists(PureVirtualFunction func |
|
||||
@@ -66,19 +66,17 @@ predicate isSource(InitializeParameterInstruction source, string msg, Class c) {
|
||||
* - `msg` is a string describing whether `source` is from a constructor or destructor.
|
||||
*/
|
||||
predicate flows(
|
||||
MustFlowPathNode source, string msg, Class sourceClass, MustFlowPathNode sink,
|
||||
UnsafeUseOfThis::PathNode source, string msg, Class sourceClass, UnsafeUseOfThis::PathNode sink,
|
||||
CallInstruction call
|
||||
) {
|
||||
exists(UnsafeUseOfThisConfig conf |
|
||||
conf.hasFlowPath(source, sink) and
|
||||
isSource(source.getInstruction(), msg, sourceClass) and
|
||||
isSink(sink.getInstruction().getAUse(), call)
|
||||
)
|
||||
UnsafeUseOfThis::flowPath(source, sink) and
|
||||
isSource(source.getInstruction(), msg, sourceClass) and
|
||||
isSink(sink.getInstruction().getAUse(), call)
|
||||
}
|
||||
|
||||
from
|
||||
MustFlowPathNode source, MustFlowPathNode sink, CallInstruction call, string msg,
|
||||
Class sourceClass
|
||||
UnsafeUseOfThis::PathNode source, UnsafeUseOfThis::PathNode sink, CallInstruction call,
|
||||
string msg, Class sourceClass
|
||||
where
|
||||
flows(source, msg, sourceClass, sink, call) and
|
||||
// Only raise an alert if there is no override of the pure virtual function in any base class.
|
||||
|
||||
3
cpp/ql/src/change-notes/released/1.5.11.md
Normal file
3
cpp/ql/src/change-notes/released/1.5.11.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.5.11
|
||||
|
||||
No user-facing changes.
|
||||
3
cpp/ql/src/change-notes/released/1.5.12.md
Normal file
3
cpp/ql/src/change-notes/released/1.5.12.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.5.12
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.5.10
|
||||
lastReleaseVersion: 1.5.12
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 1.5.10
|
||||
version: 1.5.13-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -8,6 +8,7 @@ private import semmle.code.cpp.dataflow.ExternalFlow as ExternalFlow
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate as DataFlowPrivate
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes as DataFlowNodes
|
||||
private import semmle.code.cpp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
|
||||
private import semmle.code.cpp.ir.dataflow.internal.TaintTrackingImplSpecific
|
||||
private import semmle.code.cpp.dataflow.new.TaintTracking as Tt
|
||||
@@ -403,7 +404,7 @@ private module SinkModelGeneratorInput implements SinkModelGeneratorInputSig {
|
||||
}
|
||||
|
||||
predicate apiSource(DataFlow::Node source) {
|
||||
DataFlowPrivate::nodeHasOperand(source, any(DataFlow::FieldAddress fa), 1)
|
||||
DataFlowPrivate::nodeHasOperand(source, any(DataFlowNodes::FieldAddress fa), 1)
|
||||
or
|
||||
source instanceof DataFlow::ParameterNode
|
||||
}
|
||||
@@ -416,7 +417,7 @@ private module SinkModelGeneratorInput implements SinkModelGeneratorInputSig {
|
||||
result = "Argument[" + DataFlow::repeatStars(indirectionIndex) + argumentIndex + "]"
|
||||
)
|
||||
or
|
||||
DataFlowPrivate::nodeHasOperand(source, any(DataFlow::FieldAddress fa), 1) and
|
||||
DataFlowPrivate::nodeHasOperand(source, any(DataFlowNodes::FieldAddress fa), 1) and
|
||||
result = qualifierString()
|
||||
}
|
||||
|
||||
|
||||
297
cpp/ql/test/library-tests/dataflow/external-models/azure.cpp
Normal file
297
cpp/ql/test/library-tests/dataflow/external-models/azure.cpp
Normal file
@@ -0,0 +1,297 @@
|
||||
using uint16_t = unsigned short;
|
||||
using int64_t = long long;
|
||||
using size_t = unsigned long;
|
||||
using uint8_t = unsigned char;
|
||||
using int32_t = int;
|
||||
using uint32_t = unsigned int;
|
||||
|
||||
namespace std
|
||||
{
|
||||
class string
|
||||
{
|
||||
public:
|
||||
string();
|
||||
string(const char *);
|
||||
~string();
|
||||
};
|
||||
|
||||
template <typename K, typename V>
|
||||
class map
|
||||
{
|
||||
public:
|
||||
map();
|
||||
~map();
|
||||
|
||||
V& operator[](const K& key);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class vector
|
||||
{
|
||||
public:
|
||||
vector();
|
||||
~vector();
|
||||
|
||||
T& operator[](size_t);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class unique_ptr {
|
||||
public:
|
||||
unique_ptr();
|
||||
~unique_ptr();
|
||||
|
||||
T* get();
|
||||
};
|
||||
}
|
||||
|
||||
namespace Azure
|
||||
{
|
||||
template <typename T>
|
||||
class Nullable
|
||||
{
|
||||
public:
|
||||
Nullable();
|
||||
Nullable(const T);
|
||||
Nullable(const Nullable &);
|
||||
~Nullable();
|
||||
Nullable (Nullable &&);
|
||||
Nullable & operator= (const Nullable &);
|
||||
bool HasValue() const;
|
||||
const T & Value () const;
|
||||
T& Value ();
|
||||
const T * operator-> () const;
|
||||
T * operator-> ();
|
||||
const T & operator* () const;
|
||||
T & operator* ();
|
||||
};
|
||||
|
||||
namespace Core
|
||||
{
|
||||
class Url
|
||||
{
|
||||
public:
|
||||
Url();
|
||||
Url(const std::string &);
|
||||
void AppendPath(const std::string &encodedPath);
|
||||
void AppendQueryParameter(const std::string &encodedKey,
|
||||
const std::string &encodedValue);
|
||||
|
||||
static std::string Url::Decode(const std::string &value);
|
||||
static std::string Url::Encode(const std::string &value,
|
||||
const std::string &doNotEncodeSymbols = "");
|
||||
|
||||
std::string Url::GetAbsoluteUrl() const;
|
||||
const std::string &GetHost() const;
|
||||
const std::string &GetPath() const;
|
||||
uint16_t GetPort() const;
|
||||
std::map<std::string, std::string> GetQueryParameters() const;
|
||||
std::string Url::GetRelativeUrl() const;
|
||||
const std::string &GetScheme() const;
|
||||
void RemoveQueryParameter(const std::string &encodedKey);
|
||||
void SetHost(const std::string &encodedHost);
|
||||
void SetPath(const std::string &encodedPath);
|
||||
void SetPort(uint16_t port);
|
||||
void SetQueryParameters(std::map<std::string, std::string> queryParameters);
|
||||
void SetScheme(const std::string &scheme);
|
||||
};
|
||||
|
||||
class Context
|
||||
{
|
||||
public:
|
||||
Context();
|
||||
};
|
||||
|
||||
namespace IO
|
||||
{
|
||||
class BodyStream
|
||||
{
|
||||
public:
|
||||
virtual ~BodyStream();
|
||||
virtual int64_t Length() const = 0;
|
||||
virtual void Rewind();
|
||||
size_t Read(uint8_t *buffer, size_t count, Azure::Core::Context const &context = Azure::Core::Context());
|
||||
size_t ReadToCount(uint8_t *buffer, size_t count, Azure::Core::Context const &context = Azure::Core::Context());
|
||||
std::vector<uint8_t> ReadToEnd(Azure::Core::Context const &context = Azure::Core::Context());
|
||||
};
|
||||
}
|
||||
|
||||
enum class HttpStatusCode {
|
||||
None = 0,
|
||||
Continue = 100,
|
||||
SwitchingProtocols = 101,
|
||||
Processing = 102,
|
||||
EarlyHints = 103,
|
||||
OK = 200,
|
||||
Created = 201,
|
||||
Accepted = 202,
|
||||
NonAuthoritativeInformation = 203,
|
||||
NoContent = 204,
|
||||
ResetContent = 205,
|
||||
PartialContent = 206,
|
||||
MultiStatus = 207,
|
||||
AlreadyReported = 208,
|
||||
IMUsed = 226,
|
||||
MultipleChoices = 300,
|
||||
MovedPermanently = 301,
|
||||
Found = 302,
|
||||
SeeOther = 303,
|
||||
NotModified = 304,
|
||||
UseProxy = 305,
|
||||
TemporaryRedirect = 307,
|
||||
PermanentRedirect = 308,
|
||||
BadRequest = 400,
|
||||
Unauthorized = 401,
|
||||
PaymentRequired = 402,
|
||||
Forbidden = 403,
|
||||
NotFound = 404,
|
||||
MethodNotAllowed = 405,
|
||||
NotAcceptable = 406,
|
||||
ProxyAuthenticationRequired = 407,
|
||||
RequestTimeout = 408,
|
||||
Conflict = 409,
|
||||
Gone = 410,
|
||||
LengthRequired = 411,
|
||||
PreconditionFailed = 412,
|
||||
PayloadTooLarge = 413,
|
||||
URITooLong = 414,
|
||||
UnsupportedMediaType = 415,
|
||||
RangeNotSatisfiable = 416,
|
||||
ExpectationFailed = 417,
|
||||
MisdirectedRequest = 421,
|
||||
UnprocessableEntity = 422,
|
||||
Locked = 423,
|
||||
FailedDependency = 424,
|
||||
TooEarly = 425,
|
||||
UpgradeRequired = 426,
|
||||
PreconditionRequired = 428,
|
||||
TooManyRequests = 429,
|
||||
RequestHeaderFieldsTooLarge = 431,
|
||||
UnavailableForLegalReasons = 451,
|
||||
InternalServerError = 500,
|
||||
NotImplemented = 501,
|
||||
BadGateway = 502,
|
||||
ServiceUnavailable = 503,
|
||||
GatewayTimeout = 504,
|
||||
HTTPVersionNotSupported = 505,
|
||||
VariantAlsoNegotiates = 506,
|
||||
InsufficientStorage = 507,
|
||||
LoopDetected = 508,
|
||||
NotExtended = 510,
|
||||
NetworkAuthenticationRequired = 511
|
||||
};
|
||||
|
||||
namespace Http
|
||||
{
|
||||
class HttpMethod
|
||||
{
|
||||
public:
|
||||
HttpMethod(std::string value);
|
||||
bool operator==(const HttpMethod &other) const;
|
||||
bool operator!=(const HttpMethod &other) const;
|
||||
const std::string &ToString() const;
|
||||
};
|
||||
|
||||
extern const HttpMethod Get;
|
||||
extern const HttpMethod Head;
|
||||
extern const HttpMethod Post;
|
||||
extern const HttpMethod Put;
|
||||
extern const HttpMethod Delete;
|
||||
extern const HttpMethod Patch;
|
||||
extern const HttpMethod Options;
|
||||
|
||||
class Request
|
||||
{
|
||||
public:
|
||||
explicit Request(HttpMethod httpMethod,
|
||||
Url url);
|
||||
explicit Request(HttpMethod httpMethod,
|
||||
Url url,
|
||||
bool shouldBufferResponse);
|
||||
explicit Request(HttpMethod httpMethod,
|
||||
Url url,
|
||||
IO::BodyStream *bodyStream);
|
||||
explicit Request(HttpMethod httpMethod,
|
||||
Url url,
|
||||
IO::BodyStream *bodyStream,
|
||||
bool shouldBufferResponse);
|
||||
std::map<std::string, std::string> GetHeaders () const;
|
||||
Azure::Nullable<std::string> GetHeader(std::string const &name);
|
||||
IO::BodyStream * GetBodyStream();
|
||||
Azure::Core::IO::BodyStream const* GetBodyStream () const;
|
||||
};
|
||||
|
||||
class RawResponse {
|
||||
public:
|
||||
RawResponse (int32_t majorVersion, int32_t minorVersion, HttpStatusCode statusCode, std::string const &reasonPhrase);
|
||||
RawResponse (RawResponse const &response);
|
||||
RawResponse (RawResponse &&response);
|
||||
~RawResponse ();
|
||||
void SetHeader (std::string const &name, std::string const &value);
|
||||
void SetBodyStream (std::unique_ptr< Azure::Core::IO::BodyStream > stream);
|
||||
void SetBody (std::vector< uint8_t > body);
|
||||
uint32_t GetMajorVersion () const;
|
||||
uint32_t GetMinorVersion () const;
|
||||
HttpStatusCode GetStatusCode () const;
|
||||
std::string const & GetReasonPhrase () const;
|
||||
std::map<std::string, std::string>& GetHeaders () const;
|
||||
std::unique_ptr<Azure::Core::IO::BodyStream> ExtractBodyStream ();
|
||||
std::vector<uint8_t> & GetBody ();
|
||||
std::vector<uint8_t> const& GetBody() const;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sink(char);
|
||||
void sink(std::string);
|
||||
void sink(std::vector<uint8_t>);
|
||||
void sink(Azure::Nullable<std::string>);
|
||||
|
||||
void test_BodyStream() {
|
||||
Azure::Core::Http::Request request(Azure::Core::Http::Get, Azure::Core::Url("http://example.com"));
|
||||
Azure::Core::IO::BodyStream * resp = request.GetBodyStream();
|
||||
|
||||
{
|
||||
unsigned char buffer[1024];
|
||||
resp->Read(buffer, sizeof(buffer));
|
||||
sink(*buffer); // $ ir
|
||||
}
|
||||
{
|
||||
unsigned char buffer[1024];
|
||||
resp->ReadToCount(buffer, sizeof(buffer));
|
||||
sink(*buffer); // $ ir
|
||||
}
|
||||
{
|
||||
std::vector<unsigned char> vec = resp->ReadToEnd();
|
||||
sink(vec); // $ ir
|
||||
}
|
||||
}
|
||||
|
||||
void test_RawResponse(Azure::Core::Http::RawResponse& resp) {
|
||||
{
|
||||
std::map<std::string, std::string> body = resp.GetHeaders();
|
||||
sink(body["Content-Type"]); // $ ir
|
||||
}
|
||||
{
|
||||
std::vector<uint8_t> body = resp.GetBody();
|
||||
sink(body); // $ ir
|
||||
}
|
||||
{
|
||||
std::unique_ptr<Azure::Core::IO::BodyStream> bodyStream = resp.ExtractBodyStream();
|
||||
sink(bodyStream.get()->ReadToEnd()); // $ ir
|
||||
}
|
||||
}
|
||||
|
||||
void test_GetHeader() {
|
||||
Azure::Core::Http::Request request(Azure::Core::Http::Get, Azure::Core::Url("http://example.com"));
|
||||
{
|
||||
auto headerValue = request.GetHeader("Content-Type").Value();
|
||||
sink(headerValue); // $ ir
|
||||
}
|
||||
{
|
||||
std::map<std::string, std::string> headers = request.GetHeaders();
|
||||
std::string contentType = headers["Content-Type"];
|
||||
sink(contentType); // $ ir
|
||||
}
|
||||
}
|
||||
@@ -14,45 +14,111 @@ models
|
||||
| 13 | Source: ; ; false; NtReadFile; ; ; Argument[*5]; local; manual |
|
||||
| 14 | Source: ; ; false; ReadFile; ; ; Argument[*1]; local; manual |
|
||||
| 15 | Source: ; ; false; ReadFileEx; ; ; Argument[*1]; local; manual |
|
||||
| 16 | Source: ; ; false; ymlSource; ; ; ReturnValue; local; manual |
|
||||
| 17 | Source: boost::asio; ; false; read_until; ; ; Argument[*1]; remote; manual |
|
||||
| 18 | Summary: ; ; false; CommandLineToArgvA; ; ; Argument[*0]; ReturnValue[**]; taint; manual |
|
||||
| 19 | Summary: ; ; false; CreateRemoteThread; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual |
|
||||
| 20 | Summary: ; ; false; CreateRemoteThreadEx; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual |
|
||||
| 21 | Summary: ; ; false; CreateThread; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual |
|
||||
| 22 | Summary: ; ; false; ReadFileEx; ; ; Argument[*3].Field[@hEvent]; Argument[4].Parameter[*2].Field[@hEvent]; value; manual |
|
||||
| 23 | Summary: ; ; false; RtlCopyDeviceMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual |
|
||||
| 24 | Summary: ; ; false; RtlCopyMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual |
|
||||
| 25 | Summary: ; ; false; RtlCopyMemoryNonTemporal; ; ; Argument[*@1]; Argument[*@0]; value; manual |
|
||||
| 26 | Summary: ; ; false; RtlCopyUnicodeString; ; ; Argument[*1].Field[*Buffer]; Argument[*0].Field[*Buffer]; value; manual |
|
||||
| 27 | Summary: ; ; false; RtlCopyVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual |
|
||||
| 28 | Summary: ; ; false; RtlInitUnicodeString; ; ; Argument[*1]; Argument[*0].Field[*Buffer]; value; manual |
|
||||
| 29 | Summary: ; ; false; RtlMoveMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual |
|
||||
| 30 | Summary: ; ; false; RtlMoveVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual |
|
||||
| 31 | Summary: ; ; false; callWithArgument; ; ; Argument[1]; Argument[0].Parameter[0]; value; manual |
|
||||
| 32 | Summary: ; ; false; callWithNonTypeTemplate<T>; (const T &); ; Argument[*0]; ReturnValue; value; manual |
|
||||
| 33 | Summary: ; ; false; pthread_create; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual |
|
||||
| 34 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated |
|
||||
| 35 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual |
|
||||
| 36 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual |
|
||||
| 37 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual |
|
||||
| 16 | Source: ; ; false; WinHttpQueryHeaders; ; ; Argument[*3]; remote; manual |
|
||||
| 17 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[**8]; remote; manual |
|
||||
| 18 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[*5]; remote; manual |
|
||||
| 19 | Source: ; ; false; WinHttpQueryHeadersEx; ; ; Argument[*6]; remote; manual |
|
||||
| 20 | Source: ; ; false; WinHttpReadData; ; ; Argument[*1]; remote; manual |
|
||||
| 21 | Source: ; ; false; WinHttpReadDataEx; ; ; Argument[*1]; remote; manual |
|
||||
| 22 | Source: ; ; false; ymlSource; ; ; ReturnValue; local; manual |
|
||||
| 23 | Source: Azure::Core::Http; RawResponse; true; ExtractBodyStream; ; ; ReturnValue[*]; remote; manual |
|
||||
| 24 | Source: Azure::Core::Http; RawResponse; true; GetBody; ; ; ReturnValue[*]; remote; manual |
|
||||
| 25 | Source: Azure::Core::Http; RawResponse; true; GetHeaders; ; ; ReturnValue[*]; remote; manual |
|
||||
| 26 | Source: Azure::Core::Http; Request; true; GetBodyStream; ; ; ReturnValue[*]; remote; manual |
|
||||
| 27 | Source: Azure::Core::Http; Request; true; GetHeader; ; ; ReturnValue; remote; manual |
|
||||
| 28 | Source: Azure::Core::Http; Request; true; GetHeaders; ; ; ReturnValue; remote; manual |
|
||||
| 29 | Source: boost::asio; ; false; read_until; ; ; Argument[*1]; remote; manual |
|
||||
| 30 | Summary: ; ; false; CommandLineToArgvA; ; ; Argument[*0]; ReturnValue[**]; taint; manual |
|
||||
| 31 | Summary: ; ; false; CreateRemoteThread; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual |
|
||||
| 32 | Summary: ; ; false; CreateRemoteThreadEx; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual |
|
||||
| 33 | Summary: ; ; false; CreateThread; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual |
|
||||
| 34 | Summary: ; ; false; ReadFileEx; ; ; Argument[*3].Field[@hEvent]; Argument[4].Parameter[*2].Field[@hEvent]; value; manual |
|
||||
| 35 | Summary: ; ; false; RtlCopyDeviceMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual |
|
||||
| 36 | Summary: ; ; false; RtlCopyMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual |
|
||||
| 37 | Summary: ; ; false; RtlCopyMemoryNonTemporal; ; ; Argument[*@1]; Argument[*@0]; value; manual |
|
||||
| 38 | Summary: ; ; false; RtlCopyUnicodeString; ; ; Argument[*1].Field[*Buffer]; Argument[*0].Field[*Buffer]; value; manual |
|
||||
| 39 | Summary: ; ; false; RtlCopyVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual |
|
||||
| 40 | Summary: ; ; false; RtlInitUnicodeString; ; ; Argument[*1]; Argument[*0].Field[*Buffer]; value; manual |
|
||||
| 41 | Summary: ; ; false; RtlMoveMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual |
|
||||
| 42 | Summary: ; ; false; RtlMoveVolatileMemory; ; ; Argument[*@1]; Argument[*@0]; value; manual |
|
||||
| 43 | Summary: ; ; false; WinHttpCrackUrl; ; ; Argument[*0]; Argument[*3]; taint; manual |
|
||||
| 44 | Summary: ; ; false; callWithArgument; ; ; Argument[1]; Argument[0].Parameter[0]; value; manual |
|
||||
| 45 | Summary: ; ; false; callWithNonTypeTemplate<T>; (const T &); ; Argument[*0]; ReturnValue; value; manual |
|
||||
| 46 | Summary: ; ; false; pthread_create; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual |
|
||||
| 47 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated |
|
||||
| 48 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual |
|
||||
| 49 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual |
|
||||
| 50 | Summary: Azure::Core::IO; BodyStream; true; Read; ; ; Argument[-1]; Argument[*0]; taint; manual |
|
||||
| 51 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual |
|
||||
| 52 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual |
|
||||
| 53 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual |
|
||||
| 54 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual |
|
||||
edges
|
||||
| asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | provenance | MaD:37 |
|
||||
| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:17 |
|
||||
| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:17 Sink:MaD:2 |
|
||||
| asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | provenance | MaD:54 |
|
||||
| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:29 |
|
||||
| asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:29 Sink:MaD:2 |
|
||||
| asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:98:7:98:14 | send_str | provenance | TaintFunction |
|
||||
| asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:100:64:100:71 | *send_str | provenance | TaintFunction |
|
||||
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | |
|
||||
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:101:7:101:17 | send_buffer | provenance | |
|
||||
| asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:103:29:103:39 | *send_buffer | provenance | Sink:MaD:2 |
|
||||
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | provenance | |
|
||||
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:37 |
|
||||
| test.cpp:4:5:4:17 | [summary param] 0 in ymlStepManual | test.cpp:4:5:4:17 | [summary] to write: ReturnValue in ymlStepManual | provenance | MaD:35 |
|
||||
| test.cpp:5:5:5:20 | [summary param] 0 in ymlStepGenerated | test.cpp:5:5:5:20 | [summary] to write: ReturnValue in ymlStepGenerated | provenance | MaD:34 |
|
||||
| test.cpp:6:5:6:27 | [summary param] 0 in ymlStepManual_with_body | test.cpp:6:5:6:27 | [summary] to write: ReturnValue in ymlStepManual_with_body | provenance | MaD:36 |
|
||||
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:54 |
|
||||
| azure.cpp:62:10:62:14 | [summary param] this in Value | azure.cpp:62:10:62:14 | [summary] to write: ReturnValue[*] in Value | provenance | MaD:53 |
|
||||
| azure.cpp:113:16:113:19 | [summary param] this in Read | azure.cpp:113:16:113:19 | [summary param] *0 in Read [Return] | provenance | MaD:50 |
|
||||
| azure.cpp:114:16:114:26 | [summary param] this in ReadToCount | azure.cpp:114:16:114:26 | [summary param] *0 in ReadToCount [Return] | provenance | MaD:51 |
|
||||
| azure.cpp:115:30:115:38 | [summary param] this in ReadToEnd | azure.cpp:115:30:115:38 | [summary] to write: ReturnValue.Element in ReadToEnd | provenance | MaD:52 |
|
||||
| azure.cpp:115:30:115:38 | [summary] to write: ReturnValue.Element in ReadToEnd | azure.cpp:115:30:115:38 | [summary] to write: ReturnValue in ReadToEnd [element] | provenance | |
|
||||
| azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:253:48:253:60 | *call to GetBodyStream | provenance | Src:MaD:26 |
|
||||
| azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:257:5:257:8 | *resp | provenance | |
|
||||
| azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:262:5:262:8 | *resp | provenance | |
|
||||
| azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:266:38:266:41 | *resp | provenance | |
|
||||
| azure.cpp:257:5:257:8 | *resp | azure.cpp:113:16:113:19 | [summary param] this in Read | provenance | |
|
||||
| azure.cpp:257:5:257:8 | *resp | azure.cpp:257:16:257:21 | Read output argument | provenance | MaD:50 |
|
||||
| azure.cpp:257:16:257:21 | Read output argument | azure.cpp:258:10:258:16 | * ... | provenance | |
|
||||
| azure.cpp:262:5:262:8 | *resp | azure.cpp:114:16:114:26 | [summary param] this in ReadToCount | provenance | |
|
||||
| azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | provenance | MaD:51 |
|
||||
| azure.cpp:262:23:262:28 | ReadToCount output argument | azure.cpp:263:10:263:16 | * ... | provenance | |
|
||||
| azure.cpp:266:38:266:41 | *resp | azure.cpp:115:30:115:38 | [summary param] this in ReadToEnd | provenance | |
|
||||
| azure.cpp:266:38:266:41 | *resp | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | MaD:52 |
|
||||
| azure.cpp:266:44:266:52 | call to ReadToEnd [element] | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | |
|
||||
| azure.cpp:266:44:266:52 | call to ReadToEnd [element] | azure.cpp:267:10:267:12 | vec [element] | provenance | |
|
||||
| azure.cpp:267:10:267:12 | vec [element] | azure.cpp:267:10:267:12 | vec | provenance | |
|
||||
| azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:273:62:273:64 | call to GetHeaders | provenance | Src:MaD:25 |
|
||||
| azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:274:14:274:29 | call to operator[] | provenance | TaintFunction |
|
||||
| azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:274:14:274:29 | call to operator[] | provenance | TaintFunction |
|
||||
| azure.cpp:273:62:273:64 | call to GetHeaders | azure.cpp:274:14:274:29 | call to operator[] | provenance | TaintFunction |
|
||||
| azure.cpp:274:14:274:29 | call to operator[] | azure.cpp:274:10:274:29 | call to operator[] | provenance | |
|
||||
| azure.cpp:274:14:274:29 | call to operator[] | azure.cpp:274:14:274:29 | call to operator[] | provenance | |
|
||||
| azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:277:45:277:47 | call to GetBody | provenance | Src:MaD:24 |
|
||||
| azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:278:10:278:13 | body | provenance | |
|
||||
| azure.cpp:277:45:277:47 | call to GetBody | azure.cpp:278:10:278:13 | body | provenance | |
|
||||
| azure.cpp:278:10:278:13 | body | azure.cpp:278:10:278:13 | body | provenance | |
|
||||
| azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | provenance | Src:MaD:23 |
|
||||
| azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:282:21:282:23 | *call to get | provenance | |
|
||||
| azure.cpp:282:21:282:23 | *call to get | azure.cpp:115:30:115:38 | [summary param] this in ReadToEnd | provenance | |
|
||||
| azure.cpp:282:21:282:23 | *call to get | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | MaD:52 |
|
||||
| azure.cpp:282:28:282:36 | call to ReadToEnd [element] | azure.cpp:282:10:282:38 | call to ReadToEnd | provenance | |
|
||||
| azure.cpp:282:28:282:36 | call to ReadToEnd [element] | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | |
|
||||
| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:62:10:62:14 | [summary param] this in Value | provenance | |
|
||||
| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | provenance | MaD:53 |
|
||||
| azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:24:289:56 | call to GetHeader | provenance | |
|
||||
| azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:32:289:40 | call to GetHeader | provenance | Src:MaD:27 |
|
||||
| azure.cpp:289:63:289:65 | call to Value | azure.cpp:289:63:289:65 | call to Value | provenance | |
|
||||
| azure.cpp:289:63:289:65 | call to Value | azure.cpp:290:10:290:20 | headerValue | provenance | |
|
||||
| azure.cpp:289:63:289:65 | call to Value | azure.cpp:290:10:290:20 | headerValue | provenance | |
|
||||
| azure.cpp:290:10:290:20 | headerValue | azure.cpp:290:10:290:20 | headerValue | provenance | |
|
||||
| azure.cpp:293:58:293:67 | call to GetHeaders | azure.cpp:293:58:293:67 | call to GetHeaders | provenance | Src:MaD:28 |
|
||||
| azure.cpp:293:58:293:67 | call to GetHeaders | azure.cpp:294:38:294:53 | call to operator[] | provenance | TaintFunction |
|
||||
| azure.cpp:294:38:294:53 | call to operator[] | azure.cpp:295:10:295:20 | contentType | provenance | |
|
||||
| azure.cpp:294:38:294:53 | call to operator[] | azure.cpp:295:10:295:20 | contentType | provenance | |
|
||||
| azure.cpp:295:10:295:20 | contentType | azure.cpp:295:10:295:20 | contentType | provenance | |
|
||||
| test.cpp:4:5:4:17 | [summary param] 0 in ymlStepManual | test.cpp:4:5:4:17 | [summary] to write: ReturnValue in ymlStepManual | provenance | MaD:48 |
|
||||
| test.cpp:5:5:5:20 | [summary param] 0 in ymlStepGenerated | test.cpp:5:5:5:20 | [summary] to write: ReturnValue in ymlStepGenerated | provenance | MaD:47 |
|
||||
| test.cpp:6:5:6:27 | [summary param] 0 in ymlStepManual_with_body | test.cpp:6:5:6:27 | [summary] to write: ReturnValue in ymlStepManual_with_body | provenance | MaD:49 |
|
||||
| test.cpp:7:47:7:52 | value2 | test.cpp:7:64:7:69 | value2 | provenance | |
|
||||
| test.cpp:7:64:7:69 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | provenance | |
|
||||
| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:10:10:10:18 | call to ymlSource | provenance | Src:MaD:16 |
|
||||
| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:10:10:10:18 | call to ymlSource | provenance | Src:MaD:22 |
|
||||
| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:14:10:14:10 | x | provenance | Sink:MaD:1 |
|
||||
| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:17:24:17:24 | x | provenance | |
|
||||
| test.cpp:10:10:10:18 | call to ymlSource | test.cpp:21:27:21:27 | x | provenance | |
|
||||
@@ -61,15 +127,15 @@ edges
|
||||
| test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | |
|
||||
| test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:18:10:18:10 | y | provenance | Sink:MaD:1 |
|
||||
| test.cpp:17:24:17:24 | x | test.cpp:4:5:4:17 | [summary param] 0 in ymlStepManual | provenance | |
|
||||
| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:35 |
|
||||
| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:48 |
|
||||
| test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | |
|
||||
| test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:22:10:22:10 | z | provenance | Sink:MaD:1 |
|
||||
| test.cpp:21:27:21:27 | x | test.cpp:5:5:5:20 | [summary param] 0 in ymlStepGenerated | provenance | |
|
||||
| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:34 |
|
||||
| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:47 |
|
||||
| test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | |
|
||||
| test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:26:10:26:11 | y2 | provenance | Sink:MaD:1 |
|
||||
| test.cpp:25:35:25:35 | x | test.cpp:6:5:6:27 | [summary param] 0 in ymlStepManual_with_body | provenance | |
|
||||
| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:36 |
|
||||
| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:49 |
|
||||
| test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | provenance | |
|
||||
| test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:33:10:33:11 | z2 | provenance | Sink:MaD:1 |
|
||||
| test.cpp:32:41:32:41 | x | test.cpp:7:47:7:52 | value2 | provenance | |
|
||||
@@ -77,16 +143,16 @@ edges
|
||||
| test.cpp:46:30:46:32 | *arg [x] | test.cpp:47:12:47:19 | *arg [x] | provenance | |
|
||||
| test.cpp:47:12:47:19 | *arg [x] | test.cpp:48:13:48:13 | *s [x] | provenance | |
|
||||
| test.cpp:48:13:48:13 | *s [x] | test.cpp:48:16:48:16 | x | provenance | Sink:MaD:1 |
|
||||
| test.cpp:52:5:52:18 | [summary param] *3 in pthread_create [x] | test.cpp:52:5:52:18 | [summary] to write: Argument[2].Parameter[*0] in pthread_create [x] | provenance | MaD:33 |
|
||||
| test.cpp:52:5:52:18 | [summary param] *3 in pthread_create [x] | test.cpp:52:5:52:18 | [summary] to write: Argument[2].Parameter[*0] in pthread_create [x] | provenance | MaD:46 |
|
||||
| test.cpp:52:5:52:18 | [summary] to write: Argument[2].Parameter[*0] in pthread_create [x] | test.cpp:46:30:46:32 | *arg [x] | provenance | |
|
||||
| test.cpp:56:2:56:2 | *s [post update] [x] | test.cpp:59:55:59:64 | *& ... [x] | provenance | |
|
||||
| test.cpp:56:2:56:18 | ... = ... | test.cpp:56:2:56:2 | *s [post update] [x] | provenance | |
|
||||
| test.cpp:56:8:56:16 | call to ymlSource | test.cpp:56:2:56:18 | ... = ... | provenance | Src:MaD:16 |
|
||||
| test.cpp:56:8:56:16 | call to ymlSource | test.cpp:56:2:56:18 | ... = ... | provenance | Src:MaD:22 |
|
||||
| test.cpp:59:55:59:64 | *& ... [x] | test.cpp:52:5:52:18 | [summary param] *3 in pthread_create [x] | provenance | |
|
||||
| test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | provenance | MaD:31 |
|
||||
| test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | provenance | MaD:31 |
|
||||
| test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | provenance | MaD:31 |
|
||||
| test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | provenance | MaD:31 |
|
||||
| test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | provenance | MaD:44 |
|
||||
| test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | provenance | MaD:44 |
|
||||
| test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | provenance | MaD:44 |
|
||||
| test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | provenance | MaD:44 |
|
||||
| test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | test.cpp:68:22:68:22 | y | provenance | |
|
||||
| test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | test.cpp:74:22:74:22 | y | provenance | |
|
||||
| test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | test.cpp:82:22:82:22 | y | provenance | |
|
||||
@@ -95,7 +161,7 @@ edges
|
||||
| test.cpp:74:22:74:22 | y | test.cpp:75:11:75:11 | y | provenance | Sink:MaD:1 |
|
||||
| test.cpp:82:22:82:22 | y | test.cpp:83:11:83:11 | y | provenance | Sink:MaD:1 |
|
||||
| test.cpp:88:22:88:22 | y | test.cpp:89:11:89:11 | y | provenance | Sink:MaD:1 |
|
||||
| test.cpp:94:10:94:18 | call to ymlSource | test.cpp:94:10:94:18 | call to ymlSource | provenance | Src:MaD:16 |
|
||||
| test.cpp:94:10:94:18 | call to ymlSource | test.cpp:94:10:94:18 | call to ymlSource | provenance | Src:MaD:22 |
|
||||
| test.cpp:94:10:94:18 | call to ymlSource | test.cpp:97:26:97:26 | x | provenance | |
|
||||
| test.cpp:94:10:94:18 | call to ymlSource | test.cpp:101:26:101:26 | x | provenance | |
|
||||
| test.cpp:94:10:94:18 | call to ymlSource | test.cpp:103:63:103:63 | x | provenance | |
|
||||
@@ -104,28 +170,28 @@ edges
|
||||
| test.cpp:101:26:101:26 | x | test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | provenance | |
|
||||
| test.cpp:103:63:103:63 | x | test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | provenance | |
|
||||
| test.cpp:104:62:104:62 | x | test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | provenance | |
|
||||
| test.cpp:111:3:111:25 | [summary param] *0 in callWithNonTypeTemplate | test.cpp:111:3:111:25 | [summary] to write: ReturnValue in callWithNonTypeTemplate | provenance | MaD:32 |
|
||||
| test.cpp:114:10:114:18 | call to ymlSource | test.cpp:114:10:114:18 | call to ymlSource | provenance | Src:MaD:16 |
|
||||
| test.cpp:111:3:111:25 | [summary param] *0 in callWithNonTypeTemplate | test.cpp:111:3:111:25 | [summary] to write: ReturnValue in callWithNonTypeTemplate | provenance | MaD:45 |
|
||||
| test.cpp:114:10:114:18 | call to ymlSource | test.cpp:114:10:114:18 | call to ymlSource | provenance | Src:MaD:22 |
|
||||
| test.cpp:114:10:114:18 | call to ymlSource | test.cpp:118:44:118:44 | *x | provenance | |
|
||||
| test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | |
|
||||
| test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | test.cpp:119:10:119:11 | y2 | provenance | Sink:MaD:1 |
|
||||
| test.cpp:118:44:118:44 | *x | test.cpp:111:3:111:25 | [summary param] *0 in callWithNonTypeTemplate | provenance | |
|
||||
| test.cpp:118:44:118:44 | *x | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | MaD:32 |
|
||||
| windows.cpp:17:8:17:25 | [summary param] *0 in CommandLineToArgvA | windows.cpp:17:8:17:25 | [summary] to write: ReturnValue[**] in CommandLineToArgvA | provenance | MaD:18 |
|
||||
| test.cpp:118:44:118:44 | *x | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | MaD:45 |
|
||||
| windows.cpp:17:8:17:25 | [summary param] *0 in CommandLineToArgvA | windows.cpp:17:8:17:25 | [summary] to write: ReturnValue[**] in CommandLineToArgvA | provenance | MaD:30 |
|
||||
| windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:22:15:22:29 | *call to GetCommandLineA | provenance | Src:MaD:3 |
|
||||
| windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:24:8:24:11 | * ... | provenance | |
|
||||
| windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:27:36:27:38 | *cmd | provenance | |
|
||||
| windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | |
|
||||
| windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | windows.cpp:30:8:30:15 | * ... | provenance | |
|
||||
| windows.cpp:27:36:27:38 | *cmd | windows.cpp:17:8:17:25 | [summary param] *0 in CommandLineToArgvA | provenance | |
|
||||
| windows.cpp:27:36:27:38 | *cmd | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | MaD:18 |
|
||||
| windows.cpp:27:36:27:38 | *cmd | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | provenance | MaD:30 |
|
||||
| windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | provenance | Src:MaD:4 |
|
||||
| windows.cpp:34:17:34:38 | *call to GetEnvironmentStringsA | windows.cpp:36:10:36:13 | * ... | provenance | |
|
||||
| windows.cpp:39:36:39:38 | GetEnvironmentVariableA output argument | windows.cpp:41:10:41:13 | * ... | provenance | Src:MaD:5 |
|
||||
| windows.cpp:90:6:90:15 | [summary param] *3 in ReadFileEx [*hEvent] | windows.cpp:90:6:90:15 | [summary] read: Argument[*3].Field[*hEvent] in ReadFileEx | provenance | |
|
||||
| windows.cpp:90:6:90:15 | [summary param] *3 in ReadFileEx [hEvent] | windows.cpp:90:6:90:15 | [summary] read: Argument[*3].Field[hEvent] in ReadFileEx | provenance | |
|
||||
| windows.cpp:90:6:90:15 | [summary] read: Argument[*3].Field[*hEvent] in ReadFileEx | windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2].Field[*hEvent] in ReadFileEx | provenance | MaD:22 |
|
||||
| windows.cpp:90:6:90:15 | [summary] read: Argument[*3].Field[hEvent] in ReadFileEx | windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2].Field[hEvent] in ReadFileEx | provenance | MaD:22 |
|
||||
| windows.cpp:90:6:90:15 | [summary] read: Argument[*3].Field[*hEvent] in ReadFileEx | windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2].Field[*hEvent] in ReadFileEx | provenance | MaD:34 |
|
||||
| windows.cpp:90:6:90:15 | [summary] read: Argument[*3].Field[hEvent] in ReadFileEx | windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2].Field[hEvent] in ReadFileEx | provenance | MaD:34 |
|
||||
| windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2] in ReadFileEx [*hEvent] | windows.cpp:147:16:147:27 | *lpOverlapped [*hEvent] | provenance | |
|
||||
| windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2] in ReadFileEx [hEvent] | windows.cpp:157:16:157:27 | *lpOverlapped [hEvent] | provenance | |
|
||||
| windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2].Field[*hEvent] in ReadFileEx | windows.cpp:90:6:90:15 | [summary] to write: Argument[4].Parameter[*2] in ReadFileEx [*hEvent] | provenance | |
|
||||
@@ -173,11 +239,11 @@ edges
|
||||
| windows.cpp:332:23:332:40 | *call to MapViewOfFileNuma2 | windows.cpp:332:23:332:40 | *call to MapViewOfFileNuma2 | provenance | Src:MaD:12 |
|
||||
| windows.cpp:332:23:332:40 | *call to MapViewOfFileNuma2 | windows.cpp:333:20:333:52 | *pMapView | provenance | |
|
||||
| windows.cpp:333:20:333:52 | *pMapView | windows.cpp:335:10:335:16 | * ... | provenance | |
|
||||
| windows.cpp:349:8:349:19 | [summary param] *3 in CreateThread [x] | windows.cpp:349:8:349:19 | [summary] to write: Argument[2].Parameter[*0] in CreateThread [x] | provenance | MaD:21 |
|
||||
| windows.cpp:349:8:349:19 | [summary param] *3 in CreateThread [x] | windows.cpp:349:8:349:19 | [summary] to write: Argument[2].Parameter[*0] in CreateThread [x] | provenance | MaD:33 |
|
||||
| windows.cpp:349:8:349:19 | [summary] to write: Argument[2].Parameter[*0] in CreateThread [x] | windows.cpp:403:26:403:36 | *lpParameter [x] | provenance | |
|
||||
| windows.cpp:357:8:357:25 | [summary param] *4 in CreateRemoteThread [x] | windows.cpp:357:8:357:25 | [summary] to write: Argument[3].Parameter[*0] in CreateRemoteThread [x] | provenance | MaD:19 |
|
||||
| windows.cpp:357:8:357:25 | [summary param] *4 in CreateRemoteThread [x] | windows.cpp:357:8:357:25 | [summary] to write: Argument[3].Parameter[*0] in CreateRemoteThread [x] | provenance | MaD:31 |
|
||||
| windows.cpp:357:8:357:25 | [summary] to write: Argument[3].Parameter[*0] in CreateRemoteThread [x] | windows.cpp:410:26:410:36 | *lpParameter [x] | provenance | |
|
||||
| windows.cpp:387:8:387:27 | [summary param] *4 in CreateRemoteThreadEx [x] | windows.cpp:387:8:387:27 | [summary] to write: Argument[3].Parameter[*0] in CreateRemoteThreadEx [x] | provenance | MaD:20 |
|
||||
| windows.cpp:387:8:387:27 | [summary param] *4 in CreateRemoteThreadEx [x] | windows.cpp:387:8:387:27 | [summary] to write: Argument[3].Parameter[*0] in CreateRemoteThreadEx [x] | provenance | MaD:32 |
|
||||
| windows.cpp:387:8:387:27 | [summary] to write: Argument[3].Parameter[*0] in CreateRemoteThreadEx [x] | windows.cpp:417:26:417:36 | *lpParameter [x] | provenance | |
|
||||
| windows.cpp:403:26:403:36 | *lpParameter [x] | windows.cpp:405:10:405:25 | *lpParameter [x] | provenance | |
|
||||
| windows.cpp:405:10:405:25 | *lpParameter [x] | windows.cpp:406:8:406:8 | *s [x] | provenance | |
|
||||
@@ -196,17 +262,17 @@ edges
|
||||
| windows.cpp:439:7:439:8 | *& ... [x] | windows.cpp:349:8:349:19 | [summary param] *3 in CreateThread [x] | provenance | |
|
||||
| windows.cpp:451:7:451:8 | *& ... [x] | windows.cpp:357:8:357:25 | [summary param] *4 in CreateRemoteThread [x] | provenance | |
|
||||
| windows.cpp:464:7:464:8 | *& ... [x] | windows.cpp:387:8:387:27 | [summary param] *4 in CreateRemoteThreadEx [x] | provenance | |
|
||||
| windows.cpp:473:17:473:37 | [summary param] *1 in RtlCopyVolatileMemory | windows.cpp:473:17:473:37 | [summary param] *0 in RtlCopyVolatileMemory [Return] | provenance | MaD:27 |
|
||||
| windows.cpp:479:17:479:35 | [summary param] *1 in RtlCopyDeviceMemory | windows.cpp:479:17:479:35 | [summary param] *0 in RtlCopyDeviceMemory [Return] | provenance | MaD:23 |
|
||||
| windows.cpp:485:6:485:18 | [summary param] *1 in RtlCopyMemory | windows.cpp:485:6:485:18 | [summary param] *0 in RtlCopyMemory [Return] | provenance | MaD:24 |
|
||||
| windows.cpp:493:6:493:29 | [summary param] *1 in RtlCopyMemoryNonTemporal | windows.cpp:493:6:493:29 | [summary param] *0 in RtlCopyMemoryNonTemporal [Return] | provenance | MaD:25 |
|
||||
| windows.cpp:473:17:473:37 | [summary param] *1 in RtlCopyVolatileMemory | windows.cpp:473:17:473:37 | [summary param] *0 in RtlCopyVolatileMemory [Return] | provenance | MaD:39 |
|
||||
| windows.cpp:479:17:479:35 | [summary param] *1 in RtlCopyDeviceMemory | windows.cpp:479:17:479:35 | [summary param] *0 in RtlCopyDeviceMemory [Return] | provenance | MaD:35 |
|
||||
| windows.cpp:485:6:485:18 | [summary param] *1 in RtlCopyMemory | windows.cpp:485:6:485:18 | [summary param] *0 in RtlCopyMemory [Return] | provenance | MaD:36 |
|
||||
| windows.cpp:493:6:493:29 | [summary param] *1 in RtlCopyMemoryNonTemporal | windows.cpp:493:6:493:29 | [summary param] *0 in RtlCopyMemoryNonTemporal [Return] | provenance | MaD:37 |
|
||||
| windows.cpp:510:6:510:25 | [summary param] *1 in RtlCopyUnicodeString [*Buffer] | windows.cpp:510:6:510:25 | [summary] read: Argument[*1].Field[*Buffer] in RtlCopyUnicodeString | provenance | |
|
||||
| windows.cpp:510:6:510:25 | [summary] read: Argument[*1].Field[*Buffer] in RtlCopyUnicodeString | windows.cpp:510:6:510:25 | [summary] to write: Argument[*0].Field[*Buffer] in RtlCopyUnicodeString | provenance | MaD:26 |
|
||||
| windows.cpp:510:6:510:25 | [summary] read: Argument[*1].Field[*Buffer] in RtlCopyUnicodeString | windows.cpp:510:6:510:25 | [summary] to write: Argument[*0].Field[*Buffer] in RtlCopyUnicodeString | provenance | MaD:38 |
|
||||
| windows.cpp:510:6:510:25 | [summary] to write: Argument[*0] in RtlCopyUnicodeString [*Buffer] | windows.cpp:510:6:510:25 | [summary param] *0 in RtlCopyUnicodeString [Return] [*Buffer] | provenance | |
|
||||
| windows.cpp:510:6:510:25 | [summary] to write: Argument[*0].Field[*Buffer] in RtlCopyUnicodeString | windows.cpp:510:6:510:25 | [summary] to write: Argument[*0] in RtlCopyUnicodeString [*Buffer] | provenance | |
|
||||
| windows.cpp:515:6:515:18 | [summary param] *1 in RtlMoveMemory | windows.cpp:515:6:515:18 | [summary param] *0 in RtlMoveMemory [Return] | provenance | MaD:29 |
|
||||
| windows.cpp:521:17:521:37 | [summary param] *1 in RtlMoveVolatileMemory | windows.cpp:521:17:521:37 | [summary param] *0 in RtlMoveVolatileMemory [Return] | provenance | MaD:30 |
|
||||
| windows.cpp:527:6:527:25 | [summary param] *1 in RtlInitUnicodeString | windows.cpp:527:6:527:25 | [summary] to write: Argument[*0].Field[*Buffer] in RtlInitUnicodeString | provenance | MaD:28 |
|
||||
| windows.cpp:515:6:515:18 | [summary param] *1 in RtlMoveMemory | windows.cpp:515:6:515:18 | [summary param] *0 in RtlMoveMemory [Return] | provenance | MaD:41 |
|
||||
| windows.cpp:521:17:521:37 | [summary param] *1 in RtlMoveVolatileMemory | windows.cpp:521:17:521:37 | [summary param] *0 in RtlMoveVolatileMemory [Return] | provenance | MaD:42 |
|
||||
| windows.cpp:527:6:527:25 | [summary param] *1 in RtlInitUnicodeString | windows.cpp:527:6:527:25 | [summary] to write: Argument[*0].Field[*Buffer] in RtlInitUnicodeString | provenance | MaD:40 |
|
||||
| windows.cpp:527:6:527:25 | [summary] to write: Argument[*0] in RtlInitUnicodeString [*Buffer] | windows.cpp:527:6:527:25 | [summary param] *0 in RtlInitUnicodeString [Return] [*Buffer] | provenance | |
|
||||
| windows.cpp:527:6:527:25 | [summary] to write: Argument[*0].Field[*Buffer] in RtlInitUnicodeString | windows.cpp:527:6:527:25 | [summary] to write: Argument[*0] in RtlInitUnicodeString [*Buffer] | provenance | |
|
||||
| windows.cpp:533:11:533:16 | call to source | windows.cpp:533:11:533:16 | call to source | provenance | |
|
||||
@@ -218,37 +284,51 @@ edges
|
||||
| windows.cpp:533:11:533:16 | call to source | windows.cpp:573:40:573:41 | *& ... | provenance | |
|
||||
| windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument | windows.cpp:538:10:538:23 | access to array | provenance | |
|
||||
| windows.cpp:537:40:537:41 | *& ... | windows.cpp:473:17:473:37 | [summary param] *1 in RtlCopyVolatileMemory | provenance | |
|
||||
| windows.cpp:537:40:537:41 | *& ... | windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument | provenance | MaD:27 |
|
||||
| windows.cpp:537:40:537:41 | *& ... | windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument | provenance | MaD:39 |
|
||||
| windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument | windows.cpp:543:10:543:23 | access to array | provenance | |
|
||||
| windows.cpp:542:38:542:39 | *& ... | windows.cpp:479:17:479:35 | [summary param] *1 in RtlCopyDeviceMemory | provenance | |
|
||||
| windows.cpp:542:38:542:39 | *& ... | windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument | provenance | MaD:23 |
|
||||
| windows.cpp:542:38:542:39 | *& ... | windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument | provenance | MaD:35 |
|
||||
| windows.cpp:547:19:547:29 | RtlCopyMemory output argument | windows.cpp:548:10:548:23 | access to array | provenance | |
|
||||
| windows.cpp:547:32:547:33 | *& ... | windows.cpp:485:6:485:18 | [summary param] *1 in RtlCopyMemory | provenance | |
|
||||
| windows.cpp:547:32:547:33 | *& ... | windows.cpp:547:19:547:29 | RtlCopyMemory output argument | provenance | MaD:24 |
|
||||
| windows.cpp:547:32:547:33 | *& ... | windows.cpp:547:19:547:29 | RtlCopyMemory output argument | provenance | MaD:36 |
|
||||
| windows.cpp:552:30:552:40 | RtlCopyMemoryNonTemporal output argument | windows.cpp:553:10:553:23 | access to array | provenance | |
|
||||
| windows.cpp:552:43:552:44 | *& ... | windows.cpp:493:6:493:29 | [summary param] *1 in RtlCopyMemoryNonTemporal | provenance | |
|
||||
| windows.cpp:552:43:552:44 | *& ... | windows.cpp:552:30:552:40 | RtlCopyMemoryNonTemporal output argument | provenance | MaD:25 |
|
||||
| windows.cpp:552:43:552:44 | *& ... | windows.cpp:552:30:552:40 | RtlCopyMemoryNonTemporal output argument | provenance | MaD:37 |
|
||||
| windows.cpp:559:5:559:24 | ... = ... | windows.cpp:561:39:561:44 | *buffer | provenance | |
|
||||
| windows.cpp:559:17:559:24 | call to source | windows.cpp:559:5:559:24 | ... = ... | provenance | |
|
||||
| windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | windows.cpp:562:10:562:19 | *src_string [*Buffer] | provenance | |
|
||||
| windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | windows.cpp:563:40:563:50 | *& ... [*Buffer] | provenance | |
|
||||
| windows.cpp:561:39:561:44 | *buffer | windows.cpp:527:6:527:25 | [summary param] *1 in RtlInitUnicodeString | provenance | |
|
||||
| windows.cpp:561:39:561:44 | *buffer | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | provenance | MaD:28 |
|
||||
| windows.cpp:561:39:561:44 | *buffer | windows.cpp:561:26:561:36 | RtlInitUnicodeString output argument [*Buffer] | provenance | MaD:40 |
|
||||
| windows.cpp:562:10:562:19 | *src_string [*Buffer] | windows.cpp:562:10:562:29 | access to array | provenance | |
|
||||
| windows.cpp:562:10:562:19 | *src_string [*Buffer] | windows.cpp:562:21:562:26 | *Buffer | provenance | |
|
||||
| windows.cpp:562:21:562:26 | *Buffer | windows.cpp:562:10:562:29 | access to array | provenance | |
|
||||
| windows.cpp:563:26:563:37 | RtlCopyUnicodeString output argument [*Buffer] | windows.cpp:564:10:564:20 | *dest_string [*Buffer] | provenance | |
|
||||
| windows.cpp:563:40:563:50 | *& ... [*Buffer] | windows.cpp:510:6:510:25 | [summary param] *1 in RtlCopyUnicodeString [*Buffer] | provenance | |
|
||||
| windows.cpp:563:40:563:50 | *& ... [*Buffer] | windows.cpp:563:26:563:37 | RtlCopyUnicodeString output argument [*Buffer] | provenance | MaD:26 |
|
||||
| windows.cpp:563:40:563:50 | *& ... [*Buffer] | windows.cpp:563:26:563:37 | RtlCopyUnicodeString output argument [*Buffer] | provenance | MaD:38 |
|
||||
| windows.cpp:564:10:564:20 | *dest_string [*Buffer] | windows.cpp:564:10:564:30 | access to array | provenance | |
|
||||
| windows.cpp:564:10:564:20 | *dest_string [*Buffer] | windows.cpp:564:22:564:27 | *Buffer | provenance | |
|
||||
| windows.cpp:564:22:564:27 | *Buffer | windows.cpp:564:10:564:30 | access to array | provenance | |
|
||||
| windows.cpp:568:19:568:29 | RtlMoveMemory output argument | windows.cpp:569:10:569:23 | access to array | provenance | |
|
||||
| windows.cpp:568:32:568:33 | *& ... | windows.cpp:515:6:515:18 | [summary param] *1 in RtlMoveMemory | provenance | |
|
||||
| windows.cpp:568:32:568:33 | *& ... | windows.cpp:568:19:568:29 | RtlMoveMemory output argument | provenance | MaD:29 |
|
||||
| windows.cpp:568:32:568:33 | *& ... | windows.cpp:568:19:568:29 | RtlMoveMemory output argument | provenance | MaD:41 |
|
||||
| windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | windows.cpp:574:10:574:23 | access to array | provenance | |
|
||||
| windows.cpp:573:40:573:41 | *& ... | windows.cpp:521:17:521:37 | [summary param] *1 in RtlMoveVolatileMemory | provenance | |
|
||||
| windows.cpp:573:40:573:41 | *& ... | windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | provenance | MaD:30 |
|
||||
| windows.cpp:573:40:573:41 | *& ... | windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | provenance | MaD:42 |
|
||||
| windows.cpp:645:45:645:50 | WinHttpReadData output argument | windows.cpp:647:10:647:16 | * ... | provenance | Src:MaD:20 |
|
||||
| windows.cpp:652:48:652:53 | WinHttpReadDataEx output argument | windows.cpp:654:10:654:16 | * ... | provenance | Src:MaD:21 |
|
||||
| windows.cpp:659:47:659:52 | WinHttpQueryHeaders output argument | windows.cpp:661:10:661:16 | * ... | provenance | Src:MaD:16 |
|
||||
| windows.cpp:669:70:669:79 | WinHttpQueryHeadersEx output argument | windows.cpp:673:10:673:29 | * ... | provenance | Src:MaD:18 |
|
||||
| windows.cpp:669:82:669:87 | WinHttpQueryHeadersEx output argument | windows.cpp:671:10:671:16 | * ... | provenance | Src:MaD:19 |
|
||||
| windows.cpp:669:105:669:112 | WinHttpQueryHeadersEx output argument | windows.cpp:675:10:675:27 | * ... | provenance | Src:MaD:17 |
|
||||
| windows.cpp:714:6:714:20 | [summary param] *0 in WinHttpCrackUrl | windows.cpp:714:6:714:20 | [summary param] *3 in WinHttpCrackUrl [Return] | provenance | MaD:43 |
|
||||
| windows.cpp:728:5:728:28 | ... = ... | windows.cpp:729:35:729:35 | *x | provenance | |
|
||||
| windows.cpp:728:12:728:28 | call to source | windows.cpp:728:5:728:28 | ... = ... | provenance | |
|
||||
| windows.cpp:729:35:729:35 | *x | windows.cpp:714:6:714:20 | [summary param] *0 in WinHttpCrackUrl | provenance | |
|
||||
| windows.cpp:729:35:729:35 | *x | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | provenance | MaD:43 |
|
||||
| windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:731:10:731:36 | * ... | provenance | |
|
||||
| windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:733:10:733:35 | * ... | provenance | |
|
||||
| windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | windows.cpp:735:10:735:37 | * ... | provenance | |
|
||||
nodes
|
||||
| asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | semmle.label | [summary param] *0 in buffer |
|
||||
| asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | semmle.label | [summary] to write: ReturnValue in buffer |
|
||||
@@ -262,6 +342,59 @@ nodes
|
||||
| asio_streams.cpp:100:64:100:71 | *send_str | semmle.label | *send_str |
|
||||
| asio_streams.cpp:101:7:101:17 | send_buffer | semmle.label | send_buffer |
|
||||
| asio_streams.cpp:103:29:103:39 | *send_buffer | semmle.label | *send_buffer |
|
||||
| azure.cpp:62:10:62:14 | [summary param] this in Value | semmle.label | [summary param] this in Value |
|
||||
| azure.cpp:62:10:62:14 | [summary] to write: ReturnValue[*] in Value | semmle.label | [summary] to write: ReturnValue[*] in Value |
|
||||
| azure.cpp:113:16:113:19 | [summary param] *0 in Read [Return] | semmle.label | [summary param] *0 in Read [Return] |
|
||||
| azure.cpp:113:16:113:19 | [summary param] this in Read | semmle.label | [summary param] this in Read |
|
||||
| azure.cpp:114:16:114:26 | [summary param] *0 in ReadToCount [Return] | semmle.label | [summary param] *0 in ReadToCount [Return] |
|
||||
| azure.cpp:114:16:114:26 | [summary param] this in ReadToCount | semmle.label | [summary param] this in ReadToCount |
|
||||
| azure.cpp:115:30:115:38 | [summary param] this in ReadToEnd | semmle.label | [summary param] this in ReadToEnd |
|
||||
| azure.cpp:115:30:115:38 | [summary] to write: ReturnValue in ReadToEnd [element] | semmle.label | [summary] to write: ReturnValue in ReadToEnd [element] |
|
||||
| azure.cpp:115:30:115:38 | [summary] to write: ReturnValue.Element in ReadToEnd | semmle.label | [summary] to write: ReturnValue.Element in ReadToEnd |
|
||||
| azure.cpp:253:48:253:60 | *call to GetBodyStream | semmle.label | *call to GetBodyStream |
|
||||
| azure.cpp:253:48:253:60 | *call to GetBodyStream | semmle.label | *call to GetBodyStream |
|
||||
| azure.cpp:257:5:257:8 | *resp | semmle.label | *resp |
|
||||
| azure.cpp:257:16:257:21 | Read output argument | semmle.label | Read output argument |
|
||||
| azure.cpp:258:10:258:16 | * ... | semmle.label | * ... |
|
||||
| azure.cpp:262:5:262:8 | *resp | semmle.label | *resp |
|
||||
| azure.cpp:262:23:262:28 | ReadToCount output argument | semmle.label | ReadToCount output argument |
|
||||
| azure.cpp:263:10:263:16 | * ... | semmle.label | * ... |
|
||||
| azure.cpp:266:38:266:41 | *resp | semmle.label | *resp |
|
||||
| azure.cpp:266:44:266:52 | call to ReadToEnd [element] | semmle.label | call to ReadToEnd [element] |
|
||||
| azure.cpp:266:44:266:52 | call to ReadToEnd [element] | semmle.label | call to ReadToEnd [element] |
|
||||
| azure.cpp:267:10:267:12 | vec | semmle.label | vec |
|
||||
| azure.cpp:267:10:267:12 | vec [element] | semmle.label | vec [element] |
|
||||
| azure.cpp:273:62:273:64 | call to GetHeaders | semmle.label | call to GetHeaders |
|
||||
| azure.cpp:273:62:273:64 | call to GetHeaders | semmle.label | call to GetHeaders |
|
||||
| azure.cpp:274:10:274:29 | call to operator[] | semmle.label | call to operator[] |
|
||||
| azure.cpp:274:14:274:29 | call to operator[] | semmle.label | call to operator[] |
|
||||
| azure.cpp:274:14:274:29 | call to operator[] | semmle.label | call to operator[] |
|
||||
| azure.cpp:274:14:274:29 | call to operator[] | semmle.label | call to operator[] |
|
||||
| azure.cpp:277:45:277:47 | call to GetBody | semmle.label | call to GetBody |
|
||||
| azure.cpp:277:45:277:47 | call to GetBody | semmle.label | call to GetBody |
|
||||
| azure.cpp:278:10:278:13 | body | semmle.label | body |
|
||||
| azure.cpp:278:10:278:13 | body | semmle.label | body |
|
||||
| azure.cpp:278:10:278:13 | body | semmle.label | body |
|
||||
| azure.cpp:281:68:281:84 | *call to ExtractBodyStream | semmle.label | *call to ExtractBodyStream |
|
||||
| azure.cpp:281:68:281:84 | *call to ExtractBodyStream | semmle.label | *call to ExtractBodyStream |
|
||||
| azure.cpp:282:10:282:38 | call to ReadToEnd | semmle.label | call to ReadToEnd |
|
||||
| azure.cpp:282:21:282:23 | *call to get | semmle.label | *call to get |
|
||||
| azure.cpp:282:28:282:36 | call to ReadToEnd [element] | semmle.label | call to ReadToEnd [element] |
|
||||
| azure.cpp:282:28:282:36 | call to ReadToEnd [element] | semmle.label | call to ReadToEnd [element] |
|
||||
| azure.cpp:289:24:289:56 | call to GetHeader | semmle.label | call to GetHeader |
|
||||
| azure.cpp:289:32:289:40 | call to GetHeader | semmle.label | call to GetHeader |
|
||||
| azure.cpp:289:32:289:40 | call to GetHeader | semmle.label | call to GetHeader |
|
||||
| azure.cpp:289:63:289:65 | call to Value | semmle.label | call to Value |
|
||||
| azure.cpp:289:63:289:65 | call to Value | semmle.label | call to Value |
|
||||
| azure.cpp:290:10:290:20 | headerValue | semmle.label | headerValue |
|
||||
| azure.cpp:290:10:290:20 | headerValue | semmle.label | headerValue |
|
||||
| azure.cpp:290:10:290:20 | headerValue | semmle.label | headerValue |
|
||||
| azure.cpp:293:58:293:67 | call to GetHeaders | semmle.label | call to GetHeaders |
|
||||
| azure.cpp:293:58:293:67 | call to GetHeaders | semmle.label | call to GetHeaders |
|
||||
| azure.cpp:294:38:294:53 | call to operator[] | semmle.label | call to operator[] |
|
||||
| azure.cpp:295:10:295:20 | contentType | semmle.label | contentType |
|
||||
| azure.cpp:295:10:295:20 | contentType | semmle.label | contentType |
|
||||
| azure.cpp:295:10:295:20 | contentType | semmle.label | contentType |
|
||||
| test.cpp:4:5:4:17 | [summary param] 0 in ymlStepManual | semmle.label | [summary param] 0 in ymlStepManual |
|
||||
| test.cpp:4:5:4:17 | [summary] to write: ReturnValue in ymlStepManual | semmle.label | [summary] to write: ReturnValue in ymlStepManual |
|
||||
| test.cpp:5:5:5:20 | [summary param] 0 in ymlStepGenerated | semmle.label | [summary param] 0 in ymlStepGenerated |
|
||||
@@ -482,8 +615,34 @@ nodes
|
||||
| windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument | semmle.label | RtlMoveVolatileMemory output argument |
|
||||
| windows.cpp:573:40:573:41 | *& ... | semmle.label | *& ... |
|
||||
| windows.cpp:574:10:574:23 | access to array | semmle.label | access to array |
|
||||
| windows.cpp:645:45:645:50 | WinHttpReadData output argument | semmle.label | WinHttpReadData output argument |
|
||||
| windows.cpp:647:10:647:16 | * ... | semmle.label | * ... |
|
||||
| windows.cpp:652:48:652:53 | WinHttpReadDataEx output argument | semmle.label | WinHttpReadDataEx output argument |
|
||||
| windows.cpp:654:10:654:16 | * ... | semmle.label | * ... |
|
||||
| windows.cpp:659:47:659:52 | WinHttpQueryHeaders output argument | semmle.label | WinHttpQueryHeaders output argument |
|
||||
| windows.cpp:661:10:661:16 | * ... | semmle.label | * ... |
|
||||
| windows.cpp:669:70:669:79 | WinHttpQueryHeadersEx output argument | semmle.label | WinHttpQueryHeadersEx output argument |
|
||||
| windows.cpp:669:82:669:87 | WinHttpQueryHeadersEx output argument | semmle.label | WinHttpQueryHeadersEx output argument |
|
||||
| windows.cpp:669:105:669:112 | WinHttpQueryHeadersEx output argument | semmle.label | WinHttpQueryHeadersEx output argument |
|
||||
| windows.cpp:671:10:671:16 | * ... | semmle.label | * ... |
|
||||
| windows.cpp:673:10:673:29 | * ... | semmle.label | * ... |
|
||||
| windows.cpp:675:10:675:27 | * ... | semmle.label | * ... |
|
||||
| windows.cpp:714:6:714:20 | [summary param] *0 in WinHttpCrackUrl | semmle.label | [summary param] *0 in WinHttpCrackUrl |
|
||||
| windows.cpp:714:6:714:20 | [summary param] *3 in WinHttpCrackUrl [Return] | semmle.label | [summary param] *3 in WinHttpCrackUrl [Return] |
|
||||
| windows.cpp:728:5:728:28 | ... = ... | semmle.label | ... = ... |
|
||||
| windows.cpp:728:12:728:28 | call to source | semmle.label | call to source |
|
||||
| windows.cpp:729:35:729:35 | *x | semmle.label | *x |
|
||||
| windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument | semmle.label | WinHttpCrackUrl output argument |
|
||||
| windows.cpp:731:10:731:36 | * ... | semmle.label | * ... |
|
||||
| windows.cpp:733:10:733:35 | * ... | semmle.label | * ... |
|
||||
| windows.cpp:735:10:735:37 | * ... | semmle.label | * ... |
|
||||
subpaths
|
||||
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | asio_streams.cpp:100:44:100:62 | call to buffer |
|
||||
| azure.cpp:257:5:257:8 | *resp | azure.cpp:113:16:113:19 | [summary param] this in Read | azure.cpp:113:16:113:19 | [summary param] *0 in Read [Return] | azure.cpp:257:16:257:21 | Read output argument |
|
||||
| azure.cpp:262:5:262:8 | *resp | azure.cpp:114:16:114:26 | [summary param] this in ReadToCount | azure.cpp:114:16:114:26 | [summary param] *0 in ReadToCount [Return] | azure.cpp:262:23:262:28 | ReadToCount output argument |
|
||||
| azure.cpp:266:38:266:41 | *resp | azure.cpp:115:30:115:38 | [summary param] this in ReadToEnd | azure.cpp:115:30:115:38 | [summary] to write: ReturnValue in ReadToEnd [element] | azure.cpp:266:44:266:52 | call to ReadToEnd [element] |
|
||||
| azure.cpp:282:21:282:23 | *call to get | azure.cpp:115:30:115:38 | [summary param] this in ReadToEnd | azure.cpp:115:30:115:38 | [summary] to write: ReturnValue in ReadToEnd [element] | azure.cpp:282:28:282:36 | call to ReadToEnd [element] |
|
||||
| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:62:10:62:14 | [summary param] this in Value | azure.cpp:62:10:62:14 | [summary] to write: ReturnValue[*] in Value | azure.cpp:289:63:289:65 | call to Value |
|
||||
| test.cpp:17:24:17:24 | x | test.cpp:4:5:4:17 | [summary param] 0 in ymlStepManual | test.cpp:4:5:4:17 | [summary] to write: ReturnValue in ymlStepManual | test.cpp:17:10:17:22 | call to ymlStepManual |
|
||||
| test.cpp:21:27:21:27 | x | test.cpp:5:5:5:20 | [summary param] 0 in ymlStepGenerated | test.cpp:5:5:5:20 | [summary] to write: ReturnValue in ymlStepGenerated | test.cpp:21:10:21:25 | call to ymlStepGenerated |
|
||||
| test.cpp:25:35:25:35 | x | test.cpp:6:5:6:27 | [summary param] 0 in ymlStepManual_with_body | test.cpp:6:5:6:27 | [summary] to write: ReturnValue in ymlStepManual_with_body | test.cpp:25:11:25:33 | call to ymlStepManual_with_body |
|
||||
@@ -498,4 +657,5 @@ subpaths
|
||||
| windows.cpp:563:40:563:50 | *& ... [*Buffer] | windows.cpp:510:6:510:25 | [summary param] *1 in RtlCopyUnicodeString [*Buffer] | windows.cpp:510:6:510:25 | [summary param] *0 in RtlCopyUnicodeString [Return] [*Buffer] | windows.cpp:563:26:563:37 | RtlCopyUnicodeString output argument [*Buffer] |
|
||||
| windows.cpp:568:32:568:33 | *& ... | windows.cpp:515:6:515:18 | [summary param] *1 in RtlMoveMemory | windows.cpp:515:6:515:18 | [summary param] *0 in RtlMoveMemory [Return] | windows.cpp:568:19:568:29 | RtlMoveMemory output argument |
|
||||
| windows.cpp:573:40:573:41 | *& ... | windows.cpp:521:17:521:37 | [summary param] *1 in RtlMoveVolatileMemory | windows.cpp:521:17:521:37 | [summary param] *0 in RtlMoveVolatileMemory [Return] | windows.cpp:573:27:573:37 | RtlMoveVolatileMemory output argument |
|
||||
| windows.cpp:729:35:729:35 | *x | windows.cpp:714:6:714:20 | [summary param] *0 in WinHttpCrackUrl | windows.cpp:714:6:714:20 | [summary param] *3 in WinHttpCrackUrl [Return] | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument |
|
||||
testFailures
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
| asio_streams.cpp:87:34:87:44 | read_until output argument | remote |
|
||||
| azure.cpp:253:48:253:60 | *call to GetBodyStream | remote |
|
||||
| azure.cpp:273:62:273:64 | call to GetHeaders | remote |
|
||||
| azure.cpp:277:45:277:47 | call to GetBody | remote |
|
||||
| azure.cpp:281:68:281:84 | *call to ExtractBodyStream | remote |
|
||||
| azure.cpp:289:32:289:40 | call to GetHeader | remote |
|
||||
| azure.cpp:293:58:293:67 | call to GetHeaders | remote |
|
||||
| test.cpp:10:10:10:18 | call to ymlSource | local |
|
||||
| test.cpp:56:8:56:16 | call to ymlSource | local |
|
||||
| test.cpp:94:10:94:18 | call to ymlSource | local |
|
||||
@@ -20,3 +26,9 @@
|
||||
| windows.cpp:318:23:318:37 | *call to MapViewOfFileEx | local |
|
||||
| windows.cpp:325:23:325:42 | *call to MapViewOfFileFromApp | local |
|
||||
| windows.cpp:332:23:332:40 | *call to MapViewOfFileNuma2 | local |
|
||||
| windows.cpp:645:45:645:50 | WinHttpReadData output argument | remote |
|
||||
| windows.cpp:652:48:652:53 | WinHttpReadDataEx output argument | remote |
|
||||
| windows.cpp:659:47:659:52 | WinHttpQueryHeaders output argument | remote |
|
||||
| windows.cpp:669:70:669:79 | WinHttpQueryHeadersEx output argument | remote |
|
||||
| windows.cpp:669:82:669:87 | WinHttpQueryHeadersEx output argument | remote |
|
||||
| windows.cpp:669:105:669:112 | WinHttpQueryHeadersEx output argument | remote |
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer |
|
||||
| azure.cpp:252:79:252:98 | call to string | azure.cpp:252:62:252:99 | call to Url |
|
||||
| azure.cpp:257:5:257:8 | *resp | azure.cpp:257:16:257:21 | Read output argument |
|
||||
| azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument |
|
||||
| azure.cpp:287:79:287:98 | call to string | azure.cpp:287:62:287:99 | call to Url |
|
||||
| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value |
|
||||
| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual |
|
||||
| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated |
|
||||
| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body |
|
||||
| test.cpp:28:35:28:35 | 0 | test.cpp:28:11:28:33 | call to ymlStepManual_with_body |
|
||||
| windows.cpp:27:36:27:38 | *cmd | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA |
|
||||
| windows.cpp:729:35:729:35 | *x | windows.cpp:729:44:729:57 | WinHttpCrackUrl output argument |
|
||||
|
||||
@@ -5586,3 +5586,6 @@
|
||||
| Unrecognized output specification "Field[***hEvent]" in summary model. |
|
||||
| Unrecognized output specification "Parameter[***0]" in summary model. |
|
||||
| Unrecognized output specification "Parameter[****0]" in summary model. |
|
||||
| Unrecognized output specification "ReturnValue[*****]" in summary model. |
|
||||
| Unrecognized output specification "ReturnValue[****]" in summary model. |
|
||||
| Unrecognized output specification "ReturnValue[***]" in summary model. |
|
||||
|
||||
@@ -573,4 +573,165 @@ void test_copy_and_move_memory() {
|
||||
RtlMoveVolatileMemory(dest_buffer, &x, sizeof(x));
|
||||
sink(dest_buffer[0]); // $ ir
|
||||
}
|
||||
}
|
||||
|
||||
using HINTERNET = void*;
|
||||
using ULONGLONG = unsigned long long;
|
||||
using UINT = unsigned int;
|
||||
using PDWORD = DWORD*;
|
||||
using PCSTR = const char*;
|
||||
typedef union _WINHTTP_HEADER_NAME {
|
||||
PCWSTR pwszName;
|
||||
PCSTR pszName;
|
||||
} WINHTTP_HEADER_NAME, *PWINHTTP_HEADER_NAME;
|
||||
typedef struct _WINHTTP_EXTENDED_HEADER {
|
||||
union {
|
||||
PCWSTR pwszName;
|
||||
PCSTR pszName;
|
||||
};
|
||||
union {
|
||||
PCWSTR pwszValue;
|
||||
PCSTR pszValue;
|
||||
};
|
||||
} WINHTTP_EXTENDED_HEADER, *PWINHTTP_EXTENDED_HEADER;
|
||||
|
||||
BOOL WinHttpReadData(
|
||||
HINTERNET hRequest,
|
||||
LPVOID lpBuffer,
|
||||
DWORD dwNumberOfBytesToRead,
|
||||
LPDWORD lpdwNumberOfBytesRead
|
||||
);
|
||||
|
||||
DWORD WinHttpReadDataEx(
|
||||
HINTERNET hRequest,
|
||||
LPVOID lpBuffer,
|
||||
DWORD dwNumberOfBytesToRead,
|
||||
LPDWORD lpdwNumberOfBytesRead,
|
||||
ULONGLONG ullFlags,
|
||||
DWORD cbProperty,
|
||||
PVOID pvProperty
|
||||
);
|
||||
|
||||
using LPCWSTR = const wchar_t*;
|
||||
|
||||
BOOL WinHttpQueryHeaders(
|
||||
HINTERNET hRequest,
|
||||
DWORD dwInfoLevel,
|
||||
LPCWSTR pwszName,
|
||||
LPVOID lpBuffer,
|
||||
LPDWORD lpdwBufferLength,
|
||||
LPDWORD lpdwIndex
|
||||
);
|
||||
|
||||
DWORD WinHttpQueryHeadersEx(
|
||||
HINTERNET hRequest,
|
||||
DWORD dwInfoLevel,
|
||||
ULONGLONG ullFlags,
|
||||
UINT uiCodePage,
|
||||
PDWORD pdwIndex,
|
||||
PWINHTTP_HEADER_NAME pHeaderName,
|
||||
PVOID pBuffer,
|
||||
PDWORD pdwBufferLength,
|
||||
PWINHTTP_EXTENDED_HEADER *ppHeaders,
|
||||
PDWORD pdwHeadersCount
|
||||
);
|
||||
|
||||
void sink(PCSTR);
|
||||
|
||||
void test_winhttp(HINTERNET hRequest) {
|
||||
{
|
||||
char buffer[1024];
|
||||
DWORD bytesRead;
|
||||
BOOL result = WinHttpReadData(hRequest, buffer, sizeof(buffer), &bytesRead);
|
||||
sink(buffer);
|
||||
sink(*buffer); // $ ir
|
||||
}
|
||||
{
|
||||
char buffer[1024];
|
||||
DWORD bytesRead;
|
||||
DWORD result = WinHttpReadDataEx(hRequest, buffer, sizeof(buffer), &bytesRead, 0, 0, nullptr);
|
||||
sink(buffer);
|
||||
sink(*buffer); // $ ir
|
||||
}
|
||||
{
|
||||
char buffer[1024];
|
||||
DWORD bufferLength = sizeof(buffer);
|
||||
WinHttpQueryHeaders(hRequest, 0, nullptr, buffer, &bufferLength, nullptr);
|
||||
sink(buffer);
|
||||
sink(*buffer); // $ ir
|
||||
}
|
||||
{
|
||||
char buffer[1024];
|
||||
DWORD bufferLength = sizeof(buffer);
|
||||
PWINHTTP_EXTENDED_HEADER headers;
|
||||
DWORD headersCount;
|
||||
PWINHTTP_HEADER_NAME headerName;
|
||||
DWORD result = WinHttpQueryHeadersEx(hRequest, 0, 0, 0, nullptr, headerName, buffer, &bufferLength, &headers, &headersCount);
|
||||
sink(buffer);
|
||||
sink(*buffer); // $ ir
|
||||
sink(headerName->pszName);
|
||||
sink(*headerName->pszName); // $ ir
|
||||
sink(headers->pszValue);
|
||||
sink(*headers->pszValue); // $ ir
|
||||
}
|
||||
}
|
||||
|
||||
using LPWSTR = wchar_t*;
|
||||
using INTERNET_SCHEME = enum {
|
||||
INTERNET_SCHEME_INVALID = -1,
|
||||
INTERNET_SCHEME_UNKNOWN = 0,
|
||||
INTERNET_SCHEME_HTTP = 1,
|
||||
INTERNET_SCHEME_HTTPS = 2,
|
||||
INTERNET_SCHEME_FTP = 3,
|
||||
INTERNET_SCHEME_FILE = 4,
|
||||
INTERNET_SCHEME_NEWS = 5,
|
||||
INTERNET_SCHEME_MAILTO = 6,
|
||||
INTERNET_SCHEME_SNEWS = 7,
|
||||
INTERNET_SCHEME_SOCKS = 8,
|
||||
INTERNET_SCHEME_WAIS = 9,
|
||||
INTERNET_SCHEME_LAST = 10
|
||||
};
|
||||
using INTERNET_PORT = unsigned short;
|
||||
|
||||
typedef struct _WINHTTP_URL_COMPONENTS {
|
||||
DWORD dwStructSize;
|
||||
LPWSTR lpszScheme;
|
||||
DWORD dwSchemeLength;
|
||||
INTERNET_SCHEME nScheme;
|
||||
LPWSTR lpszHostName;
|
||||
DWORD dwHostNameLength;
|
||||
INTERNET_PORT nPort;
|
||||
LPWSTR lpszUserName;
|
||||
DWORD dwUserNameLength;
|
||||
LPWSTR lpszPassword;
|
||||
DWORD dwPasswordLength;
|
||||
LPWSTR lpszUrlPath;
|
||||
DWORD dwUrlPathLength;
|
||||
LPWSTR lpszExtraInfo;
|
||||
DWORD dwExtraInfoLength;
|
||||
} URL_COMPONENTS, *LPURL_COMPONENTS;
|
||||
|
||||
BOOL WinHttpCrackUrl(
|
||||
LPCWSTR pwszUrl,
|
||||
DWORD dwUrlLength,
|
||||
DWORD dwFlags,
|
||||
LPURL_COMPONENTS lpUrlComponents
|
||||
);
|
||||
|
||||
void sink(LPWSTR);
|
||||
|
||||
void test_winhttp_crack_url() {
|
||||
{
|
||||
URL_COMPONENTS urlComponents;
|
||||
urlComponents.dwStructSize = sizeof(URL_COMPONENTS);
|
||||
wchar_t x[256];
|
||||
x[0] = (wchar_t)source();
|
||||
BOOL result = WinHttpCrackUrl(x, 0, 0, &urlComponents);
|
||||
sink(urlComponents.lpszHostName);
|
||||
sink(*urlComponents.lpszHostName); // $ ir
|
||||
sink(urlComponents.lpszUrlPath);
|
||||
sink(*urlComponents.lpszUrlPath); // $ ir
|
||||
sink(urlComponents.lpszExtraInfo);
|
||||
sink(*urlComponents.lpszExtraInfo); // $ ir
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
{
|
||||
C *c = new C();
|
||||
B *b = B::make(c);
|
||||
sink(b->c); // $ast,ir
|
||||
sink(b->c); // $ ast,ir
|
||||
}
|
||||
|
||||
void f2()
|
||||
|
||||
@@ -26,9 +26,9 @@ public:
|
||||
|
||||
void func()
|
||||
{
|
||||
sink(s1); // $ast,ir
|
||||
sink(s1); // $ ast,ir
|
||||
sink(s2); // $ MISSING: ast,ir
|
||||
sink(s3); // $ast,ir
|
||||
sink(s3); // $ ast,ir
|
||||
sink(s4); // $ MISSING: ast,ir
|
||||
}
|
||||
};
|
||||
|
||||
@@ -19,7 +19,7 @@ public:
|
||||
};
|
||||
|
||||
static void sinkWrap(Box2* b2) {
|
||||
sink(b2->getBox1()->getElem()); // $ast,ir=28:15 ast,ir=35:15 ast,ir=42:15 ast,ir=49:15
|
||||
sink(b2->getBox1()->getElem()); // $ ast,ir=28:15 ast,ir=35:15 ast,ir=42:15 ast,ir=49:15
|
||||
}
|
||||
|
||||
Box2* boxfield;
|
||||
|
||||
@@ -48,25 +48,25 @@ struct S {
|
||||
void test_setDirectly() {
|
||||
S s;
|
||||
s.setDirectly(user_input());
|
||||
sink(s.getDirectly()); // $ast ir
|
||||
sink(s.getDirectly()); // $ ast ir
|
||||
}
|
||||
|
||||
void test_setIndirectly() {
|
||||
S s;
|
||||
s.setIndirectly(user_input());
|
||||
sink(s.getIndirectly()); // $ast ir
|
||||
sink(s.getIndirectly()); // $ ast ir
|
||||
}
|
||||
|
||||
void test_setThroughNonMember() {
|
||||
S s;
|
||||
s.setThroughNonMember(user_input());
|
||||
sink(s.getThroughNonMember()); // $ast ir
|
||||
sink(s.getThroughNonMember()); // $ ast ir
|
||||
}
|
||||
|
||||
void test_nonMemberSetA() {
|
||||
S s;
|
||||
nonMemberSetA(&s, user_input());
|
||||
sink(nonMemberGetA(&s)); // $ast,ir
|
||||
sink(nonMemberGetA(&s)); // $ ast,ir
|
||||
}
|
||||
|
||||
////////////////////
|
||||
@@ -112,7 +112,7 @@ void test_outer_with_ptr(Outer *pouter) {
|
||||
sink(outer.a); // $ ast,ir
|
||||
|
||||
sink(pouter->inner_nested.a); // $ ast,ir
|
||||
sink(pouter->inner_ptr->a); // $ast,ir
|
||||
sink(pouter->inner_ptr->a); // $ ast,ir
|
||||
sink(pouter->a); // $ ast,ir
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ void single_field_test()
|
||||
A a;
|
||||
a.i = user_input();
|
||||
A a2 = a;
|
||||
sink(a2.i); //$ ast,ir
|
||||
sink(a2.i); // $ ast,ir
|
||||
}
|
||||
|
||||
struct C {
|
||||
@@ -81,7 +81,7 @@ struct C2
|
||||
|
||||
void m() {
|
||||
f2.f1 = user_input();
|
||||
sink(getf2f1()); //$ ast,ir
|
||||
sink(getf2f1()); // $ ast,ir
|
||||
}
|
||||
};
|
||||
|
||||
@@ -91,7 +91,7 @@ void single_field_test_typedef(A_typedef a)
|
||||
{
|
||||
a.i = user_input();
|
||||
A_typedef a2 = a;
|
||||
sink(a2.i); //$ ast,ir
|
||||
sink(a2.i); // $ ast,ir
|
||||
}
|
||||
|
||||
namespace TestAdditionalCallTargets {
|
||||
@@ -168,4 +168,4 @@ void test_union_with_two_instantiations_of_different_sizes() {
|
||||
sink(u_int.y); // $ MISSING: ir
|
||||
}
|
||||
|
||||
} // namespace Simple
|
||||
} // namespace Simple
|
||||
|
||||
@@ -12,14 +12,14 @@ struct Outer {
|
||||
};
|
||||
|
||||
void absink(struct AB *ab) {
|
||||
sink(ab->a); //$ ast,ir=20:20 ast,ir=27:7 ast,ir=40:20
|
||||
sink(ab->a); // $ ast,ir=20:20 ast,ir=27:7 ast,ir=40:20
|
||||
sink(ab->b); // no flow
|
||||
}
|
||||
|
||||
int struct_init(void) {
|
||||
struct AB ab = { user_input(), 0 };
|
||||
|
||||
sink(ab.a); //$ ast,ir
|
||||
sink(ab.a); // $ ast,ir
|
||||
sink(ab.b); // no flow
|
||||
absink(&ab);
|
||||
|
||||
@@ -28,9 +28,9 @@ int struct_init(void) {
|
||||
&ab,
|
||||
};
|
||||
|
||||
sink(outer.nestedAB.a); //$ ast,ir
|
||||
sink(outer.nestedAB.a); // $ ast,ir
|
||||
sink(outer.nestedAB.b); // no flow
|
||||
sink(outer.pointerAB->a); //$ ast,ir
|
||||
sink(outer.pointerAB->a); // $ ast,ir
|
||||
sink(outer.pointerAB->b); // no flow
|
||||
|
||||
absink(&outer.nestedAB);
|
||||
|
||||
@@ -15,7 +15,10 @@ predicate instructionGuardChecks(IRGuardCondition gc, Instruction checked, boole
|
||||
module BarrierGuard = DataFlow::InstructionBarrierGuard<instructionGuardChecks/3>;
|
||||
|
||||
predicate indirectBarrierGuard(DataFlow::Node node, string s) {
|
||||
node = BarrierGuard::getAnIndirectBarrierNode(_) and
|
||||
// This any(...) could technically be removed, but it helps us verify that we don't
|
||||
// accidentially change the API of this predicate (for instance, by having
|
||||
// the column be a unit parameter).
|
||||
node = BarrierGuard::getAnIndirectBarrierNode(any(int indirectionIndex)) and
|
||||
if node.isGLValue()
|
||||
then s = "glval<" + node.getType().toString().replaceAll(" ", "") + ">"
|
||||
else s = node.getType().toString().replaceAll(" ", "")
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import testModels
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes
|
||||
|
||||
string describe(DataFlow::Node n) {
|
||||
n instanceof ParameterNode and result = "ParameterNode"
|
||||
|
||||
@@ -75,7 +75,7 @@ void test_sources() {
|
||||
int e = localMadSource();
|
||||
sink(e); // $ ir
|
||||
|
||||
sink(MyNamespace::namespaceLocalMadSource()); // $: ir
|
||||
sink(MyNamespace::namespaceLocalMadSource()); // $ ir
|
||||
sink(MyNamespace::namespaceLocalMadSourceVar); // $ ir
|
||||
sink(MyNamespace::MyNamespace2::namespace2LocalMadSource()); // $ ir
|
||||
sink(MyNamespace::localMadSource()); // $ (the MyNamespace version of this function is not a source)
|
||||
@@ -475,4 +475,4 @@ void test_receive_array() {
|
||||
int array[10] = {x};
|
||||
int y = receive_array(array);
|
||||
sink(y); // $ ir
|
||||
}
|
||||
}
|
||||
|
||||
@@ -450,7 +450,7 @@ void test_qualifiers()
|
||||
b.member = source();
|
||||
sink(b); // $ ir MISSING: ast
|
||||
sink(b.member); // $ ast,ir
|
||||
sink(b.getMember()); // $ MISSING: ir ast
|
||||
sink(b.getMember()); // $ MISSING: ir ast
|
||||
|
||||
c = new MyClass2(0);
|
||||
|
||||
@@ -865,4 +865,4 @@ void test_iconv(size_t size) {
|
||||
size_t size_out;
|
||||
iconv(0, &s, &size, &p, &size_out);
|
||||
sink(*p); // $ ast,ir
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
#define NULL ((void*)0)
|
||||
|
||||
int global_var;
|
||||
|
||||
void test_address_null_comparison(int param_var) {
|
||||
int local_var;
|
||||
|
||||
if (&global_var == NULL) {} // $ VariableAddress=global_var
|
||||
if (&global_var != NULL) {} // $ VariableAddress=global_var
|
||||
if (&global_var) {} // $ VariableAddress=global_var
|
||||
if (!&global_var) {} // $ VariableAddress=global_var
|
||||
|
||||
if (&local_var == NULL) {} // $ VariableAddress=local_var
|
||||
if (&local_var != NULL) {} // $ VariableAddress=local_var
|
||||
if (&local_var) {} // $ VariableAddress=local_var
|
||||
if (!&local_var) {} // $ VariableAddress=local_var
|
||||
|
||||
if (¶m_var == NULL) {} // $ VariableAddress=param_var
|
||||
if (¶m_var != NULL) {} // $ VariableAddress=param_var
|
||||
if (¶m_var) {} // $ VariableAddress=param_var
|
||||
if (!¶m_var) {} // $ VariableAddress=param_var
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import cpp
|
||||
private import utils.test.InlineExpectationsTest
|
||||
private import semmle.code.cpp.ir.IR
|
||||
|
||||
module VariableAddressTest implements TestSig {
|
||||
string getARelevantTag() { result = "VariableAddress" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(VariableAddressInstruction vai |
|
||||
not vai.getAst() instanceof DeclarationEntry and
|
||||
not vai.getAst() instanceof Parameter and
|
||||
tag = "VariableAddress" and
|
||||
value = vai.getAstVariable().getName() and
|
||||
element = vai.toString() and
|
||||
location = vai.getLocation()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<VariableAddressTest>
|
||||
@@ -24,64 +24,64 @@ struct DerivedVI : virtual Base1 {
|
||||
};
|
||||
|
||||
void Locals() {
|
||||
Point pt = { //$ussa=pt
|
||||
1, //$ussa=pt[0..4)<int>
|
||||
2 //$ussa=pt[4..8)<int>
|
||||
Point pt = { // $ ussa=pt
|
||||
1, // $ ussa=pt[0..4)<int>
|
||||
2 // $ ussa=pt[4..8)<int>
|
||||
};
|
||||
int i = pt.x; //$ussa=pt[0..4)<int>
|
||||
i = pt.y; //$ussa=pt[4..8)<int>
|
||||
int i = pt.x; // $ ussa=pt[0..4)<int>
|
||||
i = pt.y; // $ ussa=pt[4..8)<int>
|
||||
int* p = &pt.x;
|
||||
i = *p; //$ussa=pt[0..4)<int>
|
||||
i = *p; // $ ussa=pt[0..4)<int>
|
||||
p = &pt.y;
|
||||
i = *p; //$ussa=pt[4..8)<int>
|
||||
i = *p; // $ ussa=pt[4..8)<int>
|
||||
}
|
||||
|
||||
void PointsTo(
|
||||
int a, //$raw=a
|
||||
Point& b, //$raw=b ussa=*b
|
||||
Point* c, //$raw=c ussa=*c
|
||||
int* d, //$raw=d ussa=*d
|
||||
DerivedSI* e, //$raw=e ussa=*e
|
||||
DerivedMI* f, //$raw=f ussa=*f
|
||||
DerivedVI* g //$raw=g ussa=*g
|
||||
int a, // $ raw=a
|
||||
Point& b, // $ raw=b ussa=*b
|
||||
Point* c, // $ raw=c ussa=*c
|
||||
int* d, // $ raw=d ussa=*d
|
||||
DerivedSI* e, // $ raw=e ussa=*e
|
||||
DerivedMI* f, // $ raw=f ussa=*f
|
||||
DerivedVI* g // $ raw=g ussa=*g
|
||||
) {
|
||||
|
||||
int i = a; //$raw=a
|
||||
i = *&a; //$raw=a
|
||||
i = *(&a + 0); //$raw=a
|
||||
i = b.x; //$raw=b ussa=*b[0..4)<int>
|
||||
i = b.y; //$raw=b ussa=*b[4..8)<int>
|
||||
i = c->x; //$raw=c ussa=*c[0..4)<int>
|
||||
i = c->y; //$raw=c ussa=*c[4..8)<int>
|
||||
i = *d; //$raw=d ussa=*d[0..4)<int>
|
||||
i = *(d + 0); //$raw=d ussa=*d[0..4)<int>
|
||||
i = d[5]; //$raw=d ussa=*d[20..24)<int>
|
||||
i = 5[d]; //$raw=d ussa=*d[20..24)<int>
|
||||
i = d[a]; //$raw=d raw=a ussa=*d[?..?)<int>
|
||||
i = a[d]; //$raw=d raw=a ussa=*d[?..?)<int>
|
||||
int i = a; // $ raw=a
|
||||
i = *&a; // $ raw=a
|
||||
i = *(&a + 0); // $ raw=a
|
||||
i = b.x; // $ raw=b ussa=*b[0..4)<int>
|
||||
i = b.y; // $ raw=b ussa=*b[4..8)<int>
|
||||
i = c->x; // $ raw=c ussa=*c[0..4)<int>
|
||||
i = c->y; // $ raw=c ussa=*c[4..8)<int>
|
||||
i = *d; // $ raw=d ussa=*d[0..4)<int>
|
||||
i = *(d + 0); // $ raw=d ussa=*d[0..4)<int>
|
||||
i = d[5]; // $ raw=d ussa=*d[20..24)<int>
|
||||
i = 5[d]; // $ raw=d ussa=*d[20..24)<int>
|
||||
i = d[a]; // $ raw=d raw=a ussa=*d[?..?)<int>
|
||||
i = a[d]; // $ raw=d raw=a ussa=*d[?..?)<int>
|
||||
|
||||
int* p = &b.x; //$raw=b
|
||||
i = *p; //$ussa=*b[0..4)<int>
|
||||
p = &b.y; //$raw=b
|
||||
i = *p; //$ussa=*b[4..8)<int>
|
||||
p = &c->x; //$raw=c
|
||||
i = *p; //$ussa=*c[0..4)<int>
|
||||
p = &c->y; //$raw=c
|
||||
i = *p; //$ussa=*c[4..8)<int>
|
||||
p = &d[5]; //$raw=d
|
||||
i = *p; //$ussa=*d[20..24)<int>
|
||||
p = &d[a]; //$raw=d raw=a
|
||||
i = *p; //$ussa=*d[?..?)<int>
|
||||
int* p = &b.x; // $ raw=b
|
||||
i = *p; // $ ussa=*b[0..4)<int>
|
||||
p = &b.y; // $ raw=b
|
||||
i = *p; // $ ussa=*b[4..8)<int>
|
||||
p = &c->x; // $ raw=c
|
||||
i = *p; // $ ussa=*c[0..4)<int>
|
||||
p = &c->y; // $ raw=c
|
||||
i = *p; // $ ussa=*c[4..8)<int>
|
||||
p = &d[5]; // $ raw=d
|
||||
i = *p; // $ ussa=*d[20..24)<int>
|
||||
p = &d[a]; // $ raw=d raw=a
|
||||
i = *p; // $ ussa=*d[?..?)<int>
|
||||
|
||||
Point* q = &c[a]; //$raw=c raw=a
|
||||
i = q->x; //$ussa=*c[?..?)<int>
|
||||
i = q->y; //$ussa=*c[?..?)<int>
|
||||
Point* q = &c[a]; // $ raw=c raw=a
|
||||
i = q->x; // $ ussa=*c[?..?)<int>
|
||||
i = q->y; // $ ussa=*c[?..?)<int>
|
||||
|
||||
i = e->b1; //$raw=e ussa=*e[0..4)<int>
|
||||
i = e->dsi; //$raw=e ussa=*e[4..8)<int>
|
||||
i = f->b1; //$raw=f ussa=*f[0..4)<int>
|
||||
i = f->b2; //$raw=f ussa=*f[4..8)<int>
|
||||
i = f->dmi; //$raw=f ussa=*f[8..12)<int>
|
||||
i = g->b1; //$raw=g ussa=*g[?..?)<int>
|
||||
i = g->dvi; //$raw=g ussa=*g[8..12)<int>
|
||||
}
|
||||
i = e->b1; // $ raw=e ussa=*e[0..4)<int>
|
||||
i = e->dsi; // $ raw=e ussa=*e[4..8)<int>
|
||||
i = f->b1; // $ raw=f ussa=*f[0..4)<int>
|
||||
i = f->b2; // $ raw=f ussa=*f[4..8)<int>
|
||||
i = f->dmi; // $ raw=f ussa=*f[8..12)<int>
|
||||
i = g->b1; // $ raw=g ussa=*g[?..?)<int>
|
||||
i = g->dvi; // $ raw=g ussa=*g[8..12)<int>
|
||||
}
|
||||
|
||||
@@ -10,24 +10,24 @@ struct S {
|
||||
|
||||
void unique_ptr_init(S s) {
|
||||
unique_ptr<S> p(new S); // MISSING: $ussa=dynamic{1}
|
||||
int i = (*p).x; //$ MISSING: ussa=dynamic{1}[0..4)<int>
|
||||
*p = s; //$ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
int i = (*p).x; // $ MISSING: ussa=dynamic{1}[0..4)<int>
|
||||
*p = s; // $ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
unique_ptr<S> q = std::move(p);
|
||||
*(q.get()) = s; //$ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
*(q.get()) = s; // $ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
shared_ptr<S> t(std::move(q));
|
||||
t->x = 5; //$ MISSING: ussa=dynamic{1}[0..4)<int>
|
||||
*t = s; //$ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
*(t.get()) = s; //$ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
t->x = 5; // $ MISSING: ussa=dynamic{1}[0..4)<int>
|
||||
*t = s; // $ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
*(t.get()) = s; // $ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
}
|
||||
|
||||
void shared_ptr_init(S s) {
|
||||
shared_ptr<S> p(new S); //$ MISSING: ussa=dynamic{1}
|
||||
int i = (*p).x; //$ MISSING: ussa=dynamic{1}[0..4)<int>
|
||||
*p = s; //$ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
shared_ptr<S> p(new S); // $ MISSING: ussa=dynamic{1}
|
||||
int i = (*p).x; // $ MISSING: ussa=dynamic{1}[0..4)<int>
|
||||
*p = s; // $ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
shared_ptr<S> q = std::move(p);
|
||||
*(q.get()) = s; //$ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
*(q.get()) = s; // $ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
shared_ptr<S> t(q);
|
||||
t->x = 5; //$ MISSING: ussa=dynamic{1}[0..4)<int>
|
||||
*t = s; //$ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
*(t.get()) = s; //$ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
t->x = 5; // $ MISSING: ussa=dynamic{1}[0..4)<int>
|
||||
*t = s; // $ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
*(t.get()) = s; // $ MISSING: ussa=dynamic{1}[0..4)<S>
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ int test4() {
|
||||
}
|
||||
range(total); // $ MISSING: range=>=0
|
||||
range(i); // $ range===2
|
||||
range(total + i); // $ range="<=Phi: i+2" MISSING: range===i+2 range=>=2 range=>=i+0
|
||||
range(total + i); // $ range="<=Phi: i+2" MISSING: range===i+2 range=>=2 range=>=i+0
|
||||
return total + i;
|
||||
}
|
||||
|
||||
@@ -210,7 +210,7 @@ int test14(int x) {
|
||||
int x3 = (int)(unsigned int)x;
|
||||
range(x3);
|
||||
char c0 = x;
|
||||
range(c0);
|
||||
range(c0);
|
||||
unsigned short s0 = x;
|
||||
range(s0);
|
||||
range(x0 + x1 + x2 + x3 + c0 + s0); // $ overflow=+ overflow=+-
|
||||
@@ -218,7 +218,7 @@ int test14(int x) {
|
||||
}
|
||||
|
||||
long long test15(long long x) {
|
||||
return (x > 0 && (range(x), x == (int)x)) ? // $ range=>=1
|
||||
return (x > 0 && (range(x), x == (int)x)) ? // $ range=>=1
|
||||
(range(x), x) : // $ range=>=1
|
||||
(range(x), -1);
|
||||
}
|
||||
@@ -228,7 +228,7 @@ int test_unary(int a) {
|
||||
int total = 0;
|
||||
|
||||
if (3 <= a && a <= 11) {
|
||||
range(a); // $ range=<=11 range=>=3
|
||||
range(a); // $ range=<=11 range=>=3
|
||||
int b = +a;
|
||||
range(b); // $ range=<=11 range=>=3
|
||||
int c = -a;
|
||||
@@ -384,7 +384,7 @@ int test_mult02(int a, int b) {
|
||||
total += r;
|
||||
range(total); // $ range=">=Phi: 0-143" range=">=Phi: 0-286"
|
||||
}
|
||||
range(total); // $range=">=Phi: 0-143" range=">=Phi: 0-286"
|
||||
range(total); // $ range=">=Phi: 0-143" range=">=Phi: 0-286"
|
||||
return total;
|
||||
}
|
||||
|
||||
@@ -467,7 +467,7 @@ int test_mult04(int a, int b) {
|
||||
range(a); // $ range=<=0 range=>=-17
|
||||
range(b); // $ range=<=0 range=>=-13
|
||||
int r = a*b; // 0 .. 221
|
||||
range(r); // $ range=<=221 range=>=0
|
||||
range(r); // $ range=<=221 range=>=0
|
||||
total += r;
|
||||
range(total); // $ range="<=Phi: - ...+221"
|
||||
}
|
||||
@@ -1030,7 +1030,7 @@ void test_negate_signed(int s) {
|
||||
}
|
||||
}
|
||||
|
||||
// By setting the guard after the use in another guard we
|
||||
// By setting the guard after the use in another guard we
|
||||
// don't get the useful information
|
||||
void test_guard_after_use(int pos, int size, int offset) {
|
||||
if (pos + offset >= size) { // $ overflow=+-
|
||||
@@ -1040,12 +1040,12 @@ void test_guard_after_use(int pos, int size, int offset) {
|
||||
return;
|
||||
}
|
||||
range(pos + 1); // $ overflow=+ range="==InitializeParameter: pos+1" MISSING: range="<=InitializeParameter: size-1"
|
||||
}
|
||||
}
|
||||
|
||||
int cond();
|
||||
|
||||
|
||||
// This is basically what we get when we have a loop that calls
|
||||
// This is basically what we get when we have a loop that calls
|
||||
// realloc in some iterations
|
||||
void alloc_in_loop(int origLen) {
|
||||
if (origLen <= 10) {
|
||||
@@ -1066,12 +1066,12 @@ void alloc_in_loop(int origLen) {
|
||||
}
|
||||
}
|
||||
|
||||
// This came from a case where it handled the leftovers before an unrolled loop
|
||||
// This came from a case where it handled the leftovers before an unrolled loop
|
||||
void mask_at_start(int len) {
|
||||
if (len < 0) {
|
||||
return;
|
||||
}
|
||||
int leftOver = len & 63;
|
||||
int leftOver = len & 63;
|
||||
for (int i = 0; i < leftOver; i++) {
|
||||
range(i); // $ range=<=62 range=>=0 range="<=Store: ... & ... | Store: leftOver-1" range="<=InitializeParameter: len-1"
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
void Complex(void) {
|
||||
_Complex float cf; //$irtype=cfloat8
|
||||
_Complex double cd; //$irtype=cfloat16
|
||||
_Complex long double cld; //$irtype=cfloat32
|
||||
_Complex float cf; // $ irtype=cfloat8
|
||||
_Complex double cd; // $ irtype=cfloat16
|
||||
_Complex long double cld; // $ irtype=cfloat32
|
||||
// _Complex __float128 cf128;
|
||||
}
|
||||
|
||||
void Imaginary(void) {
|
||||
_Imaginary float jf; //$irtype=ifloat4
|
||||
_Imaginary double jd; //$irtype=ifloat8
|
||||
_Imaginary long double jld; //$irtype=ifloat16
|
||||
_Imaginary float jf; // $ irtype=ifloat4
|
||||
_Imaginary double jd; // $ irtype=ifloat8
|
||||
_Imaginary long double jld; // $ irtype=ifloat16
|
||||
// _Imaginary __float128 jf128;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,44 +22,44 @@ enum class ScopedE {
|
||||
};
|
||||
|
||||
void IRTypes() {
|
||||
char c; //$irtype=int1
|
||||
signed char sc; //$irtype=int1
|
||||
unsigned char uc; //$irtype=uint1
|
||||
short s; //$irtype=int2
|
||||
signed short ss; //$irtype=int2
|
||||
unsigned short us; //$irtype=uint2
|
||||
int i; //$irtype=int4
|
||||
signed int si; //$irtype=int4
|
||||
unsigned int ui; //$irtype=uint4
|
||||
long l; //$irtype=int8
|
||||
signed long sl; //$irtype=int8
|
||||
unsigned long ul; //$irtype=uint8
|
||||
long long ll; //$irtype=int8
|
||||
signed long long sll; //$irtype=int8
|
||||
unsigned long long ull; //$irtype=uint8
|
||||
bool b; //$irtype=bool1
|
||||
float f; //$irtype=float4
|
||||
double d; //$irtype=float8
|
||||
long double ld; //$irtype=float16
|
||||
__float128 f128; //$irtype=float16
|
||||
char c; // $ irtype=int1
|
||||
signed char sc; // $ irtype=int1
|
||||
unsigned char uc; // $ irtype=uint1
|
||||
short s; // $ irtype=int2
|
||||
signed short ss; // $ irtype=int2
|
||||
unsigned short us; // $ irtype=uint2
|
||||
int i; // $ irtype=int4
|
||||
signed int si; // $ irtype=int4
|
||||
unsigned int ui; // $ irtype=uint4
|
||||
long l; // $ irtype=int8
|
||||
signed long sl; // $ irtype=int8
|
||||
unsigned long ul; // $ irtype=uint8
|
||||
long long ll; // $ irtype=int8
|
||||
signed long long sll; // $ irtype=int8
|
||||
unsigned long long ull; // $ irtype=uint8
|
||||
bool b; // $ irtype=bool1
|
||||
float f; // $ irtype=float4
|
||||
double d; // $ irtype=float8
|
||||
long double ld; // $ irtype=float16
|
||||
__float128 f128; // $ irtype=float16
|
||||
|
||||
wchar_t wc; //$irtype=uint4
|
||||
// char8_t c8; //$irtype=uint1
|
||||
char16_t c16; //$irtype=uint2
|
||||
char32_t c32; //$irtype=uint4
|
||||
wchar_t wc; // $ irtype=uint4
|
||||
// char8_t c8; // $ irtype=uint1
|
||||
char16_t c16; // $ irtype=uint2
|
||||
char32_t c32; // $ irtype=uint4
|
||||
|
||||
int* pi; //$irtype=addr8
|
||||
int& ri = i; //$irtype=addr8
|
||||
void (*pfn)() = nullptr; //$irtype=func8
|
||||
void (&rfn)() = IRTypes; //$irtype=func8
|
||||
int* pi; // $ irtype=addr8
|
||||
int& ri = i; // $ irtype=addr8
|
||||
void (*pfn)() = nullptr; // $ irtype=func8
|
||||
void (&rfn)() = IRTypes; // $ irtype=func8
|
||||
|
||||
A s_a; //$irtype=opaque4{A}
|
||||
B s_b; //$irtype=opaque16{B}
|
||||
A s_a; // $ irtype=opaque4{A}
|
||||
B s_b; // $ irtype=opaque16{B}
|
||||
|
||||
E e; //$irtype=uint4
|
||||
ScopedE se; //$irtype=uint4
|
||||
E e; // $ irtype=uint4
|
||||
ScopedE se; // $ irtype=uint4
|
||||
|
||||
B a_b[10]; //$irtype=opaque160{B[10]}
|
||||
B a_b[10]; // $ irtype=opaque160{B[10]}
|
||||
}
|
||||
|
||||
// semmle-extractor-options: -std=c++17 --clang
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user