mirror of
https://github.com/github/codeql.git
synced 2026-07-06 12:05:31 +02:00
Compare commits
564 Commits
codeql-cli
...
tiferet/co
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
07b0a742cf | ||
|
|
68133cb8ca | ||
|
|
a6841875fc | ||
|
|
9071f54e4e | ||
|
|
fad491d1f6 | ||
|
|
cea30cc463 | ||
|
|
103e778a3a | ||
|
|
a3cbf9fb46 | ||
|
|
7342ac3db2 | ||
|
|
1e4dd7a9c9 | ||
|
|
06b218f0a7 | ||
|
|
6e9eeb8eb3 | ||
|
|
3c847f7ce4 | ||
|
|
b400b583d6 | ||
|
|
9244912880 | ||
|
|
9307bf9dcd | ||
|
|
06b546f015 | ||
|
|
f1efc62e16 | ||
|
|
b3e05e9fb5 | ||
|
|
5b7147a56f | ||
|
|
ced7a33419 | ||
|
|
084f0ee57a | ||
|
|
b48c6badba | ||
|
|
25f103a010 | ||
|
|
d47007a930 | ||
|
|
e9da1f3751 | ||
|
|
dbb4fa0b1c | ||
|
|
f5833ffc3d | ||
|
|
efb6522656 | ||
|
|
1d5afaec0e | ||
|
|
43db83a28f | ||
|
|
2e4cc7efd0 | ||
|
|
bcd1ac1bb0 | ||
|
|
10b81eebb7 | ||
|
|
91109c826d | ||
|
|
abe3a2dae1 | ||
|
|
4db03cf4ae | ||
|
|
f73b3e0d97 | ||
|
|
3b508f7879 | ||
|
|
9b028476b8 | ||
|
|
24e01104a2 | ||
|
|
8f6db6b244 | ||
|
|
d6c897c9fd | ||
|
|
8d8a21b100 | ||
|
|
a27ae27101 | ||
|
|
4b6d1f7b78 | ||
|
|
66c77e890c | ||
|
|
be9c6500b8 | ||
|
|
831830831c | ||
|
|
ae69a2bcd9 | ||
|
|
65923ed2c1 | ||
|
|
a7269075e2 | ||
|
|
d3a5ee53c6 | ||
|
|
f32bb65c54 | ||
|
|
633bfdba28 | ||
|
|
db9cec6ea6 | ||
|
|
ec5425d952 | ||
|
|
7666843316 | ||
|
|
e06bcc3112 | ||
|
|
3229b37436 | ||
|
|
559570419d | ||
|
|
844171a28e | ||
|
|
ecf4d4dc02 | ||
|
|
0d4e85ff93 | ||
|
|
1211197914 | ||
|
|
41df8df182 | ||
|
|
125245aa62 | ||
|
|
8bb2b2eaea | ||
|
|
27efe524da | ||
|
|
ae4668c488 | ||
|
|
3987d8d374 | ||
|
|
fd75952c1e | ||
|
|
4db0dec82e | ||
|
|
a73b52adef | ||
|
|
39a4513fcc | ||
|
|
3c44332f17 | ||
|
|
06c7f1012c | ||
|
|
9421ba5303 | ||
|
|
f5109be2ac | ||
|
|
c14a4c4d93 | ||
|
|
4546dbe51b | ||
|
|
5d62dc3d2e | ||
|
|
0acd06a6d3 | ||
|
|
04abb87fef | ||
|
|
5dc5c3fb3f | ||
|
|
653b0128f5 | ||
|
|
c0f58371b4 | ||
|
|
cf289d57e9 | ||
|
|
459050151a | ||
|
|
01979aeb62 | ||
|
|
ef95f4c419 | ||
|
|
ac5434b3f3 | ||
|
|
ce17d94f80 | ||
|
|
bcc4cdd376 | ||
|
|
9aba7a0bca | ||
|
|
9a21539fca | ||
|
|
d76d11bd27 | ||
|
|
4603a66411 | ||
|
|
b130b2e82f | ||
|
|
94676ed713 | ||
|
|
4ed57e71db | ||
|
|
12def779e6 | ||
|
|
a6c01042eb | ||
|
|
fa36fc838b | ||
|
|
09bf2218d4 | ||
|
|
aaeb8a0aa0 | ||
|
|
959f93a766 | ||
|
|
a391c01d36 | ||
|
|
30163e4f60 | ||
|
|
c132891669 | ||
|
|
feb7c49006 | ||
|
|
32e8b130ad | ||
|
|
a9d2b936af | ||
|
|
d953ad63fe | ||
|
|
d74da30fc7 | ||
|
|
8ab3f39b5e | ||
|
|
5ff7a898a6 | ||
|
|
decd5c1ae7 | ||
|
|
54b6c6f8f7 | ||
|
|
dbfc256f40 | ||
|
|
91ce88e2d9 | ||
|
|
de1ecf943e | ||
|
|
cc608f764d | ||
|
|
dd0723c36b | ||
|
|
bdd56f1b6e | ||
|
|
8dd99b951b | ||
|
|
08557974ae | ||
|
|
04f422ea5d | ||
|
|
2c93ab99d8 | ||
|
|
d814e15a2f | ||
|
|
5792b4d363 | ||
|
|
fcd14a78ab | ||
|
|
70b85a3e00 | ||
|
|
6a5d6eb5c2 | ||
|
|
d001cc40d3 | ||
|
|
c57fcfb8fb | ||
|
|
705691b096 | ||
|
|
64f23ebb4d | ||
|
|
f54b02edb3 | ||
|
|
0c95ab2cdc | ||
|
|
4fbc747f93 | ||
|
|
fd8f7e071b | ||
|
|
fae4a8f37b | ||
|
|
8b6047dfd1 | ||
|
|
81e71c4669 | ||
|
|
6e75df4088 | ||
|
|
060c37b6a2 | ||
|
|
163bb2b94d | ||
|
|
714b61b63e | ||
|
|
219bac74bf | ||
|
|
de84dddfc1 | ||
|
|
e0a49e2999 | ||
|
|
e44aca0b33 | ||
|
|
41a53ec109 | ||
|
|
e4837f7da9 | ||
|
|
5461f94c6c | ||
|
|
41dd63adc7 | ||
|
|
f53a05bf13 | ||
|
|
a0fca20f0d | ||
|
|
c380ecbbbc | ||
|
|
6c1ebd999e | ||
|
|
25e6b976c8 | ||
|
|
7512d81331 | ||
|
|
6ee231fac5 | ||
|
|
0d1be2294c | ||
|
|
8d666d00c2 | ||
|
|
9a5dbd078e | ||
|
|
bd47c4f9ec | ||
|
|
e834f9302e | ||
|
|
9c3d141c9c | ||
|
|
7ab3bb1239 | ||
|
|
fe995dd99b | ||
|
|
025cd34dab | ||
|
|
2d95b6a049 | ||
|
|
c97dccf0de | ||
|
|
ab58d4c11f | ||
|
|
c67bfff33b | ||
|
|
4bfcc31ef0 | ||
|
|
59eea2a4a3 | ||
|
|
b6eeac5bc8 | ||
|
|
d9732361fc | ||
|
|
fbde174a89 | ||
|
|
50ff82fe51 | ||
|
|
7ddd08fb1e | ||
|
|
f6e7837cb8 | ||
|
|
0c900e4b8a | ||
|
|
d4269251be | ||
|
|
7b8ac609f7 | ||
|
|
c2f6ee320f | ||
|
|
e931d59bea | ||
|
|
e2acc26419 | ||
|
|
1b2ba15753 | ||
|
|
7bd0f53df9 | ||
|
|
998827f491 | ||
|
|
286a56c9b3 | ||
|
|
1e64748ffe | ||
|
|
955cc5a1be | ||
|
|
289f921171 | ||
|
|
a836444bc6 | ||
|
|
00f0879ff5 | ||
|
|
cce3728edf | ||
|
|
52e4076684 | ||
|
|
faecf44870 | ||
|
|
7f06109a4f | ||
|
|
0e45c9982b | ||
|
|
674799af8c | ||
|
|
d6712b2111 | ||
|
|
1a70297662 | ||
|
|
32a699e34a | ||
|
|
6eea906bbf | ||
|
|
64dd8b9488 | ||
|
|
746c2d1fca | ||
|
|
f07f0888aa | ||
|
|
393a0759db | ||
|
|
8aa80882ea | ||
|
|
8065714ebe | ||
|
|
eef3dc81df | ||
|
|
698dfa46fc | ||
|
|
77d9bac52d | ||
|
|
0c19da926c | ||
|
|
83569911ae | ||
|
|
ec7e486a3b | ||
|
|
159d8e978c | ||
|
|
4a6bceccf5 | ||
|
|
3640b6d3a8 | ||
|
|
711d7057f7 | ||
|
|
08c658e66b | ||
|
|
a5d229903d | ||
|
|
8d97fe9ed3 | ||
|
|
21d5fa836b | ||
|
|
ef97e539ec | ||
|
|
5ad7ed49dd | ||
|
|
730eae9521 | ||
|
|
9cf2acface | ||
|
|
cf64e0e85f | ||
|
|
7649772935 | ||
|
|
348165205c | ||
|
|
a816b813d1 | ||
|
|
d627358f7e | ||
|
|
079451142e | ||
|
|
b3fa844322 | ||
|
|
a82aaea514 | ||
|
|
250a0a71e1 | ||
|
|
3ee14f914b | ||
|
|
f0bb25bfce | ||
|
|
e8f1f364c5 | ||
|
|
cb53ff70a6 | ||
|
|
59402eb754 | ||
|
|
eadc605c0e | ||
|
|
5ef71f9d28 | ||
|
|
6e744093e2 | ||
|
|
f87b307ddb | ||
|
|
dd3e357ad3 | ||
|
|
a731a82a10 | ||
|
|
c98e0fa0b4 | ||
|
|
8096f86224 | ||
|
|
942cd7c275 | ||
|
|
2bbeb7383f | ||
|
|
1f77f77153 | ||
|
|
c7b41ca470 | ||
|
|
55003300fe | ||
|
|
f19f7967c2 | ||
|
|
32d95834d1 | ||
|
|
060cd9fada | ||
|
|
48ca1d0b72 | ||
|
|
ae0b4970ac | ||
|
|
da43a61506 | ||
|
|
db5bd98781 | ||
|
|
820de5d36f | ||
|
|
eeb9a88c3a | ||
|
|
f680a2ecbf | ||
|
|
bfd430b446 | ||
|
|
24c9a516c9 | ||
|
|
cacae957b5 | ||
|
|
695160d480 | ||
|
|
540ce1f0db | ||
|
|
882e909862 | ||
|
|
5fb5f1b23b | ||
|
|
3ea167cadf | ||
|
|
2d1088e923 | ||
|
|
0eaad4136e | ||
|
|
4d51e4fed0 | ||
|
|
10cd6328dc | ||
|
|
8ec5b5b7fa | ||
|
|
8fcf00b73d | ||
|
|
fa416564c7 | ||
|
|
d3d712fbff | ||
|
|
5f4e8e3e6a | ||
|
|
f03e90f894 | ||
|
|
839b88a4bc | ||
|
|
b606271a61 | ||
|
|
01b20b3a26 | ||
|
|
c448481bf7 | ||
|
|
12f78dbed4 | ||
|
|
cd5a46123e | ||
|
|
2d6cdff14b | ||
|
|
0ec4df28f5 | ||
|
|
3f589722c2 | ||
|
|
618b608962 | ||
|
|
9fc119cc55 | ||
|
|
6bfa08c5cc | ||
|
|
63d3b3ff2a | ||
|
|
0d6f17ec90 | ||
|
|
3bf3876c14 | ||
|
|
17c550bc88 | ||
|
|
7ab0f88f78 | ||
|
|
ebf0bb889b | ||
|
|
e5be8ab1e5 | ||
|
|
ce937e78c0 | ||
|
|
22c6c53993 | ||
|
|
619266d04b | ||
|
|
ce0f2b1788 | ||
|
|
b0cb65403b | ||
|
|
4cb5bea2c6 | ||
|
|
29ee1bda50 | ||
|
|
6adc04eca0 | ||
|
|
e7f85673e9 | ||
|
|
71d0a2378b | ||
|
|
2d6f3ed6c2 | ||
|
|
a45a0ee50d | ||
|
|
a63a4c29e2 | ||
|
|
0714310661 | ||
|
|
7ce5c0d55d | ||
|
|
c88f52c63e | ||
|
|
b6d97b07bf | ||
|
|
67e7b8fc23 | ||
|
|
94d80b0e87 | ||
|
|
86fd21de45 | ||
|
|
a4c0a0353f | ||
|
|
6a985a3df9 | ||
|
|
858aa9ae63 | ||
|
|
1283bcb860 | ||
|
|
d469b9711d | ||
|
|
07098bf8bf | ||
|
|
2edccec693 | ||
|
|
c28f51f820 | ||
|
|
05a4fdf6d8 | ||
|
|
a4c9120a9a | ||
|
|
2c5239ff7b | ||
|
|
a7a10de9ea | ||
|
|
8d28253175 | ||
|
|
01a2e74df7 | ||
|
|
b6a9f87238 | ||
|
|
4907e5754f | ||
|
|
2a41e6ae66 | ||
|
|
4fe4dfbf83 | ||
|
|
c0cc1c3fd5 | ||
|
|
3f805d3456 | ||
|
|
137b2c9ef9 | ||
|
|
cbb2fb9968 | ||
|
|
4d3b05e041 | ||
|
|
72d6f56df1 | ||
|
|
2288eab0fd | ||
|
|
c4fd39ec3f | ||
|
|
78a802359e | ||
|
|
50935899fa | ||
|
|
bdad847584 | ||
|
|
dda29e99b2 | ||
|
|
05b5aea477 | ||
|
|
7627a53c49 | ||
|
|
974fdd305e | ||
|
|
b75f138507 | ||
|
|
856b50735d | ||
|
|
429518bcea | ||
|
|
311cf4e7fd | ||
|
|
d839b4038e | ||
|
|
cc75a1a97e | ||
|
|
35beadc3bb | ||
|
|
40d31120d9 | ||
|
|
3a4c0a2aae | ||
|
|
4408482699 | ||
|
|
d4e6e77200 | ||
|
|
c4cf2febfb | ||
|
|
af12affc36 | ||
|
|
0affd898de | ||
|
|
676c352819 | ||
|
|
e85b2ebd20 | ||
|
|
c8f7304d9b | ||
|
|
e797b5c226 | ||
|
|
d8acc7cd17 | ||
|
|
59349ed7c7 | ||
|
|
50570dc3ee | ||
|
|
5ba59fc9a8 | ||
|
|
b68e78d908 | ||
|
|
aa4b98bbd5 | ||
|
|
9b02eb729f | ||
|
|
4f0e17bf97 | ||
|
|
c9bccd9b43 | ||
|
|
b6a709df50 | ||
|
|
686f7ccd5a | ||
|
|
9731989421 | ||
|
|
51599b3cae | ||
|
|
2ed140c696 | ||
|
|
ff53e53e8c | ||
|
|
4d327dbf4f | ||
|
|
61340c4b20 | ||
|
|
1e5b904514 | ||
|
|
d4b4d22378 | ||
|
|
92ad099c1b | ||
|
|
3bf28cc752 | ||
|
|
9647b6a3f5 | ||
|
|
e6b6369a21 | ||
|
|
5ebd50044f | ||
|
|
4720e2a30a | ||
|
|
067abacbb8 | ||
|
|
b667e0136f | ||
|
|
05314b48e8 | ||
|
|
6e8a2a6375 | ||
|
|
56b6441ef5 | ||
|
|
5c7f2ac7f7 | ||
|
|
3538cf89b9 | ||
|
|
d2ab40c184 | ||
|
|
ce5e76a3a0 | ||
|
|
557cb17f4d | ||
|
|
b8e123dc08 | ||
|
|
d4c5877484 | ||
|
|
72d03e4060 | ||
|
|
d34d7e51e5 | ||
|
|
f93b304578 | ||
|
|
e169702165 | ||
|
|
af61b45785 | ||
|
|
6f120a66d0 | ||
|
|
9aaf30691c | ||
|
|
c29dcefcf2 | ||
|
|
395bf675fe | ||
|
|
aa00424b75 | ||
|
|
2d889304bb | ||
|
|
b2bcb2d378 | ||
|
|
d4e02eb846 | ||
|
|
6e3040987a | ||
|
|
234f17b578 | ||
|
|
3249cee1c9 | ||
|
|
589e0af20a | ||
|
|
9423c21d46 | ||
|
|
391d9bed5b | ||
|
|
2ee8344e92 | ||
|
|
7f3e7224df | ||
|
|
4aeff0f8dc | ||
|
|
9f86bcb1b8 | ||
|
|
15227d3c09 | ||
|
|
6495f1911f | ||
|
|
b875d30bc6 | ||
|
|
b234bbd119 | ||
|
|
907e6299a4 | ||
|
|
24fa2be7b3 | ||
|
|
d2d7ed7bae | ||
|
|
9dc9925f59 | ||
|
|
df6f5d52b9 | ||
|
|
85751e7ddd | ||
|
|
fe3066da56 | ||
|
|
a5f7913af3 | ||
|
|
c2049c22a3 | ||
|
|
4f0a93295a | ||
|
|
6f3b5c01d5 | ||
|
|
be2d64a9d4 | ||
|
|
92359de363 | ||
|
|
1638f8edc5 | ||
|
|
40bda03180 | ||
|
|
5c641362bc | ||
|
|
04aaccb186 | ||
|
|
6eda71b659 | ||
|
|
b26f9d0ff1 | ||
|
|
b2d1cfe3d1 | ||
|
|
b97c885c8d | ||
|
|
5b6444d32d | ||
|
|
65608d7900 | ||
|
|
95f9d0761a | ||
|
|
0d5c5a7e92 | ||
|
|
9d19752c2e | ||
|
|
62cd8ca26f | ||
|
|
abf3f9f232 | ||
|
|
6471889fa6 | ||
|
|
b1f9a3d22a | ||
|
|
9165ec92c5 | ||
|
|
62b59747d1 | ||
|
|
43df6397bb | ||
|
|
802e2319b5 | ||
|
|
28b350ee95 | ||
|
|
dfcc57ba83 | ||
|
|
ec2deb0889 | ||
|
|
dc7cf272db | ||
|
|
55d7b74489 | ||
|
|
b88382e3e7 | ||
|
|
60afa6e9f0 | ||
|
|
38a3a5ebfa | ||
|
|
e029b1f0a8 | ||
|
|
467429c23e | ||
|
|
37999eaea0 | ||
|
|
f4b13e0955 | ||
|
|
fe65fb8743 | ||
|
|
7f96fe725b | ||
|
|
1264029282 | ||
|
|
7a55b003d2 | ||
|
|
38194c6ae7 | ||
|
|
f454151e7a | ||
|
|
3af085afcb | ||
|
|
8d9060f1f9 | ||
|
|
c715de2a10 | ||
|
|
5fdc293d82 | ||
|
|
0addcfa7c5 | ||
|
|
ae7a0c517c | ||
|
|
60c1505097 | ||
|
|
a928f4c9ef | ||
|
|
f96d6accbb | ||
|
|
fc9e63275f | ||
|
|
094a2b0c46 | ||
|
|
ffcb382705 | ||
|
|
75b4a0e8ea | ||
|
|
b34f99f716 | ||
|
|
6c501d15b6 | ||
|
|
88810420b1 | ||
|
|
c460eae2e1 | ||
|
|
a498ab241b | ||
|
|
27ec36298f | ||
|
|
ec2c58b416 | ||
|
|
1206b73d87 | ||
|
|
53f52df809 | ||
|
|
c42add2191 | ||
|
|
9cac4bbe0f | ||
|
|
276fec39fc | ||
|
|
b6ec9464eb | ||
|
|
ded0e570b0 | ||
|
|
34cc93846b | ||
|
|
5469a82efb | ||
|
|
64c60d59b1 | ||
|
|
9671c8824c | ||
|
|
7e3e10c34b | ||
|
|
bf650c755c | ||
|
|
a54ca38e31 | ||
|
|
e948e22186 | ||
|
|
48007d14d5 | ||
|
|
34b441c3cc | ||
|
|
5a85fa12c7 | ||
|
|
f9b5846675 | ||
|
|
4ab6a7bdfd | ||
|
|
46d6f5af7e | ||
|
|
acf6a77c6b | ||
|
|
bb0ec46eb2 | ||
|
|
00a273b959 | ||
|
|
cb8f5979d1 | ||
|
|
fe97d2a05d | ||
|
|
9d8c117c61 | ||
|
|
815b5a0312 | ||
|
|
c03ba2cc13 | ||
|
|
652c7ff1ed | ||
|
|
8bbbb95a87 | ||
|
|
d8eafea719 | ||
|
|
d1aaa9ad86 | ||
|
|
759854991a | ||
|
|
8e05fdb369 | ||
|
|
c5350ca6a0 | ||
|
|
cf094c2f4f | ||
|
|
848b24cfe4 | ||
|
|
ef44cb86c2 | ||
|
|
e9ebba3350 | ||
|
|
d228cf0e7b | ||
|
|
bce83bfc4e | ||
|
|
0a2c7d062c | ||
|
|
6bbc4f4a48 | ||
|
|
33c506d7fe | ||
|
|
5bddfc0d79 | ||
|
|
47a06d2824 | ||
|
|
7fcc548665 | ||
|
|
187cfd7be7 |
21
.git-blame-ignore-revs
Normal file
21
.git-blame-ignore-revs
Normal file
@@ -0,0 +1,21 @@
|
||||
# .git-blame-ignore-revs
|
||||
# Auto-formatted Java
|
||||
730eae952139209fe9fdf598541d608f4c0c0c84
|
||||
# Auto-formatted C#
|
||||
5ad7ed49dd3de03ec6dcfcb6848758a6a987e11c
|
||||
# Auto-formatted C/C++
|
||||
ef97e539ec1971494d4bba5cafe82e00bc8217ac
|
||||
# Auto-formatted Python
|
||||
21d5fa836b3a7d020ba45e8b8168b145a9772131
|
||||
# Auto-formatted JavaScript
|
||||
8d97fe9ed327a9546ff2eaf515cf0f5214deddd9
|
||||
# Auto-formatted Ruby
|
||||
a5d229903d2f12d45f2c2c38822f1d0e7504ae7f
|
||||
# Auto-formatted Go
|
||||
08c658e66bf867090033ea096e244a93d46c0aa7
|
||||
# Auto-formatted Swift
|
||||
711d7057f79fb7d72fc3b35e010bd018f9009169
|
||||
# Auto-formatted shared ql packs
|
||||
3640b6d3a8ce9edf8e1d3ed106fe8526cf255bc0
|
||||
# Auto-formatted taint tracking files
|
||||
159d8e978c51959b380838c080d891b66e763b19
|
||||
@@ -2,9 +2,9 @@
|
||||
/csharp/ @github/codeql-csharp
|
||||
/go/ @github/codeql-go
|
||||
/java/ @github/codeql-java
|
||||
/javascript/ @github/codeql-dynamic
|
||||
/python/ @github/codeql-dynamic
|
||||
/ruby/ @github/codeql-dynamic
|
||||
/javascript/ @github/codeql-javascript
|
||||
/python/ @github/codeql-python
|
||||
/ruby/ @github/codeql-ruby
|
||||
/swift/ @github/codeql-swift
|
||||
/misc/codegen/ @github/codeql-swift
|
||||
/java/kotlin-extractor/ @github/codeql-kotlin
|
||||
|
||||
@@ -8,16 +8,16 @@ provide:
|
||||
- "cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml"
|
||||
- "go/ql/config/legacy-support/qlpack.yml"
|
||||
- "go/build/codeql-extractor-go/codeql-extractor.yml"
|
||||
- "javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml"
|
||||
- "*/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml"
|
||||
# This pack is explicitly excluded from the workspace since most users
|
||||
# will want to use a version of this pack from the package cache. Internal
|
||||
# users can uncomment the following line and place a custom ML model
|
||||
# in the corresponding pack to test a custom ML model within their local
|
||||
# checkout.
|
||||
# - "javascript/ql/experimental/adaptivethreatmodeling/model/qlpack.yml"
|
||||
- "javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/qlpack.yml"
|
||||
- "javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml"
|
||||
- "javascript/ql/experimental/adaptivethreatmodeling/test/qlpack.yml"
|
||||
# - "*/ql/experimental/adaptivethreatmodeling/model/qlpack.yml"
|
||||
- "*/ql/experimental/adaptivethreatmodeling/modelbuilding/qlpack.yml"
|
||||
- "*/ql/experimental/adaptivethreatmodeling/src/qlpack.yml"
|
||||
- "*/ql/experimental/adaptivethreatmodeling/test/qlpack.yml"
|
||||
- "csharp/ql/campaigns/Solorigate/lib/qlpack.yml"
|
||||
- "csharp/ql/campaigns/Solorigate/src/qlpack.yml"
|
||||
- "csharp/ql/campaigns/Solorigate/test/qlpack.yml"
|
||||
|
||||
@@ -1,6 +1,28 @@
|
||||
{
|
||||
"DataFlow Java/C++/C#/Go/Python/Ruby/Swift": [
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlow.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlow.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlow.qll",
|
||||
"cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlow.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlow.qll",
|
||||
"go/ql/lib/semmle/go/dataflow/internal/DataFlow.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlow.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlow.qll",
|
||||
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlow.qll"
|
||||
],
|
||||
"DataFlowImpl Java/C++/C#/Go/Python/Ruby/Swift": [
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll",
|
||||
"cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll",
|
||||
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll",
|
||||
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll"
|
||||
],
|
||||
"DataFlow Java/C++/C#/Go/Python/Ruby/Swift Legacy Configuration": [
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl1.qll",
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll",
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll",
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll",
|
||||
@@ -8,38 +30,38 @@
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll",
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll",
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForOnActivityResult.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl1.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl1.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll",
|
||||
"cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll",
|
||||
"cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl1.qll",
|
||||
"cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll",
|
||||
"cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll",
|
||||
"cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl1.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplForContentDataFlow.qll",
|
||||
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll",
|
||||
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl1.qll",
|
||||
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl2.qll",
|
||||
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImplForStringsNewReplacer.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl1.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplForRegExp.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl1.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForHttpClientLibraries.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForPathname.qll",
|
||||
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl.qll"
|
||||
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImpl1.qll"
|
||||
],
|
||||
"DataFlow Java/C++/C#/Go/Python/Ruby/Swift Common": [
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll",
|
||||
@@ -52,7 +74,18 @@
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplCommon.qll",
|
||||
"swift/ql/lib/codeql/swift/dataflow/internal/DataFlowImplCommon.qll"
|
||||
],
|
||||
"TaintTracking::Configuration Java/C++/C#/Go/Python/Ruby/Swift": [
|
||||
"TaintTracking Java/C++/C#/Go/Python/Ruby/Swift": [
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTracking.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTracking.qll",
|
||||
"cpp/ql/lib/experimental/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTracking.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTracking.qll",
|
||||
"go/ql/lib/semmle/go/dataflow/internal/tainttracking1/TaintTracking.qll",
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/tainttracking1/TaintTracking.qll",
|
||||
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking1/TaintTracking.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttracking1/TaintTracking.qll",
|
||||
"swift/ql/lib/codeql/swift/dataflow/internal/tainttracking1/TaintTracking.qll"
|
||||
],
|
||||
"TaintTracking Legacy Configuration Java/C++/C#/Go/Python/Ruby/Swift": [
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
|
||||
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Xunit;
|
||||
using Semmle.Autobuild.Shared;
|
||||
using Semmle.Util;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Linq;
|
||||
@@ -75,6 +76,15 @@ namespace Semmle.Autobuild.Cpp.Tests
|
||||
throw new ArgumentException("Missing RunProcess " + pattern);
|
||||
}
|
||||
|
||||
int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary<string, string>? env, BuildOutputHandler onOutput, BuildOutputHandler onError)
|
||||
{
|
||||
var ret = (this as IBuildActions).RunProcess(cmd, args, workingDirectory, env, out var stdout);
|
||||
|
||||
stdout.ForEach(line => onOutput(line));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public IList<string> DirectoryDeleteIn = new List<string>();
|
||||
|
||||
void IBuildActions.DirectoryDelete(string dir, bool recursive)
|
||||
@@ -184,6 +194,15 @@ namespace Semmle.Autobuild.Cpp.Tests
|
||||
if (!DownloadFiles.Contains((address, fileName)))
|
||||
throw new ArgumentException($"Missing DownloadFile, {address}, {fileName}");
|
||||
}
|
||||
|
||||
public IDiagnosticsWriter CreateDiagnosticsWriter(string filename) => new TestDiagnosticWriter();
|
||||
}
|
||||
|
||||
internal class TestDiagnosticWriter : IDiagnosticsWriter
|
||||
{
|
||||
public IList<DiagnosticMessage> Diagnostics { get; } = new List<DiagnosticMessage>();
|
||||
|
||||
public void AddEntry(DiagnosticMessage message) => this.Diagnostics.Add(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -243,6 +262,7 @@ namespace Semmle.Autobuild.Cpp.Tests
|
||||
Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_TRAP_DIR"] = "";
|
||||
Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_SOURCE_ARCHIVE_DIR"] = "";
|
||||
Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_ROOT"] = $@"C:\codeql\{codeqlUpperLanguage.ToLowerInvariant()}";
|
||||
Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_DIAGNOSTIC_DIR"] = "";
|
||||
Actions.GetEnvironmentVariable["CODEQL_JAVA_HOME"] = @"C:\codeql\tools\java";
|
||||
Actions.GetEnvironmentVariable["CODEQL_PLATFORM"] = "win64";
|
||||
Actions.GetEnvironmentVariable["SEMMLE_DIST"] = @"C:\odasa";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Semmle.Autobuild.Shared;
|
||||
using Semmle.Util;
|
||||
|
||||
namespace Semmle.Autobuild.Cpp
|
||||
{
|
||||
@@ -21,7 +22,7 @@ namespace Semmle.Autobuild.Cpp
|
||||
|
||||
public class CppAutobuilder : Autobuilder<CppAutobuildOptions>
|
||||
{
|
||||
public CppAutobuilder(IBuildActions actions, CppAutobuildOptions options) : base(actions, options) { }
|
||||
public CppAutobuilder(IBuildActions actions, CppAutobuildOptions options) : base(actions, options, new DiagnosticClassifier()) { }
|
||||
|
||||
public override BuildScript GetBuildScript()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
category: majorAnalysis
|
||||
---
|
||||
* The main data flow and taint tracking APIs have been changed. The old APIs
|
||||
remain in place for now and translate to the new through a
|
||||
backwards-compatible wrapper. If multiple configurations are in scope
|
||||
simultaneously, then this may affect results slightly. The new API is quite
|
||||
similar to the old, but makes use of a configuration module instead of a
|
||||
configuration class.
|
||||
12
cpp/ql/lib/change-notes/2023-03-03-delete-deps.md
Normal file
12
cpp/ql/lib/change-notes/2023-03-03-delete-deps.md
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Deleted the deprecated `hasGeneratedCopyConstructor` and `hasGeneratedCopyAssignmentOperator` predicates from the `Folder` class.
|
||||
* Deleted the deprecated `getPath` and `getFolder` predicates from the `XmlFile` class.
|
||||
* Deleted the deprecated `getMustlockFunction`, `getTrylockFunction`, `getLockFunction`, and `getUnlockFunction` predicates from the `MutexType` class.
|
||||
* Deleted the deprecated `getPosInBasicBlock` predicate from the `SubBasicBlock` class.
|
||||
* Deleted the deprecated `getExpr` predicate from the `PointerDereferenceExpr` class.
|
||||
* Deleted the deprecated `getUseInstruction` and `getDefinitionInstruction` predicates from the `Operand` class.
|
||||
* Deleted the deprecated `isInParameter`, `isInParameterPointer`, and `isInQualifier` predicates from the `FunctionInput` class.
|
||||
* Deleted the deprecated `isOutParameterPointer`, `isOutQualifier`, `isOutReturnValue`, and `isOutReturnPointer` predicate from the `FunctionOutput` class.
|
||||
* Deleted the deprecated 3-argument `isGuardPhi` predicate from the `RangeSsaDefinition` class.
|
||||
4
cpp/ql/lib/change-notes/2023-03-13-mergepathgraph.md
Normal file
4
cpp/ql/lib/change-notes/2023-03-13-mergepathgraph.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Added support for merging two `PathGraph`s via disjoint union to allow results from multiple data flow computations in a single `path-problem` query.
|
||||
@@ -22,5 +22,6 @@
|
||||
import cpp
|
||||
|
||||
module DataFlow {
|
||||
import experimental.semmle.code.cpp.ir.dataflow.internal.DataFlowImpl
|
||||
import experimental.semmle.code.cpp.ir.dataflow.internal.DataFlow
|
||||
import experimental.semmle.code.cpp.ir.dataflow.internal.DataFlowImpl1
|
||||
}
|
||||
|
||||
@@ -19,5 +19,6 @@ import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
import semmle.code.cpp.ir.dataflow.DataFlow2
|
||||
|
||||
module TaintTracking {
|
||||
import experimental.semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTracking
|
||||
import experimental.semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTrackingImpl
|
||||
}
|
||||
|
||||
@@ -0,0 +1,353 @@
|
||||
/**
|
||||
* Provides an implementation of global (interprocedural) data flow. This file
|
||||
* re-exports the local (intraprocedural) data flow analysis from
|
||||
* `DataFlowImplSpecific::Public` and adds a global analysis, mainly exposed
|
||||
* through the `Make` and `MakeWithState` modules.
|
||||
*/
|
||||
|
||||
private import DataFlowImplCommon
|
||||
private import DataFlowImplSpecific::Private
|
||||
import DataFlowImplSpecific::Public
|
||||
import DataFlowImplCommonPublic
|
||||
private import DataFlowImpl
|
||||
|
||||
/** An input configuration for data flow. */
|
||||
signature module ConfigSig {
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source.
|
||||
*/
|
||||
predicate isSource(Node source);
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink.
|
||||
*/
|
||||
predicate isSink(Node sink);
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited. This completely removes
|
||||
* `node` from the data flow graph.
|
||||
*/
|
||||
default predicate isBarrier(Node node) { none() }
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
default predicate isBarrierIn(Node node) { none() }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
default predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
default predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
default predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
default int fieldFlowBranchLimit() { result = 2 }
|
||||
|
||||
/**
|
||||
* Gets a data flow configuration feature to add restrictions to the set of
|
||||
* valid flow paths.
|
||||
*
|
||||
* - `FeatureHasSourceCallContext`:
|
||||
* Assume that sources have some existing call context to disallow
|
||||
* conflicting return-flow directly following the source.
|
||||
* - `FeatureHasSinkCallContext`:
|
||||
* Assume that sinks have some existing call context to disallow
|
||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
||||
* - `FeatureEqualSourceSinkCallContext`:
|
||||
* Implies both of the above and additionally ensures that the entire flow
|
||||
* path preserves the call context.
|
||||
*
|
||||
* These features are generally not relevant for typical end-to-end data flow
|
||||
* queries, but should only be used for constructing paths that need to
|
||||
* somehow be pluggable in another path context.
|
||||
*/
|
||||
default FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
default predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (as it is in a `path-problem` query).
|
||||
*/
|
||||
default predicate includeHiddenNodes() { none() }
|
||||
}
|
||||
|
||||
/** An input configuration for data flow using flow state. */
|
||||
signature module StateConfigSig {
|
||||
bindingset[this]
|
||||
class FlowState;
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source with the given initial
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSource(Node source, FlowState state);
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
||||
*/
|
||||
predicate isSink(Node sink, FlowState state);
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited. This completely removes
|
||||
* `node` from the data flow graph.
|
||||
*/
|
||||
default predicate isBarrier(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isBarrier(Node node, FlowState state);
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
default predicate isBarrierIn(Node node) { none() }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
default predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
default predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2);
|
||||
|
||||
/**
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
default predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
default int fieldFlowBranchLimit() { result = 2 }
|
||||
|
||||
/**
|
||||
* Gets a data flow configuration feature to add restrictions to the set of
|
||||
* valid flow paths.
|
||||
*
|
||||
* - `FeatureHasSourceCallContext`:
|
||||
* Assume that sources have some existing call context to disallow
|
||||
* conflicting return-flow directly following the source.
|
||||
* - `FeatureHasSinkCallContext`:
|
||||
* Assume that sinks have some existing call context to disallow
|
||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
||||
* - `FeatureEqualSourceSinkCallContext`:
|
||||
* Implies both of the above and additionally ensures that the entire flow
|
||||
* path preserves the call context.
|
||||
*
|
||||
* These features are generally not relevant for typical end-to-end data flow
|
||||
* queries, but should only be used for constructing paths that need to
|
||||
* somehow be pluggable in another path context.
|
||||
*/
|
||||
default FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
default predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (as it is in a `path-problem` query).
|
||||
*/
|
||||
default predicate includeHiddenNodes() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
|
||||
* measured in approximate number of interprocedural steps.
|
||||
*/
|
||||
signature int explorationLimitSig();
|
||||
|
||||
/**
|
||||
* The output of a data flow computation.
|
||||
*/
|
||||
signature module DataFlowSig {
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks) and an access path.
|
||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
||||
*/
|
||||
class PathNode;
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `source` to `sink`.
|
||||
*
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink);
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `source` to `sink`.
|
||||
*/
|
||||
predicate hasFlow(Node source, Node sink);
|
||||
|
||||
/**
|
||||
* Holds if data can flow from some source to `sink`.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink);
|
||||
|
||||
/**
|
||||
* Holds if data can flow from some source to `sink`.
|
||||
*/
|
||||
predicate hasFlowToExpr(DataFlowExpr sink);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a standard data flow computation.
|
||||
*/
|
||||
module Make<ConfigSig Config> implements DataFlowSig {
|
||||
private module C implements FullStateConfigSig {
|
||||
import DefaultState<Config>
|
||||
import Config
|
||||
}
|
||||
|
||||
import Impl<C>
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a data flow computation using flow state.
|
||||
*/
|
||||
module MakeWithState<StateConfigSig Config> implements DataFlowSig {
|
||||
private module C implements FullStateConfigSig {
|
||||
import Config
|
||||
}
|
||||
|
||||
import Impl<C>
|
||||
}
|
||||
|
||||
signature class PathNodeSig {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString();
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
);
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
Node getNode();
|
||||
}
|
||||
|
||||
signature module PathGraphSig<PathNodeSig PathNode> {
|
||||
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||
predicate edges(PathNode a, PathNode b);
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
predicate nodes(PathNode n, string key, string val);
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a `PathGraph` from two `PathGraph`s by disjoint union.
|
||||
*/
|
||||
module MergePathGraph<
|
||||
PathNodeSig PathNode1, PathNodeSig PathNode2, PathGraphSig<PathNode1> Graph1,
|
||||
PathGraphSig<PathNode2> Graph2>
|
||||
{
|
||||
private newtype TPathNode =
|
||||
TPathNode1(PathNode1 p) or
|
||||
TPathNode2(PathNode2 p)
|
||||
|
||||
/** A node in a graph of path explanations that is formed by disjoint union of the two given graphs. */
|
||||
class PathNode extends TPathNode {
|
||||
/** Gets this as a projection on the first given `PathGraph`. */
|
||||
PathNode1 asPathNode1() { this = TPathNode1(result) }
|
||||
|
||||
/** Gets this as a projection on the second given `PathGraph`. */
|
||||
PathNode2 asPathNode2() { this = TPathNode2(result) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() {
|
||||
result = this.asPathNode1().toString() or
|
||||
result = this.asPathNode2().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.asPathNode1().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) or
|
||||
this.asPathNode2().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
Node getNode() {
|
||||
result = this.asPathNode1().getNode() or
|
||||
result = this.asPathNode2().getNode()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||
*/
|
||||
module PathGraph implements PathGraphSig<PathNode> {
|
||||
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||
query predicate edges(PathNode a, PathNode b) {
|
||||
Graph1::edges(a.asPathNode1(), b.asPathNode1()) or
|
||||
Graph2::edges(a.asPathNode2(), b.asPathNode2())
|
||||
}
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
Graph1::nodes(n.asPathNode1(), key, val) or
|
||||
Graph2::nodes(n.asPathNode2(), key, val)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
|
||||
Graph1::subpaths(arg.asPathNode1(), par.asPathNode1(), ret.asPathNode1(), out.asPathNode1()) or
|
||||
Graph2::subpaths(arg.asPathNode2(), par.asPathNode2(), ret.asPathNode2(), out.asPathNode2())
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,396 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Make` and `MakeWithState` instead.
|
||||
*
|
||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
||||
* flow library.
|
||||
*/
|
||||
|
||||
private import DataFlowImplCommon
|
||||
private import DataFlowImplSpecific::Private
|
||||
import DataFlowImplSpecific::Public
|
||||
private import DataFlowImpl
|
||||
import DataFlowImplCommonPublic
|
||||
import FlowStateString
|
||||
|
||||
/**
|
||||
* A configuration of interprocedural data flow analysis. This defines
|
||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
||||
* use of the global data flow 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.
|
||||
* For example, write
|
||||
*
|
||||
* ```ql
|
||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
* // Optionally override `isBarrier`.
|
||||
* // Optionally override `isAdditionalFlowStep`.
|
||||
* }
|
||||
* ```
|
||||
* Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and
|
||||
* the edges are those data-flow steps that preserve the value of the node
|
||||
* along with any additional edges defined by `isAdditionalFlowStep`.
|
||||
* Specifying nodes in `isBarrier` will remove those nodes from the graph, and
|
||||
* specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going
|
||||
* and/or out-going edges from those nodes, respectively.
|
||||
*
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
* Multiple configurations can coexist, but two classes extending
|
||||
* `DataFlow::Configuration` should never depend on each other. One of them
|
||||
* should instead depend on a `DataFlow2::Configuration`, a
|
||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
|
||||
*/
|
||||
abstract class Configuration extends string {
|
||||
bindingset[this]
|
||||
Configuration() { any() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source.
|
||||
*/
|
||||
predicate isSource(Node source) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source with the given initial
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSource(Node source, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink.
|
||||
*/
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
||||
*/
|
||||
predicate isSink(Node sink, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited. This completely removes
|
||||
* `node` from the data flow graph.
|
||||
*/
|
||||
predicate isBarrier(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isBarrier(Node node, FlowState state) { none() }
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
predicate isBarrierIn(Node node) { none() }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||
* the flow state is `state`
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
int fieldFlowBranchLimit() { result = 2 }
|
||||
|
||||
/**
|
||||
* Gets a data flow configuration feature to add restrictions to the set of
|
||||
* valid flow paths.
|
||||
*
|
||||
* - `FeatureHasSourceCallContext`:
|
||||
* Assume that sources have some existing call context to disallow
|
||||
* conflicting return-flow directly following the source.
|
||||
* - `FeatureHasSinkCallContext`:
|
||||
* Assume that sinks have some existing call context to disallow
|
||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
||||
* - `FeatureEqualSourceSinkCallContext`:
|
||||
* Implies both of the above and additionally ensures that the entire flow
|
||||
* path preserves the call context.
|
||||
*
|
||||
* These features are generally not relevant for typical end-to-end data flow
|
||||
* queries, but should only be used for constructing paths that need to
|
||||
* somehow be pluggable in another path context.
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlow(Node source, Node sink) { hasFlow(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may 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`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `FlowExploration<explorationLimit>` instead.
|
||||
*
|
||||
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
|
||||
* measured in approximate number of interprocedural steps.
|
||||
*/
|
||||
deprecated int explorationLimit() { none() }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (for example in a `path-problem` query).
|
||||
*/
|
||||
predicate includeHiddenNodes() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* This class exists to prevent mutual recursion between the user-overridden
|
||||
* member predicates of `Configuration` and the rest of the data-flow library.
|
||||
* Good performance cannot be guaranteed in the presence of such recursion, so
|
||||
* it should be replaced by using more than one copy of the data flow library.
|
||||
*/
|
||||
abstract private class ConfigurationRecursionPrevention extends Configuration {
|
||||
bindingset[this]
|
||||
ConfigurationRecursionPrevention() { any() }
|
||||
|
||||
override predicate hasFlow(Node source, Node sink) {
|
||||
strictcount(Node n | this.isSource(n)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSource(n, _)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSink(n)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSink(n, _)) < 0
|
||||
or
|
||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
|
||||
or
|
||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0
|
||||
or
|
||||
super.hasFlow(source, sink)
|
||||
}
|
||||
}
|
||||
|
||||
/** A bridge class to access the deprecated `isBarrierGuard`. */
|
||||
private class BarrierGuardGuardedNodeBridge extends Unit {
|
||||
abstract predicate guardedNode(Node n, Configuration config);
|
||||
|
||||
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
|
||||
}
|
||||
|
||||
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
|
||||
deprecated override predicate guardedNode(Node n, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private FlowState relevantState(Configuration config) {
|
||||
config.isSource(_, result) or
|
||||
config.isSink(_, result) or
|
||||
config.isBarrier(_, result) or
|
||||
config.isAdditionalFlowStep(_, result, _, _) or
|
||||
config.isAdditionalFlowStep(_, _, _, result)
|
||||
}
|
||||
|
||||
private newtype TConfigState =
|
||||
TMkConfigState(Configuration config, FlowState state) {
|
||||
state = relevantState(config) or state instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
|
||||
|
||||
private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
|
||||
|
||||
private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
|
||||
|
||||
private module Config implements FullStateConfigSig {
|
||||
class FlowState = TConfigState;
|
||||
|
||||
predicate isSource(Node source, FlowState state) {
|
||||
getConfig(state).isSource(source, getState(state))
|
||||
or
|
||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isSink(Node sink, FlowState state) {
|
||||
getConfig(state).isSink(sink, getState(state))
|
||||
or
|
||||
getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isBarrier(Node node) { none() }
|
||||
|
||||
predicate isBarrier(Node node, FlowState state) {
|
||||
getConfig(state).isBarrier(node, getState(state)) or
|
||||
getConfig(state).isBarrier(node) or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getState(state), getConfig(state)) or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getConfig(state))
|
||||
}
|
||||
|
||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
||||
|
||||
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) {
|
||||
singleConfiguration() and
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and
|
||||
getConfig(state2) = getConfig(state1)
|
||||
or
|
||||
not singleConfiguration() and
|
||||
getConfig(state1).isAdditionalFlowStep(node1, node2) and
|
||||
state2 = state1
|
||||
}
|
||||
|
||||
predicate allowImplicitRead(Node node, ContentSet c) {
|
||||
any(Configuration config).allowImplicitRead(node, c)
|
||||
}
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate sourceGrouping(Node source, string sourceGroup) {
|
||||
any(Configuration config).sourceGrouping(source, sourceGroup)
|
||||
}
|
||||
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) {
|
||||
any(Configuration config).sinkGrouping(sink, sinkGroup)
|
||||
}
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
||||
*/
|
||||
class PathNode instanceof I::PathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
final string toString() { result = super.toString() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
final string toStringWithContext() { result = super.toStringWithContext() }
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
final predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
final Node getNode() { result = super.getNode() }
|
||||
|
||||
/** Gets the `FlowState` of this node. */
|
||||
final FlowState getState() { result = getState(super.getState()) }
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
final Configuration getConfiguration() { result = getConfig(super.getState()) }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() { result = super.getASuccessor() }
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { super.isSourceGroup(group) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
source0.getNode() = source and
|
||||
sink0.getNode() = sink
|
||||
)
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
hasFlowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
predicate flowsTo = hasFlow/3;
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -3,15 +3,18 @@ private import DataFlowImplSpecific::Public
|
||||
import Cached
|
||||
|
||||
module DataFlowImplCommonPublic {
|
||||
/** A state value to track during data flow. */
|
||||
class FlowState = string;
|
||||
/** Provides `FlowState = string`. */
|
||||
module FlowStateString {
|
||||
/** A state value to track during data flow. */
|
||||
class FlowState = string;
|
||||
|
||||
/**
|
||||
* The default state, which is used when the state is unspecified for a source
|
||||
* or a sink.
|
||||
*/
|
||||
class FlowStateEmpty extends FlowState {
|
||||
FlowStateEmpty() { this = "" }
|
||||
/**
|
||||
* The default state, which is used when the state is unspecified for a source
|
||||
* or a sink.
|
||||
*/
|
||||
class FlowStateEmpty extends FlowState {
|
||||
FlowStateEmpty() { this = "" }
|
||||
}
|
||||
}
|
||||
|
||||
private newtype TFlowFeature =
|
||||
@@ -179,6 +182,7 @@ private module LambdaFlow {
|
||||
boolean toJump, DataFlowCallOption lastCall
|
||||
) {
|
||||
revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and
|
||||
not expectsContent(node, _) and
|
||||
if castNode(node) or node instanceof ArgNode or node instanceof ReturnNode
|
||||
then compatibleTypes(t, getNodeDataFlowType(node))
|
||||
else any()
|
||||
|
||||
@@ -565,3 +565,12 @@ private class MyConsistencyConfiguration extends Consistency::ConsistencyConfigu
|
||||
any()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* when calculating the (virtual) dispatch cost.
|
||||
*
|
||||
* Argument `arg` is part of a path from a source to a sink, and `p` is the target parameter.
|
||||
*/
|
||||
int getAdditionalFlowIntoCallNodeTerm(ArgumentNode arg, ParameterNode p) { none() }
|
||||
|
||||
@@ -97,23 +97,23 @@ private string getNodeProperty(DataFlow::Node node, string key) {
|
||||
|
|
||||
kind, ", "
|
||||
)
|
||||
or
|
||||
// Is there partial flow from a source to this node?
|
||||
// This property will only be emitted if partial flow is enabled by overriding
|
||||
// `DataFlow::Configuration::explorationLimit()`.
|
||||
key = "pflow" and
|
||||
result =
|
||||
strictconcat(DataFlow::PartialPathNode sourceNode, DataFlow::PartialPathNode destNode, int dist,
|
||||
int order1, int order2 |
|
||||
any(DataFlow::Configuration cfg).hasPartialFlow(sourceNode, destNode, dist) and
|
||||
destNode.getNode() = node and
|
||||
// Only print flow from a source in the same function.
|
||||
sourceNode.getNode().getEnclosingCallable() = node.getEnclosingCallable()
|
||||
|
|
||||
nodeId(sourceNode.getNode(), order1, order2) + "+" + dist.toString(), ", "
|
||||
order by
|
||||
order1, order2, dist desc
|
||||
)
|
||||
// or
|
||||
// // Is there partial flow from a source to this node?
|
||||
// // This property will only be emitted if partial flow is enabled by overriding
|
||||
// // `DataFlow::Configuration::explorationLimit()`.
|
||||
// key = "pflow" and
|
||||
// result =
|
||||
// strictconcat(DataFlow::PartialPathNode sourceNode, DataFlow::PartialPathNode destNode, int dist,
|
||||
// int order1, int order2 |
|
||||
// any(DataFlow::Configuration cfg).hasPartialFlow(sourceNode, destNode, dist) and
|
||||
// destNode.getNode() = node and
|
||||
// // Only print flow from a source in the same function.
|
||||
// sourceNode.getNode().getEnclosingCallable() = node.getEnclosingCallable()
|
||||
// |
|
||||
// nodeId(sourceNode.getNode(), order1, order2) + "+" + dist.toString(), ", "
|
||||
// order by
|
||||
// order1, order2, dist desc
|
||||
// )
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Provides classes for performing local (intra-procedural) and
|
||||
* global (inter-procedural) taint-tracking analyses.
|
||||
*/
|
||||
|
||||
import TaintTrackingParameter::Public
|
||||
private import TaintTrackingParameter::Private
|
||||
|
||||
private module AddTaintDefaults<DataFlowInternal::FullStateConfigSig Config> implements
|
||||
DataFlowInternal::FullStateConfigSig
|
||||
{
|
||||
import Config
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
Config::isBarrier(node) or defaultTaintSanitizer(node)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
Config::isAdditionalFlowStep(node1, node2) or
|
||||
defaultAdditionalTaintStep(node1, node2)
|
||||
}
|
||||
|
||||
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||
Config::allowImplicitRead(node, c)
|
||||
or
|
||||
(
|
||||
Config::isSink(node, _) or
|
||||
Config::isAdditionalFlowStep(node, _) or
|
||||
Config::isAdditionalFlowStep(node, _, _, _)
|
||||
) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a standard taint tracking computation.
|
||||
*/
|
||||
module Make<DataFlow::ConfigSig Config> implements DataFlow::DataFlowSig {
|
||||
private module Config0 implements DataFlowInternal::FullStateConfigSig {
|
||||
import DataFlowInternal::DefaultState<Config>
|
||||
import Config
|
||||
}
|
||||
|
||||
private module C implements DataFlowInternal::FullStateConfigSig {
|
||||
import AddTaintDefaults<Config0>
|
||||
}
|
||||
|
||||
import DataFlowInternal::Impl<C>
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a taint tracking computation using flow state.
|
||||
*/
|
||||
module MakeWithState<DataFlow::StateConfigSig Config> implements DataFlow::DataFlowSig {
|
||||
private module Config0 implements DataFlowInternal::FullStateConfigSig {
|
||||
import Config
|
||||
}
|
||||
|
||||
private module C implements DataFlowInternal::FullStateConfigSig {
|
||||
import AddTaintDefaults<Config0>
|
||||
}
|
||||
|
||||
import DataFlowInternal::Impl<C>
|
||||
}
|
||||
@@ -2,4 +2,5 @@ import experimental.semmle.code.cpp.ir.dataflow.internal.TaintTrackingUtil as Pu
|
||||
|
||||
module Private {
|
||||
import experimental.semmle.code.cpp.ir.dataflow.DataFlow::DataFlow as DataFlow
|
||||
import experimental.semmle.code.cpp.ir.dataflow.internal.DataFlowImpl as DataFlowInternal
|
||||
}
|
||||
|
||||
@@ -936,6 +936,15 @@ module RangeStage<DeltaSig D, BoundSig<D> Bounds, LangSig<D> LangParam, UtilSig<
|
||||
bounded(cast.getOperand(), b, delta, upper, fromBackEdge, origdelta, reason)
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a normal form of `x` where -0.0 has changed to +0.0. This can be
|
||||
* needed on the lesser side of a floating-point comparison or on both sides of
|
||||
* a floating point equality because QL does not follow IEEE in floating-point
|
||||
* comparisons but instead defines -0.0 to be less than and distinct from 0.0.
|
||||
*/
|
||||
bindingset[x]
|
||||
private float normalizeFloatUp(float x) { result = x + 0.0 }
|
||||
|
||||
/**
|
||||
* Holds if `b + delta` is a valid bound for `e`.
|
||||
* - `upper = true` : `e <= b + delta`
|
||||
@@ -1020,6 +1029,15 @@ module RangeStage<DeltaSig D, BoundSig<D> Bounds, LangSig<D> LangParam, UtilSig<
|
||||
or
|
||||
upper = false and delta = D::fromFloat(D::toFloat(d1).minimum(D::toFloat(d2)))
|
||||
)
|
||||
or
|
||||
exists(SemExpr mid, D::Delta d, float f |
|
||||
e.(SemNegateExpr).getOperand() = mid and
|
||||
b instanceof SemZeroBound and
|
||||
bounded(mid, b, d, upper.booleanNot(), fromBackEdge, origdelta, reason) and
|
||||
f = normalizeFloatUp(-D::toFloat(d)) and
|
||||
delta = D::fromFloat(f) and
|
||||
if semPositive(e) then f >= 0 else any()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* Wrapper for the semantic range analysis library that mimics the
|
||||
* interface of the simple range analysis library.
|
||||
*/
|
||||
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import experimental.semmle.code.cpp.semantic.SemanticBound
|
||||
private import experimental.semmle.code.cpp.semantic.SemanticExprSpecific
|
||||
private import RangeAnalysis
|
||||
|
||||
/**
|
||||
* Gets the lower bound of the expression.
|
||||
*
|
||||
* Note: expressions in C/C++ are often implicitly or explicitly cast to a
|
||||
* different result type. Such casts can cause the value of the expression
|
||||
* to overflow or to be truncated. This predicate computes the lower bound
|
||||
* of the expression without including the effect of the casts. To compute
|
||||
* the lower bound of the expression after all the casts have been applied,
|
||||
* call `lowerBound` like this:
|
||||
*
|
||||
* `lowerBound(expr.getFullyConverted())`
|
||||
*/
|
||||
float lowerBound(Expr expr) {
|
||||
exists(Instruction i, SemBound b | i.getAst() = expr and b instanceof SemZeroBound |
|
||||
semBounded(getSemanticExpr(i), b, result, false, _)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the upper bound of the expression.
|
||||
*
|
||||
* Note: expressions in C/C++ are often implicitly or explicitly cast to a
|
||||
* different result type. Such casts can cause the value of the expression
|
||||
* to overflow or to be truncated. This predicate computes the upper bound
|
||||
* of the expression without including the effect of the casts. To compute
|
||||
* the upper bound of the expression after all the casts have been applied,
|
||||
* call `upperBound` like this:
|
||||
*
|
||||
* `upperBound(expr.getFullyConverted())`
|
||||
*/
|
||||
float upperBound(Expr expr) {
|
||||
exists(Instruction i, SemBound b | i.getAst() = expr and b instanceof SemZeroBound |
|
||||
semBounded(getSemanticExpr(i), b, result, true, _)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the upper bound of `expr` may have been widened. This means the
|
||||
* upper bound is in practice likely to be overly wide.
|
||||
*/
|
||||
predicate upperBoundMayBeWidened(Expr e) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `expr` has a provably empty range. For example:
|
||||
*
|
||||
* 10 < expr and expr < 5
|
||||
*
|
||||
* The range of an expression can only be empty if it can never be
|
||||
* executed. For example:
|
||||
*
|
||||
* ```cpp
|
||||
* if (10 < x) {
|
||||
* if (x < 5) {
|
||||
* // Unreachable code
|
||||
* return x; // x has an empty range: 10 < x && x < 5
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
predicate exprWithEmptyRange(Expr expr) { lowerBound(expr) > upperBound(expr) }
|
||||
|
||||
/** Holds if the definition might overflow negatively. */
|
||||
predicate defMightOverflowNegatively(RangeSsaDefinition def, StackVariable v) { none() }
|
||||
|
||||
/** Holds if the definition might overflow positively. */
|
||||
predicate defMightOverflowPositively(RangeSsaDefinition def, StackVariable v) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the definition might overflow (either positively or
|
||||
* negatively).
|
||||
*/
|
||||
predicate defMightOverflow(RangeSsaDefinition def, StackVariable v) {
|
||||
defMightOverflowNegatively(def, v) or
|
||||
defMightOverflowPositively(def, v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the expression might overflow negatively. This predicate
|
||||
* does not consider the possibility that the expression might overflow
|
||||
* due to a conversion.
|
||||
*/
|
||||
predicate exprMightOverflowNegatively(Expr expr) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the expression might overflow negatively. Conversions
|
||||
* are also taken into account. For example the expression
|
||||
* `(int16)(x+y)` might overflow due to the `(int16)` cast, rather than
|
||||
* due to the addition.
|
||||
*/
|
||||
predicate convertedExprMightOverflowNegatively(Expr expr) {
|
||||
exprMightOverflowNegatively(expr) or
|
||||
convertedExprMightOverflowNegatively(expr.getConversion())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the expression might overflow positively. This predicate
|
||||
* does not consider the possibility that the expression might overflow
|
||||
* due to a conversion.
|
||||
*/
|
||||
predicate exprMightOverflowPositively(Expr expr) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the expression might overflow positively. Conversions
|
||||
* are also taken into account. For example the expression
|
||||
* `(int16)(x+y)` might overflow due to the `(int16)` cast, rather than
|
||||
* due to the addition.
|
||||
*/
|
||||
predicate convertedExprMightOverflowPositively(Expr expr) {
|
||||
exprMightOverflowPositively(expr) or
|
||||
convertedExprMightOverflowPositively(expr.getConversion())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the expression might overflow (either positively or
|
||||
* negatively). The possibility that the expression might overflow
|
||||
* due to an implicit or explicit cast is also considered.
|
||||
*/
|
||||
predicate convertedExprMightOverflow(Expr expr) {
|
||||
convertedExprMightOverflowNegatively(expr) or
|
||||
convertedExprMightOverflowPositively(expr)
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 0.5.4
|
||||
version: 0.5.5-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -227,18 +227,6 @@ class Class extends UserType {
|
||||
result = this.accessOfBaseMember(member.getDeclaringType(), member.getASpecifier())
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: name changed to `hasImplicitCopyConstructor` to reflect that
|
||||
* `= default` members are no longer included.
|
||||
*/
|
||||
deprecated predicate hasGeneratedCopyConstructor() { this.hasImplicitCopyConstructor() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: name changed to `hasImplicitCopyAssignmentOperator` to
|
||||
* reflect that `= default` members are no longer included.
|
||||
*/
|
||||
deprecated predicate hasGeneratedCopyAssignmentOperator() { this.hasImplicitCopyConstructor() }
|
||||
|
||||
/**
|
||||
* Holds if this class, struct or union has an implicitly-declared copy
|
||||
* constructor that is not _deleted_. This predicate is more accurate than
|
||||
|
||||
@@ -68,7 +68,9 @@ class Declaration extends Locatable, @declaration {
|
||||
* Holds if this declaration has the fully-qualified name `qualifiedName`.
|
||||
* See `getQualifiedName`.
|
||||
*/
|
||||
predicate hasQualifiedName(string qualifiedName) { this.getQualifiedName() = qualifiedName }
|
||||
deprecated predicate hasQualifiedName(string qualifiedName) {
|
||||
this.getQualifiedName() = qualifiedName
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this declaration has a fully-qualified name with a name-space
|
||||
@@ -184,7 +186,7 @@ class Declaration extends Locatable, @declaration {
|
||||
predicate hasDefinition() { exists(this.getDefinition()) }
|
||||
|
||||
/** DEPRECATED: Use `hasDefinition` instead. */
|
||||
predicate isDefined() { this.hasDefinition() }
|
||||
deprecated predicate isDefined() { this.hasDefinition() }
|
||||
|
||||
/** Gets the preferred location of this declaration, if any. */
|
||||
override Location getLocation() { none() }
|
||||
@@ -617,11 +619,10 @@ private class DirectAccessHolder extends Element {
|
||||
/**
|
||||
* Like `couldAccessMember` but only contains derivations in which either
|
||||
* (5.2), (5.3) or (5.4) must be invoked. In other words, the `this`
|
||||
* parameter is not ignored. This restriction makes it feasible to fully
|
||||
* enumerate this predicate even on large code bases. We check for 11.4 as
|
||||
* part of (5.3), since this further limits the number of tuples produced by
|
||||
* this predicate.
|
||||
* parameter is not ignored. We check for 11.4 as part of (5.3), since
|
||||
* this further limits the number of tuples produced by this predicate.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate thisCouldAccessMember(Class memberClass, AccessSpecifier memberAccess, Class derived) {
|
||||
// Only (5.4) is recursive, and chains of invocations of (5.4) can always
|
||||
// be collapsed to one invocation by the transitivity of 11.2/4.
|
||||
@@ -663,7 +664,9 @@ private class DirectAccessHolder extends Element {
|
||||
// bypasses `p`. Then that path must be public, or we are in case 2.
|
||||
exists(AccessSpecifier public | public.hasName("public") |
|
||||
exists(Class between, Class p |
|
||||
between.accessOfBaseMember(memberClass, memberAccess).hasName("protected") and
|
||||
between
|
||||
.accessOfBaseMember(pragma[only_bind_into](memberClass), memberAccess)
|
||||
.hasName("protected") and
|
||||
this.isFriendOfOrEqualTo(p) and
|
||||
(
|
||||
// This is case 1 from above. If `p` derives privately from `between`
|
||||
|
||||
@@ -41,7 +41,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
|
||||
* `min<int>(int, int) -> int`, and the full signature of the uninstantiated
|
||||
* template on the first line would be `min<T>(T, T) -> T`.
|
||||
*/
|
||||
string getFullSignature() {
|
||||
deprecated string getFullSignature() {
|
||||
exists(string name, string templateArgs, string args |
|
||||
result = name + templateArgs + args + " -> " + this.getType().toString() and
|
||||
name = this.getQualifiedName() and
|
||||
|
||||
@@ -65,6 +65,7 @@ class Location extends @location {
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
|
||||
@@ -159,7 +159,8 @@ class NameQualifyingElement extends Element, @namequalifyingelement {
|
||||
* A special name-qualifying element. For example: `__super`.
|
||||
*/
|
||||
library class SpecialNameQualifyingElement extends NameQualifyingElement,
|
||||
@specialnamequalifyingelement {
|
||||
@specialnamequalifyingelement
|
||||
{
|
||||
/** Gets the name of this special qualifying element. */
|
||||
override string getName() { specialnamequalifyingelements(underlyingElement(this), result) }
|
||||
|
||||
|
||||
@@ -108,20 +108,6 @@ class XmlFile extends XmlParent, File {
|
||||
/** Gets the name of this XML file. */
|
||||
override string getName() { result = File.super.getAbsolutePath() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getAbsolutePath()` instead.
|
||||
*
|
||||
* Gets the path of this XML file.
|
||||
*/
|
||||
deprecated string getPath() { result = this.getAbsolutePath() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getParentContainer().getAbsolutePath()` instead.
|
||||
*
|
||||
* Gets the path of the folder that contains this XML file.
|
||||
*/
|
||||
deprecated string getFolder() { result = this.getParentContainer().getAbsolutePath() }
|
||||
|
||||
/** Gets the encoding of this XML file. */
|
||||
string getEncoding() { xmlEncoding(this, result) }
|
||||
|
||||
|
||||
@@ -12,7 +12,9 @@ predicate freeFunction(Function f, int argNum) { argNum = f.(DeallocationFunctio
|
||||
*
|
||||
* DEPRECATED: Use `DeallocationExpr` instead (this also includes `delete` expressions).
|
||||
*/
|
||||
predicate freeCall(FunctionCall fc, Expr arg) { arg = fc.(DeallocationExpr).getFreedExpr() }
|
||||
deprecated predicate freeCall(FunctionCall fc, Expr arg) {
|
||||
arg = fc.(DeallocationExpr).getFreedExpr()
|
||||
}
|
||||
|
||||
/**
|
||||
* Is e some kind of allocation or deallocation (`new`, `alloc`, `realloc`, `delete`, `free` etc)?
|
||||
|
||||
@@ -59,26 +59,6 @@ abstract class MutexType extends Type {
|
||||
* Gets a call that unlocks any mutex of this type.
|
||||
*/
|
||||
FunctionCall getUnlockAccess() { this.unlockAccess(result, _) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use mustlockAccess(fc, arg) instead.
|
||||
*/
|
||||
deprecated Function getMustlockFunction() { result = this.getMustlockAccess().getTarget() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use trylockAccess(fc, arg) instead.
|
||||
*/
|
||||
deprecated Function getTrylockFunction() { result = this.getTrylockAccess().getTarget() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use lockAccess(fc, arg) instead.
|
||||
*/
|
||||
deprecated Function getLockFunction() { result = this.getLockAccess().getTarget() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use unlockAccess(fc, arg) instead.
|
||||
*/
|
||||
deprecated Function getUnlockFunction() { result = this.getUnlockAccess().getTarget() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -75,13 +75,6 @@ class SubBasicBlock extends ControlFlowNodeBase {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `getRankInBasicBlock` instead. Note that this predicate
|
||||
* returns a 0-based position, while `getRankInBasicBlock` returns a 1-based
|
||||
* position.
|
||||
*/
|
||||
deprecated int getPosInBasicBlock(BasicBlock bb) { result = this.getRankInBasicBlock(bb) - 1 }
|
||||
|
||||
pragma[noinline]
|
||||
private int getIndexInBasicBlock(BasicBlock bb) { this = bb.getNode(result) }
|
||||
|
||||
|
||||
@@ -20,5 +20,6 @@
|
||||
import cpp
|
||||
|
||||
module DataFlow {
|
||||
import semmle.code.cpp.dataflow.internal.DataFlowImpl
|
||||
import semmle.code.cpp.dataflow.internal.DataFlow
|
||||
import semmle.code.cpp.dataflow.internal.DataFlowImpl1
|
||||
}
|
||||
|
||||
@@ -19,5 +19,6 @@ import semmle.code.cpp.dataflow.DataFlow
|
||||
import semmle.code.cpp.dataflow.DataFlow2
|
||||
|
||||
module TaintTracking {
|
||||
import semmle.code.cpp.dataflow.internal.tainttracking1.TaintTracking
|
||||
import semmle.code.cpp.dataflow.internal.tainttracking1.TaintTrackingImpl
|
||||
}
|
||||
|
||||
353
cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlow.qll
Normal file
353
cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlow.qll
Normal file
@@ -0,0 +1,353 @@
|
||||
/**
|
||||
* Provides an implementation of global (interprocedural) data flow. This file
|
||||
* re-exports the local (intraprocedural) data flow analysis from
|
||||
* `DataFlowImplSpecific::Public` and adds a global analysis, mainly exposed
|
||||
* through the `Make` and `MakeWithState` modules.
|
||||
*/
|
||||
|
||||
private import DataFlowImplCommon
|
||||
private import DataFlowImplSpecific::Private
|
||||
import DataFlowImplSpecific::Public
|
||||
import DataFlowImplCommonPublic
|
||||
private import DataFlowImpl
|
||||
|
||||
/** An input configuration for data flow. */
|
||||
signature module ConfigSig {
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source.
|
||||
*/
|
||||
predicate isSource(Node source);
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink.
|
||||
*/
|
||||
predicate isSink(Node sink);
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited. This completely removes
|
||||
* `node` from the data flow graph.
|
||||
*/
|
||||
default predicate isBarrier(Node node) { none() }
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
default predicate isBarrierIn(Node node) { none() }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
default predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
default predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
default predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
default int fieldFlowBranchLimit() { result = 2 }
|
||||
|
||||
/**
|
||||
* Gets a data flow configuration feature to add restrictions to the set of
|
||||
* valid flow paths.
|
||||
*
|
||||
* - `FeatureHasSourceCallContext`:
|
||||
* Assume that sources have some existing call context to disallow
|
||||
* conflicting return-flow directly following the source.
|
||||
* - `FeatureHasSinkCallContext`:
|
||||
* Assume that sinks have some existing call context to disallow
|
||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
||||
* - `FeatureEqualSourceSinkCallContext`:
|
||||
* Implies both of the above and additionally ensures that the entire flow
|
||||
* path preserves the call context.
|
||||
*
|
||||
* These features are generally not relevant for typical end-to-end data flow
|
||||
* queries, but should only be used for constructing paths that need to
|
||||
* somehow be pluggable in another path context.
|
||||
*/
|
||||
default FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
default predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (as it is in a `path-problem` query).
|
||||
*/
|
||||
default predicate includeHiddenNodes() { none() }
|
||||
}
|
||||
|
||||
/** An input configuration for data flow using flow state. */
|
||||
signature module StateConfigSig {
|
||||
bindingset[this]
|
||||
class FlowState;
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source with the given initial
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSource(Node source, FlowState state);
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
||||
*/
|
||||
predicate isSink(Node sink, FlowState state);
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited. This completely removes
|
||||
* `node` from the data flow graph.
|
||||
*/
|
||||
default predicate isBarrier(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isBarrier(Node node, FlowState state);
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
default predicate isBarrierIn(Node node) { none() }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
default predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
default predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2);
|
||||
|
||||
/**
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
default predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
default int fieldFlowBranchLimit() { result = 2 }
|
||||
|
||||
/**
|
||||
* Gets a data flow configuration feature to add restrictions to the set of
|
||||
* valid flow paths.
|
||||
*
|
||||
* - `FeatureHasSourceCallContext`:
|
||||
* Assume that sources have some existing call context to disallow
|
||||
* conflicting return-flow directly following the source.
|
||||
* - `FeatureHasSinkCallContext`:
|
||||
* Assume that sinks have some existing call context to disallow
|
||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
||||
* - `FeatureEqualSourceSinkCallContext`:
|
||||
* Implies both of the above and additionally ensures that the entire flow
|
||||
* path preserves the call context.
|
||||
*
|
||||
* These features are generally not relevant for typical end-to-end data flow
|
||||
* queries, but should only be used for constructing paths that need to
|
||||
* somehow be pluggable in another path context.
|
||||
*/
|
||||
default FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
default predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (as it is in a `path-problem` query).
|
||||
*/
|
||||
default predicate includeHiddenNodes() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
|
||||
* measured in approximate number of interprocedural steps.
|
||||
*/
|
||||
signature int explorationLimitSig();
|
||||
|
||||
/**
|
||||
* The output of a data flow computation.
|
||||
*/
|
||||
signature module DataFlowSig {
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks) and an access path.
|
||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
||||
*/
|
||||
class PathNode;
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `source` to `sink`.
|
||||
*
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink);
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `source` to `sink`.
|
||||
*/
|
||||
predicate hasFlow(Node source, Node sink);
|
||||
|
||||
/**
|
||||
* Holds if data can flow from some source to `sink`.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink);
|
||||
|
||||
/**
|
||||
* Holds if data can flow from some source to `sink`.
|
||||
*/
|
||||
predicate hasFlowToExpr(DataFlowExpr sink);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a standard data flow computation.
|
||||
*/
|
||||
module Make<ConfigSig Config> implements DataFlowSig {
|
||||
private module C implements FullStateConfigSig {
|
||||
import DefaultState<Config>
|
||||
import Config
|
||||
}
|
||||
|
||||
import Impl<C>
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a data flow computation using flow state.
|
||||
*/
|
||||
module MakeWithState<StateConfigSig Config> implements DataFlowSig {
|
||||
private module C implements FullStateConfigSig {
|
||||
import Config
|
||||
}
|
||||
|
||||
import Impl<C>
|
||||
}
|
||||
|
||||
signature class PathNodeSig {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString();
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
);
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
Node getNode();
|
||||
}
|
||||
|
||||
signature module PathGraphSig<PathNodeSig PathNode> {
|
||||
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||
predicate edges(PathNode a, PathNode b);
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
predicate nodes(PathNode n, string key, string val);
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a `PathGraph` from two `PathGraph`s by disjoint union.
|
||||
*/
|
||||
module MergePathGraph<
|
||||
PathNodeSig PathNode1, PathNodeSig PathNode2, PathGraphSig<PathNode1> Graph1,
|
||||
PathGraphSig<PathNode2> Graph2>
|
||||
{
|
||||
private newtype TPathNode =
|
||||
TPathNode1(PathNode1 p) or
|
||||
TPathNode2(PathNode2 p)
|
||||
|
||||
/** A node in a graph of path explanations that is formed by disjoint union of the two given graphs. */
|
||||
class PathNode extends TPathNode {
|
||||
/** Gets this as a projection on the first given `PathGraph`. */
|
||||
PathNode1 asPathNode1() { this = TPathNode1(result) }
|
||||
|
||||
/** Gets this as a projection on the second given `PathGraph`. */
|
||||
PathNode2 asPathNode2() { this = TPathNode2(result) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() {
|
||||
result = this.asPathNode1().toString() or
|
||||
result = this.asPathNode2().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.asPathNode1().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) or
|
||||
this.asPathNode2().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
Node getNode() {
|
||||
result = this.asPathNode1().getNode() or
|
||||
result = this.asPathNode2().getNode()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||
*/
|
||||
module PathGraph implements PathGraphSig<PathNode> {
|
||||
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||
query predicate edges(PathNode a, PathNode b) {
|
||||
Graph1::edges(a.asPathNode1(), b.asPathNode1()) or
|
||||
Graph2::edges(a.asPathNode2(), b.asPathNode2())
|
||||
}
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
Graph1::nodes(n.asPathNode1(), key, val) or
|
||||
Graph2::nodes(n.asPathNode2(), key, val)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
|
||||
Graph1::subpaths(arg.asPathNode1(), par.asPathNode1(), ret.asPathNode1(), out.asPathNode1()) or
|
||||
Graph2::subpaths(arg.asPathNode2(), par.asPathNode2(), ret.asPathNode2(), out.asPathNode2())
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
396
cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl1.qll
Normal file
396
cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl1.qll
Normal file
@@ -0,0 +1,396 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Make` and `MakeWithState` instead.
|
||||
*
|
||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
||||
* flow library.
|
||||
*/
|
||||
|
||||
private import DataFlowImplCommon
|
||||
private import DataFlowImplSpecific::Private
|
||||
import DataFlowImplSpecific::Public
|
||||
private import DataFlowImpl
|
||||
import DataFlowImplCommonPublic
|
||||
import FlowStateString
|
||||
|
||||
/**
|
||||
* A configuration of interprocedural data flow analysis. This defines
|
||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
||||
* use of the global data flow 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.
|
||||
* For example, write
|
||||
*
|
||||
* ```ql
|
||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
* // Optionally override `isBarrier`.
|
||||
* // Optionally override `isAdditionalFlowStep`.
|
||||
* }
|
||||
* ```
|
||||
* Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and
|
||||
* the edges are those data-flow steps that preserve the value of the node
|
||||
* along with any additional edges defined by `isAdditionalFlowStep`.
|
||||
* Specifying nodes in `isBarrier` will remove those nodes from the graph, and
|
||||
* specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going
|
||||
* and/or out-going edges from those nodes, respectively.
|
||||
*
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
* Multiple configurations can coexist, but two classes extending
|
||||
* `DataFlow::Configuration` should never depend on each other. One of them
|
||||
* should instead depend on a `DataFlow2::Configuration`, a
|
||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
|
||||
*/
|
||||
abstract class Configuration extends string {
|
||||
bindingset[this]
|
||||
Configuration() { any() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source.
|
||||
*/
|
||||
predicate isSource(Node source) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source with the given initial
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSource(Node source, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink.
|
||||
*/
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
||||
*/
|
||||
predicate isSink(Node sink, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited. This completely removes
|
||||
* `node` from the data flow graph.
|
||||
*/
|
||||
predicate isBarrier(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isBarrier(Node node, FlowState state) { none() }
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
predicate isBarrierIn(Node node) { none() }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||
* the flow state is `state`
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
int fieldFlowBranchLimit() { result = 2 }
|
||||
|
||||
/**
|
||||
* Gets a data flow configuration feature to add restrictions to the set of
|
||||
* valid flow paths.
|
||||
*
|
||||
* - `FeatureHasSourceCallContext`:
|
||||
* Assume that sources have some existing call context to disallow
|
||||
* conflicting return-flow directly following the source.
|
||||
* - `FeatureHasSinkCallContext`:
|
||||
* Assume that sinks have some existing call context to disallow
|
||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
||||
* - `FeatureEqualSourceSinkCallContext`:
|
||||
* Implies both of the above and additionally ensures that the entire flow
|
||||
* path preserves the call context.
|
||||
*
|
||||
* These features are generally not relevant for typical end-to-end data flow
|
||||
* queries, but should only be used for constructing paths that need to
|
||||
* somehow be pluggable in another path context.
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlow(Node source, Node sink) { hasFlow(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may 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`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `FlowExploration<explorationLimit>` instead.
|
||||
*
|
||||
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
|
||||
* measured in approximate number of interprocedural steps.
|
||||
*/
|
||||
deprecated int explorationLimit() { none() }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (for example in a `path-problem` query).
|
||||
*/
|
||||
predicate includeHiddenNodes() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* This class exists to prevent mutual recursion between the user-overridden
|
||||
* member predicates of `Configuration` and the rest of the data-flow library.
|
||||
* Good performance cannot be guaranteed in the presence of such recursion, so
|
||||
* it should be replaced by using more than one copy of the data flow library.
|
||||
*/
|
||||
abstract private class ConfigurationRecursionPrevention extends Configuration {
|
||||
bindingset[this]
|
||||
ConfigurationRecursionPrevention() { any() }
|
||||
|
||||
override predicate hasFlow(Node source, Node sink) {
|
||||
strictcount(Node n | this.isSource(n)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSource(n, _)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSink(n)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSink(n, _)) < 0
|
||||
or
|
||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
|
||||
or
|
||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0
|
||||
or
|
||||
super.hasFlow(source, sink)
|
||||
}
|
||||
}
|
||||
|
||||
/** A bridge class to access the deprecated `isBarrierGuard`. */
|
||||
private class BarrierGuardGuardedNodeBridge extends Unit {
|
||||
abstract predicate guardedNode(Node n, Configuration config);
|
||||
|
||||
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
|
||||
}
|
||||
|
||||
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
|
||||
deprecated override predicate guardedNode(Node n, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private FlowState relevantState(Configuration config) {
|
||||
config.isSource(_, result) or
|
||||
config.isSink(_, result) or
|
||||
config.isBarrier(_, result) or
|
||||
config.isAdditionalFlowStep(_, result, _, _) or
|
||||
config.isAdditionalFlowStep(_, _, _, result)
|
||||
}
|
||||
|
||||
private newtype TConfigState =
|
||||
TMkConfigState(Configuration config, FlowState state) {
|
||||
state = relevantState(config) or state instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
|
||||
|
||||
private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
|
||||
|
||||
private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
|
||||
|
||||
private module Config implements FullStateConfigSig {
|
||||
class FlowState = TConfigState;
|
||||
|
||||
predicate isSource(Node source, FlowState state) {
|
||||
getConfig(state).isSource(source, getState(state))
|
||||
or
|
||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isSink(Node sink, FlowState state) {
|
||||
getConfig(state).isSink(sink, getState(state))
|
||||
or
|
||||
getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isBarrier(Node node) { none() }
|
||||
|
||||
predicate isBarrier(Node node, FlowState state) {
|
||||
getConfig(state).isBarrier(node, getState(state)) or
|
||||
getConfig(state).isBarrier(node) or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getState(state), getConfig(state)) or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getConfig(state))
|
||||
}
|
||||
|
||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
||||
|
||||
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) {
|
||||
singleConfiguration() and
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and
|
||||
getConfig(state2) = getConfig(state1)
|
||||
or
|
||||
not singleConfiguration() and
|
||||
getConfig(state1).isAdditionalFlowStep(node1, node2) and
|
||||
state2 = state1
|
||||
}
|
||||
|
||||
predicate allowImplicitRead(Node node, ContentSet c) {
|
||||
any(Configuration config).allowImplicitRead(node, c)
|
||||
}
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate sourceGrouping(Node source, string sourceGroup) {
|
||||
any(Configuration config).sourceGrouping(source, sourceGroup)
|
||||
}
|
||||
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) {
|
||||
any(Configuration config).sinkGrouping(sink, sinkGroup)
|
||||
}
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
||||
*/
|
||||
class PathNode instanceof I::PathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
final string toString() { result = super.toString() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
final string toStringWithContext() { result = super.toStringWithContext() }
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
final predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
final Node getNode() { result = super.getNode() }
|
||||
|
||||
/** Gets the `FlowState` of this node. */
|
||||
final FlowState getState() { result = getState(super.getState()) }
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
final Configuration getConfiguration() { result = getConfig(super.getState()) }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() { result = super.getASuccessor() }
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { super.isSourceGroup(group) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
source0.getNode() = source and
|
||||
sink0.getNode() = sink
|
||||
)
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
hasFlowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
predicate flowsTo = hasFlow/3;
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -3,15 +3,18 @@ private import DataFlowImplSpecific::Public
|
||||
import Cached
|
||||
|
||||
module DataFlowImplCommonPublic {
|
||||
/** A state value to track during data flow. */
|
||||
class FlowState = string;
|
||||
/** Provides `FlowState = string`. */
|
||||
module FlowStateString {
|
||||
/** A state value to track during data flow. */
|
||||
class FlowState = string;
|
||||
|
||||
/**
|
||||
* The default state, which is used when the state is unspecified for a source
|
||||
* or a sink.
|
||||
*/
|
||||
class FlowStateEmpty extends FlowState {
|
||||
FlowStateEmpty() { this = "" }
|
||||
/**
|
||||
* The default state, which is used when the state is unspecified for a source
|
||||
* or a sink.
|
||||
*/
|
||||
class FlowStateEmpty extends FlowState {
|
||||
FlowStateEmpty() { this = "" }
|
||||
}
|
||||
}
|
||||
|
||||
private newtype TFlowFeature =
|
||||
@@ -179,6 +182,7 @@ private module LambdaFlow {
|
||||
boolean toJump, DataFlowCallOption lastCall
|
||||
) {
|
||||
revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and
|
||||
not expectsContent(node, _) and
|
||||
if castNode(node) or node instanceof ArgNode or node instanceof ReturnNode
|
||||
then compatibleTypes(t, getNodeDataFlowType(node))
|
||||
else any()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -318,3 +318,12 @@ private class MyConsistencyConfiguration extends Consistency::ConsistencyConfigu
|
||||
// consistency alerts enough that most of them are interesting.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* when calculating the (virtual) dispatch cost.
|
||||
*
|
||||
* Argument `arg` is part of a path from a source to a sink, and `p` is the target parameter.
|
||||
*/
|
||||
int getAdditionalFlowIntoCallNodeTerm(ArgumentNode arg, ParameterNode p) { none() }
|
||||
|
||||
@@ -75,13 +75,6 @@ class SubBasicBlock extends ControlFlowNodeBase {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `getRankInBasicBlock` instead. Note that this predicate
|
||||
* returns a 0-based position, while `getRankInBasicBlock` returns a 1-based
|
||||
* position.
|
||||
*/
|
||||
deprecated int getPosInBasicBlock(BasicBlock bb) { result = this.getRankInBasicBlock(bb) - 1 }
|
||||
|
||||
pragma[noinline]
|
||||
private int getIndexInBasicBlock(BasicBlock bb) { this = bb.getNode(result) }
|
||||
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Provides classes for performing local (intra-procedural) and
|
||||
* global (inter-procedural) taint-tracking analyses.
|
||||
*/
|
||||
|
||||
import TaintTrackingParameter::Public
|
||||
private import TaintTrackingParameter::Private
|
||||
|
||||
private module AddTaintDefaults<DataFlowInternal::FullStateConfigSig Config> implements
|
||||
DataFlowInternal::FullStateConfigSig
|
||||
{
|
||||
import Config
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
Config::isBarrier(node) or defaultTaintSanitizer(node)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
Config::isAdditionalFlowStep(node1, node2) or
|
||||
defaultAdditionalTaintStep(node1, node2)
|
||||
}
|
||||
|
||||
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||
Config::allowImplicitRead(node, c)
|
||||
or
|
||||
(
|
||||
Config::isSink(node, _) or
|
||||
Config::isAdditionalFlowStep(node, _) or
|
||||
Config::isAdditionalFlowStep(node, _, _, _)
|
||||
) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a standard taint tracking computation.
|
||||
*/
|
||||
module Make<DataFlow::ConfigSig Config> implements DataFlow::DataFlowSig {
|
||||
private module Config0 implements DataFlowInternal::FullStateConfigSig {
|
||||
import DataFlowInternal::DefaultState<Config>
|
||||
import Config
|
||||
}
|
||||
|
||||
private module C implements DataFlowInternal::FullStateConfigSig {
|
||||
import AddTaintDefaults<Config0>
|
||||
}
|
||||
|
||||
import DataFlowInternal::Impl<C>
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a taint tracking computation using flow state.
|
||||
*/
|
||||
module MakeWithState<DataFlow::StateConfigSig Config> implements DataFlow::DataFlowSig {
|
||||
private module Config0 implements DataFlowInternal::FullStateConfigSig {
|
||||
import Config
|
||||
}
|
||||
|
||||
private module C implements DataFlowInternal::FullStateConfigSig {
|
||||
import AddTaintDefaults<Config0>
|
||||
}
|
||||
|
||||
import DataFlowInternal::Impl<C>
|
||||
}
|
||||
@@ -2,4 +2,5 @@ import semmle.code.cpp.dataflow.internal.TaintTrackingUtil as Public
|
||||
|
||||
module Private {
|
||||
import semmle.code.cpp.dataflow.DataFlow::DataFlow as DataFlow
|
||||
import semmle.code.cpp.dataflow.internal.DataFlowImpl as DataFlowInternal
|
||||
}
|
||||
|
||||
@@ -569,7 +569,8 @@ class BuiltInOperationBuiltInAddressOf extends UnaryOperation, BuiltInOperation,
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsTriviallyConstructible extends BuiltInOperation,
|
||||
@istriviallyconstructibleexpr {
|
||||
@istriviallyconstructibleexpr
|
||||
{
|
||||
override string toString() { result = "__is_trivially_constructible" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyConstructible" }
|
||||
@@ -619,7 +620,8 @@ class BuiltInOperationIsNothrowDestructible extends BuiltInOperation, @isnothrow
|
||||
* bool v = __is_trivially_destructible(MyType);
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsTriviallyDestructible extends BuiltInOperation, @istriviallydestructibleexpr {
|
||||
class BuiltInOperationIsTriviallyDestructible extends BuiltInOperation, @istriviallydestructibleexpr
|
||||
{
|
||||
override string toString() { result = "__is_trivially_destructible" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyDestructible" }
|
||||
@@ -738,7 +740,8 @@ class BuiltInOperationIsLiteralType extends BuiltInOperation, @isliteraltypeexpr
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationHasTrivialMoveConstructor extends BuiltInOperation,
|
||||
@hastrivialmoveconstructorexpr {
|
||||
@hastrivialmoveconstructorexpr
|
||||
{
|
||||
override string toString() { result = "__has_trivial_move_constructor" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasTrivialMoveConstructor" }
|
||||
@@ -1034,7 +1037,8 @@ class BuiltInOperationIsAggregate extends BuiltInOperation, @isaggregate {
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationHasUniqueObjectRepresentations extends BuiltInOperation,
|
||||
@hasuniqueobjectrepresentations {
|
||||
@hasuniqueobjectrepresentations
|
||||
{
|
||||
override string toString() { result = "__has_unique_object_representations" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BuiltInOperationHasUniqueObjectRepresentations" }
|
||||
@@ -1107,7 +1111,8 @@ class BuiltInOperationIsLayoutCompatible extends BuiltInOperation, @islayoutcomp
|
||||
* ```
|
||||
*/
|
||||
class BuiltInOperationIsPointerInterconvertibleBaseOf extends BuiltInOperation,
|
||||
@ispointerinterconvertiblebaseof {
|
||||
@ispointerinterconvertiblebaseof
|
||||
{
|
||||
override string toString() { result = "__is_pointer_interconvertible_base_of" }
|
||||
|
||||
override string getAPrimaryQlClass() {
|
||||
|
||||
@@ -719,13 +719,6 @@ class ReferenceToExpr extends Conversion, @reference_to {
|
||||
class PointerDereferenceExpr extends UnaryOperation, @indirect {
|
||||
override string getAPrimaryQlClass() { result = "PointerDereferenceExpr" }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use getOperand() instead.
|
||||
*
|
||||
* Gets the expression that is being dereferenced.
|
||||
*/
|
||||
deprecated Expr getExpr() { result = this.getOperand() }
|
||||
|
||||
override string getOperator() { result = "*" }
|
||||
|
||||
override int getPrecedence() { result = 16 }
|
||||
|
||||
@@ -22,5 +22,6 @@
|
||||
import cpp
|
||||
|
||||
module DataFlow {
|
||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl
|
||||
import semmle.code.cpp.ir.dataflow.internal.DataFlow
|
||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl1
|
||||
}
|
||||
|
||||
@@ -19,5 +19,6 @@ import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
import semmle.code.cpp.ir.dataflow.DataFlow2
|
||||
|
||||
module TaintTracking {
|
||||
import semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTracking
|
||||
import semmle.code.cpp.ir.dataflow.internal.tainttracking1.TaintTrackingImpl
|
||||
}
|
||||
|
||||
353
cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlow.qll
Normal file
353
cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlow.qll
Normal file
@@ -0,0 +1,353 @@
|
||||
/**
|
||||
* Provides an implementation of global (interprocedural) data flow. This file
|
||||
* re-exports the local (intraprocedural) data flow analysis from
|
||||
* `DataFlowImplSpecific::Public` and adds a global analysis, mainly exposed
|
||||
* through the `Make` and `MakeWithState` modules.
|
||||
*/
|
||||
|
||||
private import DataFlowImplCommon
|
||||
private import DataFlowImplSpecific::Private
|
||||
import DataFlowImplSpecific::Public
|
||||
import DataFlowImplCommonPublic
|
||||
private import DataFlowImpl
|
||||
|
||||
/** An input configuration for data flow. */
|
||||
signature module ConfigSig {
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source.
|
||||
*/
|
||||
predicate isSource(Node source);
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink.
|
||||
*/
|
||||
predicate isSink(Node sink);
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited. This completely removes
|
||||
* `node` from the data flow graph.
|
||||
*/
|
||||
default predicate isBarrier(Node node) { none() }
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
default predicate isBarrierIn(Node node) { none() }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
default predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
default predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
default predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
default int fieldFlowBranchLimit() { result = 2 }
|
||||
|
||||
/**
|
||||
* Gets a data flow configuration feature to add restrictions to the set of
|
||||
* valid flow paths.
|
||||
*
|
||||
* - `FeatureHasSourceCallContext`:
|
||||
* Assume that sources have some existing call context to disallow
|
||||
* conflicting return-flow directly following the source.
|
||||
* - `FeatureHasSinkCallContext`:
|
||||
* Assume that sinks have some existing call context to disallow
|
||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
||||
* - `FeatureEqualSourceSinkCallContext`:
|
||||
* Implies both of the above and additionally ensures that the entire flow
|
||||
* path preserves the call context.
|
||||
*
|
||||
* These features are generally not relevant for typical end-to-end data flow
|
||||
* queries, but should only be used for constructing paths that need to
|
||||
* somehow be pluggable in another path context.
|
||||
*/
|
||||
default FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
default predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (as it is in a `path-problem` query).
|
||||
*/
|
||||
default predicate includeHiddenNodes() { none() }
|
||||
}
|
||||
|
||||
/** An input configuration for data flow using flow state. */
|
||||
signature module StateConfigSig {
|
||||
bindingset[this]
|
||||
class FlowState;
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source with the given initial
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSource(Node source, FlowState state);
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
||||
*/
|
||||
predicate isSink(Node sink, FlowState state);
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited. This completely removes
|
||||
* `node` from the data flow graph.
|
||||
*/
|
||||
default predicate isBarrier(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isBarrier(Node node, FlowState state);
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
default predicate isBarrierIn(Node node) { none() }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
default predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
default predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2);
|
||||
|
||||
/**
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
default predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
default int fieldFlowBranchLimit() { result = 2 }
|
||||
|
||||
/**
|
||||
* Gets a data flow configuration feature to add restrictions to the set of
|
||||
* valid flow paths.
|
||||
*
|
||||
* - `FeatureHasSourceCallContext`:
|
||||
* Assume that sources have some existing call context to disallow
|
||||
* conflicting return-flow directly following the source.
|
||||
* - `FeatureHasSinkCallContext`:
|
||||
* Assume that sinks have some existing call context to disallow
|
||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
||||
* - `FeatureEqualSourceSinkCallContext`:
|
||||
* Implies both of the above and additionally ensures that the entire flow
|
||||
* path preserves the call context.
|
||||
*
|
||||
* These features are generally not relevant for typical end-to-end data flow
|
||||
* queries, but should only be used for constructing paths that need to
|
||||
* somehow be pluggable in another path context.
|
||||
*/
|
||||
default FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
default predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
default predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (as it is in a `path-problem` query).
|
||||
*/
|
||||
default predicate includeHiddenNodes() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
|
||||
* measured in approximate number of interprocedural steps.
|
||||
*/
|
||||
signature int explorationLimitSig();
|
||||
|
||||
/**
|
||||
* The output of a data flow computation.
|
||||
*/
|
||||
signature module DataFlowSig {
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks) and an access path.
|
||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
||||
*/
|
||||
class PathNode;
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `source` to `sink`.
|
||||
*
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink);
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `source` to `sink`.
|
||||
*/
|
||||
predicate hasFlow(Node source, Node sink);
|
||||
|
||||
/**
|
||||
* Holds if data can flow from some source to `sink`.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink);
|
||||
|
||||
/**
|
||||
* Holds if data can flow from some source to `sink`.
|
||||
*/
|
||||
predicate hasFlowToExpr(DataFlowExpr sink);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a standard data flow computation.
|
||||
*/
|
||||
module Make<ConfigSig Config> implements DataFlowSig {
|
||||
private module C implements FullStateConfigSig {
|
||||
import DefaultState<Config>
|
||||
import Config
|
||||
}
|
||||
|
||||
import Impl<C>
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a data flow computation using flow state.
|
||||
*/
|
||||
module MakeWithState<StateConfigSig Config> implements DataFlowSig {
|
||||
private module C implements FullStateConfigSig {
|
||||
import Config
|
||||
}
|
||||
|
||||
import Impl<C>
|
||||
}
|
||||
|
||||
signature class PathNodeSig {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString();
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
);
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
Node getNode();
|
||||
}
|
||||
|
||||
signature module PathGraphSig<PathNodeSig PathNode> {
|
||||
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||
predicate edges(PathNode a, PathNode b);
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
predicate nodes(PathNode n, string key, string val);
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a `PathGraph` from two `PathGraph`s by disjoint union.
|
||||
*/
|
||||
module MergePathGraph<
|
||||
PathNodeSig PathNode1, PathNodeSig PathNode2, PathGraphSig<PathNode1> Graph1,
|
||||
PathGraphSig<PathNode2> Graph2>
|
||||
{
|
||||
private newtype TPathNode =
|
||||
TPathNode1(PathNode1 p) or
|
||||
TPathNode2(PathNode2 p)
|
||||
|
||||
/** A node in a graph of path explanations that is formed by disjoint union of the two given graphs. */
|
||||
class PathNode extends TPathNode {
|
||||
/** Gets this as a projection on the first given `PathGraph`. */
|
||||
PathNode1 asPathNode1() { this = TPathNode1(result) }
|
||||
|
||||
/** Gets this as a projection on the second given `PathGraph`. */
|
||||
PathNode2 asPathNode2() { this = TPathNode2(result) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() {
|
||||
result = this.asPathNode1().toString() or
|
||||
result = this.asPathNode2().toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.asPathNode1().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) or
|
||||
this.asPathNode2().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
Node getNode() {
|
||||
result = this.asPathNode1().getNode() or
|
||||
result = this.asPathNode2().getNode()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the query predicates needed to include a graph in a path-problem query.
|
||||
*/
|
||||
module PathGraph implements PathGraphSig<PathNode> {
|
||||
/** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
|
||||
query predicate edges(PathNode a, PathNode b) {
|
||||
Graph1::edges(a.asPathNode1(), b.asPathNode1()) or
|
||||
Graph2::edges(a.asPathNode2(), b.asPathNode2())
|
||||
}
|
||||
|
||||
/** Holds if `n` is a node in the graph of data flow path explanations. */
|
||||
query predicate nodes(PathNode n, string key, string val) {
|
||||
Graph1::nodes(n.asPathNode1(), key, val) or
|
||||
Graph2::nodes(n.asPathNode2(), key, val)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
|
||||
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
|
||||
* `ret -> out` is summarized as the edge `arg -> out`.
|
||||
*/
|
||||
query predicate subpaths(PathNode arg, PathNode par, PathNode ret, PathNode out) {
|
||||
Graph1::subpaths(arg.asPathNode1(), par.asPathNode1(), ret.asPathNode1(), out.asPathNode1()) or
|
||||
Graph2::subpaths(arg.asPathNode2(), par.asPathNode2(), ret.asPathNode2(), out.asPathNode2())
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,396 @@
|
||||
/**
|
||||
* DEPRECATED: Use `Make` and `MakeWithState` instead.
|
||||
*
|
||||
* Provides a `Configuration` class backwards-compatible interface to the data
|
||||
* flow library.
|
||||
*/
|
||||
|
||||
private import DataFlowImplCommon
|
||||
private import DataFlowImplSpecific::Private
|
||||
import DataFlowImplSpecific::Public
|
||||
private import DataFlowImpl
|
||||
import DataFlowImplCommonPublic
|
||||
import FlowStateString
|
||||
|
||||
/**
|
||||
* A configuration of interprocedural data flow analysis. This defines
|
||||
* sources, sinks, and any other configurable aspect of the analysis. Each
|
||||
* use of the global data flow 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.
|
||||
* For example, write
|
||||
*
|
||||
* ```ql
|
||||
* class MyAnalysisConfiguration extends DataFlow::Configuration {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
* // Optionally override `isBarrier`.
|
||||
* // Optionally override `isAdditionalFlowStep`.
|
||||
* }
|
||||
* ```
|
||||
* Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and
|
||||
* the edges are those data-flow steps that preserve the value of the node
|
||||
* along with any additional edges defined by `isAdditionalFlowStep`.
|
||||
* Specifying nodes in `isBarrier` will remove those nodes from the graph, and
|
||||
* specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going
|
||||
* and/or out-going edges from those nodes, respectively.
|
||||
*
|
||||
* Then, to query whether there is flow between some `source` and `sink`,
|
||||
* write
|
||||
*
|
||||
* ```ql
|
||||
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
* ```
|
||||
*
|
||||
* Multiple configurations can coexist, but two classes extending
|
||||
* `DataFlow::Configuration` should never depend on each other. One of them
|
||||
* should instead depend on a `DataFlow2::Configuration`, a
|
||||
* `DataFlow3::Configuration`, or a `DataFlow4::Configuration`.
|
||||
*/
|
||||
abstract class Configuration extends string {
|
||||
bindingset[this]
|
||||
Configuration() { any() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source.
|
||||
*/
|
||||
predicate isSource(Node source) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `source` is a relevant data flow source with the given initial
|
||||
* `state`.
|
||||
*/
|
||||
predicate isSource(Node source, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink.
|
||||
*/
|
||||
predicate isSink(Node sink) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a relevant data flow sink accepting `state`.
|
||||
*/
|
||||
predicate isSink(Node sink, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited. This completely removes
|
||||
* `node` from the data flow graph.
|
||||
*/
|
||||
predicate isBarrier(Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isBarrier(Node node, FlowState state) { none() }
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
predicate isBarrierIn(Node node) { none() }
|
||||
|
||||
/** Holds if data flow out of `node` is prohibited. */
|
||||
predicate isBarrierOut(Node node) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited.
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
|
||||
*
|
||||
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||
* the flow state is `state`
|
||||
*/
|
||||
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
* taken at `node`.
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
* value of 0 disables field flow), or a larger value to get more results.
|
||||
*/
|
||||
int fieldFlowBranchLimit() { result = 2 }
|
||||
|
||||
/**
|
||||
* Gets a data flow configuration feature to add restrictions to the set of
|
||||
* valid flow paths.
|
||||
*
|
||||
* - `FeatureHasSourceCallContext`:
|
||||
* Assume that sources have some existing call context to disallow
|
||||
* conflicting return-flow directly following the source.
|
||||
* - `FeatureHasSinkCallContext`:
|
||||
* Assume that sinks have some existing call context to disallow
|
||||
* conflicting argument-to-parameter flow directly preceding the sink.
|
||||
* - `FeatureEqualSourceSinkCallContext`:
|
||||
* Implies both of the above and additionally ensures that the entire flow
|
||||
* path preserves the call context.
|
||||
*
|
||||
* These features are generally not relevant for typical end-to-end data flow
|
||||
* queries, but should only be used for constructing paths that need to
|
||||
* somehow be pluggable in another path context.
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlow(Node source, Node sink) { hasFlow(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may 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`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowTo(Node sink) { hasFlowTo(sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
*/
|
||||
predicate hasFlowToExpr(DataFlowExpr sink) { this.hasFlowTo(exprNode(sink)) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `FlowExploration<explorationLimit>` instead.
|
||||
*
|
||||
* Gets the exploration limit for `hasPartialFlow` and `hasPartialFlowRev`
|
||||
* measured in approximate number of interprocedural steps.
|
||||
*/
|
||||
deprecated int explorationLimit() { none() }
|
||||
|
||||
/**
|
||||
* Holds if hidden nodes should be included in the data flow graph.
|
||||
*
|
||||
* This feature should only be used for debugging or when the data flow graph
|
||||
* is not visualized (for example in a `path-problem` query).
|
||||
*/
|
||||
predicate includeHiddenNodes() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* This class exists to prevent mutual recursion between the user-overridden
|
||||
* member predicates of `Configuration` and the rest of the data-flow library.
|
||||
* Good performance cannot be guaranteed in the presence of such recursion, so
|
||||
* it should be replaced by using more than one copy of the data flow library.
|
||||
*/
|
||||
abstract private class ConfigurationRecursionPrevention extends Configuration {
|
||||
bindingset[this]
|
||||
ConfigurationRecursionPrevention() { any() }
|
||||
|
||||
override predicate hasFlow(Node source, Node sink) {
|
||||
strictcount(Node n | this.isSource(n)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSource(n, _)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSink(n)) < 0
|
||||
or
|
||||
strictcount(Node n | this.isSink(n, _)) < 0
|
||||
or
|
||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, n2)) < 0
|
||||
or
|
||||
strictcount(Node n1, Node n2 | this.isAdditionalFlowStep(n1, _, n2, _)) < 0
|
||||
or
|
||||
super.hasFlow(source, sink)
|
||||
}
|
||||
}
|
||||
|
||||
/** A bridge class to access the deprecated `isBarrierGuard`. */
|
||||
private class BarrierGuardGuardedNodeBridge extends Unit {
|
||||
abstract predicate guardedNode(Node n, Configuration config);
|
||||
|
||||
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
|
||||
}
|
||||
|
||||
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
|
||||
deprecated override predicate guardedNode(Node n, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
|
||||
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
|
||||
exists(BarrierGuard g |
|
||||
config.isBarrierGuard(g, state) and
|
||||
n = g.getAGuardedNode()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private FlowState relevantState(Configuration config) {
|
||||
config.isSource(_, result) or
|
||||
config.isSink(_, result) or
|
||||
config.isBarrier(_, result) or
|
||||
config.isAdditionalFlowStep(_, result, _, _) or
|
||||
config.isAdditionalFlowStep(_, _, _, result)
|
||||
}
|
||||
|
||||
private newtype TConfigState =
|
||||
TMkConfigState(Configuration config, FlowState state) {
|
||||
state = relevantState(config) or state instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
private Configuration getConfig(TConfigState state) { state = TMkConfigState(result, _) }
|
||||
|
||||
private FlowState getState(TConfigState state) { state = TMkConfigState(_, result) }
|
||||
|
||||
private predicate singleConfiguration() { 1 = strictcount(Configuration c) }
|
||||
|
||||
private module Config implements FullStateConfigSig {
|
||||
class FlowState = TConfigState;
|
||||
|
||||
predicate isSource(Node source, FlowState state) {
|
||||
getConfig(state).isSource(source, getState(state))
|
||||
or
|
||||
getConfig(state).isSource(source) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isSink(Node sink, FlowState state) {
|
||||
getConfig(state).isSink(sink, getState(state))
|
||||
or
|
||||
getConfig(state).isSink(sink) and getState(state) instanceof FlowStateEmpty
|
||||
}
|
||||
|
||||
predicate isBarrier(Node node) { none() }
|
||||
|
||||
predicate isBarrier(Node node, FlowState state) {
|
||||
getConfig(state).isBarrier(node, getState(state)) or
|
||||
getConfig(state).isBarrier(node) or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getState(state), getConfig(state)) or
|
||||
any(BarrierGuardGuardedNodeBridge b).guardedNode(node, getConfig(state))
|
||||
}
|
||||
|
||||
predicate isBarrierIn(Node node) { any(Configuration config).isBarrierIn(node) }
|
||||
|
||||
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) {
|
||||
singleConfiguration() and
|
||||
any(Configuration config).isAdditionalFlowStep(node1, node2)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
getConfig(state1).isAdditionalFlowStep(node1, getState(state1), node2, getState(state2)) and
|
||||
getConfig(state2) = getConfig(state1)
|
||||
or
|
||||
not singleConfiguration() and
|
||||
getConfig(state1).isAdditionalFlowStep(node1, node2) and
|
||||
state2 = state1
|
||||
}
|
||||
|
||||
predicate allowImplicitRead(Node node, ContentSet c) {
|
||||
any(Configuration config).allowImplicitRead(node, c)
|
||||
}
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
predicate sourceGrouping(Node source, string sourceGroup) {
|
||||
any(Configuration config).sourceGrouping(source, sourceGroup)
|
||||
}
|
||||
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) {
|
||||
any(Configuration config).sinkGrouping(sink, sinkGroup)
|
||||
}
|
||||
|
||||
predicate includeHiddenNodes() { any(Configuration config).includeHiddenNodes() }
|
||||
}
|
||||
|
||||
private import Impl<Config> as I
|
||||
import I
|
||||
|
||||
/**
|
||||
* A `Node` augmented with a call context (except for sinks), an access path, and a configuration.
|
||||
* Only those `PathNode`s that are reachable from a source, and which can reach a sink, are generated.
|
||||
*/
|
||||
class PathNode instanceof I::PathNode {
|
||||
/** Gets a textual representation of this element. */
|
||||
final string toString() { result = super.toString() }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this element, including a textual
|
||||
* representation of the call context.
|
||||
*/
|
||||
final string toStringWithContext() { result = super.toStringWithContext() }
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
final predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
/** Gets the underlying `Node`. */
|
||||
final Node getNode() { result = super.getNode() }
|
||||
|
||||
/** Gets the `FlowState` of this node. */
|
||||
final FlowState getState() { result = getState(super.getState()) }
|
||||
|
||||
/** Gets the associated configuration. */
|
||||
final Configuration getConfiguration() { result = getConfig(super.getState()) }
|
||||
|
||||
/** Gets a successor of this node, if any. */
|
||||
final PathNode getASuccessor() { result = super.getASuccessor() }
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { super.isSourceGroup(group) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { super.isSinkGroup(group) }
|
||||
}
|
||||
|
||||
private predicate hasFlow(Node source, Node sink, Configuration config) {
|
||||
exists(PathNode source0, PathNode sink0 |
|
||||
hasFlowPath(source0, sink0, config) and
|
||||
source0.getNode() = source and
|
||||
sink0.getNode() = sink
|
||||
)
|
||||
}
|
||||
|
||||
private predicate hasFlowPath(PathNode source, PathNode sink, Configuration config) {
|
||||
hasFlowPath(source, sink) and source.getConfiguration() = config
|
||||
}
|
||||
|
||||
private predicate hasFlowTo(Node sink, Configuration config) { hasFlow(_, sink, config) }
|
||||
|
||||
predicate flowsTo = hasFlow/3;
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -3,15 +3,18 @@ private import DataFlowImplSpecific::Public
|
||||
import Cached
|
||||
|
||||
module DataFlowImplCommonPublic {
|
||||
/** A state value to track during data flow. */
|
||||
class FlowState = string;
|
||||
/** Provides `FlowState = string`. */
|
||||
module FlowStateString {
|
||||
/** A state value to track during data flow. */
|
||||
class FlowState = string;
|
||||
|
||||
/**
|
||||
* The default state, which is used when the state is unspecified for a source
|
||||
* or a sink.
|
||||
*/
|
||||
class FlowStateEmpty extends FlowState {
|
||||
FlowStateEmpty() { this = "" }
|
||||
/**
|
||||
* The default state, which is used when the state is unspecified for a source
|
||||
* or a sink.
|
||||
*/
|
||||
class FlowStateEmpty extends FlowState {
|
||||
FlowStateEmpty() { this = "" }
|
||||
}
|
||||
}
|
||||
|
||||
private newtype TFlowFeature =
|
||||
@@ -179,6 +182,7 @@ private module LambdaFlow {
|
||||
boolean toJump, DataFlowCallOption lastCall
|
||||
) {
|
||||
revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and
|
||||
not expectsContent(node, _) and
|
||||
if castNode(node) or node instanceof ArgNode or node instanceof ReturnNode
|
||||
then compatibleTypes(t, getNodeDataFlowType(node))
|
||||
else any()
|
||||
|
||||
@@ -414,3 +414,12 @@ private class MyConsistencyConfiguration extends Consistency::ConsistencyConfigu
|
||||
any()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* when calculating the (virtual) dispatch cost.
|
||||
*
|
||||
* Argument `arg` is part of a path from a source to a sink, and `p` is the target parameter.
|
||||
*/
|
||||
int getAdditionalFlowIntoCallNodeTerm(ArgumentNode arg, ParameterNode p) { none() }
|
||||
|
||||
@@ -97,23 +97,23 @@ private string getNodeProperty(DataFlow::Node node, string key) {
|
||||
|
|
||||
kind, ", "
|
||||
)
|
||||
or
|
||||
// Is there partial flow from a source to this node?
|
||||
// This property will only be emitted if partial flow is enabled by overriding
|
||||
// `DataFlow::Configuration::explorationLimit()`.
|
||||
key = "pflow" and
|
||||
result =
|
||||
strictconcat(DataFlow::PartialPathNode sourceNode, DataFlow::PartialPathNode destNode, int dist,
|
||||
int order1, int order2 |
|
||||
any(DataFlow::Configuration cfg).hasPartialFlow(sourceNode, destNode, dist) and
|
||||
destNode.getNode() = node and
|
||||
// Only print flow from a source in the same function.
|
||||
sourceNode.getNode().getEnclosingCallable() = node.getEnclosingCallable()
|
||||
|
|
||||
nodeId(sourceNode.getNode(), order1, order2) + "+" + dist.toString(), ", "
|
||||
order by
|
||||
order1, order2, dist desc
|
||||
)
|
||||
// or
|
||||
// // Is there partial flow from a source to this node?
|
||||
// // This property will only be emitted if partial flow is enabled by overriding
|
||||
// // `DataFlow::Configuration::explorationLimit()`.
|
||||
// key = "pflow" and
|
||||
// result =
|
||||
// strictconcat(DataFlow::PartialPathNode sourceNode, DataFlow::PartialPathNode destNode, int dist,
|
||||
// int order1, int order2 |
|
||||
// any(DataFlow::Configuration cfg).hasPartialFlow(sourceNode, destNode, dist) and
|
||||
// destNode.getNode() = node and
|
||||
// // Only print flow from a source in the same function.
|
||||
// sourceNode.getNode().getEnclosingCallable() = node.getEnclosingCallable()
|
||||
// |
|
||||
// nodeId(sourceNode.getNode(), order1, order2) + "+" + dist.toString(), ", "
|
||||
// order by
|
||||
// order1, order2, dist desc
|
||||
// )
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Provides classes for performing local (intra-procedural) and
|
||||
* global (inter-procedural) taint-tracking analyses.
|
||||
*/
|
||||
|
||||
import TaintTrackingParameter::Public
|
||||
private import TaintTrackingParameter::Private
|
||||
|
||||
private module AddTaintDefaults<DataFlowInternal::FullStateConfigSig Config> implements
|
||||
DataFlowInternal::FullStateConfigSig
|
||||
{
|
||||
import Config
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
Config::isBarrier(node) or defaultTaintSanitizer(node)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
Config::isAdditionalFlowStep(node1, node2) or
|
||||
defaultAdditionalTaintStep(node1, node2)
|
||||
}
|
||||
|
||||
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||
Config::allowImplicitRead(node, c)
|
||||
or
|
||||
(
|
||||
Config::isSink(node, _) or
|
||||
Config::isAdditionalFlowStep(node, _) or
|
||||
Config::isAdditionalFlowStep(node, _, _, _)
|
||||
) and
|
||||
defaultImplicitTaintRead(node, c)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a standard taint tracking computation.
|
||||
*/
|
||||
module Make<DataFlow::ConfigSig Config> implements DataFlow::DataFlowSig {
|
||||
private module Config0 implements DataFlowInternal::FullStateConfigSig {
|
||||
import DataFlowInternal::DefaultState<Config>
|
||||
import Config
|
||||
}
|
||||
|
||||
private module C implements DataFlowInternal::FullStateConfigSig {
|
||||
import AddTaintDefaults<Config0>
|
||||
}
|
||||
|
||||
import DataFlowInternal::Impl<C>
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a taint tracking computation using flow state.
|
||||
*/
|
||||
module MakeWithState<DataFlow::StateConfigSig Config> implements DataFlow::DataFlowSig {
|
||||
private module Config0 implements DataFlowInternal::FullStateConfigSig {
|
||||
import Config
|
||||
}
|
||||
|
||||
private module C implements DataFlowInternal::FullStateConfigSig {
|
||||
import AddTaintDefaults<Config0>
|
||||
}
|
||||
|
||||
import DataFlowInternal::Impl<C>
|
||||
}
|
||||
@@ -2,4 +2,5 @@ import semmle.code.cpp.ir.dataflow.internal.TaintTrackingUtil as Public
|
||||
|
||||
module Private {
|
||||
import semmle.code.cpp.ir.dataflow.DataFlow::DataFlow as DataFlow
|
||||
import semmle.code.cpp.ir.dataflow.internal.DataFlowImpl as DataFlowInternal
|
||||
}
|
||||
|
||||
@@ -1082,7 +1082,8 @@ module Opcode {
|
||||
* See the `CallSideEffectInstruction` documentation for more details.
|
||||
*/
|
||||
class CallSideEffect extends WriteSideEffectOpcode, EscapedWriteOpcode, MayWriteOpcode,
|
||||
ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallSideEffect {
|
||||
ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallSideEffect
|
||||
{
|
||||
final override string toString() { result = "CallSideEffect" }
|
||||
}
|
||||
|
||||
@@ -1092,7 +1093,8 @@ module Opcode {
|
||||
* See the `CallReadSideEffectInstruction` documentation for more details.
|
||||
*/
|
||||
class CallReadSideEffect extends ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode,
|
||||
TCallReadSideEffect {
|
||||
TCallReadSideEffect
|
||||
{
|
||||
final override string toString() { result = "CallReadSideEffect" }
|
||||
}
|
||||
|
||||
@@ -1102,7 +1104,8 @@ module Opcode {
|
||||
* See the `IndirectReadSideEffectInstruction` documentation for more details.
|
||||
*/
|
||||
class IndirectReadSideEffect extends ReadSideEffectOpcode, IndirectReadOpcode,
|
||||
TIndirectReadSideEffect {
|
||||
TIndirectReadSideEffect
|
||||
{
|
||||
final override string toString() { result = "IndirectReadSideEffect" }
|
||||
}
|
||||
|
||||
@@ -1112,7 +1115,8 @@ module Opcode {
|
||||
* See the `IndirectMustWriteSideEffectInstruction` documentation for more details.
|
||||
*/
|
||||
class IndirectMustWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode,
|
||||
TIndirectMustWriteSideEffect {
|
||||
TIndirectMustWriteSideEffect
|
||||
{
|
||||
final override string toString() { result = "IndirectMustWriteSideEffect" }
|
||||
}
|
||||
|
||||
@@ -1122,7 +1126,8 @@ module Opcode {
|
||||
* See the `IndirectMayWriteSideEffectInstruction` documentation for more details.
|
||||
*/
|
||||
class IndirectMayWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode,
|
||||
MayWriteOpcode, TIndirectMayWriteSideEffect {
|
||||
MayWriteOpcode, TIndirectMayWriteSideEffect
|
||||
{
|
||||
final override string toString() { result = "IndirectMayWriteSideEffect" }
|
||||
}
|
||||
|
||||
@@ -1132,7 +1137,8 @@ module Opcode {
|
||||
* See the `BufferReadSideEffectInstruction` documentation for more details.
|
||||
*/
|
||||
class BufferReadSideEffect extends ReadSideEffectOpcode, UnsizedBufferReadOpcode,
|
||||
TBufferReadSideEffect {
|
||||
TBufferReadSideEffect
|
||||
{
|
||||
final override string toString() { result = "BufferReadSideEffect" }
|
||||
}
|
||||
|
||||
@@ -1142,7 +1148,8 @@ module Opcode {
|
||||
* See the `BufferMustWriteSideEffectInstruction` documentation for more details.
|
||||
*/
|
||||
class BufferMustWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode,
|
||||
TBufferMustWriteSideEffect {
|
||||
TBufferMustWriteSideEffect
|
||||
{
|
||||
final override string toString() { result = "BufferMustWriteSideEffect" }
|
||||
}
|
||||
|
||||
@@ -1152,7 +1159,8 @@ module Opcode {
|
||||
* See the `BufferMayWriteSideEffectInstruction` documentation for more details.
|
||||
*/
|
||||
class BufferMayWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode,
|
||||
MayWriteOpcode, TBufferMayWriteSideEffect {
|
||||
MayWriteOpcode, TBufferMayWriteSideEffect
|
||||
{
|
||||
final override string toString() { result = "BufferMayWriteSideEffect" }
|
||||
}
|
||||
|
||||
@@ -1162,7 +1170,8 @@ module Opcode {
|
||||
* See the `SizedBufferReadSideEffectInstruction` documentation for more details.
|
||||
*/
|
||||
class SizedBufferReadSideEffect extends ReadSideEffectOpcode, SizedBufferReadOpcode,
|
||||
TSizedBufferReadSideEffect {
|
||||
TSizedBufferReadSideEffect
|
||||
{
|
||||
final override string toString() { result = "SizedBufferReadSideEffect" }
|
||||
}
|
||||
|
||||
@@ -1172,7 +1181,8 @@ module Opcode {
|
||||
* See the `SizedBufferMustWriteSideEffectInstruction` documentation for more details.
|
||||
*/
|
||||
class SizedBufferMustWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode,
|
||||
TSizedBufferMustWriteSideEffect {
|
||||
TSizedBufferMustWriteSideEffect
|
||||
{
|
||||
final override string toString() { result = "SizedBufferMustWriteSideEffect" }
|
||||
}
|
||||
|
||||
@@ -1182,7 +1192,8 @@ module Opcode {
|
||||
* See the `SizedBufferMayWriteSideEffectInstruction` documentation for more details.
|
||||
*/
|
||||
class SizedBufferMayWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode,
|
||||
MayWriteOpcode, TSizedBufferMayWriteSideEffect {
|
||||
MayWriteOpcode, TSizedBufferMayWriteSideEffect
|
||||
{
|
||||
final override string toString() { result = "SizedBufferMayWriteSideEffect" }
|
||||
}
|
||||
|
||||
@@ -1192,7 +1203,8 @@ module Opcode {
|
||||
* See the `InitializeDynamicAllocationInstruction` documentation for more details.
|
||||
*/
|
||||
class InitializeDynamicAllocation extends SideEffectOpcode, EntireAllocationWriteOpcode,
|
||||
TInitializeDynamicAllocation {
|
||||
TInitializeDynamicAllocation
|
||||
{
|
||||
final override string toString() { result = "InitializeDynamicAllocation" }
|
||||
}
|
||||
|
||||
@@ -1221,7 +1233,8 @@ module Opcode {
|
||||
* See the `InlineAsmInstruction` documentation for more details.
|
||||
*/
|
||||
class InlineAsm extends Opcode, EscapedWriteOpcode, MayWriteOpcode, EscapedReadOpcode,
|
||||
MayReadOpcode, TInlineAsm {
|
||||
MayReadOpcode, TInlineAsm
|
||||
{
|
||||
final override string toString() { result = "InlineAsm" }
|
||||
|
||||
final override predicate hasOperandInternal(OperandTag tag) {
|
||||
|
||||
@@ -87,22 +87,6 @@ class Operand extends TStageOperand {
|
||||
this.getDefinitionOverlap() instanceof MustExactlyOverlap
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: renamed to `getUse`.
|
||||
*
|
||||
* Gets the `Instruction` that consumes this operand.
|
||||
*/
|
||||
deprecated final Instruction getUseInstruction() { result = this.getUse() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `getAnyDef` or `getDef`. The exact replacement for this
|
||||
* predicate is `getAnyDef`, but most uses of this predicate should probably
|
||||
* be replaced with `getDef`.
|
||||
*
|
||||
* Gets the `Instruction` whose result is the value of the operand.
|
||||
*/
|
||||
deprecated final Instruction getDefinitionInstruction() { result = this.getAnyDef() }
|
||||
|
||||
/**
|
||||
* Gets the overlap relationship between the operand's definition and its use.
|
||||
*/
|
||||
|
||||
@@ -246,7 +246,8 @@ class VariableMemoryLocation extends TVariableMemoryLocation, AllocationMemoryLo
|
||||
}
|
||||
|
||||
class EntireAllocationMemoryLocation extends TEntireAllocationMemoryLocation,
|
||||
AllocationMemoryLocation {
|
||||
AllocationMemoryLocation
|
||||
{
|
||||
EntireAllocationMemoryLocation() { this = TEntireAllocationMemoryLocation(var, isMayAccess) }
|
||||
|
||||
final override string toStringInternal() { result = var.toString() }
|
||||
|
||||
@@ -87,22 +87,6 @@ class Operand extends TStageOperand {
|
||||
this.getDefinitionOverlap() instanceof MustExactlyOverlap
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: renamed to `getUse`.
|
||||
*
|
||||
* Gets the `Instruction` that consumes this operand.
|
||||
*/
|
||||
deprecated final Instruction getUseInstruction() { result = this.getUse() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `getAnyDef` or `getDef`. The exact replacement for this
|
||||
* predicate is `getAnyDef`, but most uses of this predicate should probably
|
||||
* be replaced with `getDef`.
|
||||
*
|
||||
* Gets the `Instruction` whose result is the value of the operand.
|
||||
*/
|
||||
deprecated final Instruction getDefinitionInstruction() { result = this.getAnyDef() }
|
||||
|
||||
/**
|
||||
* Gets the overlap relationship between the operand's definition and its use.
|
||||
*/
|
||||
|
||||
@@ -511,7 +511,8 @@ abstract class TranslatedArgumentSideEffect extends TranslatedSideEffect {
|
||||
* calls other than constructor calls.
|
||||
*/
|
||||
class TranslatedArgumentExprSideEffect extends TranslatedArgumentSideEffect,
|
||||
TTranslatedArgumentExprSideEffect {
|
||||
TTranslatedArgumentExprSideEffect
|
||||
{
|
||||
Expr arg;
|
||||
|
||||
TranslatedArgumentExprSideEffect() {
|
||||
@@ -546,7 +547,8 @@ class TranslatedArgumentExprSideEffect extends TranslatedArgumentSideEffect,
|
||||
* calls to non-static member functions.
|
||||
*/
|
||||
class TranslatedStructorQualifierSideEffect extends TranslatedArgumentSideEffect,
|
||||
TTranslatedStructorQualifierSideEffect {
|
||||
TTranslatedStructorQualifierSideEffect
|
||||
{
|
||||
TranslatedStructorQualifierSideEffect() {
|
||||
this = TTranslatedStructorQualifierSideEffect(call, sideEffectOpcode) and
|
||||
index = -1
|
||||
|
||||
@@ -34,7 +34,8 @@ abstract class TranslatedCondition extends TranslatedElement {
|
||||
}
|
||||
|
||||
abstract class TranslatedFlexibleCondition extends TranslatedCondition, ConditionContext,
|
||||
TTranslatedFlexibleCondition {
|
||||
TTranslatedFlexibleCondition
|
||||
{
|
||||
TranslatedFlexibleCondition() { this = TTranslatedFlexibleCondition(expr) }
|
||||
|
||||
final override TranslatedElement getChild(int id) { id = 0 and result = getOperand() }
|
||||
|
||||
@@ -75,7 +75,8 @@ abstract class TranslatedLocalVariableDeclaration extends TranslatedVariableInit
|
||||
* The IR translation of a local variable declaration within a declaration statement.
|
||||
*/
|
||||
class TranslatedAutoVariableDeclarationEntry extends TranslatedLocalVariableDeclaration,
|
||||
TranslatedDeclarationEntry {
|
||||
TranslatedDeclarationEntry
|
||||
{
|
||||
StackVariable var;
|
||||
|
||||
TranslatedAutoVariableDeclarationEntry() { var = entry.getDeclaration() }
|
||||
@@ -217,7 +218,8 @@ class TranslatedStaticLocalVariableDeclarationEntry extends TranslatedDeclaratio
|
||||
* with a dynamic initializer.
|
||||
*/
|
||||
class TranslatedStaticLocalVariableInitialization extends TranslatedElement,
|
||||
TranslatedLocalVariableDeclaration, TTranslatedStaticLocalVariableInitialization {
|
||||
TranslatedLocalVariableDeclaration, TTranslatedStaticLocalVariableInitialization
|
||||
{
|
||||
IRVariableDeclarationEntry entry;
|
||||
StaticLocalVariable var;
|
||||
|
||||
|
||||
@@ -131,7 +131,8 @@ abstract class TranslatedCoreExpr extends TranslatedExpr {
|
||||
}
|
||||
|
||||
class TranslatedConditionValue extends TranslatedCoreExpr, ConditionContext,
|
||||
TTranslatedConditionValue {
|
||||
TTranslatedConditionValue
|
||||
{
|
||||
TranslatedConditionValue() { this = TTranslatedConditionValue(expr) }
|
||||
|
||||
override TranslatedElement getChild(int id) { id = 0 and result = this.getCondition() }
|
||||
@@ -326,7 +327,8 @@ class TranslatedLoad extends TranslatedValueCategoryAdjustment, TTranslatedLoad
|
||||
* from the AST.
|
||||
*/
|
||||
class TranslatedSyntheticTemporaryObject extends TranslatedValueCategoryAdjustment,
|
||||
TTranslatedSyntheticTemporaryObject {
|
||||
TTranslatedSyntheticTemporaryObject
|
||||
{
|
||||
TranslatedSyntheticTemporaryObject() { this = TTranslatedSyntheticTemporaryObject(expr) }
|
||||
|
||||
override string toString() { result = "Temporary materialization of " + expr.toString() }
|
||||
@@ -2302,7 +2304,8 @@ class TranslatedBinaryConditionalExpr extends TranslatedConditionalExpr {
|
||||
* its initializer.
|
||||
*/
|
||||
class TranslatedTemporaryObjectExpr extends TranslatedNonConstantExpr,
|
||||
TranslatedVariableInitialization {
|
||||
TranslatedVariableInitialization
|
||||
{
|
||||
override TemporaryObjectExpr expr;
|
||||
|
||||
final override predicate hasTempVariable(TempVariableTag tag, CppType type) {
|
||||
|
||||
@@ -566,7 +566,8 @@ private TranslatedConstructorInitList getTranslatedConstructorInitList(Function
|
||||
* instances for constructors can actually contain initializers.
|
||||
*/
|
||||
class TranslatedConstructorInitList extends TranslatedElement, InitializationContext,
|
||||
TTranslatedConstructorInitList {
|
||||
TTranslatedConstructorInitList
|
||||
{
|
||||
Function func;
|
||||
|
||||
TranslatedConstructorInitList() { this = TTranslatedConstructorInitList(func) }
|
||||
@@ -637,7 +638,8 @@ private TranslatedDestructorDestructionList getTranslatedDestructorDestructionLi
|
||||
* destructions.
|
||||
*/
|
||||
class TranslatedDestructorDestructionList extends TranslatedElement,
|
||||
TTranslatedDestructorDestructionList {
|
||||
TTranslatedDestructorDestructionList
|
||||
{
|
||||
Function func;
|
||||
|
||||
TranslatedDestructorDestructionList() { this = TTranslatedDestructorDestructionList(func) }
|
||||
|
||||
@@ -9,7 +9,8 @@ private import InstructionTag
|
||||
private import semmle.code.cpp.ir.internal.IRUtilities
|
||||
|
||||
class TranslatedGlobalOrNamespaceVarInit extends TranslatedRootElement,
|
||||
TTranslatedGlobalOrNamespaceVarInit, InitializationContext {
|
||||
TTranslatedGlobalOrNamespaceVarInit, InitializationContext
|
||||
{
|
||||
GlobalOrNamespaceVariable var;
|
||||
|
||||
TranslatedGlobalOrNamespaceVarInit() { this = TTranslatedGlobalOrNamespaceVarInit(var) }
|
||||
|
||||
@@ -440,7 +440,8 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati
|
||||
}
|
||||
|
||||
class TranslatedConstructorInitialization extends TranslatedDirectInitialization,
|
||||
StructorCallContext {
|
||||
StructorCallContext
|
||||
{
|
||||
override ConstructorCall expr;
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
@@ -528,7 +529,8 @@ abstract class TranslatedFieldInitialization extends TranslatedElement {
|
||||
* explicit element in an initializer list.
|
||||
*/
|
||||
class TranslatedExplicitFieldInitialization extends TranslatedFieldInitialization,
|
||||
InitializationContext, TTranslatedExplicitFieldInitialization {
|
||||
InitializationContext, TTranslatedExplicitFieldInitialization
|
||||
{
|
||||
Expr expr;
|
||||
|
||||
TranslatedExplicitFieldInitialization() {
|
||||
@@ -565,7 +567,8 @@ private string getZeroValue(Type type) {
|
||||
* corresponding element in the initializer list.
|
||||
*/
|
||||
class TranslatedFieldValueInitialization extends TranslatedFieldInitialization,
|
||||
TTranslatedFieldValueInitialization {
|
||||
TTranslatedFieldValueInitialization
|
||||
{
|
||||
TranslatedFieldValueInitialization() { this = TTranslatedFieldValueInitialization(ast, field) }
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
@@ -700,7 +703,8 @@ abstract class TranslatedElementInitialization extends TranslatedElement {
|
||||
* an explicit element in an initializer list.
|
||||
*/
|
||||
class TranslatedExplicitElementInitialization extends TranslatedElementInitialization,
|
||||
TTranslatedExplicitElementInitialization, InitializationContext {
|
||||
TTranslatedExplicitElementInitialization, InitializationContext
|
||||
{
|
||||
int elementIndex;
|
||||
|
||||
TranslatedExplicitElementInitialization() {
|
||||
@@ -737,7 +741,8 @@ class TranslatedExplicitElementInitialization extends TranslatedElementInitializ
|
||||
* elements without corresponding elements in the initializer list.
|
||||
*/
|
||||
class TranslatedElementValueInitialization extends TranslatedElementInitialization,
|
||||
TTranslatedElementValueInitialization {
|
||||
TTranslatedElementValueInitialization
|
||||
{
|
||||
int elementIndex;
|
||||
int elementCount;
|
||||
|
||||
@@ -881,7 +886,8 @@ abstract class TranslatedBaseStructorCall extends TranslatedStructorCallFromStru
|
||||
* Represents a call to a delegating or base class constructor from within a constructor.
|
||||
*/
|
||||
abstract class TranslatedConstructorCallFromConstructor extends TranslatedStructorCallFromStructor,
|
||||
TTranslatedConstructorBaseInit {
|
||||
TTranslatedConstructorBaseInit
|
||||
{
|
||||
TranslatedConstructorCallFromConstructor() { this = TTranslatedConstructorBaseInit(call) }
|
||||
}
|
||||
|
||||
@@ -917,7 +923,8 @@ class TranslatedConstructorDelegationInit extends TranslatedConstructorCallFromC
|
||||
* derived class constructor
|
||||
*/
|
||||
class TranslatedConstructorBaseInit extends TranslatedConstructorCallFromConstructor,
|
||||
TranslatedBaseStructorCall {
|
||||
TranslatedBaseStructorCall
|
||||
{
|
||||
TranslatedConstructorBaseInit() { not call instanceof ConstructorDelegationInit }
|
||||
|
||||
final override string toString() { result = "construct base: " + call.toString() }
|
||||
@@ -934,7 +941,8 @@ TranslatedDestructorBaseDestruction getTranslatedDestructorBaseDestruction(
|
||||
* derived class destructor.
|
||||
*/
|
||||
class TranslatedDestructorBaseDestruction extends TranslatedBaseStructorCall,
|
||||
TTranslatedDestructorBaseDestruction {
|
||||
TTranslatedDestructorBaseDestruction
|
||||
{
|
||||
TranslatedDestructorBaseDestruction() { this = TTranslatedDestructorBaseDestruction(call) }
|
||||
|
||||
final override string toString() { result = "destroy base: " + call.toString() }
|
||||
|
||||
@@ -20,7 +20,8 @@ TranslatedMicrosoftTryExceptHandler getTranslatedMicrosoftTryExceptHandler(
|
||||
}
|
||||
|
||||
class TranslatedMicrosoftTryExceptHandler extends TranslatedElement,
|
||||
TTranslatedMicrosoftTryExceptHandler {
|
||||
TTranslatedMicrosoftTryExceptHandler
|
||||
{
|
||||
MicrosoftTryExceptStmt tryExcept;
|
||||
|
||||
TranslatedMicrosoftTryExceptHandler() { this = TTranslatedMicrosoftTryExceptHandler(tryExcept) }
|
||||
|
||||
@@ -87,22 +87,6 @@ class Operand extends TStageOperand {
|
||||
this.getDefinitionOverlap() instanceof MustExactlyOverlap
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: renamed to `getUse`.
|
||||
*
|
||||
* Gets the `Instruction` that consumes this operand.
|
||||
*/
|
||||
deprecated final Instruction getUseInstruction() { result = this.getUse() }
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `getAnyDef` or `getDef`. The exact replacement for this
|
||||
* predicate is `getAnyDef`, but most uses of this predicate should probably
|
||||
* be replaced with `getDef`.
|
||||
*
|
||||
* Gets the `Instruction` whose result is the value of the operand.
|
||||
*/
|
||||
deprecated final Instruction getDefinitionInstruction() { result = this.getAnyDef() }
|
||||
|
||||
/**
|
||||
* Gets the overlap relationship between the operand's definition and its use.
|
||||
*/
|
||||
|
||||
@@ -389,7 +389,8 @@ private class NewArrayAllocationExpr extends AllocationExpr, NewArrayExpr {
|
||||
|
||||
private module HeuristicAllocation {
|
||||
/** A class that maps an `AllocationExpr` to an `HeuristicAllocationExpr`. */
|
||||
private class HeuristicAllocationModeled extends HeuristicAllocationExpr instanceof AllocationExpr {
|
||||
private class HeuristicAllocationModeled extends HeuristicAllocationExpr instanceof AllocationExpr
|
||||
{
|
||||
override Expr getSizeExpr() { result = AllocationExpr.super.getSizeExpr() }
|
||||
|
||||
override int getSizeMult() { result = AllocationExpr.super.getSizeMult() }
|
||||
@@ -406,7 +407,8 @@ private module HeuristicAllocation {
|
||||
}
|
||||
|
||||
/** A class that maps an `AllocationFunction` to an `HeuristicAllocationFunction`. */
|
||||
private class HeuristicAllocationFunctionModeled extends HeuristicAllocationFunction instanceof AllocationFunction {
|
||||
private class HeuristicAllocationFunctionModeled extends HeuristicAllocationFunction instanceof AllocationFunction
|
||||
{
|
||||
override int getSizeArg() { result = AllocationFunction.super.getSizeArg() }
|
||||
|
||||
override int getSizeMult() { result = AllocationFunction.super.getSizeMult() }
|
||||
@@ -430,7 +432,8 @@ private module HeuristicAllocation {
|
||||
* 2. The function must return a pointer type
|
||||
* 3. There must be a unique parameter of unsigned integral type.
|
||||
*/
|
||||
private class HeuristicAllocationFunctionByName extends HeuristicAllocationFunction instanceof Function {
|
||||
private class HeuristicAllocationFunctionByName extends HeuristicAllocationFunction instanceof Function
|
||||
{
|
||||
int sizeArg;
|
||||
|
||||
HeuristicAllocationFunctionByName() {
|
||||
|
||||
@@ -7,7 +7,8 @@ import semmle.code.cpp.models.interfaces.FlowSource
|
||||
* The standard functions `getdelim`, `getwdelim` and the glibc variant `__getdelim`.
|
||||
*/
|
||||
private class GetDelimFunction extends TaintFunction, AliasFunction, SideEffectFunction,
|
||||
RemoteFlowSourceFunction {
|
||||
RemoteFlowSourceFunction
|
||||
{
|
||||
GetDelimFunction() { this.hasGlobalName(["getdelim", "getwdelim", "__getdelim"]) }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput i, FunctionOutput o) {
|
||||
|
||||
@@ -14,7 +14,8 @@ import semmle.code.cpp.models.interfaces.FlowSource
|
||||
* The standard functions `fgets` and `fgetws`.
|
||||
*/
|
||||
private class FgetsFunction extends DataFlowFunction, TaintFunction, ArrayFunction, AliasFunction,
|
||||
SideEffectFunction, RemoteFlowSourceFunction {
|
||||
SideEffectFunction, RemoteFlowSourceFunction
|
||||
{
|
||||
FgetsFunction() {
|
||||
// fgets(str, num, stream)
|
||||
// fgetws(wstr, num, stream)
|
||||
@@ -69,7 +70,8 @@ private class FgetsFunction extends DataFlowFunction, TaintFunction, ArrayFuncti
|
||||
* The standard functions `gets`.
|
||||
*/
|
||||
private class GetsFunction extends DataFlowFunction, ArrayFunction, AliasFunction,
|
||||
SideEffectFunction, LocalFlowSourceFunction {
|
||||
SideEffectFunction, LocalFlowSourceFunction
|
||||
{
|
||||
GetsFunction() {
|
||||
// gets(str)
|
||||
this.hasGlobalOrStdOrBslName("gets")
|
||||
|
||||
@@ -7,7 +7,8 @@ import semmle.code.cpp.models.interfaces.SideEffect
|
||||
* The standard function templates `std::move` and `std::forward`.
|
||||
*/
|
||||
private class IdentityFunction extends DataFlowFunction, SideEffectFunction, AliasFunction,
|
||||
FunctionTemplateInstantiation {
|
||||
FunctionTemplateInstantiation
|
||||
{
|
||||
IdentityFunction() { this.hasQualifiedName("std", ["move", "forward"]) }
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
@@ -121,7 +121,8 @@ class IteratorCrementNonMemberOperator extends Operator {
|
||||
}
|
||||
|
||||
private class IteratorCrementNonMemberOperatorModel extends IteratorCrementNonMemberOperator,
|
||||
DataFlowFunction {
|
||||
DataFlowFunction
|
||||
{
|
||||
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
|
||||
input = getIteratorArgumentInput(this, 0) and
|
||||
output.isReturnValue()
|
||||
@@ -143,7 +144,8 @@ class IteratorCrementMemberOperator extends MemberFunction {
|
||||
}
|
||||
|
||||
private class IteratorCrementMemberOperatorModel extends IteratorCrementMemberOperator,
|
||||
DataFlowFunction, TaintFunction {
|
||||
DataFlowFunction, TaintFunction
|
||||
{
|
||||
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierAddress() and
|
||||
output.isReturnValue()
|
||||
@@ -204,7 +206,8 @@ class IteratorBinaryArithmeticMemberOperator extends MemberFunction {
|
||||
}
|
||||
|
||||
private class IteratorBinaryArithmeticMemberOperatorModel extends IteratorBinaryArithmeticMemberOperator,
|
||||
TaintFunction {
|
||||
TaintFunction
|
||||
{
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValue()
|
||||
@@ -258,7 +261,8 @@ class IteratorAssignArithmeticNonMemberOperator extends Operator {
|
||||
}
|
||||
|
||||
private class IteratorAssignArithmeticNonMemberOperatorModel extends IteratorAssignArithmeticNonMemberOperator,
|
||||
DataFlowFunction, TaintFunction {
|
||||
DataFlowFunction, TaintFunction
|
||||
{
|
||||
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isParameter(0) and
|
||||
output.isReturnValue()
|
||||
@@ -289,7 +293,8 @@ class IteratorAssignArithmeticMemberOperator extends MemberFunction {
|
||||
}
|
||||
|
||||
private class IteratorAssignArithmeticMemberOperatorModel extends IteratorAssignArithmeticMemberOperator,
|
||||
DataFlowFunction, TaintFunction {
|
||||
DataFlowFunction, TaintFunction
|
||||
{
|
||||
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierAddress() and
|
||||
output.isReturnValue()
|
||||
@@ -325,7 +330,8 @@ class IteratorAssignArithmeticOperator extends Function {
|
||||
* non-member and member versions, use `IteratorPointerDereferenceOperator`.
|
||||
*/
|
||||
class IteratorPointerDereferenceMemberOperator extends MemberFunction, TaintFunction,
|
||||
IteratorReferenceFunction {
|
||||
IteratorReferenceFunction
|
||||
{
|
||||
IteratorPointerDereferenceMemberOperator() {
|
||||
this.getClassAndName("operator*") instanceof Iterator
|
||||
}
|
||||
@@ -353,7 +359,8 @@ class IteratorPointerDereferenceNonMemberOperator extends Operator, IteratorRefe
|
||||
}
|
||||
|
||||
private class IteratorPointerDereferenceNonMemberOperatorModel extends IteratorPointerDereferenceNonMemberOperator,
|
||||
TaintFunction {
|
||||
TaintFunction
|
||||
{
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input = getIteratorArgumentInput(this, 0) and
|
||||
output.isReturnValue()
|
||||
@@ -389,7 +396,8 @@ private class IteratorFieldMemberOperator extends Operator, TaintFunction {
|
||||
* An `operator[]` member function of an iterator class.
|
||||
*/
|
||||
private class IteratorArrayMemberOperator extends MemberFunction, TaintFunction,
|
||||
IteratorReferenceFunction {
|
||||
IteratorReferenceFunction
|
||||
{
|
||||
IteratorArrayMemberOperator() { this.getClassAndName("operator[]") instanceof Iterator }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -418,7 +426,8 @@ class IteratorAssignmentMemberOperator extends MemberFunction {
|
||||
* `operator*` and use their own `operator=` to assign to the container.
|
||||
*/
|
||||
private class IteratorAssignmentMemberOperatorModel extends IteratorAssignmentMemberOperator,
|
||||
TaintFunction {
|
||||
TaintFunction
|
||||
{
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isParameterDeref(0) and
|
||||
output.isQualifierObject()
|
||||
|
||||
@@ -15,7 +15,8 @@ import semmle.code.cpp.models.interfaces.Taint
|
||||
* `__builtin___memcpy_chk`.
|
||||
*/
|
||||
private class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffectFunction,
|
||||
AliasFunction {
|
||||
AliasFunction
|
||||
{
|
||||
MemcpyFunction() {
|
||||
// memcpy(dest, src, num)
|
||||
// memmove(dest, src, num)
|
||||
|
||||
@@ -13,7 +13,8 @@ import semmle.code.cpp.models.interfaces.SideEffect
|
||||
* The standard function `memset` and its assorted variants
|
||||
*/
|
||||
private class MemsetFunction extends ArrayFunction, DataFlowFunction, AliasFunction,
|
||||
SideEffectFunction {
|
||||
SideEffectFunction
|
||||
{
|
||||
MemsetFunction() {
|
||||
this.hasGlobalOrStdOrBslName("memset")
|
||||
or
|
||||
|
||||
@@ -8,7 +8,8 @@ import semmle.code.cpp.models.interfaces.SideEffect
|
||||
* guaranteed to be side-effect free.
|
||||
*/
|
||||
private class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunction,
|
||||
SideEffectFunction {
|
||||
SideEffectFunction
|
||||
{
|
||||
PureStrFunction() {
|
||||
this.hasGlobalOrStdOrBslName([
|
||||
atoi(), "strcasestr", "strchnul", "strchr", "strchrnul", "strstr", "strpbrk", "strrchr",
|
||||
@@ -153,7 +154,8 @@ private class PureFunction extends TaintFunction, SideEffectFunction {
|
||||
* evaluation is guaranteed to be side-effect free.
|
||||
*/
|
||||
private class PureMemFunction extends AliasFunction, ArrayFunction, TaintFunction,
|
||||
SideEffectFunction {
|
||||
SideEffectFunction
|
||||
{
|
||||
PureMemFunction() {
|
||||
this.hasGlobalOrStdOrBslName([
|
||||
"memchr", "__builtin_memchr", "memrchr", "rawmemchr", "memcmp", "__builtin_memcmp", "memmem"
|
||||
|
||||
@@ -11,7 +11,8 @@ import semmle.code.cpp.models.interfaces.SideEffect
|
||||
|
||||
/** The function `recv` and its assorted variants */
|
||||
private class Recv extends AliasFunction, ArrayFunction, SideEffectFunction,
|
||||
RemoteFlowSourceFunction {
|
||||
RemoteFlowSourceFunction
|
||||
{
|
||||
Recv() {
|
||||
this.hasGlobalName([
|
||||
"recv", // recv(socket, dest, len, flags)
|
||||
|
||||
@@ -15,7 +15,8 @@ import semmle.code.cpp.models.interfaces.FlowSource
|
||||
* The `scanf` family of functions.
|
||||
*/
|
||||
abstract private class ScanfFunctionModel extends ArrayFunction, TaintFunction, AliasFunction,
|
||||
SideEffectFunction {
|
||||
SideEffectFunction
|
||||
{
|
||||
override predicate hasArrayWithNullTerminator(int bufParam) {
|
||||
bufParam = this.(ScanfFunction).getFormatParameterIndex()
|
||||
}
|
||||
|
||||
@@ -29,7 +29,8 @@ private class SmartPtr extends Class, PointerWrapper {
|
||||
* - `std::weak_ptr<T>::operator*()`
|
||||
*/
|
||||
private class PointerUnwrapperFunction extends MemberFunction, TaintFunction, DataFlowFunction,
|
||||
SideEffectFunction, AliasFunction {
|
||||
SideEffectFunction, AliasFunction
|
||||
{
|
||||
PointerUnwrapperFunction() {
|
||||
exists(PointerWrapper wrapper | wrapper.getAnUnwrapperFunction() = this)
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@ import semmle.code.cpp.models.interfaces.SideEffect
|
||||
* The standard function `strset` and its assorted variants
|
||||
*/
|
||||
private class StrsetFunction extends ArrayFunction, DataFlowFunction, AliasFunction,
|
||||
SideEffectFunction {
|
||||
SideEffectFunction
|
||||
{
|
||||
StrsetFunction() {
|
||||
hasGlobalName([
|
||||
"strset", "_strset", "_strset_l", "_wcsset", "_wcsset_l", "_mbsset", "_mbsset_l",
|
||||
|
||||
@@ -7,7 +7,8 @@ import semmle.code.cpp.models.interfaces.CommandExecution
|
||||
* A function for running a command using a command interpreter.
|
||||
*/
|
||||
private class SystemFunction extends CommandExecutionFunction, ArrayFunction, AliasFunction,
|
||||
SideEffectFunction {
|
||||
SideEffectFunction
|
||||
{
|
||||
SystemFunction() {
|
||||
hasGlobalOrStdName("system") or // system(command)
|
||||
hasGlobalName("popen") or // popen(command, mode)
|
||||
|
||||
@@ -40,12 +40,6 @@ class FunctionInput extends TFunctionInput {
|
||||
*/
|
||||
predicate isParameter(ParameterIndex index) { none() }
|
||||
|
||||
/**
|
||||
* Holds if this is the input value of the parameter with index `index`.
|
||||
* DEPRECATED: Use `isParameter(index)` instead.
|
||||
*/
|
||||
deprecated final predicate isInParameter(ParameterIndex index) { this.isParameter(index) }
|
||||
|
||||
/**
|
||||
* Holds if this is the input value pointed to (through `ind` number of indirections) by a
|
||||
* pointer parameter to a function, or the input value referred to by a reference parameter
|
||||
@@ -84,16 +78,6 @@ class FunctionInput extends TFunctionInput {
|
||||
*/
|
||||
predicate isParameterDeref(ParameterIndex index) { this.isParameterDeref(index, 1) }
|
||||
|
||||
/**
|
||||
* Holds if this is the input value pointed to by a pointer parameter to a function, or the input
|
||||
* value referred to by a reference parameter to a function, where the parameter has index
|
||||
* `index`.
|
||||
* DEPRECATED: Use `isParameterDeref(index)` instead.
|
||||
*/
|
||||
deprecated final predicate isInParameterPointer(ParameterIndex index) {
|
||||
this.isParameterDeref(index)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this is the input value pointed to by the `this` pointer of an instance member
|
||||
* function.
|
||||
@@ -124,13 +108,6 @@ class FunctionInput extends TFunctionInput {
|
||||
*/
|
||||
predicate isQualifierObject() { this.isQualifierObject(1) }
|
||||
|
||||
/**
|
||||
* Holds if this is the input value pointed to by the `this` pointer of an instance member
|
||||
* function.
|
||||
* DEPRECATED: Use `isQualifierObject()` instead.
|
||||
*/
|
||||
deprecated final predicate isInQualifier() { this.isQualifierObject() }
|
||||
|
||||
/**
|
||||
* Holds if this is the input value of the `this` pointer of an instance member function.
|
||||
*
|
||||
@@ -396,16 +373,6 @@ class FunctionOutput extends TFunctionOutput {
|
||||
*/
|
||||
predicate isParameterDeref(ParameterIndex i, int ind) { ind = 1 and this.isParameterDeref(i) }
|
||||
|
||||
/**
|
||||
* Holds if this is the output value pointed to by a pointer parameter to a function, or the
|
||||
* output value referred to by a reference parameter to a function, where the parameter has
|
||||
* index `index`.
|
||||
* DEPRECATED: Use `isParameterDeref(index)` instead.
|
||||
*/
|
||||
deprecated final predicate isOutParameterPointer(ParameterIndex index) {
|
||||
this.isParameterDeref(index)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this is the output value pointed to by the `this` pointer of an instance member
|
||||
* function.
|
||||
@@ -436,13 +403,6 @@ class FunctionOutput extends TFunctionOutput {
|
||||
*/
|
||||
predicate isQualifierObject(int ind) { ind = 1 and this.isQualifierObject() }
|
||||
|
||||
/**
|
||||
* Holds if this is the output value pointed to by the `this` pointer of an instance member
|
||||
* function.
|
||||
* DEPRECATED: Use `isQualifierObject()` instead.
|
||||
*/
|
||||
deprecated final predicate isOutQualifier() { this.isQualifierObject() }
|
||||
|
||||
/**
|
||||
* Holds if this is the value returned by a function.
|
||||
*
|
||||
@@ -462,12 +422,6 @@ class FunctionOutput extends TFunctionOutput {
|
||||
*/
|
||||
predicate isReturnValue() { none() }
|
||||
|
||||
/**
|
||||
* Holds if this is the value returned by a function.
|
||||
* DEPRECATED: Use `isReturnValue()` instead.
|
||||
*/
|
||||
deprecated final predicate isOutReturnValue() { this.isReturnValue() }
|
||||
|
||||
/**
|
||||
* Holds if this is the output value pointed to by the return value of a function, if the function
|
||||
* returns a pointer, or the output value referred to by the return value of a function, if the
|
||||
@@ -508,14 +462,6 @@ class FunctionOutput extends TFunctionOutput {
|
||||
*/
|
||||
predicate isReturnValueDeref(int ind) { ind = 1 and this.isReturnValueDeref() }
|
||||
|
||||
/**
|
||||
* Holds if this is the output value pointed to by the return value of a function, if the function
|
||||
* returns a pointer, or the output value referred to by the return value of a function, if the
|
||||
* function returns a reference.
|
||||
* DEPRECATED: Use `isReturnValueDeref()` instead.
|
||||
*/
|
||||
deprecated final predicate isOutReturnPointer() { this.isReturnValueDeref() }
|
||||
|
||||
/**
|
||||
* Holds if `i >= 0` and `isParameterDeref(i, ind)` holds for this is the value, or
|
||||
* if `i = -1` and `isQualifierObject(ind)` holds for this value.
|
||||
|
||||
@@ -96,15 +96,6 @@ class RangeSsaDefinition extends ControlFlowNodeBase {
|
||||
/** Whether this definition is a phi node for variable `v`. */
|
||||
predicate isPhiNode(StackVariable v) { exists(RangeSsa x | x.phi_node(v, this)) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use isGuardPhi/4 instead
|
||||
* If this definition is a phi node corresponding to a guard,
|
||||
* then return the variable access and the guard.
|
||||
*/
|
||||
deprecated predicate isGuardPhi(VariableAccess va, Expr guard, boolean branch) {
|
||||
guard_defn(va, guard, this, branch)
|
||||
}
|
||||
|
||||
/**
|
||||
* If this definition is a phi node corresponding to a guard,
|
||||
* then return the variable guarded, the variable access and the guard.
|
||||
|
||||
@@ -591,7 +591,8 @@ deprecated library class DataSensitiveExprCall extends DataSensitiveCallExpr, Ex
|
||||
|
||||
/** Call to a virtual function. */
|
||||
deprecated library class DataSensitiveOverriddenFunctionCall extends DataSensitiveCallExpr,
|
||||
FunctionCall {
|
||||
FunctionCall
|
||||
{
|
||||
DataSensitiveOverriddenFunctionCall() {
|
||||
exists(getTarget().(VirtualFunction).getAnOverridingFunction())
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||
import semmle.code.cpp.ir.dataflow.TaintTracking2
|
||||
import semmle.code.cpp.security.FlowSources
|
||||
import semmle.code.cpp.models.implementations.Strcat
|
||||
import DataFlow::PathGraph
|
||||
import ExecTaint::PathGraph
|
||||
|
||||
Expr sinkAsArgumentIndirection(DataFlow::Node sink) {
|
||||
result =
|
||||
@@ -67,28 +67,28 @@ predicate interestingConcatenation(DataFlow::Node fst, DataFlow::Node snd) {
|
||||
)
|
||||
}
|
||||
|
||||
class ConcatState extends DataFlow::FlowState {
|
||||
ConcatState() { this = "ConcatState" }
|
||||
newtype TState =
|
||||
TConcatState() or
|
||||
TExecState(DataFlow::Node fst, DataFlow::Node snd) { interestingConcatenation(fst, snd) }
|
||||
|
||||
class ConcatState extends TConcatState {
|
||||
string toString() { result = "ConcatState" }
|
||||
}
|
||||
|
||||
class ExecState extends DataFlow::FlowState {
|
||||
class ExecState extends TExecState {
|
||||
DataFlow::Node fst;
|
||||
DataFlow::Node snd;
|
||||
|
||||
ExecState() {
|
||||
this =
|
||||
"ExecState (" + fst.getLocation() + " | " + fst + ", " + snd.getLocation() + " | " + snd + ")" and
|
||||
interestingConcatenation(pragma[only_bind_into](fst), pragma[only_bind_into](snd))
|
||||
}
|
||||
ExecState() { this = TExecState(fst, snd) }
|
||||
|
||||
DataFlow::Node getFstNode() { result = fst }
|
||||
|
||||
DataFlow::Node getSndNode() { result = snd }
|
||||
|
||||
/** Holds if this is a possible `ExecState` for `sink`. */
|
||||
predicate isFeasibleForSink(DataFlow::Node sink) {
|
||||
any(ExecStateConfiguration conf).hasFlow(snd, sink)
|
||||
}
|
||||
predicate isFeasibleForSink(DataFlow::Node sink) { ExecState::hasFlow(snd, sink) }
|
||||
|
||||
string toString() { result = "ExecState" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,45 +96,42 @@ class ExecState extends DataFlow::FlowState {
|
||||
* given sink. This avoids a cartesian product between all sinks and all `ExecState`s in
|
||||
* `ExecTaintConfiguration::isSink`.
|
||||
*/
|
||||
class ExecStateConfiguration extends TaintTracking2::Configuration {
|
||||
ExecStateConfiguration() { this = "ExecStateConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
module ExecStateConfiguration implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(ExecState state | state.getSndNode() = source)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
shellCommand(sinkAsArgumentIndirection(sink), _)
|
||||
}
|
||||
predicate isSink(DataFlow::Node sink) { shellCommand(sinkAsArgumentIndirection(sink), _) }
|
||||
|
||||
override predicate isSanitizerOut(DataFlow::Node node) {
|
||||
isSink(node, _) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
|
||||
predicate isBarrierOut(DataFlow::Node node) {
|
||||
isSink(node) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
|
||||
}
|
||||
}
|
||||
|
||||
class ExecTaintConfiguration extends TaintTracking::Configuration {
|
||||
ExecTaintConfiguration() { this = "ExecTaintConfiguration" }
|
||||
module ExecState = TaintTracking::Make<ExecStateConfiguration>;
|
||||
|
||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
|
||||
module ExecTaintConfiguration implements DataFlow::StateConfigSig {
|
||||
class FlowState = TState;
|
||||
|
||||
predicate isSource(DataFlow::Node source, FlowState state) {
|
||||
source instanceof FlowSource and
|
||||
state instanceof ConcatState
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
|
||||
any(ExecStateConfiguration conf).isSink(sink) and
|
||||
predicate isSink(DataFlow::Node sink, FlowState state) {
|
||||
ExecStateConfiguration::isSink(sink) and
|
||||
state.(ExecState).isFeasibleForSink(sink)
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
|
||||
) {
|
||||
state1 instanceof ConcatState and
|
||||
state2.(ExecState).getFstNode() = node1 and
|
||||
state2.(ExecState).getSndNode() = node2
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) {
|
||||
predicate isBarrier(DataFlow::Node node, FlowState state) {
|
||||
(
|
||||
node.asInstruction().getResultType() instanceof IntegralType
|
||||
or
|
||||
@@ -143,16 +140,18 @@ class ExecTaintConfiguration extends TaintTracking::Configuration {
|
||||
state instanceof ConcatState
|
||||
}
|
||||
|
||||
override predicate isSanitizerOut(DataFlow::Node node) {
|
||||
predicate isBarrierOut(DataFlow::Node node) {
|
||||
isSink(node, _) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
|
||||
}
|
||||
}
|
||||
|
||||
module ExecTaint = TaintTracking::MakeWithState<ExecTaintConfiguration>;
|
||||
|
||||
from
|
||||
ExecTaintConfiguration conf, DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode,
|
||||
string taintCause, string callChain, DataFlow::Node concatResult
|
||||
ExecTaint::PathNode sourceNode, ExecTaint::PathNode sinkNode, string taintCause, string callChain,
|
||||
DataFlow::Node concatResult
|
||||
where
|
||||
conf.hasFlowPath(sourceNode, sinkNode) and
|
||||
ExecTaint::hasFlowPath(sourceNode, sinkNode) and
|
||||
taintCause = sourceNode.getNode().(FlowSource).getSourceType() and
|
||||
shellCommand(sinkAsArgumentIndirection(sinkNode.getNode()), callChain) and
|
||||
concatResult = sinkNode.getState().(ExecState).getSndNode()
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
int write_default_config_bad() {
|
||||
void write_default_config_bad() {
|
||||
// BAD - this is world-writable so any user can overwrite the config
|
||||
FILE* out = creat(OUTFILE, 0666);
|
||||
fprintf(out, DEFAULT_CONFIG);
|
||||
int out = creat(OUTFILE, 0666);
|
||||
dprintf(out, DEFAULT_CONFIG);
|
||||
}
|
||||
|
||||
int write_default_config_good() {
|
||||
void write_default_config_good() {
|
||||
// GOOD - this allows only the current user to modify the file
|
||||
FILE* out = creat(OUTFILE, S_IWUSR | S_IRUSR);
|
||||
fprintf(out, DEFAULT_CONFIG);
|
||||
int out = creat(OUTFILE, S_IWUSR | S_IRUSR);
|
||||
dprintf(out, DEFAULT_CONFIG);
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ import cpp
|
||||
|
||||
from FunctionCall fc, FunctionCall fc2, LocalScopeVariable v
|
||||
where
|
||||
freeCall(fc, v.getAnAccess()) and
|
||||
freeCall(fc2, v.getAnAccess()) and
|
||||
fc.(DeallocationExpr).getFreedExpr() = v.getAnAccess() and
|
||||
fc2.(DeallocationExpr).getFreedExpr() = v.getAnAccess() and
|
||||
fc != fc2 and
|
||||
fc.getASuccessor*() = fc2 and
|
||||
not exists(Expr exptmp |
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 0.5.4
|
||||
version: 0.5.5-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
| CPP-205.cpp:0:0:0:0 | CPP-205.cpp | |
|
||||
| CPP-205.cpp:1:20:1:20 | T | |
|
||||
| CPP-205.cpp:1:20:1:20 | definition of T | |
|
||||
| CPP-205.cpp:2:5:2:5 | definition of fn | function declaration entry for fn<int>(int) -> int |
|
||||
| CPP-205.cpp:2:5:2:5 | fn | function fn<int>(int) -> int |
|
||||
| CPP-205.cpp:2:5:2:6 | definition of fn | function declaration entry for fn<T>(T) -> int |
|
||||
| CPP-205.cpp:2:5:2:6 | fn | function fn<T>(T) -> int |
|
||||
| CPP-205.cpp:2:10:2:12 | definition of out | parameter declaration entry for fn<T>(T) -> int |
|
||||
| CPP-205.cpp:2:10:2:12 | definition of out | parameter declaration entry for fn<int>(int) -> int |
|
||||
| CPP-205.cpp:2:10:2:12 | out | parameter for fn<T>(T) -> int |
|
||||
| CPP-205.cpp:2:10:2:12 | out | parameter for fn<int>(int) -> int |
|
||||
| CPP-205.cpp:2:5:2:5 | definition of fn | function declaration entry for int fn<int>(int) |
|
||||
| CPP-205.cpp:2:5:2:5 | fn | function int fn<int>(int) |
|
||||
| CPP-205.cpp:2:5:2:6 | definition of fn | function declaration entry for int fn<T>(T) |
|
||||
| CPP-205.cpp:2:5:2:6 | fn | function int fn<T>(T) |
|
||||
| CPP-205.cpp:2:10:2:12 | definition of out | parameter declaration entry for int fn<T>(T) |
|
||||
| CPP-205.cpp:2:10:2:12 | definition of out | parameter declaration entry for int fn<int>(int) |
|
||||
| CPP-205.cpp:2:10:2:12 | out | parameter for int fn<T>(T) |
|
||||
| CPP-205.cpp:2:10:2:12 | out | parameter for int fn<int>(int) |
|
||||
| CPP-205.cpp:2:15:5:1 | { ... } | |
|
||||
| CPP-205.cpp:2:15:5:1 | { ... } | |
|
||||
| CPP-205.cpp:3:3:3:33 | declaration | |
|
||||
@@ -20,16 +20,16 @@
|
||||
| CPP-205.cpp:4:3:4:11 | return ... | |
|
||||
| CPP-205.cpp:4:10:4:10 | 0 | |
|
||||
| CPP-205.cpp:4:10:4:10 | 0 | |
|
||||
| CPP-205.cpp:7:5:7:8 | definition of main | function declaration entry for main() -> int |
|
||||
| CPP-205.cpp:7:5:7:8 | main | function main() -> int |
|
||||
| CPP-205.cpp:7:5:7:8 | definition of main | function declaration entry for int main() |
|
||||
| CPP-205.cpp:7:5:7:8 | main | function int main() |
|
||||
| CPP-205.cpp:7:12:9:1 | { ... } | |
|
||||
| CPP-205.cpp:8:3:8:15 | return ... | |
|
||||
| CPP-205.cpp:8:10:8:11 | call to fn | |
|
||||
| CPP-205.cpp:8:13:8:13 | 0 | |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | parameter for __va_list_tag::operator=(__va_list_tag &&) -> __va_list_tag & |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | parameter for __va_list_tag::operator=(const __va_list_tag &) -> __va_list_tag & |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | parameter for __va_list_tag& __va_list_tag::operator=(__va_list_tag const&) |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | parameter for __va_list_tag& __va_list_tag::operator=(__va_list_tag&&) |
|
||||
| file://:0:0:0:0 | __super | |
|
||||
| file://:0:0:0:0 | __va_list_tag | |
|
||||
| file://:0:0:0:0 | operator= | function __va_list_tag::operator=(__va_list_tag &&) -> __va_list_tag & |
|
||||
| file://:0:0:0:0 | operator= | function __va_list_tag::operator=(const __va_list_tag &) -> __va_list_tag & |
|
||||
| file://:0:0:0:0 | operator= | function __va_list_tag& __va_list_tag::operator=(__va_list_tag const&) |
|
||||
| file://:0:0:0:0 | operator= | function __va_list_tag& __va_list_tag::operator=(__va_list_tag&&) |
|
||||
| file://:0:0:0:0 | y | |
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.Print
|
||||
|
||||
string describe(Element e) {
|
||||
result = "function " + e.(Function).getFullSignature()
|
||||
e instanceof Function and
|
||||
result = "function " + getIdentityString(e)
|
||||
or
|
||||
result =
|
||||
"function declaration entry for " +
|
||||
e.(FunctionDeclarationEntry).getFunction().getFullSignature()
|
||||
getIdentityString(e.(FunctionDeclarationEntry).getFunction())
|
||||
or
|
||||
result = "parameter for " + e.(Parameter).getFunction().getFullSignature()
|
||||
result = "parameter for " + getIdentityString(e.(Parameter).getFunction())
|
||||
or
|
||||
result =
|
||||
"parameter declaration entry for " +
|
||||
e.(ParameterDeclarationEntry).getFunctionDeclarationEntry().getFunction().getFullSignature()
|
||||
getIdentityString(e.(ParameterDeclarationEntry).getFunctionDeclarationEntry().getFunction())
|
||||
}
|
||||
|
||||
from Element e
|
||||
|
||||
@@ -1,51 +1,51 @@
|
||||
newExprs
|
||||
| allocators.cpp:49:3:49:9 | new | int | operator new(unsigned long) -> void * | 4 | 4 | | |
|
||||
| allocators.cpp:50:3:50:15 | new | int | operator new(size_t, float) -> void * | 4 | 4 | | |
|
||||
| allocators.cpp:51:3:51:11 | new | int | operator new(unsigned long) -> void * | 4 | 4 | | |
|
||||
| allocators.cpp:52:3:52:14 | new | String | operator new(unsigned long) -> void * | 8 | 8 | | |
|
||||
| allocators.cpp:53:3:53:27 | new | String | operator new(size_t, float) -> void * | 8 | 8 | | |
|
||||
| allocators.cpp:54:3:54:17 | new | Overaligned | operator new(unsigned long, align_val_t) -> void * | 256 | 128 | aligned | |
|
||||
| allocators.cpp:55:3:55:25 | new | Overaligned | operator new(size_t, align_val_t, float) -> void * | 256 | 128 | aligned | |
|
||||
| allocators.cpp:107:3:107:18 | new | FailedInit | FailedInit::operator new(size_t) -> void * | 1 | 1 | | |
|
||||
| allocators.cpp:109:3:109:35 | new | FailedInitOveraligned | FailedInitOveraligned::operator new(size_t, align_val_t, float) -> void * | 128 | 128 | aligned | |
|
||||
| allocators.cpp:129:3:129:21 | new | int | operator new(size_t, void *) -> void * | 4 | 4 | | & ... |
|
||||
| allocators.cpp:135:3:135:26 | new | int | operator new(size_t, const nothrow_t &) -> void * | 4 | 4 | | |
|
||||
| allocators.cpp:49:3:49:9 | new | int | void* operator new(unsigned long) | 4 | 4 | | |
|
||||
| allocators.cpp:50:3:50:15 | new | int | void* operator new(size_t, float) | 4 | 4 | | |
|
||||
| allocators.cpp:51:3:51:11 | new | int | void* operator new(unsigned long) | 4 | 4 | | |
|
||||
| allocators.cpp:52:3:52:14 | new | String | void* operator new(unsigned long) | 8 | 8 | | |
|
||||
| allocators.cpp:53:3:53:27 | new | String | void* operator new(size_t, float) | 8 | 8 | | |
|
||||
| allocators.cpp:54:3:54:17 | new | Overaligned | void* operator new(unsigned long, std::align_val_t) | 256 | 128 | aligned | |
|
||||
| allocators.cpp:55:3:55:25 | new | Overaligned | void* operator new(size_t, std::align_val_t, float) | 256 | 128 | aligned | |
|
||||
| allocators.cpp:107:3:107:18 | new | FailedInit | void* FailedInit::operator new(size_t) | 1 | 1 | | |
|
||||
| allocators.cpp:109:3:109:35 | new | FailedInitOveraligned | void* FailedInitOveraligned::operator new(size_t, std::align_val_t, float) | 128 | 128 | aligned | |
|
||||
| allocators.cpp:129:3:129:21 | new | int | void* operator new(std::size_t, void*) | 4 | 4 | | & ... |
|
||||
| allocators.cpp:135:3:135:26 | new | int | void* operator new(std::size_t, std::nothrow_t const&) | 4 | 4 | | |
|
||||
newArrayExprs
|
||||
| allocators.cpp:68:3:68:12 | new[] | int[] | int | operator new[](unsigned long) -> void * | 4 | 4 | | n | |
|
||||
| allocators.cpp:69:3:69:18 | new[] | int[] | int | operator new[](size_t, float) -> void * | 4 | 4 | | n | |
|
||||
| allocators.cpp:70:3:70:15 | new[] | String[] | String | operator new[](unsigned long) -> void * | 8 | 8 | | n | |
|
||||
| allocators.cpp:71:3:71:20 | new[] | Overaligned[] | Overaligned | operator new[](unsigned long, align_val_t) -> void * | 256 | 128 | aligned | n | |
|
||||
| allocators.cpp:72:3:72:16 | new[] | String[10] | String | operator new[](unsigned long) -> void * | 8 | 8 | | | |
|
||||
| allocators.cpp:108:3:108:19 | new[] | FailedInit[] | FailedInit | FailedInit::operator new[](size_t) -> void * | 1 | 1 | | n | |
|
||||
| allocators.cpp:110:3:110:37 | new[] | FailedInitOveraligned[10] | FailedInitOveraligned | FailedInitOveraligned::operator new[](size_t, align_val_t, float) -> void * | 128 | 128 | aligned | | |
|
||||
| allocators.cpp:132:3:132:17 | new[] | int[1] | int | operator new[](size_t, void *) -> void * | 4 | 4 | | | buf |
|
||||
| allocators.cpp:136:3:136:26 | new[] | int[2] | int | operator new[](size_t, const nothrow_t &) -> void * | 4 | 4 | | | |
|
||||
| allocators.cpp:142:13:142:27 | new[] | char[][10] | char[10] | operator new[](unsigned long) -> void * | 10 | 1 | | x | |
|
||||
| allocators.cpp:143:13:143:28 | new[] | char[20][20] | char[20] | operator new[](unsigned long) -> void * | 20 | 1 | | | |
|
||||
| allocators.cpp:144:13:144:31 | new[] | char[][30][30] | char[30][30] | operator new[](unsigned long) -> void * | 900 | 1 | | x | |
|
||||
| allocators.cpp:68:3:68:12 | new[] | int[] | int | void* operator new[](unsigned long) | 4 | 4 | | n | |
|
||||
| allocators.cpp:69:3:69:18 | new[] | int[] | int | void* operator new[](size_t, float) | 4 | 4 | | n | |
|
||||
| allocators.cpp:70:3:70:15 | new[] | String[] | String | void* operator new[](unsigned long) | 8 | 8 | | n | |
|
||||
| allocators.cpp:71:3:71:20 | new[] | Overaligned[] | Overaligned | void* operator new[](unsigned long, std::align_val_t) | 256 | 128 | aligned | n | |
|
||||
| allocators.cpp:72:3:72:16 | new[] | String[10] | String | void* operator new[](unsigned long) | 8 | 8 | | | |
|
||||
| allocators.cpp:108:3:108:19 | new[] | FailedInit[] | FailedInit | void* FailedInit::operator new[](size_t) | 1 | 1 | | n | |
|
||||
| allocators.cpp:110:3:110:37 | new[] | FailedInitOveraligned[10] | FailedInitOveraligned | void* FailedInitOveraligned::operator new[](size_t, std::align_val_t, float) | 128 | 128 | aligned | | |
|
||||
| allocators.cpp:132:3:132:17 | new[] | int[1] | int | void* operator new[](std::size_t, void*) | 4 | 4 | | | buf |
|
||||
| allocators.cpp:136:3:136:26 | new[] | int[2] | int | void* operator new[](std::size_t, std::nothrow_t const&) | 4 | 4 | | | |
|
||||
| allocators.cpp:142:13:142:27 | new[] | char[][10] | char[10] | void* operator new[](unsigned long) | 10 | 1 | | x | |
|
||||
| allocators.cpp:143:13:143:28 | new[] | char[20][20] | char[20] | void* operator new[](unsigned long) | 20 | 1 | | | |
|
||||
| allocators.cpp:144:13:144:31 | new[] | char[][30][30] | char[30][30] | void* operator new[](unsigned long) | 900 | 1 | | x | |
|
||||
newExprDeallocators
|
||||
| allocators.cpp:52:3:52:14 | new | String | operator delete(void *, unsigned long) -> void | 8 | 8 | sized |
|
||||
| allocators.cpp:53:3:53:27 | new | String | operator delete(void *, float) -> void | 8 | 8 | |
|
||||
| allocators.cpp:107:3:107:18 | new | FailedInit | FailedInit::operator delete(void *, size_t) -> void | 1 | 1 | sized |
|
||||
| allocators.cpp:109:3:109:35 | new | FailedInitOveraligned | FailedInitOveraligned::operator delete(void *, align_val_t, float) -> void | 128 | 128 | aligned |
|
||||
| allocators.cpp:52:3:52:14 | new | String | void operator delete(void*, unsigned long) | 8 | 8 | sized |
|
||||
| allocators.cpp:53:3:53:27 | new | String | void operator delete(void*, float) | 8 | 8 | |
|
||||
| allocators.cpp:107:3:107:18 | new | FailedInit | void FailedInit::operator delete(void*, size_t) | 1 | 1 | sized |
|
||||
| allocators.cpp:109:3:109:35 | new | FailedInitOveraligned | void FailedInitOveraligned::operator delete(void*, std::align_val_t, float) | 128 | 128 | aligned |
|
||||
newArrayExprDeallocators
|
||||
| allocators.cpp:70:3:70:15 | new[] | String | operator delete[](void *, unsigned long) -> void | 8 | 8 | sized |
|
||||
| allocators.cpp:72:3:72:16 | new[] | String | operator delete[](void *, unsigned long) -> void | 8 | 8 | sized |
|
||||
| allocators.cpp:108:3:108:19 | new[] | FailedInit | FailedInit::operator delete[](void *, size_t) -> void | 1 | 1 | sized |
|
||||
| allocators.cpp:110:3:110:37 | new[] | FailedInitOveraligned | FailedInitOveraligned::operator delete[](void *, align_val_t, float) -> void | 128 | 128 | aligned |
|
||||
| allocators.cpp:70:3:70:15 | new[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
|
||||
| allocators.cpp:72:3:72:16 | new[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
|
||||
| allocators.cpp:108:3:108:19 | new[] | FailedInit | void FailedInit::operator delete[](void*, size_t) | 1 | 1 | sized |
|
||||
| allocators.cpp:110:3:110:37 | new[] | FailedInitOveraligned | void FailedInitOveraligned::operator delete[](void*, std::align_val_t, float) | 128 | 128 | aligned |
|
||||
deleteExprs
|
||||
| allocators.cpp:59:3:59:35 | delete | int | operator delete(void *, unsigned long) -> void | 4 | 4 | sized |
|
||||
| allocators.cpp:60:3:60:38 | delete | String | operator delete(void *, unsigned long) -> void | 8 | 8 | sized |
|
||||
| allocators.cpp:61:3:61:44 | delete | SizedDealloc | SizedDealloc::operator delete(void *, size_t) -> void | 32 | 1 | sized |
|
||||
| allocators.cpp:62:3:62:43 | delete | Overaligned | operator delete(void *, unsigned long, align_val_t) -> void | 256 | 128 | sized aligned |
|
||||
| allocators.cpp:64:3:64:44 | delete | const String | operator delete(void *, unsigned long) -> void | 8 | 8 | sized |
|
||||
| allocators.cpp:59:3:59:35 | delete | int | void operator delete(void*, unsigned long) | 4 | 4 | sized |
|
||||
| allocators.cpp:60:3:60:38 | delete | String | void operator delete(void*, unsigned long) | 8 | 8 | sized |
|
||||
| allocators.cpp:61:3:61:44 | delete | SizedDealloc | void SizedDealloc::operator delete(void*, size_t) | 32 | 1 | sized |
|
||||
| allocators.cpp:62:3:62:43 | delete | Overaligned | void operator delete(void*, unsigned long, std::align_val_t) | 256 | 128 | sized aligned |
|
||||
| allocators.cpp:64:3:64:44 | delete | const String | void operator delete(void*, unsigned long) | 8 | 8 | sized |
|
||||
deleteArrayExprs
|
||||
| allocators.cpp:78:3:78:37 | delete[] | int | operator delete[](void *, unsigned long) -> void | 4 | 4 | sized |
|
||||
| allocators.cpp:79:3:79:40 | delete[] | String | operator delete[](void *, unsigned long) -> void | 8 | 8 | sized |
|
||||
| allocators.cpp:80:3:80:46 | delete[] | SizedDealloc | SizedDealloc::operator delete[](void *, size_t) -> void | 32 | 1 | sized |
|
||||
| allocators.cpp:81:3:81:45 | delete[] | Overaligned | operator delete[](void *, unsigned long, align_val_t) -> void | 256 | 128 | sized aligned |
|
||||
| allocators.cpp:82:3:82:49 | delete[] | PolymorphicBase | operator delete[](void *, unsigned long) -> void | 8 | 8 | sized |
|
||||
| allocators.cpp:83:3:83:23 | delete[] | int | operator delete[](void *, unsigned long) -> void | 4 | 4 | sized |
|
||||
| allocators.cpp:78:3:78:37 | delete[] | int | void operator delete[](void*, unsigned long) | 4 | 4 | sized |
|
||||
| allocators.cpp:79:3:79:40 | delete[] | String | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
|
||||
| allocators.cpp:80:3:80:46 | delete[] | SizedDealloc | void SizedDealloc::operator delete[](void*, size_t) | 32 | 1 | sized |
|
||||
| allocators.cpp:81:3:81:45 | delete[] | Overaligned | void operator delete[](void*, unsigned long, std::align_val_t) | 256 | 128 | sized aligned |
|
||||
| allocators.cpp:82:3:82:49 | delete[] | PolymorphicBase | void operator delete[](void*, unsigned long) | 8 | 8 | sized |
|
||||
| allocators.cpp:83:3:83:23 | delete[] | int | void operator delete[](void*, unsigned long) | 4 | 4 | sized |
|
||||
allocationFunctions
|
||||
| allocators.cpp:7:7:7:18 | operator new | getSizeArg = 0, requiresDealloc |
|
||||
| allocators.cpp:8:7:8:20 | operator new[] | getSizeArg = 0, requiresDealloc |
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.models.implementations.Allocation
|
||||
import semmle.code.cpp.Print
|
||||
|
||||
query predicate newExprs(
|
||||
NewExpr expr, string type, string sig, int size, int alignment, string form, string placement
|
||||
) {
|
||||
exists(Function allocator, Type allocatedType |
|
||||
expr.getAllocator() = allocator and
|
||||
sig = allocator.getFullSignature() and
|
||||
sig = getIdentityString(allocator) and
|
||||
allocatedType = expr.getAllocatedType() and
|
||||
type = allocatedType.toString() and
|
||||
size = allocatedType.getSize() and
|
||||
@@ -24,7 +25,7 @@ query predicate newArrayExprs(
|
||||
) {
|
||||
exists(Function allocator, Type arrayType, Type elementType |
|
||||
expr.getAllocator() = allocator and
|
||||
sig = allocator.getFullSignature() and
|
||||
sig = getIdentityString(allocator) and
|
||||
arrayType = expr.getAllocatedType() and
|
||||
t1 = arrayType.toString() and
|
||||
elementType = expr.getAllocatedElementType() and
|
||||
@@ -44,7 +45,7 @@ query predicate newExprDeallocators(
|
||||
) {
|
||||
exists(Function deallocator, Type allocatedType |
|
||||
expr.getDeallocator() = deallocator and
|
||||
sig = deallocator.getFullSignature() and
|
||||
sig = getIdentityString(deallocator) and
|
||||
allocatedType = expr.getAllocatedType() and
|
||||
type = allocatedType.toString() and
|
||||
size = allocatedType.getSize() and
|
||||
@@ -62,7 +63,7 @@ query predicate newArrayExprDeallocators(
|
||||
) {
|
||||
exists(Function deallocator, Type elementType |
|
||||
expr.getDeallocator() = deallocator and
|
||||
sig = deallocator.getFullSignature() and
|
||||
sig = getIdentityString(deallocator) and
|
||||
elementType = expr.getAllocatedElementType() and
|
||||
type = elementType.toString() and
|
||||
size = elementType.getSize() and
|
||||
@@ -80,7 +81,7 @@ query predicate deleteExprs(
|
||||
) {
|
||||
exists(Function deallocator, Type deletedType |
|
||||
expr.getDeallocator() = deallocator and
|
||||
sig = deallocator.getFullSignature() and
|
||||
sig = getIdentityString(deallocator) and
|
||||
deletedType = expr.getDeletedObjectType() and
|
||||
type = deletedType.toString() and
|
||||
size = deletedType.getSize() and
|
||||
@@ -98,7 +99,7 @@ query predicate deleteArrayExprs(
|
||||
) {
|
||||
exists(Function deallocator, Type elementType |
|
||||
expr.getDeallocator() = deallocator and
|
||||
sig = deallocator.getFullSignature() and
|
||||
sig = getIdentityString(deallocator) and
|
||||
elementType = expr.getDeletedElementType() and
|
||||
type = elementType.toString() and
|
||||
size = elementType.getSize() and
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user