mirror of
https://github.com/github/codeql.git
synced 2026-07-07 12:35:33 +02:00
Compare commits
486 Commits
codeql-cli
...
esbena/new
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bd63f99015 | ||
|
|
b2e4276bc8 | ||
|
|
86b1305e35 | ||
|
|
4de1deefc4 | ||
|
|
0b82289950 | ||
|
|
a9c5fd2cc0 | ||
|
|
eb0a88d39c | ||
|
|
f6a517c998 | ||
|
|
310eec07c1 | ||
|
|
cb5f2559ea | ||
|
|
083214f85a | ||
|
|
ed6a182cd1 | ||
|
|
8b6baa250c | ||
|
|
7cd5e681dd | ||
|
|
47a85bbb1d | ||
|
|
a5ab0b9100 | ||
|
|
10d6803b05 | ||
|
|
8049d3f738 | ||
|
|
69ed7c543f | ||
|
|
f5420333e2 | ||
|
|
57cb300759 | ||
|
|
a358a192c4 | ||
|
|
a2371370ff | ||
|
|
4991301f36 | ||
|
|
2b0415e238 | ||
|
|
878203f1d0 | ||
|
|
0d1632a5d2 | ||
|
|
169cc75c88 | ||
|
|
a6115687aa | ||
|
|
a9c8163ab3 | ||
|
|
a204b7f3e7 | ||
|
|
c215838531 | ||
|
|
6ece3c2b46 | ||
|
|
e80c1ad91f | ||
|
|
a80860cdc6 | ||
|
|
f3bb0a676e | ||
|
|
d85d009a54 | ||
|
|
955344e175 | ||
|
|
c9c0c7f24f | ||
|
|
bdc54bcda7 | ||
|
|
887849857d | ||
|
|
7690625114 | ||
|
|
ba981c525b | ||
|
|
6b9ddf1f65 | ||
|
|
e3e741251f | ||
|
|
aa656f7542 | ||
|
|
4a0aac8505 | ||
|
|
d0ecabad19 | ||
|
|
d4fd8780e9 | ||
|
|
306388a6bc | ||
|
|
2f27a0c9f9 | ||
|
|
8285878504 | ||
|
|
bbb2637bcc | ||
|
|
83490e9a03 | ||
|
|
a517a05ca8 | ||
|
|
0e5f89a03c | ||
|
|
6853f491f4 | ||
|
|
10739b11ee | ||
|
|
6c108e43d9 | ||
|
|
cf92e1eee7 | ||
|
|
83c6406167 | ||
|
|
cc305ed766 | ||
|
|
296e268339 | ||
|
|
3c96e62be7 | ||
|
|
8816aa1431 | ||
|
|
205b6fe6d7 | ||
|
|
5da392ebfe | ||
|
|
1afc03b9b5 | ||
|
|
9e0b112f05 | ||
|
|
490168fb05 | ||
|
|
1dffbcd0bd | ||
|
|
81c0e66b1d | ||
|
|
fc0b18cf61 | ||
|
|
cd2c9e9ca3 | ||
|
|
6b4ca31783 | ||
|
|
1c3239972c | ||
|
|
75c4d6a8a0 | ||
|
|
61008fd3d0 | ||
|
|
b093aaaf27 | ||
|
|
43f7eede0b | ||
|
|
c007c9460c | ||
|
|
f34d1ee997 | ||
|
|
97bbb12e06 | ||
|
|
d52f95d24d | ||
|
|
df8c399efb | ||
|
|
4334acb6f2 | ||
|
|
0629ce00de | ||
|
|
ac6acfb660 | ||
|
|
058a04f756 | ||
|
|
c7fbddce54 | ||
|
|
ba0dbd5871 | ||
|
|
19f6cc00c8 | ||
|
|
5aee715931 | ||
|
|
68ea3e7b49 | ||
|
|
d5955f1ae1 | ||
|
|
30bf2aade4 | ||
|
|
61973c399e | ||
|
|
c75e2d306d | ||
|
|
c2d0fcfbe6 | ||
|
|
29ddc76e2f | ||
|
|
8444388ec7 | ||
|
|
1552c108b0 | ||
|
|
b05d76a131 | ||
|
|
0919746f1a | ||
|
|
ea0a0522a7 | ||
|
|
a7670fbcab | ||
|
|
12936ff5fe | ||
|
|
b009886664 | ||
|
|
a74d423d82 | ||
|
|
64b1aeaecd | ||
|
|
0aa632d149 | ||
|
|
9c9c5c09ff | ||
|
|
f6122c8a6c | ||
|
|
5b26d41d27 | ||
|
|
a50b193c40 | ||
|
|
15476c2513 | ||
|
|
79f13cae55 | ||
|
|
705970cedd | ||
|
|
84883d115d | ||
|
|
8ba01abcd6 | ||
|
|
2185a654de | ||
|
|
5d0e72755d | ||
|
|
1c56573194 | ||
|
|
dd95131630 | ||
|
|
4807f50c00 | ||
|
|
8c42545d1c | ||
|
|
fd0c386a4c | ||
|
|
5e6f042f6e | ||
|
|
75b06d8a25 | ||
|
|
4820be3b10 | ||
|
|
9180257afe | ||
|
|
f9333fc551 | ||
|
|
42980a1ab4 | ||
|
|
446c738f20 | ||
|
|
d79596354e | ||
|
|
951df380a9 | ||
|
|
06e59f3b17 | ||
|
|
1bec58dee5 | ||
|
|
062250741a | ||
|
|
a81d359669 | ||
|
|
1b61296ea5 | ||
|
|
27c368a444 | ||
|
|
3592b09d56 | ||
|
|
a31bf75169 | ||
|
|
2539e3247a | ||
|
|
2ed572095c | ||
|
|
933412eb8d | ||
|
|
9a80ab31c4 | ||
|
|
39640efc9b | ||
|
|
2b88a2aa0c | ||
|
|
f885751107 | ||
|
|
764a987b09 | ||
|
|
538bf7c321 | ||
|
|
fc69acee46 | ||
|
|
b7448d55ed | ||
|
|
4b069d41f6 | ||
|
|
a0dd3d9e75 | ||
|
|
f651bc3668 | ||
|
|
d8d9073bc2 | ||
|
|
e2b1f6ac50 | ||
|
|
0452512de2 | ||
|
|
f88c8a64a1 | ||
|
|
b33daa3d3a | ||
|
|
4be2347a30 | ||
|
|
83cbc86f50 | ||
|
|
c9c45808b4 | ||
|
|
91d8b3da23 | ||
|
|
f24e310ace | ||
|
|
ffdfc0549a | ||
|
|
987bfa6ca7 | ||
|
|
8c2fddb297 | ||
|
|
b0e652a3af | ||
|
|
9e0cf5a2fd | ||
|
|
3607d50994 | ||
|
|
02bfa1ca57 | ||
|
|
0621e65827 | ||
|
|
d0b307ecfb | ||
|
|
9505846088 | ||
|
|
33ee947f8d | ||
|
|
57ef989a89 | ||
|
|
0590e2a5fb | ||
|
|
5b13232a9d | ||
|
|
9133adac30 | ||
|
|
04892df45a | ||
|
|
af7d633f2f | ||
|
|
ef80263106 | ||
|
|
5d63a76e25 | ||
|
|
b956238efa | ||
|
|
a17b0d4e5c | ||
|
|
b089e6d84e | ||
|
|
3a20ca96c4 | ||
|
|
c4e8af983a | ||
|
|
682a71176d | ||
|
|
83ca4ef6d9 | ||
|
|
a86cbd884e | ||
|
|
3323f7ab1a | ||
|
|
9f54b1065a | ||
|
|
9c1021134a | ||
|
|
2d1278ece5 | ||
|
|
baffb0ed89 | ||
|
|
a2e9c2f4ab | ||
|
|
c13bf2a2a1 | ||
|
|
73653f77aa | ||
|
|
8c6d58e6d8 | ||
|
|
0e149f0523 | ||
|
|
40d98ad678 | ||
|
|
9913221010 | ||
|
|
f230a37004 | ||
|
|
11b8d4191f | ||
|
|
2c64fa50d2 | ||
|
|
7f7f90681f | ||
|
|
0bce8234d8 | ||
|
|
745ece6e6d | ||
|
|
eac0222f2c | ||
|
|
70e41b180e | ||
|
|
9762ce706b | ||
|
|
041aff6bfd | ||
|
|
2a44cd8c98 | ||
|
|
54aec7bb96 | ||
|
|
064aba810b | ||
|
|
5aec84b672 | ||
|
|
cbd577694c | ||
|
|
a315640082 | ||
|
|
f06632a8e7 | ||
|
|
aa91c26792 | ||
|
|
4521a9fdf0 | ||
|
|
65a4f36cf8 | ||
|
|
70b9b002cb | ||
|
|
682a2aae3a | ||
|
|
ce27acd099 | ||
|
|
fb1385b3e8 | ||
|
|
938d003e5e | ||
|
|
25792b2a45 | ||
|
|
cc8b581c06 | ||
|
|
cca77ed65c | ||
|
|
b9a1a451a9 | ||
|
|
62aa7b75bd | ||
|
|
0679142607 | ||
|
|
3463c28e24 | ||
|
|
e3fed55945 | ||
|
|
085701c7db | ||
|
|
51188aa93f | ||
|
|
5e4498a53a | ||
|
|
a62772c274 | ||
|
|
924b7320bc | ||
|
|
bb6e6f4808 | ||
|
|
ada30800c9 | ||
|
|
99ba80d492 | ||
|
|
ebe0988d9a | ||
|
|
11d7a0b712 | ||
|
|
d41e517757 | ||
|
|
ec2e4f432a | ||
|
|
74957dcb2e | ||
|
|
6359c44622 | ||
|
|
1ce9426adf | ||
|
|
98f68cb053 | ||
|
|
490df2027b | ||
|
|
d4f1a9602f | ||
|
|
eb26b4a04b | ||
|
|
c8e7df7900 | ||
|
|
600e5bad0d | ||
|
|
af1b04de9c | ||
|
|
a3cf721b9e | ||
|
|
679b0f9b73 | ||
|
|
175a06fe73 | ||
|
|
799e099d1d | ||
|
|
3d61c81456 | ||
|
|
f48c418d6d | ||
|
|
ec4cb7c90f | ||
|
|
cb4ce36d3c | ||
|
|
b0983cb726 | ||
|
|
b57a58c253 | ||
|
|
24c9bb2fb7 | ||
|
|
168fc4170d | ||
|
|
f3bde56de9 | ||
|
|
60a023d064 | ||
|
|
35d9005eae | ||
|
|
f3fc56a167 | ||
|
|
d19d37bf9b | ||
|
|
c1c63d0c28 | ||
|
|
46e62cd963 | ||
|
|
02e91b3902 | ||
|
|
45cf6344cd | ||
|
|
e9b4e571e1 | ||
|
|
447eb23356 | ||
|
|
3ae5f13c3d | ||
|
|
089bb33113 | ||
|
|
ba990f72f2 | ||
|
|
987b573709 | ||
|
|
dea8dde566 | ||
|
|
e17071723f | ||
|
|
8dcf7926de | ||
|
|
d09c3bf863 | ||
|
|
1a92fa5d92 | ||
|
|
8d2ad4ed17 | ||
|
|
89098f54be | ||
|
|
5f659f6e48 | ||
|
|
10323ac819 | ||
|
|
ee46717c76 | ||
|
|
914e621d1b | ||
|
|
976190e84d | ||
|
|
06eb93da3f | ||
|
|
7197f41e75 | ||
|
|
5488872044 | ||
|
|
413ac4e8f4 | ||
|
|
e95dc82087 | ||
|
|
cec6cd0830 | ||
|
|
39a12a8464 | ||
|
|
b11cb88a9f | ||
|
|
9a9bbe3123 | ||
|
|
46eb27cd01 | ||
|
|
ba98c0c1cb | ||
|
|
fc8b439263 | ||
|
|
a358ea8667 | ||
|
|
c294b75f6c | ||
|
|
d5e17f9ebf | ||
|
|
c7ea7ca5cd | ||
|
|
49c656d904 | ||
|
|
79549c2285 | ||
|
|
787f36f056 | ||
|
|
d47c4732e2 | ||
|
|
b7b229d59b | ||
|
|
dfb27d170c | ||
|
|
64fcbe05c3 | ||
|
|
31c34870ef | ||
|
|
3c17ac424d | ||
|
|
bb6c079e5a | ||
|
|
a3c1975a84 | ||
|
|
bdd78d2bc7 | ||
|
|
29db42c3cd | ||
|
|
e6df8164cf | ||
|
|
cf03bd8bd1 | ||
|
|
342c14887b | ||
|
|
e1101e582e | ||
|
|
768203bd36 | ||
|
|
c51fb00082 | ||
|
|
0a92b04c8b | ||
|
|
15161d8867 | ||
|
|
53ee465726 | ||
|
|
a20acfee25 | ||
|
|
f69787afd0 | ||
|
|
9b12980688 | ||
|
|
cb0f82c36e | ||
|
|
3b678bfbc5 | ||
|
|
e1750adc38 | ||
|
|
fd0fb9483e | ||
|
|
3d1d491e6b | ||
|
|
18020707b8 | ||
|
|
cfa0d46b73 | ||
|
|
e027d514f1 | ||
|
|
d5f675c2dc | ||
|
|
ded3088529 | ||
|
|
78c12dc505 | ||
|
|
ad08ccb50b | ||
|
|
95751fcc21 | ||
|
|
13417dbf14 | ||
|
|
ff21662b23 | ||
|
|
6967b06dee | ||
|
|
fc58ada92e | ||
|
|
108118afa3 | ||
|
|
d8bb5273e7 | ||
|
|
c792567904 | ||
|
|
6d9a88d1c8 | ||
|
|
3520fed752 | ||
|
|
d10dbbdd9d | ||
|
|
6bf1e87bbe | ||
|
|
91f46624b6 | ||
|
|
94f32d2985 | ||
|
|
569426b04e | ||
|
|
b0852f6c16 | ||
|
|
b985ddb868 | ||
|
|
079769ed2e | ||
|
|
fc6af0476f | ||
|
|
03bd7d7f96 | ||
|
|
92ffd8c465 | ||
|
|
b0836a620c | ||
|
|
c977cfe40a | ||
|
|
e0921ac983 | ||
|
|
7e7dfe2cc4 | ||
|
|
91a8b9fdd9 | ||
|
|
1adc5c2a5b | ||
|
|
6901d9d9c2 | ||
|
|
9f59bc8f7b | ||
|
|
e664711f47 | ||
|
|
23e4ad1abb | ||
|
|
49f8f46354 | ||
|
|
854f2a046a | ||
|
|
70e1724463 | ||
|
|
cbdabe35de | ||
|
|
032ac50034 | ||
|
|
3e5f7d0db5 | ||
|
|
b08eabec68 | ||
|
|
a4a9e2aa96 | ||
|
|
9b969e15fc | ||
|
|
f2fbeed490 | ||
|
|
81adb7dd2a | ||
|
|
4841c3037d | ||
|
|
0919042692 | ||
|
|
13741ba137 | ||
|
|
18de9f0aa3 | ||
|
|
d4564d5dd1 | ||
|
|
49f8fd2164 | ||
|
|
0c5d642489 | ||
|
|
6f03c3e252 | ||
|
|
8faeab18b9 | ||
|
|
21ed5c430d | ||
|
|
805d1d170c | ||
|
|
6c07a3e260 | ||
|
|
d6fd83dd6c | ||
|
|
88a257fcdc | ||
|
|
99881db8bd | ||
|
|
0c1f3ed0b3 | ||
|
|
a811ab3aff | ||
|
|
a9add04ee3 | ||
|
|
d3d708bc68 | ||
|
|
e7c82d7370 | ||
|
|
24668b2281 | ||
|
|
51243454c8 | ||
|
|
90bc138049 | ||
|
|
99167539fb | ||
|
|
a3de94e868 | ||
|
|
7383988988 | ||
|
|
e906ded0d1 | ||
|
|
b6bcf9fa44 | ||
|
|
b393c6a285 | ||
|
|
c36292bfd0 | ||
|
|
64685f31dc | ||
|
|
0277601705 | ||
|
|
72bf390ec5 | ||
|
|
c85cc1455b | ||
|
|
a3e1f54e33 | ||
|
|
509a3493b6 | ||
|
|
09ef8f639e | ||
|
|
83cc098412 | ||
|
|
3cd08bc724 | ||
|
|
fe1f9878ba | ||
|
|
e874fbbea2 | ||
|
|
5dc6e13ab5 | ||
|
|
4d2036fa26 | ||
|
|
c30e7ec41a | ||
|
|
181eb803e1 | ||
|
|
37c92178a5 | ||
|
|
5e265f45e1 | ||
|
|
9926892c8a | ||
|
|
9c478c502e | ||
|
|
562c8b97ad | ||
|
|
6f408f949c | ||
|
|
8f4df8603a | ||
|
|
05d83e487d | ||
|
|
c60eded2de | ||
|
|
9e63aa9d84 | ||
|
|
c2d2037726 | ||
|
|
1c7982b319 | ||
|
|
36e27f2aa4 | ||
|
|
abbd1d1dc5 | ||
|
|
6c82daef3d | ||
|
|
3d5192d6d3 | ||
|
|
a30f697537 | ||
|
|
3f5ab60fb4 | ||
|
|
8f152a5bfb | ||
|
|
67c6b35845 | ||
|
|
0e8064dbf9 | ||
|
|
8e9ac18026 | ||
|
|
ee7ccd7936 | ||
|
|
f58177f292 | ||
|
|
1d76578202 | ||
|
|
e696eaaa2f | ||
|
|
3ba9e80635 | ||
|
|
1707d67adb | ||
|
|
29ad3bf7f8 | ||
|
|
2c93bce9ad | ||
|
|
3b3350e648 | ||
|
|
32b3e416b3 | ||
|
|
6c5596d17e | ||
|
|
e27b3162e5 | ||
|
|
a9c409403c | ||
|
|
9b198c6d0a | ||
|
|
cd5a5347fc | ||
|
|
246302453f | ||
|
|
e8d0827916 | ||
|
|
b866f1b21e | ||
|
|
7af1984348 | ||
|
|
1a072f3bb9 | ||
|
|
9ef58e378c | ||
|
|
4d014717b6 | ||
|
|
fc7d340a89 |
@@ -6,6 +6,8 @@ on:
|
|||||||
- '.github/workflows/csv-coverage-pr-comment.yml'
|
- '.github/workflows/csv-coverage-pr-comment.yml'
|
||||||
- '*/ql/src/**/*.ql'
|
- '*/ql/src/**/*.ql'
|
||||||
- '*/ql/src/**/*.qll'
|
- '*/ql/src/**/*.qll'
|
||||||
|
- '*/ql/lib/**/*.ql'
|
||||||
|
- '*/ql/lib/**/*.qll'
|
||||||
- 'misc/scripts/library-coverage/*.py'
|
- 'misc/scripts/library-coverage/*.py'
|
||||||
# input data files
|
# input data files
|
||||||
- '*/documentation/library-coverage/cwe-sink.csv'
|
- '*/documentation/library-coverage/cwe-sink.csv'
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -24,3 +24,6 @@
|
|||||||
/codeql/
|
/codeql/
|
||||||
|
|
||||||
csharp/extractor/Semmle.Extraction.CSharp.Driver/Properties/launchSettings.json
|
csharp/extractor/Semmle.Extraction.CSharp.Driver/Properties/launchSettings.json
|
||||||
|
|
||||||
|
# Avoid committing cached package components
|
||||||
|
.codeql
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ This open source repository contains the standard CodeQL libraries and queries t
|
|||||||
|
|
||||||
## How do I learn CodeQL and run queries?
|
## How do I learn CodeQL and run queries?
|
||||||
|
|
||||||
There is [extensive documentation](https://help.semmle.com/QL/learn-ql/) on getting started with writing CodeQL.
|
There is [extensive documentation](https://codeql.github.com/docs/) on getting started with writing CodeQL.
|
||||||
You can use the [interactive query console](https://lgtm.com/help/lgtm/using-query-console) on LGTM.com or the [CodeQL for Visual Studio Code](https://help.semmle.com/codeql/codeql-for-vscode.html) extension to try out your queries on any open source project that's currently being analyzed.
|
You can use the [interactive query console](https://lgtm.com/help/lgtm/using-query-console) on LGTM.com or the [CodeQL for Visual Studio Code](https://codeql.github.com/docs/codeql-for-visual-studio-code/) extension to try out your queries on any open source project that's currently being analyzed.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
|||||||
@@ -367,6 +367,7 @@
|
|||||||
],
|
],
|
||||||
"Inline Test Expectations": [
|
"Inline Test Expectations": [
|
||||||
"cpp/ql/test/TestUtilities/InlineExpectationsTest.qll",
|
"cpp/ql/test/TestUtilities/InlineExpectationsTest.qll",
|
||||||
|
"csharp/ql/test/TestUtilities/InlineExpectationsTest.qll",
|
||||||
"java/ql/test/TestUtilities/InlineExpectationsTest.qll",
|
"java/ql/test/TestUtilities/InlineExpectationsTest.qll",
|
||||||
"python/ql/test/TestUtilities/InlineExpectationsTest.qll"
|
"python/ql/test/TestUtilities/InlineExpectationsTest.qll"
|
||||||
],
|
],
|
||||||
@@ -461,5 +462,12 @@
|
|||||||
"ReDoS Polynomial Python/JS": [
|
"ReDoS Polynomial Python/JS": [
|
||||||
"javascript/ql/lib/semmle/javascript/security/performance/SuperlinearBackTracking.qll",
|
"javascript/ql/lib/semmle/javascript/security/performance/SuperlinearBackTracking.qll",
|
||||||
"python/ql/lib/semmle/python/security/performance/SuperlinearBackTracking.qll"
|
"python/ql/lib/semmle/python/security/performance/SuperlinearBackTracking.qll"
|
||||||
|
],
|
||||||
|
"CodeQL Tutorial": [
|
||||||
|
"cpp/ql/lib/tutorial.qll",
|
||||||
|
"csharp/ql/lib/tutorial.qll",
|
||||||
|
"java/ql/lib/tutorial.qll",
|
||||||
|
"javascript/ql/lib/tutorial.qll",
|
||||||
|
"python/ql/lib/tutorial.qll"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
2
cpp/change-notes/2021-06-10-cleartext-transmission.md
Normal file
2
cpp/change-notes/2021-06-10-cleartext-transmission.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
lgtm,codescanning
|
||||||
|
* A new query (`cpp/cleartext-transmission`) has been added. This is similar to the `cpp/cleartext-storage-file`, `cpp/cleartext-storage-buffer` and `cpp/cleartext-storage-database` queries but looks for cases where sensitive information is most likely transmitted over a network.
|
||||||
2
cpp/change-notes/2021-09-27-command-line-injection.md
Normal file
2
cpp/change-notes/2021-09-27-command-line-injection.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
lgtm,codescanning
|
||||||
|
* The "Uncontrolled data used in OS command" (`cpp/command-line-injection`) query has been enhanced to reduce false positive results and its `@precision` increased to `high`
|
||||||
3
cpp/change-notes/2021-09-27-overflow-static.md
Normal file
3
cpp/change-notes/2021-09-27-overflow-static.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
lgtm,codescanning
|
||||||
|
* Increase precision to high for the "Static buffer overflow" query
|
||||||
|
(`cpp/static-buffer-overflow`). This means the query is run and displayed by default on Code Scanning and LGTM.
|
||||||
2
cpp/change-notes/2021-10-01-improper-null-termination.md
Normal file
2
cpp/change-notes/2021-10-01-improper-null-termination.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
lgtm,codescanning
|
||||||
|
* Several improvements made to the `NullTermination.qll` library and the 'Potential improper null termination' (cpp/improper-null-termination). These changes reduce the number of false positive results for this query and related query 'User-controlled data may not be null terminated' (cpp/user-controlled-null-termination-tainted).
|
||||||
3
cpp/change-notes/2021-10-07-extraction-errors.md
Normal file
3
cpp/change-notes/2021-10-07-extraction-errors.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
codescanning
|
||||||
|
* Problems with extraction that in most cases won't break the analysis in a significant way are now reported as warnings rather than errors.
|
||||||
|
* The failed extractor invocations query now has severity `error`.
|
||||||
@@ -275,9 +275,8 @@ class Declaration extends Locatable, @declaration {
|
|||||||
* `getTemplateArgumentKind(0)`.
|
* `getTemplateArgumentKind(0)`.
|
||||||
*/
|
*/
|
||||||
final Locatable getTemplateArgumentKind(int index) {
|
final Locatable getTemplateArgumentKind(int index) {
|
||||||
if exists(getTemplateArgumentValue(index))
|
exists(getTemplateArgumentValue(index)) and
|
||||||
then result = getTemplateArgumentType(index)
|
result = getTemplateArgumentType(index)
|
||||||
else none()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the number of template arguments for this declaration. */
|
/** Gets the number of template arguments for this declaration. */
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class Container extends Locatable, @container {
|
|||||||
* DEPRECATED: Use `getLocation` instead.
|
* DEPRECATED: Use `getLocation` instead.
|
||||||
* Gets a URL representing the location of this container.
|
* Gets a URL representing the location of this container.
|
||||||
*
|
*
|
||||||
* For more information see [Providing URLs](https://help.semmle.com/QL/learn-ql/ql/locations.html#providing-urls).
|
* For more information see [Providing URLs](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/#providing-urls).
|
||||||
*/
|
*/
|
||||||
deprecated string getURL() { none() } // overridden by subclasses
|
deprecated string getURL() { none() } // overridden by subclasses
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ class Location extends @location {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
|||||||
@@ -1650,7 +1650,6 @@ class RoutineType extends Type, @routinetype {
|
|||||||
i = 0 and result = "" and not exists(this.getAParameterType())
|
i = 0 and result = "" and not exists(this.getAParameterType())
|
||||||
or
|
or
|
||||||
(
|
(
|
||||||
exists(this.getParameterType(i)) and
|
|
||||||
if i < max(int j | exists(this.getParameterType(j)))
|
if i < max(int j | exists(this.getParameterType(j)))
|
||||||
then
|
then
|
||||||
// Not the last one
|
// Not the last one
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class XMLLocatable extends @xmllocatable, TXMLLocatable {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
@@ -108,7 +108,7 @@ class XMLParent extends @xmlparent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the text value contained in this XML parent. */
|
/** Gets the text value contained in this XML parent. */
|
||||||
string getTextValue() { result = allCharactersString() }
|
string getTextValue() { result = this.allCharactersString() }
|
||||||
|
|
||||||
/** Gets a printable representation of this XML parent. */
|
/** Gets a printable representation of this XML parent. */
|
||||||
string toString() { result = this.getName() }
|
string toString() { result = this.getName() }
|
||||||
@@ -119,7 +119,7 @@ class XMLFile extends XMLParent, File {
|
|||||||
XMLFile() { xmlEncoding(this, _) }
|
XMLFile() { xmlEncoding(this, _) }
|
||||||
|
|
||||||
/** Gets a printable representation of this XML file. */
|
/** Gets a printable representation of this XML file. */
|
||||||
override string toString() { result = getName() }
|
override string toString() { result = this.getName() }
|
||||||
|
|
||||||
/** Gets the name of this XML file. */
|
/** Gets the name of this XML file. */
|
||||||
override string getName() { result = File.super.getAbsolutePath() }
|
override string getName() { result = File.super.getAbsolutePath() }
|
||||||
@@ -129,14 +129,14 @@ class XMLFile extends XMLParent, File {
|
|||||||
*
|
*
|
||||||
* Gets the path of this XML file.
|
* Gets the path of this XML file.
|
||||||
*/
|
*/
|
||||||
deprecated string getPath() { result = getAbsolutePath() }
|
deprecated string getPath() { result = this.getAbsolutePath() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DEPRECATED: Use `getParentContainer().getAbsolutePath()` instead.
|
* DEPRECATED: Use `getParentContainer().getAbsolutePath()` instead.
|
||||||
*
|
*
|
||||||
* Gets the path of the folder that contains this XML file.
|
* Gets the path of the folder that contains this XML file.
|
||||||
*/
|
*/
|
||||||
deprecated string getFolder() { result = getParentContainer().getAbsolutePath() }
|
deprecated string getFolder() { result = this.getParentContainer().getAbsolutePath() }
|
||||||
|
|
||||||
/** Gets the encoding of this XML file. */
|
/** Gets the encoding of this XML file. */
|
||||||
string getEncoding() { xmlEncoding(this, result) }
|
string getEncoding() { xmlEncoding(this, result) }
|
||||||
@@ -200,7 +200,7 @@ class XMLDTD extends XMLLocatable, @xmldtd {
|
|||||||
*/
|
*/
|
||||||
class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
|
class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
|
||||||
/** Holds if this XML element has the given `name`. */
|
/** Holds if this XML element has the given `name`. */
|
||||||
predicate hasName(string name) { name = getName() }
|
predicate hasName(string name) { name = this.getName() }
|
||||||
|
|
||||||
/** Gets the name of this XML element. */
|
/** Gets the name of this XML element. */
|
||||||
override string getName() { xmlElements(this, result, _, _, _) }
|
override string getName() { xmlElements(this, result, _, _, _) }
|
||||||
@@ -239,7 +239,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
|
|||||||
string getAttributeValue(string name) { result = this.getAttribute(name).getValue() }
|
string getAttributeValue(string name) { result = this.getAttribute(name).getValue() }
|
||||||
|
|
||||||
/** Gets a printable representation of this XML element. */
|
/** Gets a printable representation of this XML element. */
|
||||||
override string toString() { result = getName() }
|
override string toString() { result = this.getName() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -10,44 +10,11 @@ import semmle.code.cpp.dataflow.DataFlow
|
|||||||
* char data[1]; // v
|
* char data[1]; // v
|
||||||
* };
|
* };
|
||||||
* ```
|
* ```
|
||||||
* This requires that `v` is an array of size 0 or 1, and `v` is the last member of `c`.
|
* This requires that `v` is an array of size 0 or 1.
|
||||||
* In addition, if the size of the structure is taken, there must be at least one instance
|
|
||||||
* where a `c` pointer is allocated with additional space.
|
|
||||||
* For example, holds for `c` if it occurs as
|
|
||||||
* ```
|
|
||||||
* malloc(sizeof(c) + 100 * sizeof(char))
|
|
||||||
* ```
|
|
||||||
* but not if it only ever occurs as
|
|
||||||
* ```
|
|
||||||
* malloc(sizeof(c))
|
|
||||||
* ```
|
|
||||||
*/
|
*/
|
||||||
predicate memberMayBeVarSize(Class c, MemberVariable v) {
|
predicate memberMayBeVarSize(Class c, MemberVariable v) {
|
||||||
exists(int i |
|
c = v.getDeclaringType() and
|
||||||
// `v` is the last field in `c`
|
v.getUnspecifiedType().(ArrayType).getArraySize() <= 1
|
||||||
i = max(int j | c.getCanonicalMember(j) instanceof Field | j) and
|
|
||||||
v = c.getCanonicalMember(i) and
|
|
||||||
// v is an array of size at most 1
|
|
||||||
v.getUnspecifiedType().(ArrayType).getArraySize() <= 1 and
|
|
||||||
not c instanceof Union
|
|
||||||
) and
|
|
||||||
// If the size is taken, then arithmetic is performed on the result at least once
|
|
||||||
(
|
|
||||||
// `sizeof(c)` is not taken
|
|
||||||
not exists(SizeofOperator so |
|
|
||||||
so.(SizeofTypeOperator).getTypeOperand().getUnspecifiedType() = c or
|
|
||||||
so.(SizeofExprOperator).getExprOperand().getUnspecifiedType() = c
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// or `sizeof(c)` is taken
|
|
||||||
exists(SizeofOperator so |
|
|
||||||
so.(SizeofTypeOperator).getTypeOperand().getUnspecifiedType() = c or
|
|
||||||
so.(SizeofExprOperator).getExprOperand().getUnspecifiedType() = c
|
|
||||||
|
|
|
||||||
// and arithmetic is performed on the result
|
|
||||||
so.getParent*() instanceof AddExpr
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -60,10 +27,6 @@ int getBufferSize(Expr bufferExpr, Element why) {
|
|||||||
result = bufferVar.getUnspecifiedType().(ArrayType).getSize() and
|
result = bufferVar.getUnspecifiedType().(ArrayType).getSize() and
|
||||||
why = bufferVar and
|
why = bufferVar and
|
||||||
not memberMayBeVarSize(_, bufferVar) and
|
not memberMayBeVarSize(_, bufferVar) and
|
||||||
not exists(Union bufferType |
|
|
||||||
bufferType.getAMemberVariable() = why and
|
|
||||||
bufferVar.getUnspecifiedType().(ArrayType).getSize() <= 1
|
|
||||||
) and
|
|
||||||
not result = 0 // zero sized arrays are likely to have special usage, for example
|
not result = 0 // zero sized arrays are likely to have special usage, for example
|
||||||
or
|
or
|
||||||
// behaving a bit like a 'union' overlapping other fields.
|
// behaving a bit like a 'union' overlapping other fields.
|
||||||
@@ -85,13 +48,6 @@ int getBufferSize(Expr bufferExpr, Element why) {
|
|||||||
parentPtr.getTarget().getUnspecifiedType().(PointerType).getBaseType() = parentClass and
|
parentPtr.getTarget().getUnspecifiedType().(PointerType).getBaseType() = parentClass and
|
||||||
result = getBufferSize(parentPtr, _) + bufferVar.getType().getSize() - parentClass.getSize()
|
result = getBufferSize(parentPtr, _) + bufferVar.getType().getSize() - parentClass.getSize()
|
||||||
)
|
)
|
||||||
or
|
|
||||||
exists(Union bufferType |
|
|
||||||
bufferType.getAMemberVariable() = why and
|
|
||||||
why = bufferVar and
|
|
||||||
bufferVar.getUnspecifiedType().(ArrayType).getSize() <= 1 and
|
|
||||||
result = bufferType.getSize()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// buffer is a fixed size dynamic allocation
|
// buffer is a fixed size dynamic allocation
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import cpp
|
import cpp
|
||||||
private import semmle.code.cpp.models.interfaces.ArrayFunction
|
private import semmle.code.cpp.models.interfaces.ArrayFunction
|
||||||
private import semmle.code.cpp.models.implementations.Strcat
|
private import semmle.code.cpp.models.implementations.Strcat
|
||||||
|
import semmle.code.cpp.dataflow.DataFlow
|
||||||
|
|
||||||
private predicate mayAddNullTerminatorHelper(Expr e, VariableAccess va, Expr e0) {
|
private predicate mayAddNullTerminatorHelper(Expr e, VariableAccess va, Expr e0) {
|
||||||
exists(StackVariable v0, Expr val |
|
exists(StackVariable v0, Expr val |
|
||||||
@@ -45,22 +46,28 @@ predicate mayAddNullTerminator(Expr e, VariableAccess va) {
|
|||||||
ae.getRValue().getAChild*() = va
|
ae.getRValue().getAChild*() = va
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// Function call: library function, varargs function, function
|
// Function calls...
|
||||||
// containing assembler code, or function where the relevant
|
|
||||||
// parameter is potentially added a null terminator.
|
|
||||||
exists(Call c, Function f, int i |
|
exists(Call c, Function f, int i |
|
||||||
e = c and
|
e = c and
|
||||||
f = c.getTarget() and
|
f = c.getTarget() and
|
||||||
not functionArgumentMustBeNullTerminated(f, i) and
|
not functionArgumentMustBeNullTerminated(f, i) and
|
||||||
c.getAnArgumentSubExpr(i) = va
|
c.getAnArgumentSubExpr(i) = va
|
||||||
|
|
|
|
||||||
not f.hasEntryPoint() and not functionArgumentMustBeNullTerminated(f, i)
|
// library function
|
||||||
|
not f.hasEntryPoint()
|
||||||
or
|
or
|
||||||
|
// function where the relevant parameter is potentially added a null terminator
|
||||||
mayAddNullTerminator(_, f.getParameter(i).getAnAccess())
|
mayAddNullTerminator(_, f.getParameter(i).getAnAccess())
|
||||||
or
|
or
|
||||||
|
// varargs function
|
||||||
f.isVarargs() and i >= f.getNumberOfParameters()
|
f.isVarargs() and i >= f.getNumberOfParameters()
|
||||||
or
|
or
|
||||||
|
// function containing assembler code
|
||||||
exists(AsmStmt s | s.getEnclosingFunction() = f)
|
exists(AsmStmt s | s.getEnclosingFunction() = f)
|
||||||
|
or
|
||||||
|
// function where the relevant parameter is returned (leaking it to be potentially null terminated elsewhere)
|
||||||
|
DataFlow::localFlow(DataFlow::parameterNode(f.getParameter(i)),
|
||||||
|
DataFlow::exprNode(any(ReturnStmt rs).getExpr()))
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
// Call without target (e.g., function pointer call)
|
// Call without target (e.g., function pointer call)
|
||||||
@@ -93,6 +100,15 @@ predicate variableMustBeNullTerminated(VariableAccess va) {
|
|||||||
fc.getArgument(i) = va
|
fc.getArgument(i) = va
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
|
// String argument to a formatting function (such as `printf`)
|
||||||
|
exists(int n, FormatLiteral fl |
|
||||||
|
fc.(FormattingFunctionCall).getConversionArgument(n) = va and
|
||||||
|
fl = fc.(FormattingFunctionCall).getFormat() and
|
||||||
|
fl.getConversionType(n) instanceof PointerType and // `%s`, `%ws` etc
|
||||||
|
not fl.getConversionType(n) instanceof VoidPointerType and // exclude: `%p`
|
||||||
|
not fl.hasPrecision(n) // exclude: `%.*s`
|
||||||
|
)
|
||||||
|
or
|
||||||
// Call to a wrapper function that requires null termination
|
// Call to a wrapper function that requires null termination
|
||||||
// (not itself adding a null terminator)
|
// (not itself adding a null terminator)
|
||||||
exists(Function wrapper, int i, Parameter p, VariableAccess use |
|
exists(Function wrapper, int i, Parameter p, VariableAccess use |
|
||||||
|
|||||||
@@ -253,6 +253,21 @@ class FormattingFunctionCall extends Expr {
|
|||||||
// format arguments must be known
|
// format arguments must be known
|
||||||
exists(getTarget().(FormattingFunction).getFirstFormatArgumentIndex())
|
exists(getTarget().(FormattingFunction).getFirstFormatArgumentIndex())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the argument, if any, to which the output is written. If `isStream` is
|
||||||
|
* `true`, the output argument is a stream (that is, this call behaves like
|
||||||
|
* `fprintf`). If `isStream` is `false`, the output argument is a buffer (that
|
||||||
|
* is, this call behaves like `sprintf`)
|
||||||
|
*/
|
||||||
|
Expr getOutputArgument(boolean isStream) {
|
||||||
|
result =
|
||||||
|
this.(Call)
|
||||||
|
.getArgument(this.(Call)
|
||||||
|
.getTarget()
|
||||||
|
.(FormattingFunction)
|
||||||
|
.getOutputParameterIndex(isStream))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ class BasicBlock extends ControlFlowNodeBase {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*
|
*
|
||||||
* Yields no result if this basic block spans multiple source files.
|
* Yields no result if this basic block spans multiple source files.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -344,14 +344,13 @@ private int convertIntToType(int val, IntegralType t) {
|
|||||||
then if val = 0 then result = 0 else result = 1
|
then if val = 0 then result = 0 else result = 1
|
||||||
else
|
else
|
||||||
if t.isUnsigned()
|
if t.isUnsigned()
|
||||||
then if val >= 0 and val.bitShiftRight(t.getSize() * 8) = 0 then result = val else none()
|
then val >= 0 and val.bitShiftRight(t.getSize() * 8) = 0 and result = val
|
||||||
else
|
else
|
||||||
if val >= 0 and val.bitShiftRight(t.getSize() * 8 - 1) = 0
|
if val >= 0 and val.bitShiftRight(t.getSize() * 8 - 1) = 0
|
||||||
then result = val
|
then result = val
|
||||||
else
|
else (
|
||||||
if (-(val + 1)).bitShiftRight(t.getSize() * 8 - 1) = 0
|
(-(val + 1)).bitShiftRight(t.getSize() * 8 - 1) = 0 and result = val
|
||||||
then result = val
|
)
|
||||||
else none()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -2139,7 +2139,8 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
|||||||
) and
|
) and
|
||||||
accessPathApproxCostLimits(apLimit, tupleLimit) and
|
accessPathApproxCostLimits(apLimit, tupleLimit) and
|
||||||
apLimit < tails and
|
apLimit < tails and
|
||||||
tupleLimit < (tails - 1) * nodes
|
tupleLimit < (tails - 1) * nodes and
|
||||||
|
not tc.forceHighPrecision()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2973,12 +2974,15 @@ private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
|||||||
* expected to be expensive. Holds with `unfold = true` otherwise.
|
* expected to be expensive. Holds with `unfold = true` otherwise.
|
||||||
*/
|
*/
|
||||||
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
|
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
|
||||||
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
if apa.getHead().forceHighPrecision()
|
||||||
aps = countPotentialAps(apa, config) and
|
then unfold = true
|
||||||
nodes = countNodesUsingAccessPath(apa, config) and
|
else
|
||||||
accessPathCostLimits(apLimit, tupleLimit) and
|
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
||||||
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
aps = countPotentialAps(apa, config) and
|
||||||
)
|
nodes = countNodesUsingAccessPath(apa, config) and
|
||||||
|
accessPathCostLimits(apLimit, tupleLimit) and
|
||||||
|
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -3248,7 +3252,7 @@ class PathNode extends TPathNode {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
@@ -4033,7 +4037,7 @@ private module FlowExploration {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
|||||||
@@ -2139,7 +2139,8 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
|||||||
) and
|
) and
|
||||||
accessPathApproxCostLimits(apLimit, tupleLimit) and
|
accessPathApproxCostLimits(apLimit, tupleLimit) and
|
||||||
apLimit < tails and
|
apLimit < tails and
|
||||||
tupleLimit < (tails - 1) * nodes
|
tupleLimit < (tails - 1) * nodes and
|
||||||
|
not tc.forceHighPrecision()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2973,12 +2974,15 @@ private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
|||||||
* expected to be expensive. Holds with `unfold = true` otherwise.
|
* expected to be expensive. Holds with `unfold = true` otherwise.
|
||||||
*/
|
*/
|
||||||
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
|
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
|
||||||
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
if apa.getHead().forceHighPrecision()
|
||||||
aps = countPotentialAps(apa, config) and
|
then unfold = true
|
||||||
nodes = countNodesUsingAccessPath(apa, config) and
|
else
|
||||||
accessPathCostLimits(apLimit, tupleLimit) and
|
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
||||||
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
aps = countPotentialAps(apa, config) and
|
||||||
)
|
nodes = countNodesUsingAccessPath(apa, config) and
|
||||||
|
accessPathCostLimits(apLimit, tupleLimit) and
|
||||||
|
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -3248,7 +3252,7 @@ class PathNode extends TPathNode {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
@@ -4033,7 +4037,7 @@ private module FlowExploration {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
|||||||
@@ -2139,7 +2139,8 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
|||||||
) and
|
) and
|
||||||
accessPathApproxCostLimits(apLimit, tupleLimit) and
|
accessPathApproxCostLimits(apLimit, tupleLimit) and
|
||||||
apLimit < tails and
|
apLimit < tails and
|
||||||
tupleLimit < (tails - 1) * nodes
|
tupleLimit < (tails - 1) * nodes and
|
||||||
|
not tc.forceHighPrecision()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2973,12 +2974,15 @@ private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
|||||||
* expected to be expensive. Holds with `unfold = true` otherwise.
|
* expected to be expensive. Holds with `unfold = true` otherwise.
|
||||||
*/
|
*/
|
||||||
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
|
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
|
||||||
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
if apa.getHead().forceHighPrecision()
|
||||||
aps = countPotentialAps(apa, config) and
|
then unfold = true
|
||||||
nodes = countNodesUsingAccessPath(apa, config) and
|
else
|
||||||
accessPathCostLimits(apLimit, tupleLimit) and
|
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
||||||
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
aps = countPotentialAps(apa, config) and
|
||||||
)
|
nodes = countNodesUsingAccessPath(apa, config) and
|
||||||
|
accessPathCostLimits(apLimit, tupleLimit) and
|
||||||
|
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -3248,7 +3252,7 @@ class PathNode extends TPathNode {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
@@ -4033,7 +4037,7 @@ private module FlowExploration {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
|||||||
@@ -2139,7 +2139,8 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
|||||||
) and
|
) and
|
||||||
accessPathApproxCostLimits(apLimit, tupleLimit) and
|
accessPathApproxCostLimits(apLimit, tupleLimit) and
|
||||||
apLimit < tails and
|
apLimit < tails and
|
||||||
tupleLimit < (tails - 1) * nodes
|
tupleLimit < (tails - 1) * nodes and
|
||||||
|
not tc.forceHighPrecision()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2973,12 +2974,15 @@ private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
|||||||
* expected to be expensive. Holds with `unfold = true` otherwise.
|
* expected to be expensive. Holds with `unfold = true` otherwise.
|
||||||
*/
|
*/
|
||||||
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
|
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
|
||||||
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
if apa.getHead().forceHighPrecision()
|
||||||
aps = countPotentialAps(apa, config) and
|
then unfold = true
|
||||||
nodes = countNodesUsingAccessPath(apa, config) and
|
else
|
||||||
accessPathCostLimits(apLimit, tupleLimit) and
|
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
||||||
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
aps = countPotentialAps(apa, config) and
|
||||||
)
|
nodes = countNodesUsingAccessPath(apa, config) and
|
||||||
|
accessPathCostLimits(apLimit, tupleLimit) and
|
||||||
|
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -3248,7 +3252,7 @@ class PathNode extends TPathNode {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
@@ -4033,7 +4037,7 @@ private module FlowExploration {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
|||||||
@@ -937,7 +937,7 @@ class CallContextSpecificCall extends CallContextCall, TSpecificCall {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override predicate relevantFor(DataFlowCallable callable) {
|
override predicate relevantFor(DataFlowCallable callable) {
|
||||||
recordDataFlowCallSite(getCall(), callable)
|
recordDataFlowCallSite(this.getCall(), callable)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate matchesCall(DataFlowCall call) { call = this.getCall() }
|
override predicate matchesCall(DataFlowCall call) { call = this.getCall() }
|
||||||
@@ -1236,6 +1236,13 @@ class TypedContent extends MkTypedContent {
|
|||||||
|
|
||||||
/** Gets a textual representation of this content. */
|
/** Gets a textual representation of this content. */
|
||||||
string toString() { result = c.toString() }
|
string toString() { result = c.toString() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if access paths with this `TypedContent` at their head always should
|
||||||
|
* be tracked at high precision. This disables adaptive access path precision
|
||||||
|
* for such access paths.
|
||||||
|
*/
|
||||||
|
predicate forceHighPrecision() { forceHighPrecision(c) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1250,7 +1257,7 @@ abstract class AccessPathFront extends TAccessPathFront {
|
|||||||
|
|
||||||
TypedContent getHead() { this = TFrontHead(result) }
|
TypedContent getHead() { this = TFrontHead(result) }
|
||||||
|
|
||||||
predicate isClearedAt(Node n) { clearsContentCached(n, getHead().getContent()) }
|
predicate isClearedAt(Node n) { clearsContentCached(n, this.getHead().getContent()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
|
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
|
||||||
|
|||||||
@@ -2139,7 +2139,8 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
|||||||
) and
|
) and
|
||||||
accessPathApproxCostLimits(apLimit, tupleLimit) and
|
accessPathApproxCostLimits(apLimit, tupleLimit) and
|
||||||
apLimit < tails and
|
apLimit < tails and
|
||||||
tupleLimit < (tails - 1) * nodes
|
tupleLimit < (tails - 1) * nodes and
|
||||||
|
not tc.forceHighPrecision()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2973,12 +2974,15 @@ private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
|||||||
* expected to be expensive. Holds with `unfold = true` otherwise.
|
* expected to be expensive. Holds with `unfold = true` otherwise.
|
||||||
*/
|
*/
|
||||||
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
|
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
|
||||||
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
if apa.getHead().forceHighPrecision()
|
||||||
aps = countPotentialAps(apa, config) and
|
then unfold = true
|
||||||
nodes = countNodesUsingAccessPath(apa, config) and
|
else
|
||||||
accessPathCostLimits(apLimit, tupleLimit) and
|
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
||||||
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
aps = countPotentialAps(apa, config) and
|
||||||
)
|
nodes = countNodesUsingAccessPath(apa, config) and
|
||||||
|
accessPathCostLimits(apLimit, tupleLimit) and
|
||||||
|
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -3248,7 +3252,7 @@ class PathNode extends TPathNode {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
@@ -4033,7 +4037,7 @@ private module FlowExploration {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
|||||||
@@ -219,15 +219,13 @@ class DataFlowExpr = Expr;
|
|||||||
class DataFlowType = Type;
|
class DataFlowType = Type;
|
||||||
|
|
||||||
/** A function call relevant for data flow. */
|
/** A function call relevant for data flow. */
|
||||||
class DataFlowCall extends Expr {
|
class DataFlowCall extends Expr instanceof Call {
|
||||||
DataFlowCall() { this instanceof Call }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the nth argument for this call.
|
* Gets the nth argument for this call.
|
||||||
*
|
*
|
||||||
* The range of `n` is from `0` to `getNumberOfArguments() - 1`.
|
* The range of `n` is from `0` to `getNumberOfArguments() - 1`.
|
||||||
*/
|
*/
|
||||||
Expr getArgument(int n) { result = this.(Call).getArgument(n) }
|
Expr getArgument(int n) { result = super.getArgument(n) }
|
||||||
|
|
||||||
/** Gets the data flow node corresponding to this call. */
|
/** Gets the data flow node corresponding to this call. */
|
||||||
ExprNode getNode() { result.getExpr() = this }
|
ExprNode getNode() { result.getExpr() = this }
|
||||||
@@ -240,6 +238,12 @@ predicate isUnreachableInCall(Node n, DataFlowCall call) { none() } // stub impl
|
|||||||
|
|
||||||
int accessPathLimit() { result = 5 }
|
int accessPathLimit() { result = 5 }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if access paths with `c` at their head always should be tracked at high
|
||||||
|
* precision. This disables adaptive access path precision for such access paths.
|
||||||
|
*/
|
||||||
|
predicate forceHighPrecision(Content c) { none() }
|
||||||
|
|
||||||
/** The unit type. */
|
/** The unit type. */
|
||||||
private newtype TUnit = TMkUnit()
|
private newtype TUnit = TMkUnit()
|
||||||
|
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ class Node extends TNode {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
|||||||
@@ -75,24 +75,26 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
final override predicate isBarrier(DataFlow::Node node) {
|
final override predicate isBarrier(DataFlow::Node node) {
|
||||||
isSanitizer(node) or
|
this.isSanitizer(node) or
|
||||||
defaultTaintSanitizer(node)
|
defaultTaintSanitizer(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if taint propagation into `node` is prohibited. */
|
/** Holds if taint propagation into `node` is prohibited. */
|
||||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) }
|
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
||||||
|
|
||||||
/** Holds if taint propagation out of `node` is prohibited. */
|
/** Holds if taint propagation out of `node` is prohibited. */
|
||||||
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) }
|
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||||
|
|
||||||
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||||
|
|
||||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) }
|
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||||
|
this.isSanitizerGuard(guard)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the additional taint propagation step from `node1` to `node2`
|
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||||
@@ -101,7 +103,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||||
|
|
||||||
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||||
isAdditionalTaintStep(node1, node2) or
|
this.isAdditionalTaintStep(node1, node2) or
|
||||||
defaultAdditionalTaintStep(node1, node2)
|
defaultAdditionalTaintStep(node1, node2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,24 +75,26 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
final override predicate isBarrier(DataFlow::Node node) {
|
final override predicate isBarrier(DataFlow::Node node) {
|
||||||
isSanitizer(node) or
|
this.isSanitizer(node) or
|
||||||
defaultTaintSanitizer(node)
|
defaultTaintSanitizer(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if taint propagation into `node` is prohibited. */
|
/** Holds if taint propagation into `node` is prohibited. */
|
||||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) }
|
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
||||||
|
|
||||||
/** Holds if taint propagation out of `node` is prohibited. */
|
/** Holds if taint propagation out of `node` is prohibited. */
|
||||||
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) }
|
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||||
|
|
||||||
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||||
|
|
||||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) }
|
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||||
|
this.isSanitizerGuard(guard)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the additional taint propagation step from `node1` to `node2`
|
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||||
@@ -101,7 +103,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||||
|
|
||||||
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||||
isAdditionalTaintStep(node1, node2) or
|
this.isAdditionalTaintStep(node1, node2) or
|
||||||
defaultAdditionalTaintStep(node1, node2)
|
defaultAdditionalTaintStep(node1, node2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ private import semmle.code.cpp.ir.dataflow.DataFlow
|
|||||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||||
private import semmle.code.cpp.ir.dataflow.DataFlow3
|
private import semmle.code.cpp.ir.dataflow.DataFlow3
|
||||||
private import semmle.code.cpp.ir.IR
|
private import semmle.code.cpp.ir.IR
|
||||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowDispatch as Dispatch
|
private import semmle.code.cpp.ir.dataflow.ResolveCall
|
||||||
private import semmle.code.cpp.controlflow.IRGuards
|
private import semmle.code.cpp.controlflow.IRGuards
|
||||||
private import semmle.code.cpp.models.interfaces.Taint
|
private import semmle.code.cpp.models.interfaces.Taint
|
||||||
private import semmle.code.cpp.models.interfaces.DataFlow
|
private import semmle.code.cpp.models.interfaces.DataFlow
|
||||||
@@ -355,20 +355,6 @@ predicate taintedIncludingGlobalVars(Expr source, Element tainted, string global
|
|||||||
*/
|
*/
|
||||||
GlobalOrNamespaceVariable globalVarFromId(string id) { id = result.getQualifiedName() }
|
GlobalOrNamespaceVariable globalVarFromId(string id) { id = result.getQualifiedName() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolve potential target function(s) for `call`.
|
|
||||||
*
|
|
||||||
* If `call` is a call through a function pointer (`ExprCall`) or
|
|
||||||
* targets a virtual method, simple data flow analysis is performed
|
|
||||||
* in order to identify target(s).
|
|
||||||
*/
|
|
||||||
Function resolveCall(Call call) {
|
|
||||||
exists(CallInstruction callInstruction |
|
|
||||||
callInstruction.getAST() = call and
|
|
||||||
result = Dispatch::viableCallable(callInstruction)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides definitions for augmenting source/sink pairs with data-flow paths
|
* Provides definitions for augmenting source/sink pairs with data-flow paths
|
||||||
* between them. From a `@kind path-problem` query, import this module in the
|
* between them. From a `@kind path-problem` query, import this module in the
|
||||||
@@ -479,7 +465,7 @@ module TaintedWithPath {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
|||||||
23
cpp/ql/lib/semmle/code/cpp/ir/dataflow/ResolveCall.qll
Normal file
23
cpp/ql/lib/semmle/code/cpp/ir/dataflow/ResolveCall.qll
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* Provides a predicate for non-contextual virtual dispatch and function
|
||||||
|
* pointer resolution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import cpp
|
||||||
|
private import semmle.code.cpp.ir.ValueNumbering
|
||||||
|
private import internal.DataFlowDispatch
|
||||||
|
private import semmle.code.cpp.ir.IR
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve potential target function(s) for `call`.
|
||||||
|
*
|
||||||
|
* If `call` is a call through a function pointer (`ExprCall`) or its target is
|
||||||
|
* a virtual member function, simple data flow analysis is performed in order
|
||||||
|
* to identify the possible target(s).
|
||||||
|
*/
|
||||||
|
Function resolveCall(Call call) {
|
||||||
|
exists(CallInstruction callInstruction |
|
||||||
|
callInstruction.getAST() = call and
|
||||||
|
result = viableCallable(callInstruction)
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -2139,7 +2139,8 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
|||||||
) and
|
) and
|
||||||
accessPathApproxCostLimits(apLimit, tupleLimit) and
|
accessPathApproxCostLimits(apLimit, tupleLimit) and
|
||||||
apLimit < tails and
|
apLimit < tails and
|
||||||
tupleLimit < (tails - 1) * nodes
|
tupleLimit < (tails - 1) * nodes and
|
||||||
|
not tc.forceHighPrecision()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2973,12 +2974,15 @@ private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
|||||||
* expected to be expensive. Holds with `unfold = true` otherwise.
|
* expected to be expensive. Holds with `unfold = true` otherwise.
|
||||||
*/
|
*/
|
||||||
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
|
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
|
||||||
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
if apa.getHead().forceHighPrecision()
|
||||||
aps = countPotentialAps(apa, config) and
|
then unfold = true
|
||||||
nodes = countNodesUsingAccessPath(apa, config) and
|
else
|
||||||
accessPathCostLimits(apLimit, tupleLimit) and
|
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
||||||
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
aps = countPotentialAps(apa, config) and
|
||||||
)
|
nodes = countNodesUsingAccessPath(apa, config) and
|
||||||
|
accessPathCostLimits(apLimit, tupleLimit) and
|
||||||
|
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -3248,7 +3252,7 @@ class PathNode extends TPathNode {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
@@ -4033,7 +4037,7 @@ private module FlowExploration {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
|||||||
@@ -2139,7 +2139,8 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
|||||||
) and
|
) and
|
||||||
accessPathApproxCostLimits(apLimit, tupleLimit) and
|
accessPathApproxCostLimits(apLimit, tupleLimit) and
|
||||||
apLimit < tails and
|
apLimit < tails and
|
||||||
tupleLimit < (tails - 1) * nodes
|
tupleLimit < (tails - 1) * nodes and
|
||||||
|
not tc.forceHighPrecision()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2973,12 +2974,15 @@ private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
|||||||
* expected to be expensive. Holds with `unfold = true` otherwise.
|
* expected to be expensive. Holds with `unfold = true` otherwise.
|
||||||
*/
|
*/
|
||||||
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
|
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
|
||||||
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
if apa.getHead().forceHighPrecision()
|
||||||
aps = countPotentialAps(apa, config) and
|
then unfold = true
|
||||||
nodes = countNodesUsingAccessPath(apa, config) and
|
else
|
||||||
accessPathCostLimits(apLimit, tupleLimit) and
|
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
||||||
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
aps = countPotentialAps(apa, config) and
|
||||||
)
|
nodes = countNodesUsingAccessPath(apa, config) and
|
||||||
|
accessPathCostLimits(apLimit, tupleLimit) and
|
||||||
|
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -3248,7 +3252,7 @@ class PathNode extends TPathNode {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
@@ -4033,7 +4037,7 @@ private module FlowExploration {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
|||||||
@@ -2139,7 +2139,8 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
|||||||
) and
|
) and
|
||||||
accessPathApproxCostLimits(apLimit, tupleLimit) and
|
accessPathApproxCostLimits(apLimit, tupleLimit) and
|
||||||
apLimit < tails and
|
apLimit < tails and
|
||||||
tupleLimit < (tails - 1) * nodes
|
tupleLimit < (tails - 1) * nodes and
|
||||||
|
not tc.forceHighPrecision()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2973,12 +2974,15 @@ private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
|||||||
* expected to be expensive. Holds with `unfold = true` otherwise.
|
* expected to be expensive. Holds with `unfold = true` otherwise.
|
||||||
*/
|
*/
|
||||||
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
|
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
|
||||||
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
if apa.getHead().forceHighPrecision()
|
||||||
aps = countPotentialAps(apa, config) and
|
then unfold = true
|
||||||
nodes = countNodesUsingAccessPath(apa, config) and
|
else
|
||||||
accessPathCostLimits(apLimit, tupleLimit) and
|
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
||||||
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
aps = countPotentialAps(apa, config) and
|
||||||
)
|
nodes = countNodesUsingAccessPath(apa, config) and
|
||||||
|
accessPathCostLimits(apLimit, tupleLimit) and
|
||||||
|
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -3248,7 +3252,7 @@ class PathNode extends TPathNode {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
@@ -4033,7 +4037,7 @@ private module FlowExploration {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
|||||||
@@ -2139,7 +2139,8 @@ private predicate expensiveLen2unfolding(TypedContent tc, Configuration config)
|
|||||||
) and
|
) and
|
||||||
accessPathApproxCostLimits(apLimit, tupleLimit) and
|
accessPathApproxCostLimits(apLimit, tupleLimit) and
|
||||||
apLimit < tails and
|
apLimit < tails and
|
||||||
tupleLimit < (tails - 1) * nodes
|
tupleLimit < (tails - 1) * nodes and
|
||||||
|
not tc.forceHighPrecision()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2973,12 +2974,15 @@ private AccessPathApprox getATail(AccessPathApprox apa, Configuration config) {
|
|||||||
* expected to be expensive. Holds with `unfold = true` otherwise.
|
* expected to be expensive. Holds with `unfold = true` otherwise.
|
||||||
*/
|
*/
|
||||||
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
|
private predicate evalUnfold(AccessPathApprox apa, boolean unfold, Configuration config) {
|
||||||
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
if apa.getHead().forceHighPrecision()
|
||||||
aps = countPotentialAps(apa, config) and
|
then unfold = true
|
||||||
nodes = countNodesUsingAccessPath(apa, config) and
|
else
|
||||||
accessPathCostLimits(apLimit, tupleLimit) and
|
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
||||||
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
aps = countPotentialAps(apa, config) and
|
||||||
)
|
nodes = countNodesUsingAccessPath(apa, config) and
|
||||||
|
accessPathCostLimits(apLimit, tupleLimit) and
|
||||||
|
if apLimit < aps and tupleLimit < (aps - 1) * nodes then unfold = false else unfold = true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -3248,7 +3252,7 @@ class PathNode extends TPathNode {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
@@ -4033,7 +4037,7 @@ private module FlowExploration {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
|||||||
@@ -937,7 +937,7 @@ class CallContextSpecificCall extends CallContextCall, TSpecificCall {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override predicate relevantFor(DataFlowCallable callable) {
|
override predicate relevantFor(DataFlowCallable callable) {
|
||||||
recordDataFlowCallSite(getCall(), callable)
|
recordDataFlowCallSite(this.getCall(), callable)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate matchesCall(DataFlowCall call) { call = this.getCall() }
|
override predicate matchesCall(DataFlowCall call) { call = this.getCall() }
|
||||||
@@ -1236,6 +1236,13 @@ class TypedContent extends MkTypedContent {
|
|||||||
|
|
||||||
/** Gets a textual representation of this content. */
|
/** Gets a textual representation of this content. */
|
||||||
string toString() { result = c.toString() }
|
string toString() { result = c.toString() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if access paths with this `TypedContent` at their head always should
|
||||||
|
* be tracked at high precision. This disables adaptive access path precision
|
||||||
|
* for such access paths.
|
||||||
|
*/
|
||||||
|
predicate forceHighPrecision() { forceHighPrecision(c) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1250,7 +1257,7 @@ abstract class AccessPathFront extends TAccessPathFront {
|
|||||||
|
|
||||||
TypedContent getHead() { this = TFrontHead(result) }
|
TypedContent getHead() { this = TFrontHead(result) }
|
||||||
|
|
||||||
predicate isClearedAt(Node n) { clearsContentCached(n, getHead().getContent()) }
|
predicate isClearedAt(Node n) { clearsContentCached(n, this.getHead().getContent()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
|
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
|
||||||
|
|||||||
@@ -466,6 +466,12 @@ predicate isUnreachableInCall(Node n, DataFlowCall call) { none() } // stub impl
|
|||||||
|
|
||||||
int accessPathLimit() { result = 5 }
|
int accessPathLimit() { result = 5 }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if access paths with `c` at their head always should be tracked at high
|
||||||
|
* precision. This disables adaptive access path precision for such access paths.
|
||||||
|
*/
|
||||||
|
predicate forceHighPrecision(Content c) { none() }
|
||||||
|
|
||||||
/** The unit type. */
|
/** The unit type. */
|
||||||
private newtype TUnit = TMkUnit()
|
private newtype TUnit = TMkUnit()
|
||||||
|
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ class Node extends TIRDataFlowNode {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
|||||||
@@ -38,5 +38,8 @@ Instruction callOutput(CallInstruction call, FunctionOutput output) {
|
|||||||
effect.getPrimaryInstruction() = call and
|
effect.getPrimaryInstruction() = call and
|
||||||
output.isParameterDerefOrQualifierObject(effect.getIndex())
|
output.isParameterDerefOrQualifierObject(effect.getIndex())
|
||||||
)
|
)
|
||||||
// TODO: return value dereference
|
or
|
||||||
|
// TODO: modify this when we get return value dereferences
|
||||||
|
result = call and
|
||||||
|
output.isReturnValueDeref()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,24 +75,26 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
final override predicate isBarrier(DataFlow::Node node) {
|
final override predicate isBarrier(DataFlow::Node node) {
|
||||||
isSanitizer(node) or
|
this.isSanitizer(node) or
|
||||||
defaultTaintSanitizer(node)
|
defaultTaintSanitizer(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if taint propagation into `node` is prohibited. */
|
/** Holds if taint propagation into `node` is prohibited. */
|
||||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) }
|
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
||||||
|
|
||||||
/** Holds if taint propagation out of `node` is prohibited. */
|
/** Holds if taint propagation out of `node` is prohibited. */
|
||||||
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) }
|
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||||
|
|
||||||
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||||
|
|
||||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) }
|
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||||
|
this.isSanitizerGuard(guard)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the additional taint propagation step from `node1` to `node2`
|
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||||
@@ -101,7 +103,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||||
|
|
||||||
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||||
isAdditionalTaintStep(node1, node2) or
|
this.isAdditionalTaintStep(node1, node2) or
|
||||||
defaultAdditionalTaintStep(node1, node2)
|
defaultAdditionalTaintStep(node1, node2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,24 +75,26 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
final override predicate isBarrier(DataFlow::Node node) {
|
final override predicate isBarrier(DataFlow::Node node) {
|
||||||
isSanitizer(node) or
|
this.isSanitizer(node) or
|
||||||
defaultTaintSanitizer(node)
|
defaultTaintSanitizer(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if taint propagation into `node` is prohibited. */
|
/** Holds if taint propagation into `node` is prohibited. */
|
||||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) }
|
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
||||||
|
|
||||||
/** Holds if taint propagation out of `node` is prohibited. */
|
/** Holds if taint propagation out of `node` is prohibited. */
|
||||||
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) }
|
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||||
|
|
||||||
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||||
|
|
||||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) }
|
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||||
|
this.isSanitizerGuard(guard)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the additional taint propagation step from `node1` to `node2`
|
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||||
@@ -101,7 +103,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||||
|
|
||||||
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||||
isAdditionalTaintStep(node1, node2) or
|
this.isAdditionalTaintStep(node1, node2) or
|
||||||
defaultAdditionalTaintStep(node1, node2)
|
defaultAdditionalTaintStep(node1, node2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,24 +75,26 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
final override predicate isBarrier(DataFlow::Node node) {
|
final override predicate isBarrier(DataFlow::Node node) {
|
||||||
isSanitizer(node) or
|
this.isSanitizer(node) or
|
||||||
defaultTaintSanitizer(node)
|
defaultTaintSanitizer(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Holds if taint propagation into `node` is prohibited. */
|
/** Holds if taint propagation into `node` is prohibited. */
|
||||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) }
|
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
|
||||||
|
|
||||||
/** Holds if taint propagation out of `node` is prohibited. */
|
/** Holds if taint propagation out of `node` is prohibited. */
|
||||||
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
||||||
|
|
||||||
final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) }
|
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
||||||
|
|
||||||
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
|
||||||
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
|
||||||
|
|
||||||
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) }
|
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||||
|
this.isSanitizerGuard(guard)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the additional taint propagation step from `node1` to `node2`
|
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||||
@@ -101,7 +103,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||||
|
|
||||||
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||||
isAdditionalTaintStep(node1, node2) or
|
this.isAdditionalTaintStep(node1, node2) or
|
||||||
defaultAdditionalTaintStep(node1, node2)
|
defaultAdditionalTaintStep(node1, node2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class IRBlockBase extends TIRBlock {
|
|||||||
final string toString() { result = getFirstInstruction(this).toString() }
|
final string toString() { result = getFirstInstruction(this).toString() }
|
||||||
|
|
||||||
/** Gets the source location of the first non-`Phi` instruction in this block. */
|
/** Gets the source location of the first non-`Phi` instruction in this block. */
|
||||||
final Language::Location getLocation() { result = getFirstInstruction().getLocation() }
|
final Language::Location getLocation() { result = this.getFirstInstruction().getLocation() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* INTERNAL: Do not use.
|
* INTERNAL: Do not use.
|
||||||
@@ -39,7 +39,7 @@ class IRBlockBase extends TIRBlock {
|
|||||||
) and
|
) and
|
||||||
this =
|
this =
|
||||||
rank[result + 1](IRBlock funcBlock, int sortOverride, int sortKey1, int sortKey2 |
|
rank[result + 1](IRBlock funcBlock, int sortOverride, int sortKey1, int sortKey2 |
|
||||||
funcBlock.getEnclosingFunction() = getEnclosingFunction() and
|
funcBlock.getEnclosingFunction() = this.getEnclosingFunction() and
|
||||||
funcBlock.getFirstInstruction().hasSortKeys(sortKey1, sortKey2) and
|
funcBlock.getFirstInstruction().hasSortKeys(sortKey1, sortKey2) and
|
||||||
// Ensure that the block containing `EnterFunction` always comes first.
|
// Ensure that the block containing `EnterFunction` always comes first.
|
||||||
if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction
|
if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction
|
||||||
@@ -59,15 +59,15 @@ class IRBlockBase extends TIRBlock {
|
|||||||
* Get the `Phi` instructions that appear at the start of this block.
|
* Get the `Phi` instructions that appear at the start of this block.
|
||||||
*/
|
*/
|
||||||
final PhiInstruction getAPhiInstruction() {
|
final PhiInstruction getAPhiInstruction() {
|
||||||
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
|
Construction::getPhiInstructionBlockStart(result) = this.getFirstInstruction()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets an instruction in this block. This includes `Phi` instructions.
|
* Gets an instruction in this block. This includes `Phi` instructions.
|
||||||
*/
|
*/
|
||||||
final Instruction getAnInstruction() {
|
final Instruction getAnInstruction() {
|
||||||
result = getInstruction(_) or
|
result = this.getInstruction(_) or
|
||||||
result = getAPhiInstruction()
|
result = this.getAPhiInstruction()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -78,7 +78,9 @@ class IRBlockBase extends TIRBlock {
|
|||||||
/**
|
/**
|
||||||
* Gets the last instruction in this block.
|
* Gets the last instruction in this block.
|
||||||
*/
|
*/
|
||||||
final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) }
|
final Instruction getLastInstruction() {
|
||||||
|
result = this.getInstruction(this.getInstructionCount() - 1)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the number of non-`Phi` instructions in this block.
|
* Gets the number of non-`Phi` instructions in this block.
|
||||||
@@ -149,7 +151,7 @@ class IRBlock extends IRBlockBase {
|
|||||||
* Block `A` dominates block `B` if any control flow path from the entry block of the function to
|
* Block `A` dominates block `B` if any control flow path from the entry block of the function to
|
||||||
* block `B` must pass through block `A`. A block always dominates itself.
|
* block `B` must pass through block `A`. A block always dominates itself.
|
||||||
*/
|
*/
|
||||||
final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block }
|
final predicate dominates(IRBlock block) { this.strictlyDominates(block) or this = block }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a block on the dominance frontier of this block.
|
* Gets a block on the dominance frontier of this block.
|
||||||
@@ -159,8 +161,8 @@ class IRBlock extends IRBlockBase {
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
final IRBlock dominanceFrontier() {
|
final IRBlock dominanceFrontier() {
|
||||||
dominates(result.getAPredecessor()) and
|
this.dominates(result.getAPredecessor()) and
|
||||||
not strictlyDominates(result)
|
not this.strictlyDominates(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -189,7 +191,7 @@ class IRBlock extends IRBlockBase {
|
|||||||
* Block `A` post-dominates block `B` if any control flow path from `B` to the exit block of the
|
* Block `A` post-dominates block `B` if any control flow path from `B` to the exit block of the
|
||||||
* function must pass through block `A`. A block always post-dominates itself.
|
* function must pass through block `A`. A block always post-dominates itself.
|
||||||
*/
|
*/
|
||||||
final predicate postDominates(IRBlock block) { strictlyPostDominates(block) or this = block }
|
final predicate postDominates(IRBlock block) { this.strictlyPostDominates(block) or this = block }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a block on the post-dominance frontier of this block.
|
* Gets a block on the post-dominance frontier of this block.
|
||||||
@@ -199,16 +201,16 @@ class IRBlock extends IRBlockBase {
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
final IRBlock postPominanceFrontier() {
|
final IRBlock postPominanceFrontier() {
|
||||||
postDominates(result.getASuccessor()) and
|
this.postDominates(result.getASuccessor()) and
|
||||||
not strictlyPostDominates(result)
|
not this.strictlyPostDominates(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if this block is reachable from the entry block of its function.
|
* Holds if this block is reachable from the entry block of its function.
|
||||||
*/
|
*/
|
||||||
final predicate isReachableFromFunctionEntry() {
|
final predicate isReachableFromFunctionEntry() {
|
||||||
this = getEnclosingIRFunction().getEntryBlock() or
|
this = this.getEnclosingIRFunction().getEntryBlock() or
|
||||||
getAPredecessor().isReachableFromFunctionEntry()
|
this.getAPredecessor().isReachableFromFunctionEntry()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -46,12 +46,12 @@ class Operand extends TStageOperand {
|
|||||||
/**
|
/**
|
||||||
* Gets the location of the source code for this operand.
|
* Gets the location of the source code for this operand.
|
||||||
*/
|
*/
|
||||||
final Language::Location getLocation() { result = getUse().getLocation() }
|
final Language::Location getLocation() { result = this.getUse().getLocation() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the function that contains this operand.
|
* Gets the function that contains this operand.
|
||||||
*/
|
*/
|
||||||
final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() }
|
final IRFunction getEnclosingIRFunction() { result = this.getUse().getEnclosingIRFunction() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the `Instruction` that consumes this operand.
|
* Gets the `Instruction` that consumes this operand.
|
||||||
@@ -74,7 +74,7 @@ class Operand extends TStageOperand {
|
|||||||
*/
|
*/
|
||||||
final Instruction getDef() {
|
final Instruction getDef() {
|
||||||
result = this.getAnyDef() and
|
result = this.getAnyDef() and
|
||||||
getDefinitionOverlap() instanceof MustExactlyOverlap
|
this.getDefinitionOverlap() instanceof MustExactlyOverlap
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -82,7 +82,7 @@ class Operand extends TStageOperand {
|
|||||||
*
|
*
|
||||||
* Gets the `Instruction` that consumes this operand.
|
* Gets the `Instruction` that consumes this operand.
|
||||||
*/
|
*/
|
||||||
deprecated final Instruction getUseInstruction() { result = getUse() }
|
deprecated final Instruction getUseInstruction() { result = this.getUse() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DEPRECATED: use `getAnyDef` or `getDef`. The exact replacement for this
|
* DEPRECATED: use `getAnyDef` or `getDef`. The exact replacement for this
|
||||||
@@ -91,7 +91,7 @@ class Operand extends TStageOperand {
|
|||||||
*
|
*
|
||||||
* Gets the `Instruction` whose result is the value of the operand.
|
* Gets the `Instruction` whose result is the value of the operand.
|
||||||
*/
|
*/
|
||||||
deprecated final Instruction getDefinitionInstruction() { result = getAnyDef() }
|
deprecated final Instruction getDefinitionInstruction() { result = this.getAnyDef() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the overlap relationship between the operand's definition and its use.
|
* Gets the overlap relationship between the operand's definition and its use.
|
||||||
@@ -101,7 +101,9 @@ class Operand extends TStageOperand {
|
|||||||
/**
|
/**
|
||||||
* Holds if the result of the definition instruction does not exactly overlap this use.
|
* Holds if the result of the definition instruction does not exactly overlap this use.
|
||||||
*/
|
*/
|
||||||
final predicate isDefinitionInexact() { not getDefinitionOverlap() instanceof MustExactlyOverlap }
|
final predicate isDefinitionInexact() {
|
||||||
|
not this.getDefinitionOverlap() instanceof MustExactlyOverlap
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a prefix to use when dumping the operand in an operand list.
|
* Gets a prefix to use when dumping the operand in an operand list.
|
||||||
@@ -121,7 +123,7 @@ class Operand extends TStageOperand {
|
|||||||
* For example: `this:r3_5`
|
* For example: `this:r3_5`
|
||||||
*/
|
*/
|
||||||
final string getDumpString() {
|
final string getDumpString() {
|
||||||
result = getDumpLabel() + getInexactSpecifier() + getDefinitionId()
|
result = this.getDumpLabel() + this.getInexactSpecifier() + this.getDefinitionId()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -129,9 +131,9 @@ class Operand extends TStageOperand {
|
|||||||
* definition is not modeled in SSA.
|
* definition is not modeled in SSA.
|
||||||
*/
|
*/
|
||||||
private string getDefinitionId() {
|
private string getDefinitionId() {
|
||||||
result = getAnyDef().getResultId()
|
result = this.getAnyDef().getResultId()
|
||||||
or
|
or
|
||||||
not exists(getAnyDef()) and result = "m?"
|
not exists(this.getAnyDef()) and result = "m?"
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -140,7 +142,7 @@ class Operand extends TStageOperand {
|
|||||||
* the empty string.
|
* the empty string.
|
||||||
*/
|
*/
|
||||||
private string getInexactSpecifier() {
|
private string getInexactSpecifier() {
|
||||||
if isDefinitionInexact() then result = "~" else result = ""
|
if this.isDefinitionInexact() then result = "~" else result = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -155,7 +157,7 @@ class Operand extends TStageOperand {
|
|||||||
* the definition type, such as in the case of a partial read or a read from a pointer that
|
* the definition type, such as in the case of a partial read or a read from a pointer that
|
||||||
* has been cast to a different type.
|
* has been cast to a different type.
|
||||||
*/
|
*/
|
||||||
Language::LanguageType getLanguageType() { result = getAnyDef().getResultLanguageType() }
|
Language::LanguageType getLanguageType() { result = this.getAnyDef().getResultLanguageType() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the language-neutral type of the value consumed by this operand. This is usually the same
|
* Gets the language-neutral type of the value consumed by this operand. This is usually the same
|
||||||
@@ -164,7 +166,7 @@ class Operand extends TStageOperand {
|
|||||||
* from the definition type, such as in the case of a partial read or a read from a pointer that
|
* from the definition type, such as in the case of a partial read or a read from a pointer that
|
||||||
* has been cast to a different type.
|
* has been cast to a different type.
|
||||||
*/
|
*/
|
||||||
final IRType getIRType() { result = getLanguageType().getIRType() }
|
final IRType getIRType() { result = this.getLanguageType().getIRType() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the type of the value consumed by this operand. This is usually the same as the
|
* Gets the type of the value consumed by this operand. This is usually the same as the
|
||||||
@@ -173,7 +175,7 @@ class Operand extends TStageOperand {
|
|||||||
* the definition type, such as in the case of a partial read or a read from a pointer that
|
* the definition type, such as in the case of a partial read or a read from a pointer that
|
||||||
* has been cast to a different type.
|
* has been cast to a different type.
|
||||||
*/
|
*/
|
||||||
final Language::Type getType() { getLanguageType().hasType(result, _) }
|
final Language::Type getType() { this.getLanguageType().hasType(result, _) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the value consumed by this operand is a glvalue. If this
|
* Holds if the value consumed by this operand is a glvalue. If this
|
||||||
@@ -182,13 +184,13 @@ class Operand extends TStageOperand {
|
|||||||
* not hold, the value of the operand represents a value whose type is
|
* not hold, the value of the operand represents a value whose type is
|
||||||
* given by `getType()`.
|
* given by `getType()`.
|
||||||
*/
|
*/
|
||||||
final predicate isGLValue() { getLanguageType().hasType(_, true) }
|
final predicate isGLValue() { this.getLanguageType().hasType(_, true) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the size of the value consumed by this operand, in bytes. If the operand does not have
|
* Gets the size of the value consumed by this operand, in bytes. If the operand does not have
|
||||||
* a known constant size, this predicate does not hold.
|
* a known constant size, this predicate does not hold.
|
||||||
*/
|
*/
|
||||||
final int getSize() { result = getLanguageType().getByteSize() }
|
final int getSize() { result = this.getLanguageType().getByteSize() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -205,7 +207,7 @@ class MemoryOperand extends Operand {
|
|||||||
/**
|
/**
|
||||||
* Gets the kind of memory access performed by the operand.
|
* Gets the kind of memory access performed by the operand.
|
||||||
*/
|
*/
|
||||||
MemoryAccessKind getMemoryAccess() { result = getUse().getOpcode().getReadMemoryAccess() }
|
MemoryAccessKind getMemoryAccess() { result = this.getUse().getOpcode().getReadMemoryAccess() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the memory access performed by this operand will not always read from every bit in the
|
* Holds if the memory access performed by this operand will not always read from every bit in the
|
||||||
@@ -215,7 +217,7 @@ class MemoryOperand extends Operand {
|
|||||||
* conservative estimate of the memory that might actually be accessed at runtime (for example,
|
* conservative estimate of the memory that might actually be accessed at runtime (for example,
|
||||||
* the global side effects of a function call).
|
* the global side effects of a function call).
|
||||||
*/
|
*/
|
||||||
predicate hasMayReadMemoryAccess() { getUse().getOpcode().hasMayReadMemoryAccess() }
|
predicate hasMayReadMemoryAccess() { this.getUse().getOpcode().hasMayReadMemoryAccess() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the operand that holds the memory address from which the current operand loads its
|
* Returns the operand that holds the memory address from which the current operand loads its
|
||||||
@@ -223,8 +225,8 @@ class MemoryOperand extends Operand {
|
|||||||
* is `r1`.
|
* is `r1`.
|
||||||
*/
|
*/
|
||||||
final AddressOperand getAddressOperand() {
|
final AddressOperand getAddressOperand() {
|
||||||
getMemoryAccess().usesAddressOperand() and
|
this.getMemoryAccess().usesAddressOperand() and
|
||||||
result.getUse() = getUse()
|
result.getUse() = this.getUse()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,7 +296,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe
|
|||||||
result = unique(Instruction defInstr | hasDefinition(defInstr, _))
|
result = unique(Instruction defInstr | hasDefinition(defInstr, _))
|
||||||
}
|
}
|
||||||
|
|
||||||
final override Overlap getDefinitionOverlap() { hasDefinition(_, result) }
|
final override Overlap getDefinitionOverlap() { this.hasDefinition(_, result) }
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate hasDefinition(Instruction defInstr, Overlap overlap) {
|
private predicate hasDefinition(Instruction defInstr, Overlap overlap) {
|
||||||
@@ -449,13 +451,17 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand {
|
|||||||
|
|
||||||
final override Overlap getDefinitionOverlap() { result = overlap }
|
final override Overlap getDefinitionOverlap() { result = overlap }
|
||||||
|
|
||||||
final override int getDumpSortOrder() { result = 11 + getPredecessorBlock().getDisplayIndex() }
|
final override int getDumpSortOrder() {
|
||||||
|
result = 11 + this.getPredecessorBlock().getDisplayIndex()
|
||||||
final override string getDumpLabel() {
|
|
||||||
result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final override string getDumpId() { result = getPredecessorBlock().getDisplayIndex().toString() }
|
final override string getDumpLabel() {
|
||||||
|
result = "from " + this.getPredecessorBlock().getDisplayIndex().toString() + ":"
|
||||||
|
}
|
||||||
|
|
||||||
|
final override string getDumpId() {
|
||||||
|
result = this.getPredecessorBlock().getDisplayIndex().toString()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the predecessor block from which this value comes.
|
* Gets the predecessor block from which this value comes.
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class IRBlockBase extends TIRBlock {
|
|||||||
final string toString() { result = getFirstInstruction(this).toString() }
|
final string toString() { result = getFirstInstruction(this).toString() }
|
||||||
|
|
||||||
/** Gets the source location of the first non-`Phi` instruction in this block. */
|
/** Gets the source location of the first non-`Phi` instruction in this block. */
|
||||||
final Language::Location getLocation() { result = getFirstInstruction().getLocation() }
|
final Language::Location getLocation() { result = this.getFirstInstruction().getLocation() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* INTERNAL: Do not use.
|
* INTERNAL: Do not use.
|
||||||
@@ -39,7 +39,7 @@ class IRBlockBase extends TIRBlock {
|
|||||||
) and
|
) and
|
||||||
this =
|
this =
|
||||||
rank[result + 1](IRBlock funcBlock, int sortOverride, int sortKey1, int sortKey2 |
|
rank[result + 1](IRBlock funcBlock, int sortOverride, int sortKey1, int sortKey2 |
|
||||||
funcBlock.getEnclosingFunction() = getEnclosingFunction() and
|
funcBlock.getEnclosingFunction() = this.getEnclosingFunction() and
|
||||||
funcBlock.getFirstInstruction().hasSortKeys(sortKey1, sortKey2) and
|
funcBlock.getFirstInstruction().hasSortKeys(sortKey1, sortKey2) and
|
||||||
// Ensure that the block containing `EnterFunction` always comes first.
|
// Ensure that the block containing `EnterFunction` always comes first.
|
||||||
if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction
|
if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction
|
||||||
@@ -59,15 +59,15 @@ class IRBlockBase extends TIRBlock {
|
|||||||
* Get the `Phi` instructions that appear at the start of this block.
|
* Get the `Phi` instructions that appear at the start of this block.
|
||||||
*/
|
*/
|
||||||
final PhiInstruction getAPhiInstruction() {
|
final PhiInstruction getAPhiInstruction() {
|
||||||
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
|
Construction::getPhiInstructionBlockStart(result) = this.getFirstInstruction()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets an instruction in this block. This includes `Phi` instructions.
|
* Gets an instruction in this block. This includes `Phi` instructions.
|
||||||
*/
|
*/
|
||||||
final Instruction getAnInstruction() {
|
final Instruction getAnInstruction() {
|
||||||
result = getInstruction(_) or
|
result = this.getInstruction(_) or
|
||||||
result = getAPhiInstruction()
|
result = this.getAPhiInstruction()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -78,7 +78,9 @@ class IRBlockBase extends TIRBlock {
|
|||||||
/**
|
/**
|
||||||
* Gets the last instruction in this block.
|
* Gets the last instruction in this block.
|
||||||
*/
|
*/
|
||||||
final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) }
|
final Instruction getLastInstruction() {
|
||||||
|
result = this.getInstruction(this.getInstructionCount() - 1)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the number of non-`Phi` instructions in this block.
|
* Gets the number of non-`Phi` instructions in this block.
|
||||||
@@ -149,7 +151,7 @@ class IRBlock extends IRBlockBase {
|
|||||||
* Block `A` dominates block `B` if any control flow path from the entry block of the function to
|
* Block `A` dominates block `B` if any control flow path from the entry block of the function to
|
||||||
* block `B` must pass through block `A`. A block always dominates itself.
|
* block `B` must pass through block `A`. A block always dominates itself.
|
||||||
*/
|
*/
|
||||||
final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block }
|
final predicate dominates(IRBlock block) { this.strictlyDominates(block) or this = block }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a block on the dominance frontier of this block.
|
* Gets a block on the dominance frontier of this block.
|
||||||
@@ -159,8 +161,8 @@ class IRBlock extends IRBlockBase {
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
final IRBlock dominanceFrontier() {
|
final IRBlock dominanceFrontier() {
|
||||||
dominates(result.getAPredecessor()) and
|
this.dominates(result.getAPredecessor()) and
|
||||||
not strictlyDominates(result)
|
not this.strictlyDominates(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -189,7 +191,7 @@ class IRBlock extends IRBlockBase {
|
|||||||
* Block `A` post-dominates block `B` if any control flow path from `B` to the exit block of the
|
* Block `A` post-dominates block `B` if any control flow path from `B` to the exit block of the
|
||||||
* function must pass through block `A`. A block always post-dominates itself.
|
* function must pass through block `A`. A block always post-dominates itself.
|
||||||
*/
|
*/
|
||||||
final predicate postDominates(IRBlock block) { strictlyPostDominates(block) or this = block }
|
final predicate postDominates(IRBlock block) { this.strictlyPostDominates(block) or this = block }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a block on the post-dominance frontier of this block.
|
* Gets a block on the post-dominance frontier of this block.
|
||||||
@@ -199,16 +201,16 @@ class IRBlock extends IRBlockBase {
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
final IRBlock postPominanceFrontier() {
|
final IRBlock postPominanceFrontier() {
|
||||||
postDominates(result.getASuccessor()) and
|
this.postDominates(result.getASuccessor()) and
|
||||||
not strictlyPostDominates(result)
|
not this.strictlyPostDominates(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if this block is reachable from the entry block of its function.
|
* Holds if this block is reachable from the entry block of its function.
|
||||||
*/
|
*/
|
||||||
final predicate isReachableFromFunctionEntry() {
|
final predicate isReachableFromFunctionEntry() {
|
||||||
this = getEnclosingIRFunction().getEntryBlock() or
|
this = this.getEnclosingIRFunction().getEntryBlock() or
|
||||||
getAPredecessor().isReachableFromFunctionEntry()
|
this.getAPredecessor().isReachableFromFunctionEntry()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -46,12 +46,12 @@ class Operand extends TStageOperand {
|
|||||||
/**
|
/**
|
||||||
* Gets the location of the source code for this operand.
|
* Gets the location of the source code for this operand.
|
||||||
*/
|
*/
|
||||||
final Language::Location getLocation() { result = getUse().getLocation() }
|
final Language::Location getLocation() { result = this.getUse().getLocation() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the function that contains this operand.
|
* Gets the function that contains this operand.
|
||||||
*/
|
*/
|
||||||
final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() }
|
final IRFunction getEnclosingIRFunction() { result = this.getUse().getEnclosingIRFunction() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the `Instruction` that consumes this operand.
|
* Gets the `Instruction` that consumes this operand.
|
||||||
@@ -74,7 +74,7 @@ class Operand extends TStageOperand {
|
|||||||
*/
|
*/
|
||||||
final Instruction getDef() {
|
final Instruction getDef() {
|
||||||
result = this.getAnyDef() and
|
result = this.getAnyDef() and
|
||||||
getDefinitionOverlap() instanceof MustExactlyOverlap
|
this.getDefinitionOverlap() instanceof MustExactlyOverlap
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -82,7 +82,7 @@ class Operand extends TStageOperand {
|
|||||||
*
|
*
|
||||||
* Gets the `Instruction` that consumes this operand.
|
* Gets the `Instruction` that consumes this operand.
|
||||||
*/
|
*/
|
||||||
deprecated final Instruction getUseInstruction() { result = getUse() }
|
deprecated final Instruction getUseInstruction() { result = this.getUse() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DEPRECATED: use `getAnyDef` or `getDef`. The exact replacement for this
|
* DEPRECATED: use `getAnyDef` or `getDef`. The exact replacement for this
|
||||||
@@ -91,7 +91,7 @@ class Operand extends TStageOperand {
|
|||||||
*
|
*
|
||||||
* Gets the `Instruction` whose result is the value of the operand.
|
* Gets the `Instruction` whose result is the value of the operand.
|
||||||
*/
|
*/
|
||||||
deprecated final Instruction getDefinitionInstruction() { result = getAnyDef() }
|
deprecated final Instruction getDefinitionInstruction() { result = this.getAnyDef() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the overlap relationship between the operand's definition and its use.
|
* Gets the overlap relationship between the operand's definition and its use.
|
||||||
@@ -101,7 +101,9 @@ class Operand extends TStageOperand {
|
|||||||
/**
|
/**
|
||||||
* Holds if the result of the definition instruction does not exactly overlap this use.
|
* Holds if the result of the definition instruction does not exactly overlap this use.
|
||||||
*/
|
*/
|
||||||
final predicate isDefinitionInexact() { not getDefinitionOverlap() instanceof MustExactlyOverlap }
|
final predicate isDefinitionInexact() {
|
||||||
|
not this.getDefinitionOverlap() instanceof MustExactlyOverlap
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a prefix to use when dumping the operand in an operand list.
|
* Gets a prefix to use when dumping the operand in an operand list.
|
||||||
@@ -121,7 +123,7 @@ class Operand extends TStageOperand {
|
|||||||
* For example: `this:r3_5`
|
* For example: `this:r3_5`
|
||||||
*/
|
*/
|
||||||
final string getDumpString() {
|
final string getDumpString() {
|
||||||
result = getDumpLabel() + getInexactSpecifier() + getDefinitionId()
|
result = this.getDumpLabel() + this.getInexactSpecifier() + this.getDefinitionId()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -129,9 +131,9 @@ class Operand extends TStageOperand {
|
|||||||
* definition is not modeled in SSA.
|
* definition is not modeled in SSA.
|
||||||
*/
|
*/
|
||||||
private string getDefinitionId() {
|
private string getDefinitionId() {
|
||||||
result = getAnyDef().getResultId()
|
result = this.getAnyDef().getResultId()
|
||||||
or
|
or
|
||||||
not exists(getAnyDef()) and result = "m?"
|
not exists(this.getAnyDef()) and result = "m?"
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -140,7 +142,7 @@ class Operand extends TStageOperand {
|
|||||||
* the empty string.
|
* the empty string.
|
||||||
*/
|
*/
|
||||||
private string getInexactSpecifier() {
|
private string getInexactSpecifier() {
|
||||||
if isDefinitionInexact() then result = "~" else result = ""
|
if this.isDefinitionInexact() then result = "~" else result = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -155,7 +157,7 @@ class Operand extends TStageOperand {
|
|||||||
* the definition type, such as in the case of a partial read or a read from a pointer that
|
* the definition type, such as in the case of a partial read or a read from a pointer that
|
||||||
* has been cast to a different type.
|
* has been cast to a different type.
|
||||||
*/
|
*/
|
||||||
Language::LanguageType getLanguageType() { result = getAnyDef().getResultLanguageType() }
|
Language::LanguageType getLanguageType() { result = this.getAnyDef().getResultLanguageType() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the language-neutral type of the value consumed by this operand. This is usually the same
|
* Gets the language-neutral type of the value consumed by this operand. This is usually the same
|
||||||
@@ -164,7 +166,7 @@ class Operand extends TStageOperand {
|
|||||||
* from the definition type, such as in the case of a partial read or a read from a pointer that
|
* from the definition type, such as in the case of a partial read or a read from a pointer that
|
||||||
* has been cast to a different type.
|
* has been cast to a different type.
|
||||||
*/
|
*/
|
||||||
final IRType getIRType() { result = getLanguageType().getIRType() }
|
final IRType getIRType() { result = this.getLanguageType().getIRType() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the type of the value consumed by this operand. This is usually the same as the
|
* Gets the type of the value consumed by this operand. This is usually the same as the
|
||||||
@@ -173,7 +175,7 @@ class Operand extends TStageOperand {
|
|||||||
* the definition type, such as in the case of a partial read or a read from a pointer that
|
* the definition type, such as in the case of a partial read or a read from a pointer that
|
||||||
* has been cast to a different type.
|
* has been cast to a different type.
|
||||||
*/
|
*/
|
||||||
final Language::Type getType() { getLanguageType().hasType(result, _) }
|
final Language::Type getType() { this.getLanguageType().hasType(result, _) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the value consumed by this operand is a glvalue. If this
|
* Holds if the value consumed by this operand is a glvalue. If this
|
||||||
@@ -182,13 +184,13 @@ class Operand extends TStageOperand {
|
|||||||
* not hold, the value of the operand represents a value whose type is
|
* not hold, the value of the operand represents a value whose type is
|
||||||
* given by `getType()`.
|
* given by `getType()`.
|
||||||
*/
|
*/
|
||||||
final predicate isGLValue() { getLanguageType().hasType(_, true) }
|
final predicate isGLValue() { this.getLanguageType().hasType(_, true) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the size of the value consumed by this operand, in bytes. If the operand does not have
|
* Gets the size of the value consumed by this operand, in bytes. If the operand does not have
|
||||||
* a known constant size, this predicate does not hold.
|
* a known constant size, this predicate does not hold.
|
||||||
*/
|
*/
|
||||||
final int getSize() { result = getLanguageType().getByteSize() }
|
final int getSize() { result = this.getLanguageType().getByteSize() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -205,7 +207,7 @@ class MemoryOperand extends Operand {
|
|||||||
/**
|
/**
|
||||||
* Gets the kind of memory access performed by the operand.
|
* Gets the kind of memory access performed by the operand.
|
||||||
*/
|
*/
|
||||||
MemoryAccessKind getMemoryAccess() { result = getUse().getOpcode().getReadMemoryAccess() }
|
MemoryAccessKind getMemoryAccess() { result = this.getUse().getOpcode().getReadMemoryAccess() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the memory access performed by this operand will not always read from every bit in the
|
* Holds if the memory access performed by this operand will not always read from every bit in the
|
||||||
@@ -215,7 +217,7 @@ class MemoryOperand extends Operand {
|
|||||||
* conservative estimate of the memory that might actually be accessed at runtime (for example,
|
* conservative estimate of the memory that might actually be accessed at runtime (for example,
|
||||||
* the global side effects of a function call).
|
* the global side effects of a function call).
|
||||||
*/
|
*/
|
||||||
predicate hasMayReadMemoryAccess() { getUse().getOpcode().hasMayReadMemoryAccess() }
|
predicate hasMayReadMemoryAccess() { this.getUse().getOpcode().hasMayReadMemoryAccess() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the operand that holds the memory address from which the current operand loads its
|
* Returns the operand that holds the memory address from which the current operand loads its
|
||||||
@@ -223,8 +225,8 @@ class MemoryOperand extends Operand {
|
|||||||
* is `r1`.
|
* is `r1`.
|
||||||
*/
|
*/
|
||||||
final AddressOperand getAddressOperand() {
|
final AddressOperand getAddressOperand() {
|
||||||
getMemoryAccess().usesAddressOperand() and
|
this.getMemoryAccess().usesAddressOperand() and
|
||||||
result.getUse() = getUse()
|
result.getUse() = this.getUse()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,7 +296,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe
|
|||||||
result = unique(Instruction defInstr | hasDefinition(defInstr, _))
|
result = unique(Instruction defInstr | hasDefinition(defInstr, _))
|
||||||
}
|
}
|
||||||
|
|
||||||
final override Overlap getDefinitionOverlap() { hasDefinition(_, result) }
|
final override Overlap getDefinitionOverlap() { this.hasDefinition(_, result) }
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate hasDefinition(Instruction defInstr, Overlap overlap) {
|
private predicate hasDefinition(Instruction defInstr, Overlap overlap) {
|
||||||
@@ -449,13 +451,17 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand {
|
|||||||
|
|
||||||
final override Overlap getDefinitionOverlap() { result = overlap }
|
final override Overlap getDefinitionOverlap() { result = overlap }
|
||||||
|
|
||||||
final override int getDumpSortOrder() { result = 11 + getPredecessorBlock().getDisplayIndex() }
|
final override int getDumpSortOrder() {
|
||||||
|
result = 11 + this.getPredecessorBlock().getDisplayIndex()
|
||||||
final override string getDumpLabel() {
|
|
||||||
result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final override string getDumpId() { result = getPredecessorBlock().getDisplayIndex().toString() }
|
final override string getDumpLabel() {
|
||||||
|
result = "from " + this.getPredecessorBlock().getDisplayIndex().toString() + ":"
|
||||||
|
}
|
||||||
|
|
||||||
|
final override string getDumpId() {
|
||||||
|
result = this.getPredecessorBlock().getDisplayIndex().toString()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the predecessor block from which this value comes.
|
* Gets the predecessor block from which this value comes.
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class IRBlockBase extends TIRBlock {
|
|||||||
final string toString() { result = getFirstInstruction(this).toString() }
|
final string toString() { result = getFirstInstruction(this).toString() }
|
||||||
|
|
||||||
/** Gets the source location of the first non-`Phi` instruction in this block. */
|
/** Gets the source location of the first non-`Phi` instruction in this block. */
|
||||||
final Language::Location getLocation() { result = getFirstInstruction().getLocation() }
|
final Language::Location getLocation() { result = this.getFirstInstruction().getLocation() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* INTERNAL: Do not use.
|
* INTERNAL: Do not use.
|
||||||
@@ -39,7 +39,7 @@ class IRBlockBase extends TIRBlock {
|
|||||||
) and
|
) and
|
||||||
this =
|
this =
|
||||||
rank[result + 1](IRBlock funcBlock, int sortOverride, int sortKey1, int sortKey2 |
|
rank[result + 1](IRBlock funcBlock, int sortOverride, int sortKey1, int sortKey2 |
|
||||||
funcBlock.getEnclosingFunction() = getEnclosingFunction() and
|
funcBlock.getEnclosingFunction() = this.getEnclosingFunction() and
|
||||||
funcBlock.getFirstInstruction().hasSortKeys(sortKey1, sortKey2) and
|
funcBlock.getFirstInstruction().hasSortKeys(sortKey1, sortKey2) and
|
||||||
// Ensure that the block containing `EnterFunction` always comes first.
|
// Ensure that the block containing `EnterFunction` always comes first.
|
||||||
if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction
|
if funcBlock.getFirstInstruction() instanceof EnterFunctionInstruction
|
||||||
@@ -59,15 +59,15 @@ class IRBlockBase extends TIRBlock {
|
|||||||
* Get the `Phi` instructions that appear at the start of this block.
|
* Get the `Phi` instructions that appear at the start of this block.
|
||||||
*/
|
*/
|
||||||
final PhiInstruction getAPhiInstruction() {
|
final PhiInstruction getAPhiInstruction() {
|
||||||
Construction::getPhiInstructionBlockStart(result) = getFirstInstruction()
|
Construction::getPhiInstructionBlockStart(result) = this.getFirstInstruction()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets an instruction in this block. This includes `Phi` instructions.
|
* Gets an instruction in this block. This includes `Phi` instructions.
|
||||||
*/
|
*/
|
||||||
final Instruction getAnInstruction() {
|
final Instruction getAnInstruction() {
|
||||||
result = getInstruction(_) or
|
result = this.getInstruction(_) or
|
||||||
result = getAPhiInstruction()
|
result = this.getAPhiInstruction()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -78,7 +78,9 @@ class IRBlockBase extends TIRBlock {
|
|||||||
/**
|
/**
|
||||||
* Gets the last instruction in this block.
|
* Gets the last instruction in this block.
|
||||||
*/
|
*/
|
||||||
final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) }
|
final Instruction getLastInstruction() {
|
||||||
|
result = this.getInstruction(this.getInstructionCount() - 1)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the number of non-`Phi` instructions in this block.
|
* Gets the number of non-`Phi` instructions in this block.
|
||||||
@@ -149,7 +151,7 @@ class IRBlock extends IRBlockBase {
|
|||||||
* Block `A` dominates block `B` if any control flow path from the entry block of the function to
|
* Block `A` dominates block `B` if any control flow path from the entry block of the function to
|
||||||
* block `B` must pass through block `A`. A block always dominates itself.
|
* block `B` must pass through block `A`. A block always dominates itself.
|
||||||
*/
|
*/
|
||||||
final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block }
|
final predicate dominates(IRBlock block) { this.strictlyDominates(block) or this = block }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a block on the dominance frontier of this block.
|
* Gets a block on the dominance frontier of this block.
|
||||||
@@ -159,8 +161,8 @@ class IRBlock extends IRBlockBase {
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
final IRBlock dominanceFrontier() {
|
final IRBlock dominanceFrontier() {
|
||||||
dominates(result.getAPredecessor()) and
|
this.dominates(result.getAPredecessor()) and
|
||||||
not strictlyDominates(result)
|
not this.strictlyDominates(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -189,7 +191,7 @@ class IRBlock extends IRBlockBase {
|
|||||||
* Block `A` post-dominates block `B` if any control flow path from `B` to the exit block of the
|
* Block `A` post-dominates block `B` if any control flow path from `B` to the exit block of the
|
||||||
* function must pass through block `A`. A block always post-dominates itself.
|
* function must pass through block `A`. A block always post-dominates itself.
|
||||||
*/
|
*/
|
||||||
final predicate postDominates(IRBlock block) { strictlyPostDominates(block) or this = block }
|
final predicate postDominates(IRBlock block) { this.strictlyPostDominates(block) or this = block }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a block on the post-dominance frontier of this block.
|
* Gets a block on the post-dominance frontier of this block.
|
||||||
@@ -199,16 +201,16 @@ class IRBlock extends IRBlockBase {
|
|||||||
*/
|
*/
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
final IRBlock postPominanceFrontier() {
|
final IRBlock postPominanceFrontier() {
|
||||||
postDominates(result.getASuccessor()) and
|
this.postDominates(result.getASuccessor()) and
|
||||||
not strictlyPostDominates(result)
|
not this.strictlyPostDominates(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if this block is reachable from the entry block of its function.
|
* Holds if this block is reachable from the entry block of its function.
|
||||||
*/
|
*/
|
||||||
final predicate isReachableFromFunctionEntry() {
|
final predicate isReachableFromFunctionEntry() {
|
||||||
this = getEnclosingIRFunction().getEntryBlock() or
|
this = this.getEnclosingIRFunction().getEntryBlock() or
|
||||||
getAPredecessor().isReachableFromFunctionEntry()
|
this.getAPredecessor().isReachableFromFunctionEntry()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -46,12 +46,12 @@ class Operand extends TStageOperand {
|
|||||||
/**
|
/**
|
||||||
* Gets the location of the source code for this operand.
|
* Gets the location of the source code for this operand.
|
||||||
*/
|
*/
|
||||||
final Language::Location getLocation() { result = getUse().getLocation() }
|
final Language::Location getLocation() { result = this.getUse().getLocation() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the function that contains this operand.
|
* Gets the function that contains this operand.
|
||||||
*/
|
*/
|
||||||
final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() }
|
final IRFunction getEnclosingIRFunction() { result = this.getUse().getEnclosingIRFunction() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the `Instruction` that consumes this operand.
|
* Gets the `Instruction` that consumes this operand.
|
||||||
@@ -74,7 +74,7 @@ class Operand extends TStageOperand {
|
|||||||
*/
|
*/
|
||||||
final Instruction getDef() {
|
final Instruction getDef() {
|
||||||
result = this.getAnyDef() and
|
result = this.getAnyDef() and
|
||||||
getDefinitionOverlap() instanceof MustExactlyOverlap
|
this.getDefinitionOverlap() instanceof MustExactlyOverlap
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -82,7 +82,7 @@ class Operand extends TStageOperand {
|
|||||||
*
|
*
|
||||||
* Gets the `Instruction` that consumes this operand.
|
* Gets the `Instruction` that consumes this operand.
|
||||||
*/
|
*/
|
||||||
deprecated final Instruction getUseInstruction() { result = getUse() }
|
deprecated final Instruction getUseInstruction() { result = this.getUse() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DEPRECATED: use `getAnyDef` or `getDef`. The exact replacement for this
|
* DEPRECATED: use `getAnyDef` or `getDef`. The exact replacement for this
|
||||||
@@ -91,7 +91,7 @@ class Operand extends TStageOperand {
|
|||||||
*
|
*
|
||||||
* Gets the `Instruction` whose result is the value of the operand.
|
* Gets the `Instruction` whose result is the value of the operand.
|
||||||
*/
|
*/
|
||||||
deprecated final Instruction getDefinitionInstruction() { result = getAnyDef() }
|
deprecated final Instruction getDefinitionInstruction() { result = this.getAnyDef() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the overlap relationship between the operand's definition and its use.
|
* Gets the overlap relationship between the operand's definition and its use.
|
||||||
@@ -101,7 +101,9 @@ class Operand extends TStageOperand {
|
|||||||
/**
|
/**
|
||||||
* Holds if the result of the definition instruction does not exactly overlap this use.
|
* Holds if the result of the definition instruction does not exactly overlap this use.
|
||||||
*/
|
*/
|
||||||
final predicate isDefinitionInexact() { not getDefinitionOverlap() instanceof MustExactlyOverlap }
|
final predicate isDefinitionInexact() {
|
||||||
|
not this.getDefinitionOverlap() instanceof MustExactlyOverlap
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a prefix to use when dumping the operand in an operand list.
|
* Gets a prefix to use when dumping the operand in an operand list.
|
||||||
@@ -121,7 +123,7 @@ class Operand extends TStageOperand {
|
|||||||
* For example: `this:r3_5`
|
* For example: `this:r3_5`
|
||||||
*/
|
*/
|
||||||
final string getDumpString() {
|
final string getDumpString() {
|
||||||
result = getDumpLabel() + getInexactSpecifier() + getDefinitionId()
|
result = this.getDumpLabel() + this.getInexactSpecifier() + this.getDefinitionId()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -129,9 +131,9 @@ class Operand extends TStageOperand {
|
|||||||
* definition is not modeled in SSA.
|
* definition is not modeled in SSA.
|
||||||
*/
|
*/
|
||||||
private string getDefinitionId() {
|
private string getDefinitionId() {
|
||||||
result = getAnyDef().getResultId()
|
result = this.getAnyDef().getResultId()
|
||||||
or
|
or
|
||||||
not exists(getAnyDef()) and result = "m?"
|
not exists(this.getAnyDef()) and result = "m?"
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -140,7 +142,7 @@ class Operand extends TStageOperand {
|
|||||||
* the empty string.
|
* the empty string.
|
||||||
*/
|
*/
|
||||||
private string getInexactSpecifier() {
|
private string getInexactSpecifier() {
|
||||||
if isDefinitionInexact() then result = "~" else result = ""
|
if this.isDefinitionInexact() then result = "~" else result = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -155,7 +157,7 @@ class Operand extends TStageOperand {
|
|||||||
* the definition type, such as in the case of a partial read or a read from a pointer that
|
* the definition type, such as in the case of a partial read or a read from a pointer that
|
||||||
* has been cast to a different type.
|
* has been cast to a different type.
|
||||||
*/
|
*/
|
||||||
Language::LanguageType getLanguageType() { result = getAnyDef().getResultLanguageType() }
|
Language::LanguageType getLanguageType() { result = this.getAnyDef().getResultLanguageType() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the language-neutral type of the value consumed by this operand. This is usually the same
|
* Gets the language-neutral type of the value consumed by this operand. This is usually the same
|
||||||
@@ -164,7 +166,7 @@ class Operand extends TStageOperand {
|
|||||||
* from the definition type, such as in the case of a partial read or a read from a pointer that
|
* from the definition type, such as in the case of a partial read or a read from a pointer that
|
||||||
* has been cast to a different type.
|
* has been cast to a different type.
|
||||||
*/
|
*/
|
||||||
final IRType getIRType() { result = getLanguageType().getIRType() }
|
final IRType getIRType() { result = this.getLanguageType().getIRType() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the type of the value consumed by this operand. This is usually the same as the
|
* Gets the type of the value consumed by this operand. This is usually the same as the
|
||||||
@@ -173,7 +175,7 @@ class Operand extends TStageOperand {
|
|||||||
* the definition type, such as in the case of a partial read or a read from a pointer that
|
* the definition type, such as in the case of a partial read or a read from a pointer that
|
||||||
* has been cast to a different type.
|
* has been cast to a different type.
|
||||||
*/
|
*/
|
||||||
final Language::Type getType() { getLanguageType().hasType(result, _) }
|
final Language::Type getType() { this.getLanguageType().hasType(result, _) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the value consumed by this operand is a glvalue. If this
|
* Holds if the value consumed by this operand is a glvalue. If this
|
||||||
@@ -182,13 +184,13 @@ class Operand extends TStageOperand {
|
|||||||
* not hold, the value of the operand represents a value whose type is
|
* not hold, the value of the operand represents a value whose type is
|
||||||
* given by `getType()`.
|
* given by `getType()`.
|
||||||
*/
|
*/
|
||||||
final predicate isGLValue() { getLanguageType().hasType(_, true) }
|
final predicate isGLValue() { this.getLanguageType().hasType(_, true) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the size of the value consumed by this operand, in bytes. If the operand does not have
|
* Gets the size of the value consumed by this operand, in bytes. If the operand does not have
|
||||||
* a known constant size, this predicate does not hold.
|
* a known constant size, this predicate does not hold.
|
||||||
*/
|
*/
|
||||||
final int getSize() { result = getLanguageType().getByteSize() }
|
final int getSize() { result = this.getLanguageType().getByteSize() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -205,7 +207,7 @@ class MemoryOperand extends Operand {
|
|||||||
/**
|
/**
|
||||||
* Gets the kind of memory access performed by the operand.
|
* Gets the kind of memory access performed by the operand.
|
||||||
*/
|
*/
|
||||||
MemoryAccessKind getMemoryAccess() { result = getUse().getOpcode().getReadMemoryAccess() }
|
MemoryAccessKind getMemoryAccess() { result = this.getUse().getOpcode().getReadMemoryAccess() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the memory access performed by this operand will not always read from every bit in the
|
* Holds if the memory access performed by this operand will not always read from every bit in the
|
||||||
@@ -215,7 +217,7 @@ class MemoryOperand extends Operand {
|
|||||||
* conservative estimate of the memory that might actually be accessed at runtime (for example,
|
* conservative estimate of the memory that might actually be accessed at runtime (for example,
|
||||||
* the global side effects of a function call).
|
* the global side effects of a function call).
|
||||||
*/
|
*/
|
||||||
predicate hasMayReadMemoryAccess() { getUse().getOpcode().hasMayReadMemoryAccess() }
|
predicate hasMayReadMemoryAccess() { this.getUse().getOpcode().hasMayReadMemoryAccess() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the operand that holds the memory address from which the current operand loads its
|
* Returns the operand that holds the memory address from which the current operand loads its
|
||||||
@@ -223,8 +225,8 @@ class MemoryOperand extends Operand {
|
|||||||
* is `r1`.
|
* is `r1`.
|
||||||
*/
|
*/
|
||||||
final AddressOperand getAddressOperand() {
|
final AddressOperand getAddressOperand() {
|
||||||
getMemoryAccess().usesAddressOperand() and
|
this.getMemoryAccess().usesAddressOperand() and
|
||||||
result.getUse() = getUse()
|
result.getUse() = this.getUse()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,7 +296,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe
|
|||||||
result = unique(Instruction defInstr | hasDefinition(defInstr, _))
|
result = unique(Instruction defInstr | hasDefinition(defInstr, _))
|
||||||
}
|
}
|
||||||
|
|
||||||
final override Overlap getDefinitionOverlap() { hasDefinition(_, result) }
|
final override Overlap getDefinitionOverlap() { this.hasDefinition(_, result) }
|
||||||
|
|
||||||
pragma[noinline]
|
pragma[noinline]
|
||||||
private predicate hasDefinition(Instruction defInstr, Overlap overlap) {
|
private predicate hasDefinition(Instruction defInstr, Overlap overlap) {
|
||||||
@@ -449,13 +451,17 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand {
|
|||||||
|
|
||||||
final override Overlap getDefinitionOverlap() { result = overlap }
|
final override Overlap getDefinitionOverlap() { result = overlap }
|
||||||
|
|
||||||
final override int getDumpSortOrder() { result = 11 + getPredecessorBlock().getDisplayIndex() }
|
final override int getDumpSortOrder() {
|
||||||
|
result = 11 + this.getPredecessorBlock().getDisplayIndex()
|
||||||
final override string getDumpLabel() {
|
|
||||||
result = "from " + getPredecessorBlock().getDisplayIndex().toString() + ":"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final override string getDumpId() { result = getPredecessorBlock().getDisplayIndex().toString() }
|
final override string getDumpLabel() {
|
||||||
|
result = "from " + this.getPredecessorBlock().getDisplayIndex().toString() + ":"
|
||||||
|
}
|
||||||
|
|
||||||
|
final override string getDumpId() {
|
||||||
|
result = this.getPredecessorBlock().getDisplayIndex().toString()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the predecessor block from which this value comes.
|
* Gets the predecessor block from which this value comes.
|
||||||
|
|||||||
@@ -18,10 +18,11 @@ Overlap getOverlap(IntValue defStart, IntValue defEnd, IntValue useStart, IntVal
|
|||||||
else
|
else
|
||||||
if isLE(defStart, useStart) and isGE(defEnd, useEnd)
|
if isLE(defStart, useStart) and isGE(defEnd, useEnd)
|
||||||
then result instanceof MustTotallyOverlap
|
then result instanceof MustTotallyOverlap
|
||||||
else
|
else (
|
||||||
if isLE(defEnd, useStart) or isGE(defStart, useEnd)
|
not isLE(defEnd, useStart) and
|
||||||
then none()
|
not isGE(defStart, useEnd) and
|
||||||
else result instanceof MayPartiallyOverlap
|
result instanceof MayPartiallyOverlap
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -36,3 +36,4 @@ private import implementations.Select
|
|||||||
private import implementations.MySql
|
private import implementations.MySql
|
||||||
private import implementations.SqLite3
|
private import implementations.SqLite3
|
||||||
private import implementations.PostgreSql
|
private import implementations.PostgreSql
|
||||||
|
private import implementations.System
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ private class MallocAllocationFunction extends AllocationFunction {
|
|||||||
]) and
|
]) and
|
||||||
sizeArg = 1
|
sizeArg = 1
|
||||||
or
|
or
|
||||||
hasGlobalName(["HeapAlloc"]) and // HeapAlloc(heap, flags, size)
|
hasGlobalName("HeapAlloc") and // HeapAlloc(heap, flags, size)
|
||||||
sizeArg = 2
|
sizeArg = 2
|
||||||
or
|
or
|
||||||
hasGlobalName([
|
hasGlobalName([
|
||||||
|
|||||||
@@ -85,4 +85,6 @@ private class Recv extends AliasFunction, ArrayFunction, SideEffectFunction,
|
|||||||
) and
|
) and
|
||||||
description = "Buffer read by " + this.getName()
|
description = "Buffer read by " + this.getName()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override predicate hasSocketInput(FunctionInput input) { input.isParameter(0) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,4 +60,6 @@ private class Send extends AliasFunction, ArrayFunction, SideEffectFunction, Rem
|
|||||||
override predicate hasRemoteFlowSink(FunctionInput input, string description) {
|
override predicate hasRemoteFlowSink(FunctionInput input, string description) {
|
||||||
input.isParameterDeref(1) and description = "Buffer sent by " + this.getName()
|
input.isParameterDeref(1) and description = "Buffer sent by " + this.getName()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override predicate hasSocketInput(FunctionInput input) { input.isParameter(0) }
|
||||||
}
|
}
|
||||||
|
|||||||
43
cpp/ql/lib/semmle/code/cpp/models/implementations/System.qll
Normal file
43
cpp/ql/lib/semmle/code/cpp/models/implementations/System.qll
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import cpp
|
||||||
|
import semmle.code.cpp.models.interfaces.SideEffect
|
||||||
|
import semmle.code.cpp.models.interfaces.Alias
|
||||||
|
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 {
|
||||||
|
SystemFunction() {
|
||||||
|
hasGlobalOrStdName("system") or // system(command)
|
||||||
|
hasGlobalName("popen") or // popen(command, mode)
|
||||||
|
// Windows variants
|
||||||
|
hasGlobalName("_popen") or // _popen(command, mode)
|
||||||
|
hasGlobalName("_wpopen") or // _wpopen(command, mode)
|
||||||
|
hasGlobalName("_wsystem") // _wsystem(command)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate hasCommandArgument(FunctionInput input) { input.isParameterDeref(0) }
|
||||||
|
|
||||||
|
override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = 0 or bufParam = 1 }
|
||||||
|
|
||||||
|
override predicate hasArrayInput(int bufParam) { bufParam = 0 or bufParam = 1 }
|
||||||
|
|
||||||
|
override predicate parameterNeverEscapes(int index) { index = 0 or index = 1 }
|
||||||
|
|
||||||
|
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||||
|
|
||||||
|
override predicate parameterIsAlwaysReturned(int index) { none() }
|
||||||
|
|
||||||
|
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||||
|
|
||||||
|
override predicate hasOnlySpecificWriteSideEffects() {
|
||||||
|
hasGlobalOrStdName("system") or
|
||||||
|
hasGlobalName("_wsystem")
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||||
|
(i = 0 or i = 1) and
|
||||||
|
buffer = true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* Provides classes for modeling functions that execute new programs by
|
||||||
|
* interpreting string data as shell commands. To use this QL library, create
|
||||||
|
* a QL class extending `CommandExecutionFunction` with a characteristic
|
||||||
|
* predicate that selects the function or set of functions you are modeling.
|
||||||
|
* Within that class, override the `hasCommandArgument` predicate to indicate
|
||||||
|
* which parameters are interpreted as shell commands.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import cpp
|
||||||
|
import FunctionInputsAndOutputs
|
||||||
|
import semmle.code.cpp.models.Models
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function, such as `exec` or `popen` that starts a new process by
|
||||||
|
* interpreting a string as a shell command.
|
||||||
|
*/
|
||||||
|
abstract class CommandExecutionFunction extends Function {
|
||||||
|
/**
|
||||||
|
* Holds if `input` is interpreted as a shell command.
|
||||||
|
*/
|
||||||
|
abstract predicate hasCommandArgument(FunctionInput input);
|
||||||
|
}
|
||||||
@@ -18,6 +18,12 @@ abstract class RemoteFlowSourceFunction extends Function {
|
|||||||
* Holds if remote data described by `description` flows from `output` of a call to this function.
|
* Holds if remote data described by `description` flows from `output` of a call to this function.
|
||||||
*/
|
*/
|
||||||
abstract predicate hasRemoteFlowSource(FunctionOutput output, string description);
|
abstract predicate hasRemoteFlowSource(FunctionOutput output, string description);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if remote data from this source comes from a socket described by
|
||||||
|
* `input`. There is no result if a socket is not specified.
|
||||||
|
*/
|
||||||
|
predicate hasSocketInput(FunctionInput input) { none() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -51,4 +57,10 @@ abstract class RemoteFlowSinkFunction extends Function {
|
|||||||
* send over a network connection.
|
* send over a network connection.
|
||||||
*/
|
*/
|
||||||
abstract predicate hasRemoteFlowSink(FunctionInput input, string description);
|
abstract predicate hasRemoteFlowSink(FunctionInput input, string description);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if data put into this sink is transmitted through a socket described
|
||||||
|
* by `input`. There is no result if a socket is not specified.
|
||||||
|
*/
|
||||||
|
predicate hasSocketInput(FunctionInput input) { none() }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,8 +29,7 @@ predicate nanExcludingComparison(ComparisonOperation guard, boolean polarity) {
|
|||||||
*/
|
*/
|
||||||
private predicate excludesNan(RangeSsaDefinition def, VariableAccess v) {
|
private predicate excludesNan(RangeSsaDefinition def, VariableAccess v) {
|
||||||
exists(VariableAccess inCond, ComparisonOperation guard, boolean branch, StackVariable lsv |
|
exists(VariableAccess inCond, ComparisonOperation guard, boolean branch, StackVariable lsv |
|
||||||
def.isGuardPhi(inCond, guard, branch) and
|
def.isGuardPhi(lsv, inCond, guard, branch) and
|
||||||
inCond.getTarget() = lsv and
|
|
||||||
v = def.getAUse(lsv) and
|
v = def.getAUse(lsv) and
|
||||||
guard.getAnOperand() = inCond and
|
guard.getAnOperand() = inCond and
|
||||||
nanExcludingComparison(guard, branch)
|
nanExcludingComparison(guard, branch)
|
||||||
|
|||||||
@@ -94,10 +94,11 @@ class RangeSsaDefinition extends ControlFlowNodeBase {
|
|||||||
predicate isPhiNode(StackVariable v) { exists(RangeSSA x | x.phi_node(v, this.(BasicBlock))) }
|
predicate isPhiNode(StackVariable v) { exists(RangeSSA x | x.phi_node(v, this.(BasicBlock))) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DEPRECATED: Use isGuardPhi/4 instead
|
||||||
* If this definition is a phi node corresponding to a guard,
|
* If this definition is a phi node corresponding to a guard,
|
||||||
* then return the variable access and the guard.
|
* then return the variable access and the guard.
|
||||||
*/
|
*/
|
||||||
predicate isGuardPhi(VariableAccess va, Expr guard, boolean branch) {
|
deprecated predicate isGuardPhi(VariableAccess va, Expr guard, boolean branch) {
|
||||||
guard_defn(va, guard, this, branch)
|
guard_defn(va, guard, this, branch)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,9 +143,8 @@ class RangeSsaDefinition extends ControlFlowNodeBase {
|
|||||||
// below excludes definitions which can only reach guard phi
|
// below excludes definitions which can only reach guard phi
|
||||||
// nodes by going through the corresponding guard.
|
// nodes by going through the corresponding guard.
|
||||||
not exists(VariableAccess access |
|
not exists(VariableAccess access |
|
||||||
v = access.getTarget() and
|
|
||||||
pred.contains(access) and
|
pred.contains(access) and
|
||||||
this.isGuardPhi(access, _, _)
|
this.isGuardPhi(v, access, _, _)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -433,10 +433,7 @@ private predicate exprDependsOnDef(Expr e, RangeSsaDefinition srcDef, StackVaria
|
|||||||
private predicate phiDependsOnDef(
|
private predicate phiDependsOnDef(
|
||||||
RangeSsaDefinition phi, StackVariable v, RangeSsaDefinition srcDef, StackVariable srcVar
|
RangeSsaDefinition phi, StackVariable v, RangeSsaDefinition srcDef, StackVariable srcVar
|
||||||
) {
|
) {
|
||||||
exists(VariableAccess access, Expr guard |
|
exists(VariableAccess access, Expr guard | phi.isGuardPhi(v, access, guard, _) |
|
||||||
access = v.getAnAccess() and
|
|
||||||
phi.isGuardPhi(access, guard, _)
|
|
||||||
|
|
|
||||||
exprDependsOnDef(guard.(ComparisonOperation).getAnOperand(), srcDef, srcVar) or
|
exprDependsOnDef(guard.(ComparisonOperation).getAnOperand(), srcDef, srcVar) or
|
||||||
exprDependsOnDef(access, srcDef, srcVar)
|
exprDependsOnDef(access, srcDef, srcVar)
|
||||||
)
|
)
|
||||||
@@ -1204,8 +1201,7 @@ private float boolConversionUpperBound(Expr expr) {
|
|||||||
*/
|
*/
|
||||||
private float getPhiLowerBounds(StackVariable v, RangeSsaDefinition phi) {
|
private float getPhiLowerBounds(StackVariable v, RangeSsaDefinition phi) {
|
||||||
exists(VariableAccess access, Expr guard, boolean branch, float defLB, float guardLB |
|
exists(VariableAccess access, Expr guard, boolean branch, float defLB, float guardLB |
|
||||||
access = v.getAnAccess() and
|
phi.isGuardPhi(v, access, guard, branch) and
|
||||||
phi.isGuardPhi(access, guard, branch) and
|
|
||||||
lowerBoundFromGuard(guard, access, guardLB, branch) and
|
lowerBoundFromGuard(guard, access, guardLB, branch) and
|
||||||
defLB = getFullyConvertedLowerBounds(access)
|
defLB = getFullyConvertedLowerBounds(access)
|
||||||
|
|
|
|
||||||
@@ -1230,8 +1226,7 @@ private float getPhiLowerBounds(StackVariable v, RangeSsaDefinition phi) {
|
|||||||
/** See comment for `getPhiLowerBounds`, above. */
|
/** See comment for `getPhiLowerBounds`, above. */
|
||||||
private float getPhiUpperBounds(StackVariable v, RangeSsaDefinition phi) {
|
private float getPhiUpperBounds(StackVariable v, RangeSsaDefinition phi) {
|
||||||
exists(VariableAccess access, Expr guard, boolean branch, float defUB, float guardUB |
|
exists(VariableAccess access, Expr guard, boolean branch, float defUB, float guardUB |
|
||||||
access = v.getAnAccess() and
|
phi.isGuardPhi(v, access, guard, branch) and
|
||||||
phi.isGuardPhi(access, guard, branch) and
|
|
||||||
upperBoundFromGuard(guard, access, guardUB, branch) and
|
upperBoundFromGuard(guard, access, guardUB, branch) and
|
||||||
defUB = getFullyConvertedUpperBounds(access)
|
defUB = getFullyConvertedUpperBounds(access)
|
||||||
|
|
|
|
||||||
@@ -1493,8 +1488,7 @@ private predicate isNEPhi(
|
|||||||
exists(
|
exists(
|
||||||
ComparisonOperation cmp, boolean branch, Expr linearExpr, Expr rExpr, float p, float q, float r
|
ComparisonOperation cmp, boolean branch, Expr linearExpr, Expr rExpr, float p, float q, float r
|
||||||
|
|
|
|
||||||
access.getTarget() = v and
|
phi.isGuardPhi(v, access, cmp, branch) and
|
||||||
phi.isGuardPhi(access, cmp, branch) and
|
|
||||||
eqOpWithSwapAndNegate(cmp, linearExpr, rExpr, false, branch) and
|
eqOpWithSwapAndNegate(cmp, linearExpr, rExpr, false, branch) and
|
||||||
v.getUnspecifiedType() instanceof IntegralOrEnumType and // Float `!=` is too imprecise
|
v.getUnspecifiedType() instanceof IntegralOrEnumType and // Float `!=` is too imprecise
|
||||||
r = getValue(rExpr).toFloat() and
|
r = getValue(rExpr).toFloat() and
|
||||||
@@ -1503,8 +1497,7 @@ private predicate isNEPhi(
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(Expr op, boolean branch, Expr linearExpr, float p, float q |
|
exists(Expr op, boolean branch, Expr linearExpr, float p, float q |
|
||||||
access.getTarget() = v and
|
phi.isGuardPhi(v, access, op, branch) and
|
||||||
phi.isGuardPhi(access, op, branch) and
|
|
||||||
eqZeroWithNegate(op, linearExpr, false, branch) and
|
eqZeroWithNegate(op, linearExpr, false, branch) and
|
||||||
v.getUnspecifiedType() instanceof IntegralOrEnumType and // Float `!` is too imprecise
|
v.getUnspecifiedType() instanceof IntegralOrEnumType and // Float `!` is too imprecise
|
||||||
linearAccess(linearExpr, access, p, q) and
|
linearAccess(linearExpr, access, p, q) and
|
||||||
@@ -1524,8 +1517,7 @@ private predicate isUnsupportedGuardPhi(Variable v, RangeSsaDefinition phi, Vari
|
|||||||
or
|
or
|
||||||
eqZeroWithNegate(cmp, _, false, branch)
|
eqZeroWithNegate(cmp, _, false, branch)
|
||||||
|
|
|
|
||||||
access.getTarget() = v and
|
phi.isGuardPhi(v, access, cmp, branch) and
|
||||||
phi.isGuardPhi(access, cmp, branch) and
|
|
||||||
not isNEPhi(v, phi, access, _)
|
not isNEPhi(v, phi, access, _)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1594,6 +1586,15 @@ private module SimpleRangeAnalysisCached {
|
|||||||
result = min([max(getTruncatedUpperBounds(expr)), getGuardedUpperBound(expr)])
|
result = min([max(getTruncatedUpperBounds(expr)), getGuardedUpperBound(expr)])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Holds if the upper bound of `expr` may have been widened. This means the the upper bound is in practice likely to be overly wide. */
|
||||||
|
cached
|
||||||
|
predicate upperBoundMayBeWidened(Expr e) {
|
||||||
|
isRecursiveExpr(e) and
|
||||||
|
// Widening is not a problem if the post-analysis in `getGuardedUpperBound` has overridden the widening.
|
||||||
|
// Note that the RHS of `<` may be multi-valued.
|
||||||
|
not getGuardedUpperBound(e) < getTruncatedUpperBounds(e)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `expr` has a provably empty range. For example:
|
* Holds if `expr` has a provably empty range. For example:
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -365,7 +365,7 @@ class GetsBW extends BufferWriteCall {
|
|||||||
/**
|
/**
|
||||||
* Gets the index of the parameter that is the maximum number of characters to be read.
|
* Gets the index of the parameter that is the maximum number of characters to be read.
|
||||||
*/
|
*/
|
||||||
int getParamSize() { if exists(getArgument(1)) then result = 1 else none() }
|
int getParamSize() { exists(getArgument(1)) and result = 1 }
|
||||||
|
|
||||||
override Type getBufferType() { result = this.getTarget().getParameter(0).getUnspecifiedType() }
|
override Type getBufferType() { result = this.getTarget().getParameter(0).getUnspecifiedType() }
|
||||||
|
|
||||||
|
|||||||
@@ -4,42 +4,20 @@ import cpp
|
|||||||
import semmle.code.cpp.security.FunctionWithWrappers
|
import semmle.code.cpp.security.FunctionWithWrappers
|
||||||
import semmle.code.cpp.models.interfaces.SideEffect
|
import semmle.code.cpp.models.interfaces.SideEffect
|
||||||
import semmle.code.cpp.models.interfaces.Alias
|
import semmle.code.cpp.models.interfaces.Alias
|
||||||
|
import semmle.code.cpp.models.interfaces.CommandExecution
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A function for running a command using a command interpreter.
|
* A function for running a command using a command interpreter.
|
||||||
*/
|
*/
|
||||||
class SystemFunction extends FunctionWithWrappers, ArrayFunction, AliasFunction, SideEffectFunction {
|
class SystemFunction extends FunctionWithWrappers instanceof CommandExecutionFunction {
|
||||||
SystemFunction() {
|
override predicate interestingArg(int arg) {
|
||||||
hasGlobalOrStdName("system") or // system(command)
|
exists(FunctionInput input |
|
||||||
hasGlobalName("popen") or // popen(command, mode)
|
this.(CommandExecutionFunction).hasCommandArgument(input) and
|
||||||
// Windows variants
|
(
|
||||||
hasGlobalName("_popen") or // _popen(command, mode)
|
input.isParameterDerefOrQualifierObject(arg) or
|
||||||
hasGlobalName("_wpopen") or // _wpopen(command, mode)
|
input.isParameterOrQualifierAddress(arg)
|
||||||
hasGlobalName("_wsystem") // _wsystem(command)
|
)
|
||||||
}
|
)
|
||||||
|
|
||||||
override predicate interestingArg(int arg) { arg = 0 }
|
|
||||||
|
|
||||||
override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = 0 or bufParam = 1 }
|
|
||||||
|
|
||||||
override predicate hasArrayInput(int bufParam) { bufParam = 0 or bufParam = 1 }
|
|
||||||
|
|
||||||
override predicate parameterNeverEscapes(int index) { index = 0 or index = 1 }
|
|
||||||
|
|
||||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
|
||||||
|
|
||||||
override predicate parameterIsAlwaysReturned(int index) { none() }
|
|
||||||
|
|
||||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
|
||||||
|
|
||||||
override predicate hasOnlySpecificWriteSideEffects() {
|
|
||||||
hasGlobalOrStdName("system") or
|
|
||||||
hasGlobalName("_wsystem")
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
|
||||||
(i = 0 or i = 1) and
|
|
||||||
buffer = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
import PrintfLike
|
import PrintfLike
|
||||||
private import TaintTracking
|
private import semmle.code.cpp.ir.dataflow.ResolveCall
|
||||||
|
|
||||||
bindingset[index]
|
bindingset[index]
|
||||||
private string toCause(Function func, int index) {
|
private string toCause(Function func, int index) {
|
||||||
|
|||||||
@@ -245,7 +245,7 @@ svnchurn(
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `file`.
|
* column `endcolumn` of line `endline` in file `file`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
locations_default(
|
locations_default(
|
||||||
/** The location of an element that is not an expression or a statement. */
|
/** The location of an element that is not an expression or a statement. */
|
||||||
@@ -262,7 +262,7 @@ locations_default(
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `file`.
|
* column `endcolumn` of line `endline` in file `file`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
locations_stmt(
|
locations_stmt(
|
||||||
/** The location of a statement. */
|
/** The location of a statement. */
|
||||||
@@ -279,7 +279,7 @@ locations_stmt(
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `file`.
|
* column `endcolumn` of line `endline` in file `file`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
locations_expr(
|
locations_expr(
|
||||||
/** The location of an expression. */
|
/** The location of an expression. */
|
||||||
|
|||||||
1207
cpp/ql/lib/tutorial.qll
Normal file
1207
cpp/ql/lib/tutorial.qll
Normal file
File diff suppressed because it is too large
Load Diff
@@ -60,20 +60,18 @@ class SuppressionComment extends Comment {
|
|||||||
/**
|
/**
|
||||||
* The scope of an alert suppression comment.
|
* The scope of an alert suppression comment.
|
||||||
*/
|
*/
|
||||||
class SuppressionScope extends ElementBase {
|
class SuppressionScope extends ElementBase instanceof SuppressionComment {
|
||||||
SuppressionScope() { this instanceof SuppressionComment }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if this element is at the specified location.
|
* Holds if this element is at the specified location.
|
||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
) {
|
) {
|
||||||
this.(SuppressionComment).covers(filepath, startline, startcolumn, endline, endcolumn)
|
super.covers(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @problem.severity warning
|
* @problem.severity warning
|
||||||
* @security-severity 9.3
|
* @security-severity 9.3
|
||||||
* @precision medium
|
* @precision high
|
||||||
* @id cpp/static-buffer-overflow
|
* @id cpp/static-buffer-overflow
|
||||||
* @tags reliability
|
* @tags reliability
|
||||||
* security
|
* security
|
||||||
@@ -55,6 +55,8 @@ predicate overflowOffsetInLoop(BufferAccess bufaccess, string msg) {
|
|||||||
loop.counter().getAnAccess() = bufaccess.getArrayOffset() and
|
loop.counter().getAnAccess() = bufaccess.getArrayOffset() and
|
||||||
// Ensure that we don't have an upper bound on the array index that's less than the buffer size.
|
// Ensure that we don't have an upper bound on the array index that's less than the buffer size.
|
||||||
not upperBound(bufaccess.getArrayOffset().getFullyConverted()) < bufaccess.bufferSize() and
|
not upperBound(bufaccess.getArrayOffset().getFullyConverted()) < bufaccess.bufferSize() and
|
||||||
|
// The upper bounds analysis must not have been widended
|
||||||
|
not upperBoundMayBeWidened(bufaccess.getArrayOffset().getFullyConverted()) and
|
||||||
msg =
|
msg =
|
||||||
"Potential buffer-overflow: counter '" + loop.counter().toString() + "' <= " +
|
"Potential buffer-overflow: counter '" + loop.counter().toString() + "' <= " +
|
||||||
loop.limit().toString() + " but '" + bufaccess.buffer().getName() + "' has " +
|
loop.limit().toString() + " but '" + bufaccess.buffer().getName() + "' has " +
|
||||||
@@ -130,11 +132,13 @@ predicate outOfBounds(BufferAccess bufaccess, string msg) {
|
|||||||
(
|
(
|
||||||
access > size
|
access > size
|
||||||
or
|
or
|
||||||
access = size and not exists(AddressOfExpr addof | bufaccess = addof.getOperand())
|
access = size and
|
||||||
|
not exists(AddressOfExpr addof | bufaccess = addof.getOperand()) and
|
||||||
|
not exists(BuiltInOperationBuiltInOffsetOf offsetof | offsetof.getAChild() = bufaccess)
|
||||||
) and
|
) and
|
||||||
msg =
|
msg =
|
||||||
"Potential buffer-overflow: '" + buf + "' has size " + size.toString() + " but '" + buf + "[" +
|
"Potential buffer-overflow: '" + buf + "' has size " + size.toString() + " but '" + buf + "[" +
|
||||||
access.toString() + "]' is accessed here."
|
access.toString() + "]' may be accessed here."
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
/**
|
|
||||||
* @name Extraction errors
|
|
||||||
* @description List all extraction errors for files in the source code directory.
|
|
||||||
* @kind diagnostic
|
|
||||||
* @id cpp/diagnostics/extraction-errors
|
|
||||||
*/
|
|
||||||
|
|
||||||
import cpp
|
|
||||||
import ExtractionErrors
|
|
||||||
|
|
||||||
from ExtractionError error
|
|
||||||
where
|
|
||||||
error instanceof ExtractionUnknownError or
|
|
||||||
exists(error.getFile().getRelativePath())
|
|
||||||
select error, "Extraction failed in " + error.getFile() + " with error " + error.getErrorMessage(),
|
|
||||||
error.getSeverity()
|
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
/**
|
/**
|
||||||
* Provides a common hierarchy of all types of errors that can occur during extraction.
|
* Provides a common hierarchy of all types of problems that can occur during extraction.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A note about how the C/C++ extractor emits diagnostics:
|
* A note about how the C/C++ extractor emits diagnostics:
|
||||||
* When the extractor frontend encounters an error, it emits a diagnostic message,
|
* When the extractor frontend encounters a problem, it emits a diagnostic message,
|
||||||
* that includes a message, location and severity.
|
* that includes a message, location and severity.
|
||||||
* However, that process is best-effort and may fail (e.g. due to lack of memory).
|
* However, that process is best-effort and may fail (e.g. due to lack of memory).
|
||||||
* Thus, if the extractor emitted at least one diagnostic of severity discretionary
|
* Thus, if the extractor emitted at least one diagnostic of severity discretionary
|
||||||
@@ -15,17 +15,17 @@ import cpp
|
|||||||
* In the common case, this means that a compilation during which one or more errors happened also gets
|
* In the common case, this means that a compilation during which one or more errors happened also gets
|
||||||
* the catch-all diagnostic.
|
* the catch-all diagnostic.
|
||||||
* This diagnostic has the empty string as file path.
|
* This diagnostic has the empty string as file path.
|
||||||
* We filter out these useless diagnostics if there is at least one error-level diagnostic
|
* We filter out these useless diagnostics if there is at least one warning-level diagnostic
|
||||||
* for the affected compilation in the database.
|
* for the affected compilation in the database.
|
||||||
* Otherwise, we show it to indicate that something went wrong and that we
|
* Otherwise, we show it to indicate that something went wrong and that we
|
||||||
* don't know what exactly happened.
|
* don't know what exactly happened.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An error that, if present, leads to a file being marked as non-successfully extracted.
|
* A problem with a file that, if present, leads to a file being marked as non-successfully extracted.
|
||||||
*/
|
*/
|
||||||
class ReportableError extends Diagnostic {
|
class ReportableWarning extends Diagnostic {
|
||||||
ReportableError() {
|
ReportableWarning() {
|
||||||
(
|
(
|
||||||
this instanceof CompilerDiscretionaryError or
|
this instanceof CompilerDiscretionaryError or
|
||||||
this instanceof CompilerError or
|
this instanceof CompilerError or
|
||||||
@@ -36,39 +36,35 @@ class ReportableError extends Diagnostic {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private newtype TExtractionError =
|
private newtype TExtractionProblem =
|
||||||
TReportableError(ReportableError err) or
|
TReportableWarning(ReportableWarning err) or
|
||||||
TCompilationFailed(Compilation c, File f) {
|
TCompilationFailed(Compilation c, File f) {
|
||||||
f = c.getAFileCompiled() and not c.normalTermination()
|
f = c.getAFileCompiled() and not c.normalTermination()
|
||||||
} or
|
} or
|
||||||
// Show the catch-all diagnostic (see note above) only if we haven't seen any other error-level diagnostic
|
// Show the catch-all diagnostic (see note above) only if we haven't seen any other error-level diagnostic
|
||||||
// for that compilation
|
// for that compilation
|
||||||
TUnknownError(CompilerError err) {
|
TUnknownProblem(CompilerError err) {
|
||||||
not exists(ReportableError e | e.getCompilation() = err.getCompilation())
|
not exists(ReportableWarning e | e.getCompilation() = err.getCompilation())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Superclass for the extraction error hierarchy.
|
* Superclass for the extraction problem hierarchy.
|
||||||
*/
|
*/
|
||||||
class ExtractionError extends TExtractionError {
|
class ExtractionProblem extends TExtractionProblem {
|
||||||
/** Gets the string representation of the error. */
|
/** Gets the string representation of the problem. */
|
||||||
string toString() { none() }
|
string toString() { none() }
|
||||||
|
|
||||||
/** Gets the error message for this error. */
|
/** Gets the problem message for this problem. */
|
||||||
string getErrorMessage() { none() }
|
string getProblemMessage() { none() }
|
||||||
|
|
||||||
/** Gets the file this error occured in. */
|
/** Gets the file this problem occured in. */
|
||||||
File getFile() { none() }
|
File getFile() { none() }
|
||||||
|
|
||||||
/** Gets the location this error occured in. */
|
/** Gets the location this problem occured in. */
|
||||||
Location getLocation() { none() }
|
Location getLocation() { none() }
|
||||||
|
|
||||||
/** Gets the SARIF severity of this error. */
|
/** Gets the SARIF severity of this problem. */
|
||||||
int getSeverity() {
|
int getSeverity() { none() }
|
||||||
// Unfortunately, we can't distinguish between errors and fatal errors in SARIF,
|
|
||||||
// so all errors have severity 2.
|
|
||||||
result = 2
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -79,7 +75,7 @@ class ExtractionError extends TExtractionError {
|
|||||||
* - stack overflow
|
* - stack overflow
|
||||||
* - out of memory
|
* - out of memory
|
||||||
*/
|
*/
|
||||||
class ExtractionUnrecoverableError extends ExtractionError, TCompilationFailed {
|
class ExtractionUnrecoverableError extends ExtractionProblem, TCompilationFailed {
|
||||||
Compilation c;
|
Compilation c;
|
||||||
File f;
|
File f;
|
||||||
|
|
||||||
@@ -89,49 +85,67 @@ class ExtractionUnrecoverableError extends ExtractionError, TCompilationFailed {
|
|||||||
result = "Unrecoverable extraction error while compiling " + f.toString()
|
result = "Unrecoverable extraction error while compiling " + f.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
override string getErrorMessage() { result = "unrecoverable compilation failure." }
|
override string getProblemMessage() { result = "unrecoverable compilation failure." }
|
||||||
|
|
||||||
override File getFile() { result = f }
|
override File getFile() { result = f }
|
||||||
|
|
||||||
override Location getLocation() { result = f.getLocation() }
|
override Location getLocation() { result = f.getLocation() }
|
||||||
|
|
||||||
|
override int getSeverity() {
|
||||||
|
// These extractor errors break the analysis, so we mark them in SARIF as
|
||||||
|
// [errors](https://docs.oasis-open.org/sarif/sarif/v2.1.0/csprd01/sarif-v2.1.0-csprd01.html#_Toc10541338).
|
||||||
|
result = 2
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A recoverable extraction error.
|
* A recoverable extraction warning.
|
||||||
* These are compiler errors from the frontend.
|
* These are compiler errors from the frontend.
|
||||||
* Upon encountering one of these, we still continue extraction, but the
|
* Upon encountering one of these, we still continue extraction, but the
|
||||||
* database will be incomplete for that file.
|
* database will be incomplete for that file.
|
||||||
*/
|
*/
|
||||||
class ExtractionRecoverableError extends ExtractionError, TReportableError {
|
class ExtractionRecoverableWarning extends ExtractionProblem, TReportableWarning {
|
||||||
ReportableError err;
|
ReportableWarning err;
|
||||||
|
|
||||||
ExtractionRecoverableError() { this = TReportableError(err) }
|
ExtractionRecoverableWarning() { this = TReportableWarning(err) }
|
||||||
|
|
||||||
override string toString() { result = "Recoverable extraction error: " + err }
|
override string toString() { result = "Recoverable extraction error: " + err }
|
||||||
|
|
||||||
override string getErrorMessage() { result = err.getFullMessage() }
|
override string getProblemMessage() { result = err.getFullMessage() }
|
||||||
|
|
||||||
override File getFile() { result = err.getFile() }
|
override File getFile() { result = err.getFile() }
|
||||||
|
|
||||||
override Location getLocation() { result = err.getLocation() }
|
override Location getLocation() { result = err.getLocation() }
|
||||||
|
|
||||||
|
override int getSeverity() {
|
||||||
|
// Recoverable extraction problems don't tend to break the analysis, so we mark them in SARIF as
|
||||||
|
// [warnings](https://docs.oasis-open.org/sarif/sarif/v2.1.0/csprd01/sarif-v2.1.0-csprd01.html#_Toc10541338).
|
||||||
|
result = 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An unknown error happened during extraction.
|
* An unknown problem happened during extraction.
|
||||||
* These are only displayed if we know that we encountered an error during extraction,
|
* These are only displayed if we know that we encountered an problem during extraction,
|
||||||
* but, for some reason, failed to emit a proper diagnostic with location information
|
* but, for some reason, failed to emit a proper diagnostic with location information
|
||||||
* and error message.
|
* and problem message.
|
||||||
*/
|
*/
|
||||||
class ExtractionUnknownError extends ExtractionError, TUnknownError {
|
class ExtractionUnknownProblem extends ExtractionProblem, TUnknownProblem {
|
||||||
CompilerError err;
|
CompilerError err;
|
||||||
|
|
||||||
ExtractionUnknownError() { this = TUnknownError(err) }
|
ExtractionUnknownProblem() { this = TUnknownProblem(err) }
|
||||||
|
|
||||||
override string toString() { result = "Unknown extraction error: " + err }
|
override string toString() { result = "Unknown extraction problem: " + err }
|
||||||
|
|
||||||
override string getErrorMessage() { result = err.getFullMessage() }
|
override string getProblemMessage() { result = err.getFullMessage() }
|
||||||
|
|
||||||
override File getFile() { result = err.getFile() }
|
override File getFile() { result = err.getFile() }
|
||||||
|
|
||||||
override Location getLocation() { result = err.getLocation() }
|
override Location getLocation() { result = err.getLocation() }
|
||||||
|
|
||||||
|
override int getSeverity() {
|
||||||
|
// Unknown extraction problems don't tend to break the analysis, so we mark them in SARIF as
|
||||||
|
// [warnings](https://docs.oasis-open.org/sarif/sarif/v2.1.0/csprd01/sarif-v2.1.0-csprd01.html#_Toc10541338).
|
||||||
|
result = 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
18
cpp/ql/src/Diagnostics/ExtractionWarnings.ql
Normal file
18
cpp/ql/src/Diagnostics/ExtractionWarnings.ql
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* @name Extraction warnings
|
||||||
|
* @description List all extraction warnings for files in the source code directory.
|
||||||
|
* @kind diagnostic
|
||||||
|
* @id cpp/diagnostics/extraction-warnings
|
||||||
|
*/
|
||||||
|
|
||||||
|
import cpp
|
||||||
|
import ExtractionProblems
|
||||||
|
|
||||||
|
from ExtractionProblem warning
|
||||||
|
where
|
||||||
|
warning instanceof ExtractionRecoverableWarning and exists(warning.getFile().getRelativePath())
|
||||||
|
or
|
||||||
|
warning instanceof ExtractionUnknownProblem
|
||||||
|
select warning,
|
||||||
|
"Extraction failed in " + warning.getFile() + " with warning " + warning.getProblemMessage(),
|
||||||
|
warning.getSeverity()
|
||||||
@@ -13,6 +13,9 @@ string describe(Compilation c) {
|
|||||||
else result = "extractor invocation " + concat(int i | | c.getArgument(i), " " order by i)
|
else result = "extractor invocation " + concat(int i | | c.getArgument(i), " " order by i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Gets the SARIF severity level that indicates an error. */
|
||||||
|
private int getErrorSeverity() { result = 2 }
|
||||||
|
|
||||||
from Compilation c
|
from Compilation c
|
||||||
where not c.normalTermination()
|
where not c.normalTermination()
|
||||||
select "Extraction aborted for " + describe(c)
|
select "Extraction aborted for " + describe(c), getErrorSeverity()
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
/**
|
/**
|
||||||
* @name Successfully extracted files
|
* @name Successfully extracted files
|
||||||
* @description Lists all files in the source code directory that were extracted without encountering an error in the file.
|
* @description Lists all files in the source code directory that were extracted without encountering a problem in the file.
|
||||||
* @kind diagnostic
|
* @kind diagnostic
|
||||||
* @id cpp/diagnostics/successfully-extracted-files
|
* @id cpp/diagnostics/successfully-extracted-files
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
import ExtractionErrors
|
import ExtractionProblems
|
||||||
|
|
||||||
from File f
|
from File f
|
||||||
where
|
where
|
||||||
not exists(ExtractionError e | e.getFile() = f) and
|
not exists(ExtractionProblem e | e.getFile() = f) and
|
||||||
exists(f.getRelativePath())
|
exists(f.getRelativePath())
|
||||||
select f, ""
|
select f, "File successfully extracted"
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ class CommentBlock extends Comment {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
|||||||
@@ -166,6 +166,7 @@ class VarAnalyzableExpr extends AnalyzableExpr, VariableAccess {
|
|||||||
* Holds if `t` is not an instance of `IntegralType`,
|
* Holds if `t` is not an instance of `IntegralType`,
|
||||||
* or if `me` cannot be proven to not overflow
|
* or if `me` cannot be proven to not overflow
|
||||||
*/
|
*/
|
||||||
|
pragma[inline]
|
||||||
predicate overflows(MulExpr me, Type t) {
|
predicate overflows(MulExpr me, Type t) {
|
||||||
t instanceof IntegralType
|
t instanceof IntegralType
|
||||||
implies
|
implies
|
||||||
|
|||||||
@@ -50,10 +50,7 @@ where
|
|||||||
// If either of the operands is constant, then don't include it.
|
// If either of the operands is constant, then don't include it.
|
||||||
(
|
(
|
||||||
if cmp.getLeftOperand().isConstant()
|
if cmp.getLeftOperand().isConstant()
|
||||||
then
|
then not cmp.getRightOperand().isConstant() and reason = rightReason
|
||||||
if cmp.getRightOperand().isConstant()
|
|
||||||
then none() // Both operands are constant so don't create a message.
|
|
||||||
else reason = rightReason
|
|
||||||
else
|
else
|
||||||
if cmp.getRightOperand().isConstant()
|
if cmp.getRightOperand().isConstant()
|
||||||
then reason = leftReason
|
then reason = leftReason
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/improper-null-termination
|
* @id cpp/improper-null-termination
|
||||||
* @problem.severity warning
|
* @problem.severity warning
|
||||||
|
* @precision medium
|
||||||
* @security-severity 7.8
|
* @security-severity 7.8
|
||||||
* @tags security
|
* @tags security
|
||||||
* external/cwe/cwe-170
|
* external/cwe/cwe-170
|
||||||
@@ -53,6 +54,7 @@ class ImproperNullTerminationReachability extends StackVariableReachabilityWithR
|
|||||||
override predicate isBarrier(ControlFlowNode node, StackVariable v) {
|
override predicate isBarrier(ControlFlowNode node, StackVariable v) {
|
||||||
exprDefinition(v, node, _) or
|
exprDefinition(v, node, _) or
|
||||||
mayAddNullTerminator(node, v.getAnAccess()) or
|
mayAddNullTerminator(node, v.getAnAccess()) or
|
||||||
|
node.(AddressOfExpr).getOperand() = v.getAnAccess() or // address taken
|
||||||
isSinkActual(node, v) // only report first use
|
isSinkActual(node, v) // only report first use
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class RangeFunction extends Function {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
||||||
super.getLocation().hasLocationInfo(path, sl, sc, _, _) and
|
super.getLocation().hasLocationInfo(path, sl, sc, _, _) and
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
* @description Using user-supplied data in an OS command, without
|
* @description Using user-supplied data in an OS command, without
|
||||||
* neutralizing special elements, can make code vulnerable
|
* neutralizing special elements, can make code vulnerable
|
||||||
* to command injection.
|
* to command injection.
|
||||||
* @kind problem
|
* @kind path-problem
|
||||||
* @problem.severity error
|
* @problem.severity error
|
||||||
* @security-severity 9.8
|
* @security-severity 9.8
|
||||||
* @precision low
|
* @precision high
|
||||||
* @id cpp/command-line-injection
|
* @id cpp/command-line-injection
|
||||||
* @tags security
|
* @tags security
|
||||||
* external/cwe/cwe-078
|
* external/cwe/cwe-078
|
||||||
@@ -16,13 +16,204 @@
|
|||||||
import cpp
|
import cpp
|
||||||
import semmle.code.cpp.security.CommandExecution
|
import semmle.code.cpp.security.CommandExecution
|
||||||
import semmle.code.cpp.security.Security
|
import semmle.code.cpp.security.Security
|
||||||
import semmle.code.cpp.security.TaintTracking
|
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||||
|
import semmle.code.cpp.ir.IR
|
||||||
|
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
|
||||||
|
|
||||||
from Expr taintedArg, Expr taintSource, string taintCause, string callChain
|
Expr sinkAsArgumentIndirection(DataFlow::Node sink) {
|
||||||
|
result =
|
||||||
|
sink.asOperand()
|
||||||
|
.(SideEffectOperand)
|
||||||
|
.getAddressOperand()
|
||||||
|
.getAnyDef()
|
||||||
|
.getUnconvertedResultExpression()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `fst` is a string that is used in a format or concatenation function resulting in `snd`,
|
||||||
|
* and is *not* placed at the start of the resulting string. This indicates that the author did not
|
||||||
|
* expect `fst` to control what program is run if the resulting string is eventually interpreted as
|
||||||
|
* a command line, for example as an argument to `system`.
|
||||||
|
*/
|
||||||
|
predicate interestingConcatenation(DataFlow::Node fst, DataFlow::Node snd) {
|
||||||
|
exists(FormattingFunctionCall call, int index, FormatLiteral literal |
|
||||||
|
sinkAsArgumentIndirection(fst) = call.getConversionArgument(index) and
|
||||||
|
snd.asDefiningArgument() = call.getOutputArgument(false) and
|
||||||
|
literal = call.getFormat() and
|
||||||
|
not literal.getConvSpecOffset(index) = 0 and
|
||||||
|
literal.getConversionChar(index) = ["s", "S"]
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// strcat and friends
|
||||||
|
exists(StrcatFunction strcatFunc, CallInstruction call, ReadSideEffectInstruction rse |
|
||||||
|
call.getStaticCallTarget() = strcatFunc and
|
||||||
|
rse.getArgumentDef() = call.getArgument(strcatFunc.getParamSrc()) and
|
||||||
|
fst.asOperand() = rse.getSideEffectOperand() and
|
||||||
|
snd.asInstruction().(WriteSideEffectInstruction).getDestinationAddress() =
|
||||||
|
call.getArgument(strcatFunc.getParamDest())
|
||||||
|
)
|
||||||
|
or
|
||||||
|
exists(CallInstruction call, Operator op, ReadSideEffectInstruction rse |
|
||||||
|
call.getStaticCallTarget() = op and
|
||||||
|
op.hasQualifiedName("std", "operator+") and
|
||||||
|
op.getType().(UserType).hasQualifiedName("std", "basic_string") and
|
||||||
|
call.getArgument(1) = rse.getArgumentOperand().getAnyDef() and // left operand
|
||||||
|
fst.asOperand() = rse.getSideEffectOperand() and
|
||||||
|
call = snd.asInstruction()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
class TaintToConcatenationConfiguration extends TaintTracking::Configuration {
|
||||||
|
TaintToConcatenationConfiguration() { this = "TaintToConcatenationConfiguration" }
|
||||||
|
|
||||||
|
override predicate isSource(DataFlow::Node source) { source instanceof FlowSource }
|
||||||
|
|
||||||
|
override predicate isSink(DataFlow::Node sink) { interestingConcatenation(sink, _) }
|
||||||
|
|
||||||
|
override predicate isSanitizer(DataFlow::Node node) {
|
||||||
|
node.asInstruction().getResultType() instanceof IntegralType
|
||||||
|
or
|
||||||
|
node.asInstruction().getResultType() instanceof FloatingPointType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ExecTaintConfiguration extends TaintTracking2::Configuration {
|
||||||
|
ExecTaintConfiguration() { this = "ExecTaintConfiguration" }
|
||||||
|
|
||||||
|
override predicate isSource(DataFlow::Node source) {
|
||||||
|
exists(DataFlow::Node prevSink, TaintToConcatenationConfiguration conf |
|
||||||
|
conf.hasFlow(_, prevSink) and
|
||||||
|
interestingConcatenation(prevSink, source)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module StitchedPathGraph {
|
||||||
|
// There's a different PathNode class for each DataFlowImplN.qll, so we can't simply combine the
|
||||||
|
// PathGraph predicates directly. Instead, we use a newtype so there's a single type that
|
||||||
|
// contains both sets of PathNodes.
|
||||||
|
newtype TMergedPathNode =
|
||||||
|
TPathNode1(DataFlow::PathNode node) or
|
||||||
|
TPathNode2(DataFlow2::PathNode node)
|
||||||
|
|
||||||
|
// this wraps the toString and location predicates so we can use the merged node type in a
|
||||||
|
// selection
|
||||||
|
class MergedPathNode extends TMergedPathNode {
|
||||||
|
string toString() {
|
||||||
|
exists(DataFlow::PathNode n |
|
||||||
|
this = TPathNode1(n) and
|
||||||
|
result = n.toString()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
exists(DataFlow2::PathNode n |
|
||||||
|
this = TPathNode2(n) and
|
||||||
|
result = n.toString()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
DataFlow::Node getNode() {
|
||||||
|
exists(DataFlow::PathNode n |
|
||||||
|
this = TPathNode1(n) and
|
||||||
|
result = n.getNode()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
exists(DataFlow2::PathNode n |
|
||||||
|
this = TPathNode2(n) and
|
||||||
|
result = n.getNode()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
DataFlow::PathNode getPathNode1() { this = TPathNode1(result) }
|
||||||
|
|
||||||
|
DataFlow2::PathNode getPathNode2() { this = TPathNode2(result) }
|
||||||
|
|
||||||
|
predicate hasLocationInfo(
|
||||||
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
) {
|
||||||
|
exists(DataFlow::PathNode n |
|
||||||
|
this = TPathNode1(n) and
|
||||||
|
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
exists(DataFlow2::PathNode n |
|
||||||
|
this = TPathNode2(n) and
|
||||||
|
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate edges(MergedPathNode a, MergedPathNode b) {
|
||||||
|
exists(DataFlow::PathNode an, DataFlow::PathNode bn |
|
||||||
|
a = TPathNode1(an) and
|
||||||
|
b = TPathNode1(bn) and
|
||||||
|
DataFlow::PathGraph::edges(an, bn)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
exists(DataFlow2::PathNode an, DataFlow2::PathNode bn |
|
||||||
|
a = TPathNode2(an) and
|
||||||
|
b = TPathNode2(bn) and
|
||||||
|
DataFlow2::PathGraph::edges(an, bn)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// This is where paths from the two configurations are connected. `interestingConcatenation`
|
||||||
|
// is the only thing in this module that's actually specific to the query - everything else is
|
||||||
|
// just using types and predicates from the DataFlow library.
|
||||||
|
interestingConcatenation(a.getNode(), b.getNode()) and
|
||||||
|
a instanceof TPathNode1 and
|
||||||
|
b instanceof TPathNode2
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate nodes(MergedPathNode mpn, string key, string val) {
|
||||||
|
// here we just need the union of the underlying `nodes` predicates
|
||||||
|
exists(DataFlow::PathNode n |
|
||||||
|
mpn = TPathNode1(n) and
|
||||||
|
DataFlow::PathGraph::nodes(n, key, val)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
exists(DataFlow2::PathNode n |
|
||||||
|
mpn = TPathNode2(n) and
|
||||||
|
DataFlow2::PathGraph::nodes(n, key, val)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
query predicate subpaths(
|
||||||
|
MergedPathNode arg, MergedPathNode par, MergedPathNode ret, MergedPathNode out
|
||||||
|
) {
|
||||||
|
// just forward subpaths from the underlying libraries. This might be slightly awkward when
|
||||||
|
// the concatenation is deep in a call chain.
|
||||||
|
DataFlow::PathGraph::subpaths(arg.getPathNode1(), par.getPathNode1(), ret.getPathNode1(),
|
||||||
|
out.getPathNode1())
|
||||||
|
or
|
||||||
|
DataFlow2::PathGraph::subpaths(arg.getPathNode2(), par.getPathNode2(), ret.getPathNode2(),
|
||||||
|
out.getPathNode2())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
import StitchedPathGraph
|
||||||
|
|
||||||
|
from
|
||||||
|
DataFlow::PathNode sourceNode, DataFlow::PathNode concatSink, DataFlow2::PathNode concatSource,
|
||||||
|
DataFlow2::PathNode sinkNode, string taintCause, string callChain,
|
||||||
|
TaintToConcatenationConfiguration conf1, ExecTaintConfiguration conf2
|
||||||
where
|
where
|
||||||
shellCommand(taintedArg, callChain) and
|
taintCause = sourceNode.getNode().(FlowSource).getSourceType() and
|
||||||
tainted(taintSource, taintedArg) and
|
conf1.hasFlowPath(sourceNode, concatSink) and
|
||||||
isUserInput(taintSource, taintCause)
|
interestingConcatenation(concatSink.getNode(), concatSource.getNode()) and // this loses call context
|
||||||
select taintedArg,
|
conf2.hasFlowPath(concatSource, sinkNode) and
|
||||||
"This argument to an OS command is derived from $@ and then passed to " + callChain, taintSource,
|
shellCommand(sinkAsArgumentIndirection(sinkNode.getNode()), callChain)
|
||||||
"user input (" + taintCause + ")"
|
select sinkAsArgumentIndirection(sinkNode.getNode()), TPathNode1(sourceNode).(MergedPathNode),
|
||||||
|
TPathNode2(sinkNode).(MergedPathNode),
|
||||||
|
"This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to "
|
||||||
|
+ callChain, sourceNode, "user input (" + taintCause + ")", concatSource,
|
||||||
|
concatSource.toString()
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/user-controlled-null-termination-tainted
|
* @id cpp/user-controlled-null-termination-tainted
|
||||||
* @problem.severity warning
|
* @problem.severity warning
|
||||||
|
* @precision medium
|
||||||
* @security-severity 10.0
|
* @security-severity 10.0
|
||||||
* @tags security
|
* @tags security
|
||||||
* external/cwe/cwe-170
|
* external/cwe/cwe-170
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ storage.</p>
|
|||||||
</overview>
|
</overview>
|
||||||
<recommendation>
|
<recommendation>
|
||||||
|
|
||||||
<p>Ensure that sensitive information is always encrypted before being stored, especially before writing to a file.
|
<p>Ensure that sensitive information is always encrypted before being stored to a file or transmitted over the network.
|
||||||
It may be wise to encrypt information before it is put into a buffer that may be readable in memory.</p>
|
It may be wise to encrypt information before it is put into a buffer that may be readable in memory.</p>
|
||||||
|
|
||||||
<p>In general, decrypt sensitive information only at the point where it is necessary for it to be used in
|
<p>In general, decrypt sensitive information only at the point where it is necessary for it to be used in
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<!DOCTYPE qhelp PUBLIC
|
||||||
|
"-//Semmle//qhelp//EN"
|
||||||
|
"qhelp.dtd">
|
||||||
|
<qhelp>
|
||||||
|
<include src="CleartextStorage.inc.qhelp" /></qhelp>
|
||||||
124
cpp/ql/src/Security/CWE/CWE-311/CleartextTransmission.ql
Normal file
124
cpp/ql/src/Security/CWE/CWE-311/CleartextTransmission.ql
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
/**
|
||||||
|
* @name Cleartext transmission of sensitive information
|
||||||
|
* @description Transmitting sensitive information across a network in
|
||||||
|
* cleartext can expose it to an attacker.
|
||||||
|
* @kind path-problem
|
||||||
|
* @problem.severity warning
|
||||||
|
* @security-severity 7.5
|
||||||
|
* @precision medium
|
||||||
|
* @id cpp/cleartext-transmission
|
||||||
|
* @tags security
|
||||||
|
* external/cwe/cwe-319
|
||||||
|
*/
|
||||||
|
|
||||||
|
import cpp
|
||||||
|
import semmle.code.cpp.security.SensitiveExprs
|
||||||
|
import semmle.code.cpp.dataflow.TaintTracking
|
||||||
|
import semmle.code.cpp.models.interfaces.FlowSource
|
||||||
|
import DataFlow::PathGraph
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function call that sends or receives data over a network.
|
||||||
|
*/
|
||||||
|
abstract class NetworkSendRecv extends FunctionCall {
|
||||||
|
/**
|
||||||
|
* Gets the expression for the socket or similar object used for sending or
|
||||||
|
* receiving data (if any).
|
||||||
|
*/
|
||||||
|
abstract Expr getSocketExpr();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the expression for the buffer to be sent from / received into.
|
||||||
|
*/
|
||||||
|
abstract Expr getDataExpr();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function call that sends data over a network.
|
||||||
|
*
|
||||||
|
* note: functions such as `write` may be writing to a network source or a file. We could attempt to determine which, and sort results into `cpp/cleartext-transmission` and perhaps `cpp/cleartext-storage-file`. In practice it usually isn't very important which query reports a result as long as its reported exactly once.
|
||||||
|
*/
|
||||||
|
class NetworkSend extends NetworkSendRecv {
|
||||||
|
RemoteFlowSinkFunction target;
|
||||||
|
|
||||||
|
NetworkSend() { target = this.getTarget() }
|
||||||
|
|
||||||
|
override Expr getSocketExpr() {
|
||||||
|
exists(FunctionInput input, int arg |
|
||||||
|
target.hasSocketInput(input) and
|
||||||
|
input.isParameter(arg) and
|
||||||
|
result = this.getArgument(arg)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override Expr getDataExpr() {
|
||||||
|
exists(FunctionInput input, int arg |
|
||||||
|
target.hasRemoteFlowSink(input, _) and
|
||||||
|
input.isParameterDeref(arg) and
|
||||||
|
result = this.getArgument(arg)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function call that receives data over a network.
|
||||||
|
*/
|
||||||
|
class NetworkRecv extends NetworkSendRecv {
|
||||||
|
RemoteFlowSourceFunction target;
|
||||||
|
|
||||||
|
NetworkRecv() { target = this.getTarget() }
|
||||||
|
|
||||||
|
override Expr getSocketExpr() {
|
||||||
|
exists(FunctionInput input, int arg |
|
||||||
|
target.hasSocketInput(input) and
|
||||||
|
input.isParameter(arg) and
|
||||||
|
result = this.getArgument(arg)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override Expr getDataExpr() {
|
||||||
|
exists(FunctionOutput output, int arg |
|
||||||
|
target.hasRemoteFlowSource(output, _) and
|
||||||
|
output.isParameterDeref(arg) and
|
||||||
|
result = this.getArgument(arg)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Taint flow from a sensitive expression to a network operation with data
|
||||||
|
* tainted by that expression.
|
||||||
|
*/
|
||||||
|
class SensitiveSendRecvConfiguration extends TaintTracking::Configuration {
|
||||||
|
SensitiveSendRecvConfiguration() { this = "SensitiveSendRecvConfiguration" }
|
||||||
|
|
||||||
|
override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof SensitiveExpr }
|
||||||
|
|
||||||
|
override predicate isSink(DataFlow::Node sink) {
|
||||||
|
exists(NetworkSendRecv transmission |
|
||||||
|
sink.asExpr() = transmission.getDataExpr() and
|
||||||
|
// a zero socket descriptor is standard input, which is not interesting for this query.
|
||||||
|
not exists(Zero zero |
|
||||||
|
DataFlow::localFlow(DataFlow::exprNode(zero),
|
||||||
|
DataFlow::exprNode(transmission.getSocketExpr()))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
from
|
||||||
|
SensitiveSendRecvConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink,
|
||||||
|
NetworkSendRecv transmission, string msg
|
||||||
|
where
|
||||||
|
config.hasFlowPath(source, sink) and
|
||||||
|
sink.getNode().asExpr() = transmission.getDataExpr() and
|
||||||
|
if transmission instanceof NetworkSend
|
||||||
|
then
|
||||||
|
msg =
|
||||||
|
"This operation transmits '" + sink.toString() +
|
||||||
|
"', which may contain unencrypted sensitive data from $@"
|
||||||
|
else
|
||||||
|
msg =
|
||||||
|
"This operation receives into '" + sink.toString() +
|
||||||
|
"', which may put unencrypted sensitive data into $@"
|
||||||
|
select transmission, source, sink, msg, source, source.getNode().asExpr().toString()
|
||||||
@@ -121,16 +121,14 @@ predicate exprSourceType(Expr use, Type sourceType, Location sourceLoc) {
|
|||||||
else
|
else
|
||||||
if use instanceof CrementOperation
|
if use instanceof CrementOperation
|
||||||
then exprSourceType(use.(CrementOperation).getOperand(), sourceType, sourceLoc)
|
then exprSourceType(use.(CrementOperation).getOperand(), sourceType, sourceLoc)
|
||||||
else
|
else (
|
||||||
// Conversions are not in the AST, so ignore them.
|
// Conversions are not in the AST, so ignore them.
|
||||||
if use instanceof Conversion
|
not use instanceof Conversion and
|
||||||
then none()
|
// Source expressions
|
||||||
else (
|
sourceType = use.getUnspecifiedType() and
|
||||||
// Source expressions
|
isPointerType(sourceType) and
|
||||||
sourceType = use.getUnspecifiedType() and
|
sourceLoc = use.getLocation()
|
||||||
isPointerType(sourceType) and
|
)
|
||||||
sourceLoc = use.getLocation()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -4,10 +4,13 @@
|
|||||||
* @kind problem
|
* @kind problem
|
||||||
* @id cpp/incorrect-allocation-error-handling
|
* @id cpp/incorrect-allocation-error-handling
|
||||||
* @problem.severity warning
|
* @problem.severity warning
|
||||||
|
* @security-severity 7.5
|
||||||
* @precision medium
|
* @precision medium
|
||||||
* @tags correctness
|
* @tags correctness
|
||||||
* security
|
* security
|
||||||
* external/cwe/cwe-570
|
* external/cwe/cwe-570
|
||||||
|
* external/cwe/cwe-252
|
||||||
|
* external/cwe/cwe-755
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class Top extends Element {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
pragma[noopt]
|
pragma[noopt]
|
||||||
final predicate hasLocationInfo(
|
final predicate hasLocationInfo(
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
...
|
||||||
|
int myFclose(FILE * fmy)
|
||||||
|
{
|
||||||
|
if(!fclose(fmy)) {
|
||||||
|
fmy = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
...
|
||||||
|
fe = fopen("myFile.txt", "wt");
|
||||||
|
...
|
||||||
|
fclose(fe); // BAD
|
||||||
|
...
|
||||||
|
fe = fopen("myFile.txt", "wt");
|
||||||
|
...
|
||||||
|
myFclose(fe); // GOOD
|
||||||
|
...
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<!DOCTYPE qhelp PUBLIC
|
||||||
|
"-//Semmle//qhelp//EN"
|
||||||
|
"qhelp.dtd">
|
||||||
|
<qhelp>
|
||||||
|
<overview>
|
||||||
|
<p>The presence of a shell function with additional check indicates the possible risks of the call. Use this check everywhere.</p>
|
||||||
|
|
||||||
|
</overview>
|
||||||
|
|
||||||
|
<example>
|
||||||
|
<p>The following example demonstrates fallacious and fixed methods of using wrapper functions.</p>
|
||||||
|
<sample src="FindWrapperFunctions.cpp" />
|
||||||
|
|
||||||
|
</example>
|
||||||
|
<references>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
CERT C Coding Standard:
|
||||||
|
<a href="https://wiki.sei.cmu.edu/confluence/display/java/JNI00-J.+Define+wrappers+around+native+methods">JNI00-J. Define wrappers around native methods</a>.
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</references>
|
||||||
|
</qhelp>
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
/**
|
||||||
|
* @name Missed opportunity to call wrapper function
|
||||||
|
* @description If a wrapper function is defined for a given function, any call to the given function should be via the wrapper function.
|
||||||
|
* @kind problem
|
||||||
|
* @id cpp/call-to-function-without-wrapper
|
||||||
|
* @problem.severity warning
|
||||||
|
* @precision medium
|
||||||
|
* @tags correctness
|
||||||
|
* maintainability
|
||||||
|
* security
|
||||||
|
* external/cwe/cwe-1041
|
||||||
|
*/
|
||||||
|
|
||||||
|
import cpp
|
||||||
|
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||||
|
import semmle.code.cpp.commons.Assertions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function call that is used in error situations (logging, throwing an exception, abnormal termination).
|
||||||
|
*/
|
||||||
|
class CallUsedToHandleErrors extends FunctionCall {
|
||||||
|
CallUsedToHandleErrors() {
|
||||||
|
// call that is known to not return
|
||||||
|
not exists(this.(ControlFlowNode).getASuccessor())
|
||||||
|
or
|
||||||
|
// call throwing an exception
|
||||||
|
exists(ThrowExpr tex | tex = this.(ControlFlowNode).getASuccessor())
|
||||||
|
or
|
||||||
|
// call logging a message, possibly an error
|
||||||
|
exists(FormattingFunction ff | ff = this.(ControlFlowNode).getASuccessor())
|
||||||
|
or
|
||||||
|
// enabling recursive search
|
||||||
|
exists(CallUsedToHandleErrors fr | getTarget() = fr.getEnclosingFunction())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if the conditions for a call outside the wrapper function are met. */
|
||||||
|
predicate conditionsOutsideWrapper(FunctionCall fcp) {
|
||||||
|
fcp.getNumberOfArguments() > 0 and
|
||||||
|
not exists(ConditionalStmt cdtmp | fcp.getEnclosingStmt().getParentStmt*() = cdtmp) and
|
||||||
|
not exists(Loop lptmp | fcp.getEnclosingStmt().getParentStmt*() = lptmp) and
|
||||||
|
not exists(ReturnStmt rttmp | fcp.getEnclosingStmt().getParentStmt*() = rttmp) and
|
||||||
|
not exists(FunctionCall fctmp2 | fcp = fctmp2.getAnArgument().getAChild*()) and
|
||||||
|
not exists(Assignment astmp | fcp = astmp.getRValue().getAChild*()) and
|
||||||
|
not exists(Initializer intmp | fcp = intmp.getExpr().getAChild*()) and
|
||||||
|
not exists(Assertion astmp | fcp = astmp.getAsserted().getAChild*()) and
|
||||||
|
not exists(Operation optmp | fcp = optmp.getAChild*()) and
|
||||||
|
not exists(ArrayExpr aetmp | fcp = aetmp.getAChild*()) and
|
||||||
|
not exists(ExprCall ectmp | fcp = ectmp.getAnArgument().getAChild*())
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if the conditions for calling `fcp` inside the `fnp` wrapper function are met. */
|
||||||
|
pragma[inline]
|
||||||
|
predicate conditionsInsideWrapper(FunctionCall fcp, Function fnp) {
|
||||||
|
not exists(FunctionCall fctmp2 |
|
||||||
|
fctmp2.getEnclosingFunction() = fnp and fcp = fctmp2.getAnArgument().getAChild*()
|
||||||
|
) and
|
||||||
|
not fcp instanceof CallUsedToHandleErrors and
|
||||||
|
not fcp.getAnArgument().isConstant() and
|
||||||
|
fcp.getEnclosingFunction() = fnp and
|
||||||
|
fnp.getNumberOfParameters() > 0 and
|
||||||
|
// the call arguments must be passed through the arguments of the wrapper function
|
||||||
|
forall(int i | i in [0 .. fcp.getNumberOfArguments() - 1] |
|
||||||
|
globalValueNumber(fcp.getArgument(i)) = globalValueNumber(fnp.getAParameter().getAnAccess())
|
||||||
|
) and
|
||||||
|
// there should be no more than one required call inside the wrapper function
|
||||||
|
not exists(FunctionCall fctmp |
|
||||||
|
fctmp.getTarget() = fcp.getTarget() and
|
||||||
|
fctmp.getFile() = fcp.getFile() and
|
||||||
|
fctmp != fcp and
|
||||||
|
fctmp.getEnclosingFunction() = fnp
|
||||||
|
) and
|
||||||
|
// inside the wrapper function there should be no calls without paths to the desired function
|
||||||
|
not exists(FunctionCall fctmp |
|
||||||
|
fctmp.getEnclosingFunction() = fnp and
|
||||||
|
fctmp.getFile() = fcp.getFile() and
|
||||||
|
fctmp != fcp and
|
||||||
|
(
|
||||||
|
fctmp = fcp.getAPredecessor+()
|
||||||
|
or
|
||||||
|
not exists(FunctionCall fctmp1 |
|
||||||
|
fctmp1 = fcp and
|
||||||
|
(
|
||||||
|
fctmp.getASuccessor+() = fctmp1 or
|
||||||
|
fctmp.getAPredecessor+() = fctmp1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Holds if the conditions for the wrapper function are met. */
|
||||||
|
pragma[inline]
|
||||||
|
predicate conditionsForWrapper(FunctionCall fcp, Function fnp) {
|
||||||
|
not exists(ExprCall ectmp | fnp = ectmp.getEnclosingFunction()) and
|
||||||
|
not exists(Loop lp | lp.getEnclosingFunction() = fnp) and
|
||||||
|
not exists(SwitchStmt sw | sw.getEnclosingFunction() = fnp) and
|
||||||
|
not fnp instanceof Operator and
|
||||||
|
// inside the wrapper function there should be checks of arguments or the result,
|
||||||
|
// perhaps by means of passing the latter as an argument to some function
|
||||||
|
(
|
||||||
|
exists(IfStmt ifs |
|
||||||
|
ifs.getEnclosingFunction() = fnp and
|
||||||
|
(
|
||||||
|
globalValueNumber(ifs.getCondition().getAChild*()) = globalValueNumber(fcp.getAnArgument()) and
|
||||||
|
ifs.getASuccessor*() = fcp
|
||||||
|
or
|
||||||
|
ifs.getCondition().getAChild() = fcp
|
||||||
|
)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
exists(FunctionCall fctmp |
|
||||||
|
fctmp.getEnclosingFunction() = fnp and
|
||||||
|
globalValueNumber(fctmp.getAnArgument().getAChild*()) = globalValueNumber(fcp)
|
||||||
|
)
|
||||||
|
) and
|
||||||
|
// inside the wrapper function there must be a function call to handle the error
|
||||||
|
exists(CallUsedToHandleErrors fctmp |
|
||||||
|
fctmp.getEnclosingFunction() = fnp and
|
||||||
|
forall(int i | i in [0 .. fnp.getNumberOfParameters() - 1] |
|
||||||
|
fnp.getParameter(i).getAnAccess().getTarget() =
|
||||||
|
fcp.getAnArgument().(VariableAccess).getTarget() or
|
||||||
|
fnp.getParameter(i).getUnspecifiedType() instanceof Class or
|
||||||
|
fnp.getParameter(i).getUnspecifiedType().(ReferenceType).getBaseType() instanceof Class or
|
||||||
|
fnp.getParameter(i).getAnAccess().getTarget() =
|
||||||
|
fctmp.getAnArgument().(VariableAccess).getTarget()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
from FunctionCall fc, Function fn
|
||||||
|
where
|
||||||
|
exists(FunctionCall fctmp |
|
||||||
|
conditionsInsideWrapper(fctmp, fn) and
|
||||||
|
conditionsForWrapper(fctmp, fn) and
|
||||||
|
conditionsOutsideWrapper(fc) and
|
||||||
|
fctmp.getTarget() = fc.getTarget() and
|
||||||
|
fc.getEnclosingFunction() != fn and
|
||||||
|
fc.getEnclosingFunction().getMetrics().getNumberOfCalls() > fn.getMetrics().getNumberOfCalls()
|
||||||
|
)
|
||||||
|
select fc, "Consider changing the call to $@", fn, fn.getName()
|
||||||
2
cpp/ql/src/external/CodeDuplication.qll
vendored
2
cpp/ql/src/external/CodeDuplication.qll
vendored
@@ -61,7 +61,7 @@ class Copy extends @duplication_or_similarity {
|
|||||||
* The location spans column `startcolumn` of line `startline` to
|
* The location spans column `startcolumn` of line `startline` to
|
||||||
* column `endcolumn` of line `endline` in file `filepath`.
|
* column `endcolumn` of line `endline` in file `filepath`.
|
||||||
* For more information, see
|
* For more information, see
|
||||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
predicate hasLocationInfo(
|
predicate hasLocationInfo(
|
||||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||||
|
|||||||
2
cpp/ql/src/external/DefectFilter.qll
vendored
2
cpp/ql/src/external/DefectFilter.qll
vendored
@@ -8,7 +8,7 @@ import cpp
|
|||||||
* column `startcolumn` of line `startline` to column `endcolumn` of line `endline`
|
* column `startcolumn` of line `startline` to column `endcolumn` of line `endline`
|
||||||
* in file `filepath`.
|
* in file `filepath`.
|
||||||
*
|
*
|
||||||
* For more information, see [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* For more information, see [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
external predicate defectResults(
|
external predicate defectResults(
|
||||||
int id, string queryPath, string file, int startline, int startcol, int endline, int endcol,
|
int id, string queryPath, string file, int startline, int startcol, int endline, int endcol,
|
||||||
|
|||||||
2
cpp/ql/src/external/MetricFilter.qll
vendored
2
cpp/ql/src/external/MetricFilter.qll
vendored
@@ -8,7 +8,7 @@ import cpp
|
|||||||
* column `startcolumn` of line `startline` to column `endcolumn` of line `endline`
|
* column `startcolumn` of line `startline` to column `endcolumn` of line `endline`
|
||||||
* in file `filepath`.
|
* in file `filepath`.
|
||||||
*
|
*
|
||||||
* For more information, see [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
* For more information, see [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||||
*/
|
*/
|
||||||
external predicate metricResults(
|
external predicate metricResults(
|
||||||
int id, string queryPath, string file, int startline, int startcol, int endline, int endcol,
|
int id, string queryPath, string file, int startline, int startcol, int endline, int endcol,
|
||||||
|
|||||||
@@ -230,13 +230,13 @@ predicate leakedInSameMethod(Resource r, Expr acquire) {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
or
|
)
|
||||||
exists(FunctionAccess fa, string kind |
|
or
|
||||||
// the address of a function that releases `r` is taken (and likely
|
exists(FunctionAccess fa, string kind |
|
||||||
// used to release `r` at some point).
|
// the address of a function that releases `r` is taken (and likely
|
||||||
r.acquisitionWithRequiredKind(acquire, kind) and
|
// used to release `r` at some point).
|
||||||
fa.getTarget() = r.getAReleaseExpr(kind).getEnclosingFunction()
|
r.acquisitionWithRequiredKind(acquire, kind) and
|
||||||
)
|
fa.getTarget() = r.getAReleaseExpr(kind).getEnclosingFunction()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
* (in that the `.expected` file should always be empty).
|
* (in that the `.expected` file should always be empty).
|
||||||
*
|
*
|
||||||
* To add this framework to a new language:
|
* To add this framework to a new language:
|
||||||
* - Add a file `InlineExpectationsTestPrivate.qll` that defines a `LineComment` class. This class
|
* - Add a file `InlineExpectationsTestPrivate.qll` that defines a `ExpectationComment` class. This class
|
||||||
* must support a `getContents` method that returns the contents of the given comment, _excluding_
|
* must support a `getContents` method that returns the contents of the given comment, _excluding_
|
||||||
* the comment indicator itself. It should also define `toString` and `getLocation` as usual.
|
* the comment indicator itself. It should also define `toString` and `getLocation` as usual.
|
||||||
*
|
*
|
||||||
@@ -60,8 +60,8 @@
|
|||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
* ```cpp
|
* ```cpp
|
||||||
* int i = x + 5; // $const=5
|
* int i = x + 5; // $ const=5
|
||||||
* int j = y + (7 - 3) // $const=7 const=3 const=4 // The result of the subtraction is a constant.
|
* int j = y + (7 - 3) // $ const=7 const=3 const=4 // The result of the subtraction is a constant.
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* For tests that contain known missing and spurious results, it is possible to further
|
* For tests that contain known missing and spurious results, it is possible to further
|
||||||
@@ -194,7 +194,7 @@ private int getEndOfColumnPosition(int start, string content) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private predicate getAnExpectation(
|
private predicate getAnExpectation(
|
||||||
LineComment comment, TColumn column, string expectation, string tags, string value
|
ExpectationComment comment, TColumn column, string expectation, string tags, string value
|
||||||
) {
|
) {
|
||||||
exists(string content |
|
exists(string content |
|
||||||
content = comment.getContents().regexpCapture(expectationCommentPattern(), 1) and
|
content = comment.getContents().regexpCapture(expectationCommentPattern(), 1) and
|
||||||
@@ -247,14 +247,14 @@ private newtype TFailureLocatable =
|
|||||||
) {
|
) {
|
||||||
test.hasActualResult(location, element, tag, value)
|
test.hasActualResult(location, element, tag, value)
|
||||||
} or
|
} or
|
||||||
TValidExpectation(LineComment comment, string tag, string value, string knownFailure) {
|
TValidExpectation(ExpectationComment comment, string tag, string value, string knownFailure) {
|
||||||
exists(TColumn column, string tags |
|
exists(TColumn column, string tags |
|
||||||
getAnExpectation(comment, column, _, tags, value) and
|
getAnExpectation(comment, column, _, tags, value) and
|
||||||
tag = tags.splitAt(",") and
|
tag = tags.splitAt(",") and
|
||||||
knownFailure = getColumnString(column)
|
knownFailure = getColumnString(column)
|
||||||
)
|
)
|
||||||
} or
|
} or
|
||||||
TInvalidExpectation(LineComment comment, string expectation) {
|
TInvalidExpectation(ExpectationComment comment, string expectation) {
|
||||||
getAnExpectation(comment, _, expectation, _, _) and
|
getAnExpectation(comment, _, expectation, _, _) and
|
||||||
not expectation.regexpMatch(expectationPattern())
|
not expectation.regexpMatch(expectationPattern())
|
||||||
}
|
}
|
||||||
@@ -292,7 +292,7 @@ class ActualResult extends FailureLocatable, TActualResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract private class Expectation extends FailureLocatable {
|
abstract private class Expectation extends FailureLocatable {
|
||||||
LineComment comment;
|
ExpectationComment comment;
|
||||||
|
|
||||||
override string toString() { result = comment.toString() }
|
override string toString() { result = comment.toString() }
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
import cpp
|
import cpp
|
||||||
|
|
||||||
private newtype TLineComment = MkLineComment(CppStyleComment c)
|
private newtype TExpectationComment = MkExpectationComment(CppStyleComment c)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a line comment in the CPP style.
|
* Represents a line comment in the CPP style.
|
||||||
* Unlike the `CppStyleComment` class, however, the string returned by `getContents` does _not_
|
* Unlike the `CppStyleComment` class, however, the string returned by `getContents` does _not_
|
||||||
* include the preceding comment marker (`//`).
|
* include the preceding comment marker (`//`).
|
||||||
*/
|
*/
|
||||||
class LineComment extends TLineComment {
|
class ExpectationComment extends TExpectationComment {
|
||||||
CppStyleComment comment;
|
CppStyleComment comment;
|
||||||
|
|
||||||
LineComment() { this = MkLineComment(comment) }
|
ExpectationComment() { this = MkExpectationComment(comment) }
|
||||||
|
|
||||||
/** Returns the contents of the given comment, _without_ the preceding comment marker (`//`). */
|
/** Returns the contents of the given comment, _without_ the preceding comment marker (`//`). */
|
||||||
string getContents() { result = comment.getContents().suffix(2) }
|
string getContents() { result = comment.getContents().suffix(2) }
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
| test.cpp:23:3:23:8 | call to fclose | Consider changing the call to $@ | test.cpp:9:6:9:13 | myFclose | myFclose |
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
experimental/Security/CWE/CWE-1041/FindWrapperFunctions.ql
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#define NULL (0)
|
||||||
|
typedef int FILE;
|
||||||
|
FILE *fopen(const char *filename, const char *mode);
|
||||||
|
int fclose(FILE *stream);
|
||||||
|
extern FILE * fe;
|
||||||
|
extern int printf(const char *fmt, ...);
|
||||||
|
void exit(int status);
|
||||||
|
|
||||||
|
void myFclose(FILE * fmy)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if(fmy) {
|
||||||
|
i = fclose(fmy);
|
||||||
|
fmy = NULL;
|
||||||
|
printf("close end is code %d",i);
|
||||||
|
if(i!=0) exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
fe = fopen("myFile.txt", "wt");
|
||||||
|
fclose(fe); // BAD
|
||||||
|
fe = fopen("myFile.txt", "wt");
|
||||||
|
myFclose(fe); // GOOD
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
97
cpp/ql/test/include/iterator.h
Normal file
97
cpp/ql/test/include/iterator.h
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
#if !defined(CODEQL_ITERATOR_H)
|
||||||
|
#define CODEQL_ITERATOR_H
|
||||||
|
|
||||||
|
typedef unsigned long size_t;
|
||||||
|
|
||||||
|
#include "type_traits.h"
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
struct ptrdiff_t;
|
||||||
|
|
||||||
|
template<class I> struct iterator_traits;
|
||||||
|
|
||||||
|
template <class Category,
|
||||||
|
class value_type,
|
||||||
|
class difference_type = ptrdiff_t,
|
||||||
|
class pointer_type = value_type*,
|
||||||
|
class reference_type = value_type&>
|
||||||
|
struct iterator {
|
||||||
|
typedef Category iterator_category;
|
||||||
|
|
||||||
|
iterator();
|
||||||
|
iterator(iterator<Category, remove_const_t<value_type> > const &other); // non-const -> const conversion constructor
|
||||||
|
|
||||||
|
iterator &operator++();
|
||||||
|
iterator operator++(int);
|
||||||
|
iterator &operator--();
|
||||||
|
iterator operator--(int);
|
||||||
|
bool operator==(iterator other) const;
|
||||||
|
bool operator!=(iterator other) const;
|
||||||
|
reference_type operator*() const;
|
||||||
|
pointer_type operator->() const;
|
||||||
|
iterator operator+(int);
|
||||||
|
iterator operator-(int);
|
||||||
|
iterator &operator+=(int);
|
||||||
|
iterator &operator-=(int);
|
||||||
|
int operator-(iterator);
|
||||||
|
reference_type operator[](int);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct input_iterator_tag {};
|
||||||
|
struct forward_iterator_tag : public input_iterator_tag {};
|
||||||
|
struct bidirectional_iterator_tag : public forward_iterator_tag {};
|
||||||
|
struct random_access_iterator_tag : public bidirectional_iterator_tag {};
|
||||||
|
|
||||||
|
struct output_iterator_tag {};
|
||||||
|
|
||||||
|
template<class Container>
|
||||||
|
class back_insert_iterator {
|
||||||
|
protected:
|
||||||
|
Container* container = nullptr;
|
||||||
|
public:
|
||||||
|
using iterator_category = output_iterator_tag;
|
||||||
|
using value_type = void;
|
||||||
|
using difference_type = ptrdiff_t;
|
||||||
|
using pointer = void;
|
||||||
|
using reference = void;
|
||||||
|
using container_type = Container;
|
||||||
|
constexpr back_insert_iterator() noexcept = default;
|
||||||
|
constexpr explicit back_insert_iterator(Container& x);
|
||||||
|
back_insert_iterator& operator=(const typename Container::value_type& value);
|
||||||
|
back_insert_iterator& operator=(typename Container::value_type&& value);
|
||||||
|
back_insert_iterator& operator*();
|
||||||
|
back_insert_iterator& operator++();
|
||||||
|
back_insert_iterator operator++(int);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Container>
|
||||||
|
constexpr back_insert_iterator<Container> back_inserter(Container& x) {
|
||||||
|
return back_insert_iterator<Container>(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Container>
|
||||||
|
class front_insert_iterator {
|
||||||
|
protected:
|
||||||
|
Container* container = nullptr;
|
||||||
|
public:
|
||||||
|
using iterator_category = output_iterator_tag;
|
||||||
|
using value_type = void;
|
||||||
|
using difference_type = ptrdiff_t;
|
||||||
|
using pointer = void;
|
||||||
|
using reference = void;
|
||||||
|
using container_type = Container;
|
||||||
|
constexpr front_insert_iterator() noexcept = default;
|
||||||
|
constexpr explicit front_insert_iterator(Container& x);
|
||||||
|
constexpr front_insert_iterator& operator=(const typename Container::value_type& value);
|
||||||
|
constexpr front_insert_iterator& operator=(typename Container::value_type&& value);
|
||||||
|
constexpr front_insert_iterator& operator*();
|
||||||
|
constexpr front_insert_iterator& operator++();
|
||||||
|
constexpr front_insert_iterator operator++(int);
|
||||||
|
};
|
||||||
|
template<class Container>
|
||||||
|
constexpr front_insert_iterator<Container> front_inserter(Container& x) {
|
||||||
|
return front_insert_iterator<Container>(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user