mirror of
https://github.com/github/codeql.git
synced 2026-05-21 14:47:10 +02:00
Compare commits
273 Commits
tiferet/ad
...
codeql-cli
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
413b4c6eb0 | ||
|
|
141bc41881 | ||
|
|
44f91ad723 | ||
|
|
cbbce9b98a | ||
|
|
6aaaf4267b | ||
|
|
0518eda7ab | ||
|
|
dee66354cc | ||
|
|
094a9f4aa7 | ||
|
|
028ab325f4 | ||
|
|
4aa92dfd88 | ||
|
|
169a465214 | ||
|
|
401a46d655 | ||
|
|
9f75a768ea | ||
|
|
ae4bc3eb09 | ||
|
|
75fc9d0c6a | ||
|
|
d1aacb7260 | ||
|
|
b4f7239f54 | ||
|
|
c1efb7f3f4 | ||
|
|
986c15cd08 | ||
|
|
dded684ad6 | ||
|
|
7b6aa09646 | ||
|
|
b89dd3d8ac | ||
|
|
2ac736cd74 | ||
|
|
23b02f4f27 | ||
|
|
731419fc80 | ||
|
|
96476cb50d | ||
|
|
f31a7cf921 | ||
|
|
d893768726 | ||
|
|
6884db120a | ||
|
|
90c6771dd1 | ||
|
|
dea9adbad4 | ||
|
|
2b24870a3d | ||
|
|
a1b6bfb270 | ||
|
|
5a57844dab | ||
|
|
7aca35d52b | ||
|
|
42a438cdcb | ||
|
|
26908ea281 | ||
|
|
60e326b160 | ||
|
|
31ab22e3a0 | ||
|
|
6869ad48e4 | ||
|
|
38b8cf4fd4 | ||
|
|
86e2333e67 | ||
|
|
3e1d49ad80 | ||
|
|
9eafee365f | ||
|
|
6dee013baa | ||
|
|
0d7b27d4e4 | ||
|
|
1142b77f8d | ||
|
|
0def31a2ce | ||
|
|
c66569bd43 | ||
|
|
5898615f5a | ||
|
|
1dc6640bc1 | ||
|
|
229c3e6e8f | ||
|
|
97db2c91f1 | ||
|
|
9780990836 | ||
|
|
434c5ea188 | ||
|
|
114d337210 | ||
|
|
0624324962 | ||
|
|
ae40b0aba2 | ||
|
|
59b6d657cc | ||
|
|
7e5a9fbe2e | ||
|
|
179941daab | ||
|
|
33ae086861 | ||
|
|
d6ae5c898a | ||
|
|
a9b6a12317 | ||
|
|
85961f5dce | ||
|
|
8ec06d45e0 | ||
|
|
b22ccc114e | ||
|
|
0ac0277639 | ||
|
|
a407f0a4ac | ||
|
|
da4c178534 | ||
|
|
c1e6d4c82a | ||
|
|
c451fa8ad4 | ||
|
|
ea127c3d99 | ||
|
|
b5f849463b | ||
|
|
c06db6b67c | ||
|
|
fb0959bcea | ||
|
|
5f835da838 | ||
|
|
36a6ccba8b | ||
|
|
a76d47681d | ||
|
|
8eeba92a47 | ||
|
|
7f5df4fc0e | ||
|
|
42259ef8d1 | ||
|
|
357c823b92 | ||
|
|
d03817ce2d | ||
|
|
277b5b483d | ||
|
|
950c4c811c | ||
|
|
9ee36215bd | ||
|
|
ee0811df26 | ||
|
|
f9215ec5ca | ||
|
|
72999c7af1 | ||
|
|
3c3442d8f0 | ||
|
|
dcd082e955 | ||
|
|
40c2b3c43b | ||
|
|
093ff4061d | ||
|
|
7644ecad52 | ||
|
|
0a91ee1019 | ||
|
|
df7f0cf9a9 | ||
|
|
c06b8a68e5 | ||
|
|
c663da5be6 | ||
|
|
4bd7e24b5f | ||
|
|
605c7113a2 | ||
|
|
e2240abc78 | ||
|
|
545c2f67e9 | ||
|
|
d345cec339 | ||
|
|
24c413fbf9 | ||
|
|
8f02463411 | ||
|
|
a2ac1384cb | ||
|
|
f589ba8b9c | ||
|
|
5b14ebf22a | ||
|
|
29c47ad515 | ||
|
|
0deb2d4c5f | ||
|
|
63fcbb5969 | ||
|
|
0219c2b02b | ||
|
|
80b2f0d3cd | ||
|
|
d45c35a02e | ||
|
|
47f07d83b8 | ||
|
|
e13eb79f5b | ||
|
|
2bd151ba9c | ||
|
|
7c74350d5e | ||
|
|
e105c13e77 | ||
|
|
254a5b0928 | ||
|
|
bbcef98e06 | ||
|
|
d8b5a04f97 | ||
|
|
c92989ca04 | ||
|
|
659f86cecf | ||
|
|
95fdea8b77 | ||
|
|
11188304a7 | ||
|
|
780297152c | ||
|
|
5ab77600b8 | ||
|
|
45d4318e0e | ||
|
|
ba894e21e8 | ||
|
|
a7dc29bad4 | ||
|
|
49f476d3b4 | ||
|
|
a6f6936719 | ||
|
|
baaafadeb0 | ||
|
|
b70a9d172b | ||
|
|
ae38d5d8b7 | ||
|
|
2796c46598 | ||
|
|
1c69a1f012 | ||
|
|
27df44f5ad | ||
|
|
d6c5132f39 | ||
|
|
dfc72edba2 | ||
|
|
ad7c0f9ebc | ||
|
|
a3ff83595a | ||
|
|
b4b8649fd6 | ||
|
|
8b6bf910ba | ||
|
|
983851fc60 | ||
|
|
e4b0d8dbf3 | ||
|
|
3894fad54d | ||
|
|
7d9ce53080 | ||
|
|
a9023d06d0 | ||
|
|
9f2d89c903 | ||
|
|
fc614ad4d0 | ||
|
|
b6978128b1 | ||
|
|
63e9ae3b93 | ||
|
|
67b6a82cf1 | ||
|
|
c9241cc933 | ||
|
|
0d70b5c776 | ||
|
|
c42663723f | ||
|
|
5f6f72ba8e | ||
|
|
c1be93a34c | ||
|
|
e547be5e9a | ||
|
|
48c37a2c0f | ||
|
|
35078738bc | ||
|
|
d6a395ba37 | ||
|
|
6c0bef7e6e | ||
|
|
7a0e248096 | ||
|
|
782c82a2d3 | ||
|
|
54a6f066b3 | ||
|
|
468a6f2a70 | ||
|
|
266a0874b5 | ||
|
|
91b7798be8 | ||
|
|
76c6943159 | ||
|
|
67e8ec1a5f | ||
|
|
bfb0ca7968 | ||
|
|
f0c3d039a1 | ||
|
|
94bca4399a | ||
|
|
7d4ea47611 | ||
|
|
8bf0bbb715 | ||
|
|
798b03f29d | ||
|
|
bafb9ae020 | ||
|
|
55dc929a1f | ||
|
|
cc960377ac | ||
|
|
255123cbf9 | ||
|
|
7ae41ff165 | ||
|
|
6d465aaf52 | ||
|
|
63f715e650 | ||
|
|
dd4e1d0ac3 | ||
|
|
10a3b3bd14 | ||
|
|
359d703ded | ||
|
|
f48b57c95a | ||
|
|
e6dd3673a1 | ||
|
|
b4216767ad | ||
|
|
775a5507a6 | ||
|
|
c085c1f3ad | ||
|
|
0bce1894ae | ||
|
|
92190e5095 | ||
|
|
706858e211 | ||
|
|
85fe226256 | ||
|
|
3d21f89f1d | ||
|
|
0d9e28012e | ||
|
|
3d11e5bb32 | ||
|
|
c91e20c6b5 | ||
|
|
a3d33e27e2 | ||
|
|
3ebb7cfa1b | ||
|
|
88a0c4053b | ||
|
|
784475dd66 | ||
|
|
84cb59b942 | ||
|
|
0c14759e86 | ||
|
|
6d1421a6f9 | ||
|
|
307d2d5dc1 | ||
|
|
acab8e8632 | ||
|
|
d4f3e38062 | ||
|
|
ac85d2eb3e | ||
|
|
de833d620e | ||
|
|
ed3270fb04 | ||
|
|
2e2fcd49bf | ||
|
|
762ebad66e | ||
|
|
d0521f15f1 | ||
|
|
d2c0250b41 | ||
|
|
9f357837fa | ||
|
|
5cfc494e16 | ||
|
|
155b64d3fc | ||
|
|
b7e14311be | ||
|
|
27681ac987 | ||
|
|
c70f3d35d0 | ||
|
|
ec04f0c88f | ||
|
|
8cb68b79c1 | ||
|
|
b0b5761a8c | ||
|
|
364336e22a | ||
|
|
1f90f7dd4d | ||
|
|
d4c6f873af | ||
|
|
65567fa1ce | ||
|
|
e98d1df5f4 | ||
|
|
a8973c1147 | ||
|
|
75ef5b1b0b | ||
|
|
30c66303ba | ||
|
|
0ce4500b48 | ||
|
|
da7788dd64 | ||
|
|
8109a7b67a | ||
|
|
e5e3bb3705 | ||
|
|
563a56af9d | ||
|
|
65c1e239eb | ||
|
|
8d9b106be1 | ||
|
|
67f31ffdf0 | ||
|
|
bd78e73131 | ||
|
|
81a1fa167a | ||
|
|
32f60fd112 | ||
|
|
dc2cd994d4 | ||
|
|
a749212707 | ||
|
|
eda028721e | ||
|
|
3260c81397 | ||
|
|
5ea03b1ded | ||
|
|
8147d2048e | ||
|
|
25ac3499c2 | ||
|
|
53f1985e77 | ||
|
|
ee02265ac2 | ||
|
|
b3b7711149 | ||
|
|
ade83b3cfe | ||
|
|
8e546e8496 | ||
|
|
8b33e6d175 | ||
|
|
6bc12e8f2b | ||
|
|
33cca29a8e | ||
|
|
aafef382dc | ||
|
|
c13e8e4f48 | ||
|
|
bb4bc55c6a | ||
|
|
f09e3bd3ac | ||
|
|
d4919d04ba | ||
|
|
f222cc1f3e | ||
|
|
6de1abcb0e | ||
|
|
a2b924bbdf | ||
|
|
dbf2673a91 | ||
|
|
46627a737e |
@@ -1,24 +0,0 @@
|
||||
---
|
||||
name: LGTM.com - false positive
|
||||
about: Tell us about an alert that shouldn't be reported
|
||||
title: LGTM.com - false positive
|
||||
labels: false-positive
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Description of the false positive**
|
||||
|
||||
<!-- Please explain briefly why you think it shouldn't be included. -->
|
||||
|
||||
**URL to the alert on the project page on LGTM.com**
|
||||
|
||||
<!--
|
||||
1. Open the project on LGTM.com.
|
||||
For example, https://lgtm.com/projects/g/pallets/click/.
|
||||
2. Switch to the `Alerts` tab. For example, https://lgtm.com/projects/g/pallets/click/alerts/.
|
||||
3. Scroll to the alert that you would like to report.
|
||||
4. Click on the right most icon `View this alert within the complete file`.
|
||||
5. A new browser tab opens. Copy and paste the page URL here.
|
||||
For example, https://lgtm.com/projects/g/pallets/click/snapshot/719fb7d8322b0767cdd1e5903ba3eb3233ba8dd5/files/click/_winconsole.py#xa08d213ab3289f87:1.
|
||||
-->
|
||||
2
.github/ISSUE_TEMPLATE/ql---general.md
vendored
2
.github/ISSUE_TEMPLATE/ql---general.md
vendored
@@ -10,5 +10,5 @@ assignees: ''
|
||||
**Description of the issue**
|
||||
|
||||
<!-- Please explain briefly what is the problem.
|
||||
If it is about an LGTM project, please include its URL.-->
|
||||
If it is about a GitHub project, please include its URL. -->
|
||||
|
||||
|
||||
36
.github/ISSUE_TEMPLATE/ql--false-positive.md
vendored
Normal file
36
.github/ISSUE_TEMPLATE/ql--false-positive.md
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
---
|
||||
name: CodeQL False positive
|
||||
about: Report CodeQL alerts that you think should not have been detected (not applicable, not exploitable, etc.)
|
||||
title: False positive
|
||||
labels: false-positive
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Description of the false positive**
|
||||
|
||||
<!-- Please explain briefly why you think it shouldn't be included. -->
|
||||
|
||||
**Code samples or links to source code**
|
||||
|
||||
<!--
|
||||
For open source code: file links with line numbers on GitHub, for example:
|
||||
https://github.com/github/codeql/blob/dc440aaee6695deb0d9676b87e06ea984e1b4ae5/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection/exec-sh2.js#L10
|
||||
|
||||
For closed source code: (redacted) code samples that illustrate the problem, for example:
|
||||
|
||||
```
|
||||
function execSh(command, options) {
|
||||
return cp.spawn(getShell(), ["-c", command], options) // <- command line injection
|
||||
};
|
||||
```
|
||||
-->
|
||||
|
||||
**URL to the alert on GitHub code scanning (optional)**
|
||||
|
||||
<!--
|
||||
1. Open the project on GitHub.com.
|
||||
2. Switch to the `Security` tab.
|
||||
3. Browse to the alert that you would like to report.
|
||||
4. Copy and paste the page URL here.
|
||||
-->
|
||||
14
.github/workflows/compile-queries.yml
vendored
14
.github/workflows/compile-queries.yml
vendored
@@ -56,4 +56,16 @@ jobs:
|
||||
# do full compile if running on main - this populates the cache
|
||||
if : ${{ github.event_name != 'pull_request' }}
|
||||
shell: bash
|
||||
run: codeql query compile -j0 */ql/src --keep-going --warnings=error
|
||||
run: |
|
||||
# Move all the existing cache into another folder, so we only preserve the cache for the current queries.
|
||||
mkdir -p ${COMBINED_CACHE_DIR}
|
||||
rm */ql/src/.cache/{lock,size}
|
||||
# copy the contents of the .cache folders into the combined cache folder.
|
||||
cp -r */ql/src/.cache/* ${COMBINED_CACHE_DIR}/
|
||||
# clean up the .cache folders
|
||||
rm -rf */ql/src/.cache/*
|
||||
|
||||
# compile the queries
|
||||
codeql query compile -j0 */ql/src --keep-going --warnings=error --compilation-cache ${COMBINED_CACHE_DIR}
|
||||
env:
|
||||
COMBINED_CACHE_DIR: ${{ github.workspace }}/compilation-dir
|
||||
4
.github/workflows/swift.yml
vendored
4
.github/workflows/swift.yml
vendored
@@ -27,7 +27,7 @@ jobs:
|
||||
with:
|
||||
filters: |
|
||||
codegen:
|
||||
- 'github/workflows/swift.yml'
|
||||
- '.github/workflows/swift.yml'
|
||||
- "misc/bazel/**"
|
||||
- "*.bazel*"
|
||||
- 'swift/actions/setup-env/**'
|
||||
@@ -111,7 +111,7 @@ jobs:
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: swift-generated-cpp-files
|
||||
path: swift/generated-cpp-files/**
|
||||
path: generated-cpp-files/**
|
||||
database-upgrade-scripts:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
@@ -45,4 +45,4 @@ WORKSPACE.bazel @github/codeql-ci-reviewers
|
||||
/.github/workflows/js-ml-tests.yml @github/codeql-ml-powered-queries-reviewers
|
||||
/.github/workflows/ql-for-ql-* @github/codeql-ql-for-ql-reviewers
|
||||
/.github/workflows/ruby-* @github/codeql-ruby
|
||||
/.github/workflows/swift-* @github/codeql-c
|
||||
/.github/workflows/swift.yml @github/codeql-c
|
||||
|
||||
@@ -11,11 +11,12 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.IO.FileSystem" Version="4.3.0" />
|
||||
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
|
||||
<PackageReference Include="xunit" Version="2.4.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Build" Version="16.11.0" />
|
||||
<PackageReference Include="Microsoft.Build" Version="17.3.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
## 0.4.5
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.4
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.3
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
3
cpp/ql/lib/change-notes/released/0.4.4.md
Normal file
3
cpp/ql/lib/change-notes/released/0.4.4.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.4.4
|
||||
|
||||
No user-facing changes.
|
||||
3
cpp/ql/lib/change-notes/released/0.4.5.md
Normal file
3
cpp/ql/lib/change-notes/released/0.4.5.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.4.5
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.4.3
|
||||
lastReleaseVersion: 0.4.5
|
||||
|
||||
@@ -12,8 +12,8 @@ import IDEContextual
|
||||
*
|
||||
* In some cases it is preferable to modify locations (the
|
||||
* `hasLocationInfo()` predicate) so that they are short, and
|
||||
* non-overlapping with other locations that might be highlighted in
|
||||
* the LGTM interface.
|
||||
* non-overlapping with other locations that might be reported as
|
||||
* code scanning alerts on GitHub.
|
||||
*
|
||||
* We need to give locations that may not be in the database, so
|
||||
* we use `hasLocationInfo()` rather than `getLocation()`.
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2712,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2920,6 +2938,22 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2959,7 +2993,9 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
@@ -3015,6 +3051,12 @@ class PathNode instanceof PathNodeImpl {
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3136,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3495,6 +3594,15 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2712,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2920,6 +2938,22 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2959,7 +2993,9 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
@@ -3015,6 +3051,12 @@ class PathNode instanceof PathNodeImpl {
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3136,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3495,6 +3594,15 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2712,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2920,6 +2938,22 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2959,7 +2993,9 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
@@ -3015,6 +3051,12 @@ class PathNode instanceof PathNodeImpl {
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3136,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3495,6 +3594,15 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2712,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2920,6 +2938,22 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2959,7 +2993,9 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
@@ -3015,6 +3051,12 @@ class PathNode instanceof PathNodeImpl {
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3136,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3495,6 +3594,15 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 0.4.4-dev
|
||||
version: 0.4.5
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2712,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2920,6 +2938,22 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2959,7 +2993,9 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
@@ -3015,6 +3051,12 @@ class PathNode instanceof PathNodeImpl {
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3136,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3495,6 +3594,15 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2712,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2920,6 +2938,22 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2959,7 +2993,9 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
@@ -3015,6 +3051,12 @@ class PathNode instanceof PathNodeImpl {
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3136,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3495,6 +3594,15 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2712,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2920,6 +2938,22 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2959,7 +2993,9 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
@@ -3015,6 +3051,12 @@ class PathNode instanceof PathNodeImpl {
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3136,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3495,6 +3594,15 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2712,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2920,6 +2938,22 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2959,7 +2993,9 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
@@ -3015,6 +3051,12 @@ class PathNode instanceof PathNodeImpl {
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3136,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3495,6 +3594,15 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2712,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2920,6 +2938,22 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2959,7 +2993,9 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
@@ -3015,6 +3051,12 @@ class PathNode instanceof PathNodeImpl {
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3136,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3495,6 +3594,15 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2712,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2920,6 +2938,22 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2959,7 +2993,9 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
@@ -3015,6 +3051,12 @@ class PathNode instanceof PathNodeImpl {
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3136,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3495,6 +3594,15 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2712,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2920,6 +2938,22 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2959,7 +2993,9 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
@@ -3015,6 +3051,12 @@ class PathNode instanceof PathNodeImpl {
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3136,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3495,6 +3594,15 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2712,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2920,6 +2938,22 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2959,7 +2993,9 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
@@ -3015,6 +3051,12 @@ class PathNode instanceof PathNodeImpl {
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3136,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3495,6 +3594,15 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2712,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2920,6 +2938,22 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2959,7 +2993,9 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
@@ -3015,6 +3051,12 @@ class PathNode instanceof PathNodeImpl {
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3136,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3495,6 +3594,15 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
## 0.4.5
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.4
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.3
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note: this query is not assigned a precision yet because we don't want it on
|
||||
* LGTM until its performance is well understood.
|
||||
* Note: this query is not assigned a precision yet because we don't want it
|
||||
* to be included in query suites until its performance is well understood.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
@@ -52,7 +52,7 @@ class Library extends LibraryT {
|
||||
// The versions reported for C/C++ dependencies are just the versions that
|
||||
// happen to be installed on the system where the build takes place.
|
||||
// Reporting those versions is likely to cause misunderstandings, both for
|
||||
// people reading them and for the vulnerability checker of lgtm.
|
||||
// people reading them and for vulnerability checkers.
|
||||
result = "unknown"
|
||||
}
|
||||
|
||||
|
||||
3
cpp/ql/src/change-notes/released/0.4.4.md
Normal file
3
cpp/ql/src/change-notes/released/0.4.4.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.4.4
|
||||
|
||||
No user-facing changes.
|
||||
3
cpp/ql/src/change-notes/released/0.4.5.md
Normal file
3
cpp/ql/src/change-notes/released/0.4.5.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.4.5
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.4.3
|
||||
lastReleaseVersion: 0.4.5
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 0.4.4-dev
|
||||
version: 0.4.5
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -6,17 +6,17 @@
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.IO.FileSystem" Version="4.3.0"/>
|
||||
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0"/>
|
||||
<PackageReference Include="xunit" Version="2.4.1"/>
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PackageReference Include="System.IO.FileSystem" Version="4.3.0" />
|
||||
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0"/>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Autobuild.CSharp\Semmle.Autobuild.CSharp.csproj"/>
|
||||
<ProjectReference Include="..\Semmle.Autobuild.Shared\Semmle.Autobuild.Shared.csproj"/>
|
||||
<ProjectReference Include="..\Semmle.Autobuild.CSharp\Semmle.Autobuild.CSharp.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Autobuild.Shared\Semmle.Autobuild.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -11,15 +11,15 @@
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\"/>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Build" Version="16.11.0"/>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1"/>
|
||||
<PackageReference Include="Microsoft.Build" Version="17.3.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\extractor\Semmle.Util\Semmle.Util.csproj"/>
|
||||
<ProjectReference Include="..\..\extractor\Semmle.Extraction.CSharp\Semmle.Extraction.CSharp.csproj"/>
|
||||
<ProjectReference Include="..\Semmle.Autobuild.Shared\Semmle.Autobuild.Shared.csproj"/>
|
||||
<ProjectReference Include="..\..\extractor\Semmle.Util\Semmle.Util.csproj" />
|
||||
<ProjectReference Include="..\..\extractor\Semmle.Extraction.CSharp\Semmle.Extraction.CSharp.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Autobuild.Shared\Semmle.Autobuild.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -8,12 +8,12 @@
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\"/>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Build" Version="16.11.0"/>
|
||||
<PackageReference Include="Microsoft.Build" Version="17.3.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\extractor\Semmle.Util\Semmle.Util.csproj"/>
|
||||
<ProjectReference Include="..\..\extractor\Semmle.Util\Semmle.Util.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
@@ -24,7 +24,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.DiaSymReader" Version="1.3.0" />
|
||||
<PackageReference Include="Microsoft.DiaSymReader" Version="1.4.0" />
|
||||
<PackageReference Include="Microsoft.DiaSymReader.Native" Version="1.7.0" />
|
||||
<PackageReference Include="Microsoft.DiaSymReader.PortablePdb" Version="1.6.0"><IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
|
||||
@@ -12,17 +12,17 @@
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Extraction.CSharp\Semmle.Extraction.CSharp.csproj"/>
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj"/>
|
||||
<ProjectReference Include="..\Semmle.Extraction.CSharp\Semmle.Extraction.CSharp.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\"/>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Build" Version="16.11.0"/>
|
||||
<PackageReference Include="Microsoft.Win32.Primitives" Version="4.3.0"/>
|
||||
<PackageReference Include="System.Net.Primitives" Version="4.3.1"/>
|
||||
<PackageReference Include="System.Security.Principal" Version="4.3.0"/>
|
||||
<PackageReference Include="System.Threading.ThreadPool" Version="4.3.0"/>
|
||||
<PackageReference Include="Microsoft.Build" Version="17.3.2" />
|
||||
<PackageReference Include="Microsoft.Win32.Primitives" Version="4.3.0" />
|
||||
<PackageReference Include="System.Net.Primitives" Version="4.3.1" />
|
||||
<PackageReference Include="System.Security.Principal" Version="4.3.0" />
|
||||
<PackageReference Include="System.Threading.ThreadPool" Version="4.3.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -2,6 +2,7 @@ using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
@@ -162,6 +163,13 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
operatorName = "false";
|
||||
break;
|
||||
default:
|
||||
var match = Regex.Match(methodName, "^op_Checked(.*)$");
|
||||
if (match.Success)
|
||||
{
|
||||
OperatorSymbol("op_" + match.Groups[1], out var uncheckedName);
|
||||
operatorName = "checked " + uncheckedName;
|
||||
break;
|
||||
}
|
||||
operatorName = methodName;
|
||||
success = false;
|
||||
break;
|
||||
|
||||
@@ -10,15 +10,15 @@
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Extraction.CIL\Semmle.Extraction.CIL.csproj"/>
|
||||
<ProjectReference Include="..\Semmle.Extraction\Semmle.Extraction.csproj"/>
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj"/>
|
||||
<ProjectReference Include="..\Semmle.Extraction.CIL\Semmle.Extraction.CIL.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Extraction\Semmle.Extraction.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\"/>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.0.1"/>
|
||||
<PackageReference Include="Microsoft.Build" Version="16.11.0"/>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.4.0" />
|
||||
<PackageReference Include="Microsoft.Build" Version="17.3.2" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -6,19 +6,19 @@
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.IO.FileSystem" Version="4.3.0"/>
|
||||
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0"/>
|
||||
<PackageReference Include="xunit" Version="2.4.1"/>
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PackageReference Include="System.IO.FileSystem" Version="4.3.0" />
|
||||
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0"/>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Extraction.CSharp.Standalone\Semmle.Extraction.CSharp.Standalone.csproj"/>
|
||||
<ProjectReference Include="..\Semmle.Extraction.CSharp\Semmle.Extraction.CSharp.csproj"/>
|
||||
<ProjectReference Include="..\Semmle.Extraction\Semmle.Extraction.csproj"/>
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj"/>
|
||||
<ProjectReference Include="..\Semmle.Extraction.CSharp.Standalone\Semmle.Extraction.CSharp.Standalone.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Extraction.CSharp\Semmle.Extraction.CSharp.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Extraction\Semmle.Extraction.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -12,13 +12,13 @@
|
||||
<DefineConstants>TRACE;DEBUG;DEBUG_LABELS</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis" Version="4.0.1"/>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis" Version="4.4.0" />
|
||||
<PackageReference Include="GitInfo" Version="2.2.0">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj"/>
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -6,14 +6,14 @@
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="xunit" Version="2.4.1"/>
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PackageReference Include="xunit" Version="2.4.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0"/>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj"/>
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,3 +1,11 @@
|
||||
## 1.3.5
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.3.4
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.3.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
## 1.3.4
|
||||
|
||||
No user-facing changes.
|
||||
@@ -0,0 +1,3 @@
|
||||
## 1.3.5
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.3.3
|
||||
lastReleaseVersion: 1.3.5
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-all
|
||||
version: 1.3.4-dev
|
||||
version: 1.3.5
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
## 1.3.5
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.3.4
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.3.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
## 1.3.4
|
||||
|
||||
No user-facing changes.
|
||||
@@ -0,0 +1,3 @@
|
||||
## 1.3.5
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.3.3
|
||||
lastReleaseVersion: 1.3.5
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-queries
|
||||
version: 1.3.4-dev
|
||||
version: 1.3.5
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import csharp
|
||||
import semmle.code.csharp.dataflow.internal.SsaImpl::Consistency
|
||||
import semmle.code.csharp.dataflow.internal.SsaImpl as Impl
|
||||
import Impl::Consistency
|
||||
import Ssa
|
||||
|
||||
class MyRelevantDefinition extends RelevantDefinition, Ssa::Definition {
|
||||
@@ -10,6 +11,14 @@ class MyRelevantDefinition extends RelevantDefinition, Ssa::Definition {
|
||||
}
|
||||
}
|
||||
|
||||
class MyRelevantDefinitionExt extends RelevantDefinitionExt, Impl::DefinitionExt {
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
|
||||
query predicate localDeclWithSsaDef(LocalVariableDeclExpr d) {
|
||||
// Local variables in C# must be initialized before every use, so uninitialized
|
||||
// local variables should not have an SSA definition, as that would imply that
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.1.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.3.0" />
|
||||
<PackageReference Include="coverlet.collector" Version="3.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
## 0.4.5
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.4
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `[Summary|Sink|Source]ModelCsv` classes have been deprecated and Models as Data models are defined as data extensions instead.
|
||||
|
||||
## 0.4.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `[Summary|Sink|Source]ModelCsv` classes have been deprecated and Models as Data models are defined as data extensions instead.
|
||||
## 0.4.4
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `[Summary|Sink|Source]ModelCsv` classes have been deprecated and Models as Data models are defined as data extensions instead.
|
||||
3
csharp/ql/lib/change-notes/released/0.4.5.md
Normal file
3
csharp/ql/lib/change-notes/released/0.4.5.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.4.5
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.4.3
|
||||
lastReleaseVersion: 0.4.5
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-all
|
||||
version: 0.4.4-dev
|
||||
version: 0.4.5
|
||||
groups: csharp
|
||||
dbscheme: semmlecode.csharp.dbscheme
|
||||
extractor: csharp
|
||||
|
||||
@@ -138,25 +138,6 @@ module Ssa {
|
||||
}
|
||||
}
|
||||
|
||||
private string getSplitString(Definition def) {
|
||||
exists(ControlFlow::BasicBlock bb, int i, ControlFlow::Node cfn |
|
||||
def.definesAt(_, bb, i) and
|
||||
result = cfn.(ControlFlow::Nodes::ElementNode).getSplitsString()
|
||||
|
|
||||
cfn = bb.getNode(i)
|
||||
or
|
||||
not exists(bb.getNode(i)) and
|
||||
cfn = bb.getFirstNode()
|
||||
)
|
||||
}
|
||||
|
||||
private string getToStringPrefix(Definition def) {
|
||||
result = "[" + getSplitString(def) + "] "
|
||||
or
|
||||
not exists(getSplitString(def)) and
|
||||
result = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* A static single assignment (SSA) definition. Either an explicit variable
|
||||
* definition (`ExplicitDefinition`), an implicit variable definition
|
||||
@@ -521,8 +502,8 @@ module Ssa {
|
||||
|
||||
override string toString() {
|
||||
if this.getADefinition() instanceof AssignableDefinitions::ImplicitParameterDefinition
|
||||
then result = getToStringPrefix(this) + "SSA param(" + this.getSourceVariable() + ")"
|
||||
else result = getToStringPrefix(this) + "SSA def(" + this.getSourceVariable() + ")"
|
||||
then result = SsaImpl::getToStringPrefix(this) + "SSA param(" + this.getSourceVariable() + ")"
|
||||
else result = SsaImpl::getToStringPrefix(this) + "SSA def(" + this.getSourceVariable() + ")"
|
||||
}
|
||||
|
||||
override Location getLocation() { result = ad.getLocation() }
|
||||
@@ -570,8 +551,12 @@ module Ssa {
|
||||
|
||||
override string toString() {
|
||||
if this.getSourceVariable().getAssignable() instanceof LocalScopeVariable
|
||||
then result = getToStringPrefix(this) + "SSA capture def(" + this.getSourceVariable() + ")"
|
||||
else result = getToStringPrefix(this) + "SSA entry def(" + this.getSourceVariable() + ")"
|
||||
then
|
||||
result =
|
||||
SsaImpl::getToStringPrefix(this) + "SSA capture def(" + this.getSourceVariable() + ")"
|
||||
else
|
||||
result =
|
||||
SsaImpl::getToStringPrefix(this) + "SSA entry def(" + this.getSourceVariable() + ")"
|
||||
}
|
||||
|
||||
override Location getLocation() { result = this.getCallable().getLocation() }
|
||||
@@ -612,7 +597,7 @@ module Ssa {
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = getToStringPrefix(this) + "SSA call def(" + this.getSourceVariable() + ")"
|
||||
result = SsaImpl::getToStringPrefix(this) + "SSA call def(" + this.getSourceVariable() + ")"
|
||||
}
|
||||
|
||||
override Location getLocation() { result = this.getCall().getLocation() }
|
||||
@@ -640,7 +625,8 @@ module Ssa {
|
||||
final Definition getQualifierDefinition() { result = q }
|
||||
|
||||
override string toString() {
|
||||
result = getToStringPrefix(this) + "SSA qualifier def(" + this.getSourceVariable() + ")"
|
||||
result =
|
||||
SsaImpl::getToStringPrefix(this) + "SSA qualifier def(" + this.getSourceVariable() + ")"
|
||||
}
|
||||
|
||||
override Location getLocation() { result = this.getQualifierDefinition().getLocation() }
|
||||
@@ -682,7 +668,7 @@ module Ssa {
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = getToStringPrefix(this) + "SSA phi(" + this.getSourceVariable() + ")"
|
||||
result = SsaImpl::getToStringPrefix(this) + "SSA phi(" + this.getSourceVariable() + ")"
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2712,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2920,6 +2938,22 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2959,7 +2993,9 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
@@ -3015,6 +3051,12 @@ class PathNode instanceof PathNodeImpl {
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3136,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3495,6 +3594,15 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2712,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2920,6 +2938,22 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2959,7 +2993,9 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
@@ -3015,6 +3051,12 @@ class PathNode instanceof PathNodeImpl {
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3136,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3495,6 +3594,15 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2712,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2920,6 +2938,22 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2959,7 +2993,9 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
@@ -3015,6 +3051,12 @@ class PathNode instanceof PathNodeImpl {
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3136,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3495,6 +3594,15 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2712,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2920,6 +2938,22 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2959,7 +2993,9 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
@@ -3015,6 +3051,12 @@ class PathNode instanceof PathNodeImpl {
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3136,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3495,6 +3594,15 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2712,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2920,6 +2938,22 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2959,7 +2993,9 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
@@ -3015,6 +3051,12 @@ class PathNode instanceof PathNodeImpl {
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3136,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3495,6 +3594,15 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
|
||||
@@ -147,6 +147,12 @@ abstract class Configuration extends string {
|
||||
*/
|
||||
FlowFeature getAFeature() { none() }
|
||||
|
||||
/** Holds if sources should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sourceGrouping(Node source, string sourceGroup) { none() }
|
||||
|
||||
/** Holds if sinks should be grouped in the result of `hasFlowPath`. */
|
||||
predicate sinkGrouping(Node sink, string sinkGroup) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `source` to `sink` for this configuration.
|
||||
*/
|
||||
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
|
||||
* The corresponding paths are generated from the end-points and the graph
|
||||
* included in the module `PathGraph`.
|
||||
*/
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { flowsTo(source, sink, _, _, this) }
|
||||
predicate hasFlowPath(PathNode source, PathNode sink) { hasFlowPath(source, sink, this) }
|
||||
|
||||
/**
|
||||
* Holds if data may flow from some source to `sink` for this configuration.
|
||||
@@ -2712,6 +2718,18 @@ private newtype TPathNode =
|
||||
state = sink.getState() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSourceGroup(string sourceGroup, Configuration config) {
|
||||
exists(PathNodeImpl source |
|
||||
sourceGroup = source.getSourceGroup() and
|
||||
config = source.getConfiguration()
|
||||
)
|
||||
} or
|
||||
TPathNodeSinkGroup(string sinkGroup, Configuration config) {
|
||||
exists(PathNodeSink sink |
|
||||
sinkGroup = sink.getSinkGroup() and
|
||||
config = sink.getConfiguration()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2920,6 +2938,22 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
)
|
||||
}
|
||||
|
||||
string getSourceGroup() {
|
||||
this.isSource() and
|
||||
this.getConfiguration().sourceGrouping(this.getNodeEx().asNode(), result)
|
||||
}
|
||||
|
||||
predicate isFlowSource() {
|
||||
this.isSource() and not exists(this.getSourceGroup())
|
||||
or
|
||||
this instanceof PathNodeSourceGroup
|
||||
}
|
||||
|
||||
predicate isFlowSink() {
|
||||
this = any(PathNodeSink sink | not exists(sink.getSinkGroup())) or
|
||||
this instanceof PathNodeSinkGroup
|
||||
}
|
||||
|
||||
private string ppAp() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
@@ -2959,7 +2993,9 @@ abstract private class PathNodeImpl extends TPathNode {
|
||||
|
||||
/** Holds if `n` can reach a sink. */
|
||||
private predicate directReach(PathNodeImpl n) {
|
||||
n instanceof PathNodeSink or directReach(n.getANonHiddenSuccessor())
|
||||
n instanceof PathNodeSink or
|
||||
n instanceof PathNodeSinkGroup or
|
||||
directReach(n.getANonHiddenSuccessor())
|
||||
}
|
||||
|
||||
/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
|
||||
@@ -3015,6 +3051,12 @@ class PathNode instanceof PathNodeImpl {
|
||||
|
||||
/** Holds if this node is a source. */
|
||||
final predicate isSource() { super.isSource() }
|
||||
|
||||
/** Holds if this node is a grouping of source nodes. */
|
||||
final predicate isSourceGroup(string group) { this = TPathNodeSourceGroup(group, _) }
|
||||
|
||||
/** Holds if this node is a grouping of sink nodes. */
|
||||
final predicate isSinkGroup(string group) { this = TPathNodeSinkGroup(group, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3136,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result = TPathNodeSinkGroup(this.getSinkGroup(), config)
|
||||
}
|
||||
|
||||
override predicate isSource() { sourceNode(node, state, config) }
|
||||
|
||||
string getSinkGroup() { config.sinkGrouping(node.asNode(), result) }
|
||||
}
|
||||
|
||||
private class PathNodeSourceGroup extends PathNodeImpl, TPathNodeSourceGroup {
|
||||
string sourceGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSourceGroup() { this = TPathNodeSourceGroup(sourceGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() {
|
||||
result.getSourceGroup() = sourceGroup and
|
||||
result.getConfiguration() = config
|
||||
}
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sourceGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private class PathNodeSinkGroup extends PathNodeImpl, TPathNodeSinkGroup {
|
||||
string sinkGroup;
|
||||
Configuration config;
|
||||
|
||||
PathNodeSinkGroup() { this = TPathNodeSinkGroup(sinkGroup, config) }
|
||||
|
||||
override NodeEx getNodeEx() { none() }
|
||||
|
||||
override FlowState getState() { none() }
|
||||
|
||||
override Configuration getConfiguration() { result = config }
|
||||
|
||||
override PathNodeImpl getASuccessorImpl() { none() }
|
||||
|
||||
override predicate isSource() { none() }
|
||||
|
||||
override string toString() { result = sinkGroup }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
}
|
||||
|
||||
private predicate pathNode(
|
||||
@@ -3495,6 +3594,15 @@ private module Subpaths {
|
||||
* Will only have results if `configuration` has non-empty sources and
|
||||
* sinks.
|
||||
*/
|
||||
private predicate hasFlowPath(
|
||||
PathNodeImpl flowsource, PathNodeImpl flowsink, Configuration configuration
|
||||
) {
|
||||
flowsource.isFlowSource() and
|
||||
flowsource.getConfiguration() = configuration and
|
||||
(flowsource = flowsink or pathSuccPlus(flowsource, flowsink)) and
|
||||
flowsink.isFlowSink()
|
||||
}
|
||||
|
||||
private predicate flowsTo(
|
||||
PathNodeImpl flowsource, PathNodeSink flowsink, Node source, Node sink,
|
||||
Configuration configuration
|
||||
|
||||
@@ -49,7 +49,23 @@ private module SsaInput implements SsaImplCommon::InputSig {
|
||||
}
|
||||
}
|
||||
|
||||
import SsaImplCommon::Make<SsaInput>
|
||||
private import SsaImplCommon::Make<SsaInput> as Impl
|
||||
|
||||
class Definition = Impl::Definition;
|
||||
|
||||
class WriteDefinition = Impl::WriteDefinition;
|
||||
|
||||
class UncertainWriteDefinition = Impl::UncertainWriteDefinition;
|
||||
|
||||
class PhiNode = Impl::PhiNode;
|
||||
|
||||
module Consistency = Impl::Consistency;
|
||||
|
||||
module ExposedForTestingOnly {
|
||||
predicate ssaDefReachesReadExt = Impl::ssaDefReachesReadExt/4;
|
||||
|
||||
predicate phiHasInputFromBlockExt = Impl::phiHasInputFromBlockExt/3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `i`th node of basic block `bb` reads source variable `v`.
|
||||
@@ -1072,7 +1088,7 @@ private predicate adjacentDefRead(
|
||||
Definition def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2,
|
||||
SsaInput::SourceVariable v
|
||||
) {
|
||||
adjacentDefRead(def, bb1, i1, bb2, i2) and
|
||||
Impl::adjacentDefRead(def, bb1, i1, bb2, i2) and
|
||||
v = def.getSourceVariable()
|
||||
}
|
||||
|
||||
@@ -1088,7 +1104,7 @@ private predicate adjacentDefReachesRead(
|
||||
exists(SsaInput::BasicBlock bb3, int i3 |
|
||||
adjacentDefReachesRead(def, bb1, i1, bb3, i3) and
|
||||
SsaInput::variableRead(bb3, i3, _, false) and
|
||||
adjacentDefRead(def, bb3, i3, bb2, i2)
|
||||
Impl::adjacentDefRead(def, bb3, i3, bb2, i2)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1111,11 +1127,11 @@ private predicate adjacentDefReachesUncertainRead(
|
||||
/** Same as `lastRefRedef`, but skips uncertain reads. */
|
||||
pragma[nomagic]
|
||||
private predicate lastRefSkipUncertainReads(Definition def, SsaInput::BasicBlock bb, int i) {
|
||||
lastRef(def, bb, i) and
|
||||
Impl::lastRef(def, bb, i) and
|
||||
not SsaInput::variableRead(bb, i, def.getSourceVariable(), false)
|
||||
or
|
||||
exists(SsaInput::BasicBlock bb0, int i0 |
|
||||
lastRef(def, bb0, i0) and
|
||||
Impl::lastRef(def, bb0, i0) and
|
||||
adjacentDefReachesUncertainRead(def, bb, i, bb0, i0)
|
||||
)
|
||||
}
|
||||
@@ -1237,7 +1253,7 @@ private module Cached {
|
||||
v = def.getSourceVariable() and
|
||||
capturedReadIn(_, _, v, edef.getSourceVariable(), c, additionalCalls) and
|
||||
def = def0.getAnUltimateDefinition() and
|
||||
ssaDefReachesRead(_, def0, bb, i) and
|
||||
Impl::ssaDefReachesRead(_, def0, bb, i) and
|
||||
capturedReadIn(bb, i, v, _, _, _) and
|
||||
c = bb.getNode(i)
|
||||
)
|
||||
@@ -1264,18 +1280,18 @@ private module Cached {
|
||||
|
||||
cached
|
||||
predicate isLiveAtEndOfBlock(Definition def, ControlFlow::BasicBlock bb) {
|
||||
ssaDefReachesEndOfBlock(bb, def, _)
|
||||
Impl::ssaDefReachesEndOfBlock(bb, def, _)
|
||||
}
|
||||
|
||||
cached
|
||||
Definition phiHasInputFromBlock(PhiNode phi, ControlFlow::BasicBlock bb) {
|
||||
phiHasInputFromBlock(phi, result, bb)
|
||||
Definition phiHasInputFromBlock(Ssa::PhiNode phi, ControlFlow::BasicBlock bb) {
|
||||
Impl::phiHasInputFromBlock(phi, result, bb)
|
||||
}
|
||||
|
||||
cached
|
||||
AssignableRead getAReadAtNode(Definition def, ControlFlow::Node cfn) {
|
||||
exists(Ssa::SourceVariable v, ControlFlow::BasicBlock bb, int i |
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
Impl::ssaDefReachesRead(v, def, bb, i) and
|
||||
variableReadActual(bb, i, v) and
|
||||
cfn = bb.getNode(i) and
|
||||
result.getAControlFlowNode() = cfn
|
||||
@@ -1313,11 +1329,11 @@ private module Cached {
|
||||
/** Same as `lastRefRedef`, but skips uncertain reads. */
|
||||
cached
|
||||
predicate lastRefBeforeRedef(Definition def, ControlFlow::BasicBlock bb, int i, Definition next) {
|
||||
lastRefRedef(def, bb, i, next) and
|
||||
Impl::lastRefRedef(def, bb, i, next) and
|
||||
not SsaInput::variableRead(bb, i, def.getSourceVariable(), false)
|
||||
or
|
||||
exists(SsaInput::BasicBlock bb0, int i0 |
|
||||
lastRefRedef(def, bb0, i0, next) and
|
||||
Impl::lastRefRedef(def, bb0, i0, next) and
|
||||
adjacentDefReachesUncertainRead(def, bb, i, bb0, i0)
|
||||
)
|
||||
}
|
||||
@@ -1333,7 +1349,7 @@ private module Cached {
|
||||
|
||||
cached
|
||||
Definition uncertainWriteDefinitionInput(UncertainWriteDefinition def) {
|
||||
uncertainWriteDefinitionInput(def, result)
|
||||
Impl::uncertainWriteDefinitionInput(def, result)
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -1343,10 +1359,57 @@ private module Cached {
|
||||
v = def.getSourceVariable() and
|
||||
p = v.getAssignable() and
|
||||
def = def0.getAnUltimateDefinition() and
|
||||
ssaDefReachesRead(_, def0, bb, i) and
|
||||
Impl::ssaDefReachesRead(_, def0, bb, i) and
|
||||
outRefExitRead(bb, i, v)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import Cached
|
||||
|
||||
private string getSplitString(DefinitionExt def) {
|
||||
exists(ControlFlow::BasicBlock bb, int i, ControlFlow::Node cfn |
|
||||
def.definesAt(_, bb, i, _) and
|
||||
result = cfn.(ControlFlow::Nodes::ElementNode).getSplitsString()
|
||||
|
|
||||
cfn = bb.getNode(i)
|
||||
or
|
||||
not exists(bb.getNode(i)) and
|
||||
cfn = bb.getFirstNode()
|
||||
)
|
||||
}
|
||||
|
||||
string getToStringPrefix(DefinitionExt def) {
|
||||
result = "[" + getSplitString(def) + "] "
|
||||
or
|
||||
not exists(getSplitString(def)) and
|
||||
result = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* An extended static single assignment (SSA) definition.
|
||||
*
|
||||
* This is either a normal SSA definition (`Definition`) or a
|
||||
* phi-read node (`PhiReadNode`).
|
||||
*
|
||||
* Only intended for internal use.
|
||||
*/
|
||||
class DefinitionExt extends Impl::DefinitionExt {
|
||||
override string toString() { result = this.(Ssa::Definition).toString() }
|
||||
|
||||
/** Gets the location of this definition. */
|
||||
Location getLocation() { result = this.(Ssa::Definition).getLocation() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A phi-read node.
|
||||
*
|
||||
* Only intended for internal use.
|
||||
*/
|
||||
class PhiReadNode extends DefinitionExt, Impl::PhiReadNode {
|
||||
override string toString() {
|
||||
result = getToStringPrefix(this) + "SSA phi read(" + this.getSourceVariable() + ")"
|
||||
}
|
||||
|
||||
override Location getLocation() { result = this.getBasicBlock().getLocation() }
|
||||
}
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
## 0.4.5
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.4
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.4.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
3
csharp/ql/src/change-notes/released/0.4.4.md
Normal file
3
csharp/ql/src/change-notes/released/0.4.4.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.4.4
|
||||
|
||||
No user-facing changes.
|
||||
3
csharp/ql/src/change-notes/released/0.4.5.md
Normal file
3
csharp/ql/src/change-notes/released/0.4.5.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.4.5
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.4.3
|
||||
lastReleaseVersion: 0.4.5
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-queries
|
||||
version: 0.4.4-dev
|
||||
version: 0.4.5
|
||||
groups:
|
||||
- csharp
|
||||
- queries
|
||||
|
||||
@@ -5,7 +5,8 @@ AnonymousObjectCreation.cs:
|
||||
# 7| 1: [TypeMention] AnonObj
|
||||
# 7| 1: [AssignExpr] ... = ...
|
||||
# 7| 0: [FieldAccess] access to field l
|
||||
# 7| 1: [ObjectCreation] object creation of type List<AnonObj>
|
||||
# 7| 1: [CastExpr] (...) ...
|
||||
# 7| 1: [ObjectCreation] object creation of type List<AnonObj>
|
||||
# 9| 6: [Property] Prop1
|
||||
# 9| -1: [TypeMention] int
|
||||
# 9| 3: [Getter] get_Prop1
|
||||
@@ -21,13 +22,15 @@ AnonymousObjectCreation.cs:
|
||||
# 13| 0: [ExprStmt] ...;
|
||||
# 13| 0: [MethodCall] call to method M1
|
||||
# 13| -1: [ThisAccess] this access
|
||||
# 13| 0: [ObjectCreation] object creation of type AnonObj
|
||||
# 13| -1: [ObjectInitializer] { ..., ... }
|
||||
# 13| 0: [MemberInitializer] ... = ...
|
||||
# 13| 0: [PropertyCall] access to property Prop1
|
||||
# 13| 1: [IntLiteral] 1
|
||||
# 13| 0: [CastExpr] (...) ...
|
||||
# 13| 1: [ObjectCreation] object creation of type AnonObj
|
||||
# 13| -1: [ObjectInitializer] { ..., ... }
|
||||
# 13| 0: [MemberInitializer] ... = ...
|
||||
# 13| 0: [PropertyCall] access to property Prop1
|
||||
# 13| 1: [IntLiteral] 1
|
||||
# 14| 1: [ReturnStmt] return ...;
|
||||
# 14| 0: [ObjectCreation] object creation of type AnonObj
|
||||
# 14| 0: [CastExpr] (...) ...
|
||||
# 14| 1: [ObjectCreation] object creation of type AnonObj
|
||||
# 17| 8: [DelegateType] D
|
||||
#-----| 2: (Parameters)
|
||||
# 17| 0: [Parameter] x
|
||||
@@ -42,9 +45,10 @@ AnonymousObjectCreation.cs:
|
||||
# 21| -1: [TypeMention] D
|
||||
# 21| 4: [BlockStmt] {...}
|
||||
# 21| 0: [ReturnStmt] return ...;
|
||||
# 21| 0: [ExplicitDelegateCreation] delegate creation of type D
|
||||
# 21| 0: [ImplicitDelegateCreation] delegate creation of type D
|
||||
# 21| 0: [MethodAccess] access to method M2
|
||||
# 21| 0: [CastExpr] (...) ...
|
||||
# 21| 1: [ExplicitDelegateCreation] delegate creation of type D
|
||||
# 21| 0: [ImplicitDelegateCreation] delegate creation of type D
|
||||
# 21| 0: [MethodAccess] access to method M2
|
||||
# 23| 11: [Method] MethodAdd
|
||||
# 23| -1: [TypeMention] Void
|
||||
# 24| 4: [BlockStmt] {...}
|
||||
@@ -53,7 +57,8 @@ AnonymousObjectCreation.cs:
|
||||
# 25| -1: [TypeMention] List<int>
|
||||
# 25| 1: [TypeMention] int
|
||||
# 25| 0: [LocalVariableAccess] access to local variable list
|
||||
# 25| 1: [ObjectCreation] object creation of type List<Int32>
|
||||
# 25| 1: [CastExpr] (...) ...
|
||||
# 25| 1: [ObjectCreation] object creation of type List<Int32>
|
||||
BinaryPattern.cs:
|
||||
# 3| [Class] BinaryPattern
|
||||
# 5| 5: [Property] P1
|
||||
|
||||
@@ -1,4 +1,30 @@
|
||||
| DefUse.cs:63:9:63:14 | this.Field2 | DefUse.cs:80:30:80:31 | access to local variable x1 |
|
||||
| Fields.cs:65:24:65:32 | this.LoopField | Fields.cs:63:16:63:28 | this access |
|
||||
| Properties.cs:65:24:65:31 | this.LoopProp | Properties.cs:63:16:63:16 | access to parameter i |
|
||||
| Test.cs:78:13:78:13 | x | Test.cs:90:9:97:9 | if (...) ... |
|
||||
phiReadNode
|
||||
| DefUse.cs:80:30:80:31 | SSA phi read(this.Field2) | DefUse.cs:63:9:63:14 | this.Field2 |
|
||||
| Fields.cs:63:16:63:28 | SSA phi read(this.LoopField) | Fields.cs:65:24:65:32 | this.LoopField |
|
||||
| Patterns.cs:20:9:38:9 | SSA phi read(o) | Patterns.cs:7:16:7:16 | o |
|
||||
| Properties.cs:63:16:63:16 | SSA phi read(this.LoopProp) | Properties.cs:65:24:65:31 | this.LoopProp |
|
||||
| Test.cs:25:16:25:16 | SSA phi read(x) | Test.cs:8:13:8:13 | x |
|
||||
| Test.cs:90:9:97:9 | SSA phi read(x) | Test.cs:78:13:78:13 | x |
|
||||
| Test.cs:99:9:99:15 | SSA phi read(x) | Test.cs:78:13:78:13 | x |
|
||||
phiReadNodeRead
|
||||
| DefUse.cs:80:30:80:31 | SSA phi read(this.Field2) | DefUse.cs:63:9:63:14 | this.Field2 | DefUse.cs:80:37:80:42 | access to field Field2 |
|
||||
| Fields.cs:63:16:63:28 | SSA phi read(this.LoopField) | Fields.cs:65:24:65:32 | this.LoopField | Fields.cs:65:24:65:32 | access to field LoopField |
|
||||
| Patterns.cs:20:9:38:9 | SSA phi read(o) | Patterns.cs:7:16:7:16 | o | Patterns.cs:20:17:20:17 | access to local variable o |
|
||||
| Properties.cs:63:16:63:16 | SSA phi read(this.LoopProp) | Properties.cs:65:24:65:31 | this.LoopProp | Properties.cs:65:24:65:31 | access to property LoopProp |
|
||||
| Test.cs:25:16:25:16 | SSA phi read(x) | Test.cs:8:13:8:13 | x | Test.cs:25:16:25:16 | access to local variable x |
|
||||
| Test.cs:90:9:97:9 | SSA phi read(x) | Test.cs:78:13:78:13 | x | Test.cs:92:17:92:17 | access to local variable x |
|
||||
| Test.cs:90:9:97:9 | SSA phi read(x) | Test.cs:78:13:78:13 | x | Test.cs:96:17:96:17 | access to local variable x |
|
||||
| Test.cs:99:9:99:15 | SSA phi read(x) | Test.cs:78:13:78:13 | x | Test.cs:99:13:99:13 | access to local variable x |
|
||||
| Test.cs:99:9:99:15 | SSA phi read(x) | Test.cs:78:13:78:13 | x | Test.cs:104:17:104:17 | access to local variable x |
|
||||
phiReadInput
|
||||
| DefUse.cs:80:30:80:31 | SSA phi read(this.Field2) | DefUse.cs:63:9:63:18 | SSA def(this.Field2) |
|
||||
| DefUse.cs:80:30:80:31 | SSA phi read(this.Field2) | DefUse.cs:80:30:80:31 | SSA phi read(this.Field2) |
|
||||
| Fields.cs:63:16:63:28 | SSA phi read(this.LoopField) | Fields.cs:61:17:61:17 | SSA entry def(this.LoopField) |
|
||||
| Fields.cs:63:16:63:28 | SSA phi read(this.LoopField) | Fields.cs:63:16:63:28 | SSA phi read(this.LoopField) |
|
||||
| Patterns.cs:20:9:38:9 | SSA phi read(o) | Patterns.cs:7:16:7:23 | SSA def(o) |
|
||||
| Properties.cs:63:16:63:16 | SSA phi read(this.LoopProp) | Properties.cs:61:17:61:17 | SSA entry def(this.LoopProp) |
|
||||
| Properties.cs:63:16:63:16 | SSA phi read(this.LoopProp) | Properties.cs:63:16:63:16 | SSA phi read(this.LoopProp) |
|
||||
| Test.cs:25:16:25:16 | SSA phi read(x) | Test.cs:24:9:24:15 | SSA phi(x) |
|
||||
| Test.cs:25:16:25:16 | SSA phi read(x) | Test.cs:25:16:25:16 | SSA phi read(x) |
|
||||
| Test.cs:90:9:97:9 | SSA phi read(x) | Test.cs:78:13:78:17 | SSA def(x) |
|
||||
| Test.cs:99:9:99:15 | SSA phi read(x) | Test.cs:90:9:97:9 | SSA phi read(x) |
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
import csharp
|
||||
import semmle.code.csharp.dataflow.internal.SsaImpl
|
||||
import ExposedForTestingOnly
|
||||
|
||||
from Ssa::SourceVariable v, ControlFlow::BasicBlock bb
|
||||
where phiReadExposedForTesting(bb, v)
|
||||
select v, bb
|
||||
query predicate phiReadNode(PhiReadNode phi, Ssa::SourceVariable v) { phi.getSourceVariable() = v }
|
||||
|
||||
query predicate phiReadNodeRead(PhiReadNode phi, Ssa::SourceVariable v, ControlFlow::Node read) {
|
||||
phi.getSourceVariable() = v and
|
||||
exists(ControlFlow::BasicBlock bb, int i |
|
||||
ssaDefReachesReadExt(v, phi, bb, i) and
|
||||
read = bb.getNode(i)
|
||||
)
|
||||
}
|
||||
|
||||
query predicate phiReadInput(PhiReadNode phi, DefinitionExt inp) {
|
||||
phiHasInputFromBlockExt(phi, inp, _)
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ class Test
|
||||
{
|
||||
use(x);
|
||||
}
|
||||
// no phi_use for `x`, because actual use exists in the block
|
||||
// phi_use for `x`, even though there is an actual use in the block
|
||||
use(x);
|
||||
|
||||
|
||||
|
||||
@@ -168,7 +168,9 @@ generate a database, therefore the build method must be available to the CLI.
|
||||
Detecting the build system
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The CodeQL CLI includes autobuilders for C/C++, C#, Go, and Java code. CodeQL
|
||||
.. include:: ../reusables/kotlin-beta-note.rst
|
||||
|
||||
The CodeQL CLI includes autobuilders for C/C++, C#, Go, Java and Kotlin code. CodeQL
|
||||
autobuilders allow you to build projects for compiled languages without
|
||||
specifying any build commands. When an autobuilder is invoked, CodeQL examines
|
||||
the source for evidence of a build system and attempts to run the optimal set of
|
||||
|
||||
@@ -30,7 +30,7 @@ You can then use the CodeQL CLI to publish your pack to share with others. For m
|
||||
Viewing CodeQL packs and their dependencies in Visual Studio Code
|
||||
-----------------------------------------------------------------
|
||||
To download a CodeQL pack that someone else has created, run the **CodeQL: Download Packs** command from the Command Palette.
|
||||
You can download all the core CodeQL query packs, or enter the full name of a specific pack to download. For example, to download the core queries for analyzing Java, enter ``codeql/java-queries``.
|
||||
You can download all the core CodeQL query packs, or enter the full name of a specific pack to download. For example, to download the core queries for analyzing Java or Kotlin, enter ``codeql/java-queries``.
|
||||
|
||||
Whether you have downloaded a CodeQL pack or created your own, you can open the ``qlpack.yml`` file in the root of a CodeQL pack directory in Visual Studio Code and view the dependencies section to see what libraries the pack depends on.
|
||||
|
||||
|
||||
@@ -7,6 +7,10 @@ CodeQL has a large selection of classes for representing the abstract syntax tre
|
||||
|
||||
.. include:: ../reusables/abstract-syntax-tree.rst
|
||||
|
||||
.. include:: ../reusables/kotlin-beta-note.rst
|
||||
|
||||
.. include:: ../reusables/kotlin-java-differences.rst
|
||||
|
||||
Statement classes
|
||||
-----------------
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ Example finding unreachable AST nodes
|
||||
where not exists(node.getAFlowNode())
|
||||
select node
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/669220024/>`__. The demo projects on LGTM.com all have some code that has no control flow node, and is therefore unreachable. However, since the ``Module`` class is also a subclass of the ``AstNode`` class, the query also finds any modules implemented in C or with no source code. Therefore, it is better to find all unreachable statements.
|
||||
Many codebases have some code that has no control flow node, and is therefore unreachable. However, since the ``Module`` class is also a subclass of the ``AstNode`` class, the query also finds any modules implemented in C or with no source code. Therefore, it is better to find all unreachable statements.
|
||||
|
||||
Example finding unreachable statements
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@@ -60,7 +60,7 @@ Example finding unreachable statements
|
||||
where not exists(s.getAFlowNode())
|
||||
select s
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/670720181/>`__. This query gives fewer results, but most of the projects have some unreachable nodes. These are also highlighted by the standard "Unreachable code" query. For more information, see `Unreachable code <https://lgtm.com/rules/3980095>`__ on LGTM.com.
|
||||
This query should give fewer results. You can also find unreachable code using the standard "Unreachable code" query. For more information, see `Unreachable code <https://codeql.github.com/codeql-query-help/python/py-unreachable-statement/>`__.
|
||||
|
||||
The ``BasicBlock`` class
|
||||
------------------------
|
||||
@@ -114,7 +114,7 @@ Example finding mutually exclusive blocks within the same function
|
||||
)
|
||||
select b1, b2
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/671000028/>`__. This typically gives a very large number of results, because it is a common occurrence in normal control flow. It is, however, an example of the sort of control-flow analysis that is possible. Control-flow analyses such as this are an important aid to data flow analysis. For more information, see ":doc:`Analyzing data flow in Python <analyzing-data-flow-in-python>`."
|
||||
This typically gives a very large number of results, because it is a common occurrence in normal control flow. It is, however, an example of the sort of control-flow analysis that is possible. Control-flow analyses such as this are an important aid to data flow analysis. For more information, see ":doc:`Analyzing data flow in Python <analyzing-data-flow-in-python>`."
|
||||
|
||||
Further reading
|
||||
---------------
|
||||
|
||||
@@ -5,6 +5,10 @@ Analyzing data flow in Java
|
||||
|
||||
You can use CodeQL to track the flow of data through a Java program to its use.
|
||||
|
||||
.. include:: ../reusables/kotlin-beta-note.rst
|
||||
|
||||
.. include:: ../reusables/kotlin-java-differences.rst
|
||||
|
||||
About this article
|
||||
------------------
|
||||
|
||||
|
||||
@@ -97,11 +97,9 @@ Python has builtin functionality for reading and writing files, such as the func
|
||||
call = API::moduleImport("os").getMember("open").getACall()
|
||||
select call.getArg(0)
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/8635258505893505141/>`__. Two of the demo projects make use of this low-level API.
|
||||
|
||||
Notice the use of the ``API`` module for referring to library functions. For more information, see ":doc:`Using API graphs in Python <using-api-graphs-in-python>`."
|
||||
|
||||
Unfortunately this will only give the expression in the argument, not the values which could be passed to it. So we use local data flow to find all expressions that flow into the argument:
|
||||
Unfortunately this query will only give the expression in the argument, not the values which could be passed to it. So we use local data flow to find all expressions that flow into the argument:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
@@ -115,9 +113,7 @@ Unfortunately this will only give the expression in the argument, not the values
|
||||
DataFlow::localFlow(expr, call.getArg(0))
|
||||
select call, expr
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/8213643003890447109/>`__. Many expressions flow to the same call.
|
||||
|
||||
We see that we get several data-flow nodes for an expression as it flows towards a call (notice repeated locations in the ``call`` column). We are mostly interested in the "first" of these, what might be called the local source for the file name. To restrict attention to such local sources, and to simultaneously make the analysis more performant, we have the QL class ``LocalSourceNode``. We could demand that ``expr`` is such a node:
|
||||
Typically, you will see several data-flow nodes for an expression as it flows towards a call (notice repeated locations in the ``call`` column). We are mostly interested in the "first" of these, what might be called the local source for the file name. To restrict attention to such local sources, and to simultaneously make the analysis more performant, we have the QL class ``LocalSourceNode``. We could demand that ``expr`` is such a node:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
@@ -160,9 +156,9 @@ As an alternative, we can ask more directly that ``expr`` is a local source of t
|
||||
expr = call.getArg(0).getALocalSource()
|
||||
select call, expr
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/6602079735954016687/>`__. All these three queries give identical results. We now mostly have one expression per call.
|
||||
These three queries all give identical results. We now mostly have one expression per call.
|
||||
|
||||
We still have some cases of more than one expression flowing to a call, but then they flow through different code paths (possibly due to control-flow splitting, as in the second case).
|
||||
We still have some cases of more than one expression flowing to a call, but then they flow through different code paths (possibly due to control-flow splitting).
|
||||
|
||||
We might want to make the source more specific, for example a parameter to a function or method. This query finds instances where a parameter is used as the name when opening a file:
|
||||
|
||||
@@ -178,7 +174,7 @@ We might want to make the source more specific, for example a parameter to a fun
|
||||
DataFlow::localFlow(p, call.getArg(0))
|
||||
select call, p
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/3998032643497238063/>`__. Very few results now; these could feasibly be inspected manually.
|
||||
For most codebases, this will return only a few results and these could be inspected manually.
|
||||
|
||||
Using the exact name supplied via the parameter may be too strict. If we want to know if the parameter influences the file name, we can use taint tracking instead of data flow. This query finds calls to ``os.open`` where the filename is derived from a parameter:
|
||||
|
||||
@@ -194,7 +190,7 @@ Using the exact name supplied via the parameter may be too strict. If we want to
|
||||
TaintTracking::localTaint(p, call.getArg(0))
|
||||
select call, p
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/2129957933670836953/>`__. Now we get more results and in more projects.
|
||||
Typically, this finds more results.
|
||||
|
||||
Global data flow
|
||||
----------------
|
||||
@@ -369,8 +365,6 @@ This data flow configuration tracks data flow from environment variables to open
|
||||
select fileOpen, "This call to 'os.open' uses data from $@.",
|
||||
environment, "call to 'os.getenv'"
|
||||
|
||||
➤ `Running this in the query console on LGTM.com <https://lgtm.com/query/6582374907796191895/>`__ unsurprisingly yields no results in the demo projects.
|
||||
|
||||
|
||||
Further reading
|
||||
---------------
|
||||
|
||||
@@ -51,7 +51,7 @@ We could then write this query to find all ``@SuppressWarnings`` annotations att
|
||||
anntp.hasQualifiedName("java.lang", "SuppressWarnings")
|
||||
select ann, ann.getValue("value")
|
||||
|
||||
➤ `See the full query in the query console on LGTM.com <https://lgtm.com/query/1775658606775222283/>`__. Several of the LGTM.com demo projects use the ``@SuppressWarnings`` annotation. Looking at the ``value``\ s of the annotation element returned by the query, we can see that the *apache/activemq* project uses the ``"rawtypes"`` value described above.
|
||||
If the codebase you are analyzing uses the ``@SuppressWarnings`` annotation, you can check the ``value``\ s of the annotation element returned by the query. They should use the ``"rawtypes"`` value described above.
|
||||
|
||||
As another example, this query finds all annotation types that only have a single annotation element, which has name ``value``:
|
||||
|
||||
@@ -66,8 +66,6 @@ As another example, this query finds all annotation types that only have a singl
|
||||
)
|
||||
select anntp
|
||||
|
||||
➤ `See the full query in the query console on LGTM.com <https://lgtm.com/query/2145264152490258283/>`__.
|
||||
|
||||
Example: Finding missing ``@Override`` annotations
|
||||
--------------------------------------------------
|
||||
|
||||
@@ -124,7 +122,7 @@ This makes it very easy to write our query for finding methods that override ano
|
||||
not overriding.getAnAnnotation() instanceof OverrideAnnotation
|
||||
select overriding, "Method overrides another method, but does not have an @Override annotation."
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/7419756266089837339/>`__. In practice, this query may yield many results from compiled library code, which aren't very interesting. It's therefore a good idea to add another conjunct ``overriding.fromSource()`` to restrict the result to only report methods for which source code is available.
|
||||
In practice, this query may yield many results from compiled library code, which aren't very interesting. It's therefore a good idea to add another conjunct ``overriding.fromSource()`` to restrict the result to only report methods for which source code is available.
|
||||
|
||||
Example: Finding calls to deprecated methods
|
||||
--------------------------------------------
|
||||
@@ -237,7 +235,7 @@ Now we can extend our query to filter out calls in methods carrying a ``Suppress
|
||||
and not call.getCaller().getAnAnnotation() instanceof SuppressDeprecationWarningAnnotation
|
||||
select call, "This call invokes a deprecated method."
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/8706367340403790260/>`__. It's fairly common for projects to contain calls to methods that appear to be deprecated.
|
||||
It's fairly common for projects to contain calls to methods that appear to be deprecated.
|
||||
|
||||
Further reading
|
||||
---------------
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
Basic query for C and C++ code
|
||||
==============================
|
||||
|
||||
Learn to write and run a simple CodeQL query using LGTM.
|
||||
Learn to write and run a simple CodeQL query using Visual Studio Code with the CodeQL extension.
|
||||
|
||||
.. include:: ../reusables/vs-code-basic-instructions/setup-to-run-queries.rst
|
||||
|
||||
About the query
|
||||
---------------
|
||||
@@ -14,62 +16,33 @@ The query we're going to run performs a basic search of the code for ``if`` stat
|
||||
|
||||
if (error) { }
|
||||
|
||||
Running the query
|
||||
-----------------
|
||||
.. include:: ../reusables/vs-code-basic-instructions/find-database.rst
|
||||
|
||||
#. In the main search box on LGTM.com, search for the project you want to query. For tips, see `Searching <https://lgtm.com/help/lgtm/searching>`__.
|
||||
Running a quick query
|
||||
---------------------
|
||||
|
||||
#. Click the project in the search results.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/run-quick-query-1.rst
|
||||
|
||||
#. Click **Query this project**.
|
||||
|
||||
This opens the query console. (For information about using this, see `Using the query console <https://lgtm.com/help/lgtm/using-query-console>`__.)
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Alternatively, you can go straight to the query console by clicking **Query console** (at the top of any page), selecting **C/C++** from the **Language** drop-down list, then choosing one or more projects to query from those displayed in the **Project** drop-down list.
|
||||
|
||||
#. Copy the following query into the text box in the query console:
|
||||
#. In the quick query tab, delete ``select ""`` and paste the following query beneath the import statement ``import cpp``.
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import cpp
|
||||
|
||||
from IfStmt ifstmt, BlockStmt block
|
||||
where ifstmt.getThen() = block and
|
||||
block.getNumStmt() = 0
|
||||
select ifstmt, "This 'if' statement is redundant."
|
||||
|
||||
LGTM checks whether your query compiles and, if all is well, the **Run** button changes to green to indicate that you can go ahead and run the query.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/run-quick-query-2.rst
|
||||
|
||||
#. Click **Run**.
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-cpp-query-results-1.png
|
||||
:align: center
|
||||
|
||||
The name of the project you are querying, and the ID of the most recently analyzed commit to the project, are listed below the query box. To the right of this is an icon that indicates the progress of the query operation:
|
||||
If any matching code is found, click a link in the ``ifstmt`` column to open the file and highlight the matching ``if`` statement.
|
||||
|
||||
.. image:: ../images/query-progress.png
|
||||
:align: center
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-cpp-query-results-2.png
|
||||
:align: center
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Your query is always run against the most recently analyzed commit to the selected project.
|
||||
|
||||
The query will take a few moments to return results. When the query completes, the results are displayed below the project name. The query results are listed in two columns, corresponding to the two expressions in the ``select`` clause of the query. The first column corresponds to the expression ``ifstmt`` and is linked to the location in the source code of the project where ``ifstmt`` occurs. The second column is the alert message.
|
||||
|
||||
➤ `Example query results <https://lgtm.com/query/4242591143131494898/>`__
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
An ellipsis (…) at the bottom of the table indicates that the entire list is not displayed—click it to show more results.
|
||||
|
||||
#. If any matching code is found, click a link in the ``ifstmt`` column to view the ``if`` statement in the code viewer.
|
||||
|
||||
The matching ``if`` statement is highlighted with a yellow background in the code viewer. If any code in the file also matches a query from the standard query library for that language, you will see a red alert message at the appropriate point within the code.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/note-store-quick-query.rst
|
||||
|
||||
About the query structure
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -120,7 +93,7 @@ In this case, identifying the ``if`` statement with the empty ``then`` branch as
|
||||
|
||||
To exclude ``if`` statements that have an ``else`` branch:
|
||||
|
||||
#. Extend the ``where`` clause to include the following extra condition:
|
||||
#. Edit your query and extend the ``where`` clause to include the following extra condition:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
@@ -134,14 +107,24 @@ To exclude ``if`` statements that have an ``else`` branch:
|
||||
block.getNumStmt() = 0 and
|
||||
not ifstmt.hasElse()
|
||||
|
||||
#. Click **Run**.
|
||||
#. Re-run the query.
|
||||
|
||||
There are now fewer results because ``if`` statements with an ``else`` branch are no longer reported.
|
||||
|
||||
➤ `See this in the query console <https://lgtm.com/query/1899933116489579248/>`__
|
||||
|
||||
Further reading
|
||||
---------------
|
||||
|
||||
.. include:: ../reusables/cpp-further-reading.rst
|
||||
.. include:: ../reusables/codeql-ref-tools-further-reading.rst
|
||||
|
||||
.. Article-specific substitutions for the reusables used in docs/codeql/reusables/vs-code-basic-instructions
|
||||
|
||||
.. |language-text| replace:: C/C++
|
||||
|
||||
.. |language-code| replace:: ``cpp``
|
||||
|
||||
.. |example-url| replace:: https://github.com/protocolbuffers/protobuf
|
||||
|
||||
.. |image-quick-query| image:: ../images/codeql-for-visual-studio-code/quick-query-tab-cpp.png
|
||||
|
||||
.. |result-col-1| replace:: The first column corresponds to the expression ``ifstmt`` and is linked to the location in the source code of the project where ``ifstmt`` occurs.
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
Basic query for C# code
|
||||
=======================
|
||||
|
||||
Learn to write and run a simple CodeQL query using LGTM.
|
||||
Learn to write and run a simple CodeQL query using Visual Studio Code with the CodeQL extension.
|
||||
|
||||
.. include:: ../reusables/vs-code-basic-instructions/setup-to-run-queries.rst
|
||||
|
||||
About the query
|
||||
---------------
|
||||
@@ -14,62 +16,33 @@ The query we're going to run performs a basic search of the code for ``if`` stat
|
||||
|
||||
if (error) { }
|
||||
|
||||
Running the query
|
||||
-----------------
|
||||
.. include:: ../reusables/vs-code-basic-instructions/find-database.rst
|
||||
|
||||
#. In the main search box on LGTM.com, search for the project you want to query. For tips, see `Searching <https://lgtm.com/help/lgtm/searching>`__.
|
||||
Running a quick query
|
||||
---------------------
|
||||
|
||||
#. Click the project in the search results.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/run-quick-query-1.rst
|
||||
|
||||
#. Click **Query this project**.
|
||||
|
||||
This opens the query console. (For information about using this, see `Using the query console <https://lgtm.com/help/lgtm/using-query-console>`__.)
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Alternatively, you can go straight to the query console by clicking **Query console** (at the top of any page), selecting **C#** from the **Language** drop-down list, then choosing one or more projects to query from those displayed in the **Project** drop-down list.
|
||||
|
||||
#. Copy the following query into the text box in the query console:
|
||||
#. In the quick query tab, delete ``select ""`` and paste the following query beneath the import statement ``import csharp``.
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import csharp
|
||||
|
||||
from IfStmt ifstmt, BlockStmt block
|
||||
where ifstmt.getThen() = block and
|
||||
block.isEmpty()
|
||||
select ifstmt, "This 'if' statement is redundant."
|
||||
|
||||
LGTM checks whether your query compiles and, if all is well, the **Run** button changes to green to indicate that you can go ahead and run the query.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/run-quick-query-2.rst
|
||||
|
||||
#. Click **Run**.
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-csharp-query-results-1.png
|
||||
:align: center
|
||||
|
||||
The name of the project you are querying, and the ID of the most recently analyzed commit to the project, are listed below the query box. To the right of this is an icon that indicates the progress of the query operation:
|
||||
If any matching code is found, click a link in the ``ifstmt`` column to open the file and highlight the matching ``if`` statement.
|
||||
|
||||
.. image:: ../images/query-progress.png
|
||||
:align: center
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-csharp-query-results-2.png
|
||||
:align: center
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Your query is always run against the most recently analyzed commit to the selected project.
|
||||
|
||||
The query will take a few moments to return results. When the query completes, the results are displayed below the project name. The query results are listed in two columns, corresponding to the two expressions in the ``select`` clause of the query. The first column corresponds to the expression ``ifstmt`` and is linked to the location in the source code of the project where ``ifstmt`` occurs. The second column is the alert message.
|
||||
|
||||
➤ `Example query results <https://lgtm.com/query/1214010107827821393/>`__
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
An ellipsis (…) at the bottom of the table indicates that the entire list is not displayed—click it to show more results.
|
||||
|
||||
#. If any matching code is found, click a link in the ``ifstmt`` column to view the ``if`` statement in the code viewer.
|
||||
|
||||
The matching ``if`` statement is highlighted with a yellow background in the code viewer. If any code in the file also matches a query from the standard query library for that language, you will see a red alert message at the appropriate point within the code.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/note-store-quick-query.rst
|
||||
|
||||
About the query structure
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -139,14 +112,23 @@ To exclude ``if`` statements that have an ``else`` branch:
|
||||
block.isEmpty() and
|
||||
not exists(ifstmt.getElse())
|
||||
|
||||
#. Click **Run**.
|
||||
#. Re-run the query.
|
||||
|
||||
There are now fewer results because ``if`` statements with an ``else`` branch are no longer included.
|
||||
|
||||
➤ `See this in the query console <https://lgtm.com/query/6233102733683510530/>`__
|
||||
|
||||
Further reading
|
||||
---------------
|
||||
|
||||
.. include:: ../reusables/csharp-further-reading.rst
|
||||
.. include:: ../reusables/codeql-ref-tools-further-reading.rst
|
||||
|
||||
.. Article-specific substitutions for the reusables used in docs/codeql/reusables/vs-code-basic-instructions
|
||||
.. |language-text| replace:: C#
|
||||
|
||||
.. |language-code| replace:: ``csharp``
|
||||
|
||||
.. |example-url| replace:: https://github.com/PowerShell/PowerShell
|
||||
|
||||
.. |image-quick-query| image:: ../images/codeql-for-visual-studio-code/quick-query-tab-csharp.png
|
||||
|
||||
.. |result-col-1| replace:: The first column corresponds to the expression ``ifstmt`` and is linked to the location in the source code of the project where ``ifstmt`` occurs.
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
Basic query for Go code
|
||||
=======================
|
||||
|
||||
Learn to write and run a simple CodeQL query using LGTM.
|
||||
Learn to write and run a simple CodeQL query using Visual Studio Code with the CodeQL extension.
|
||||
|
||||
.. include:: ../reusables/vs-code-basic-instructions/setup-to-run-queries.rst
|
||||
|
||||
About the query
|
||||
---------------
|
||||
@@ -22,29 +24,17 @@ This is problematic because the receiver argument is passed by value, not by ref
|
||||
|
||||
For further information on using methods on values or pointers in Go, see the `Go FAQ <https://golang.org/doc/faq#methods_on_values_or_pointers>`__.
|
||||
|
||||
Running the query
|
||||
-----------------
|
||||
.. include:: ../reusables/vs-code-basic-instructions/find-database.rst
|
||||
|
||||
#. In the main search box on LGTM.com, search for the project you want to query. For tips, see `Searching <https://lgtm.com/help/lgtm/searching>`__.
|
||||
Running a quick query
|
||||
---------------------
|
||||
|
||||
#. Click the project in the search results.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/run-quick-query-1.rst
|
||||
|
||||
#. Click **Query this project**.
|
||||
|
||||
This opens the query console. (For information about using this, see `Using the query console <https://lgtm.com/help/lgtm/using-query-console>`__.)
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Alternatively, you can go straight to the query console by clicking **Query console** (at the top of any page), selecting **Go** from the **Language** drop-down list, then choosing one or more projects to query from those displayed in the **Project** drop-down list.
|
||||
|
||||
#. Copy the following query into the text box in the query console:
|
||||
#. In the quick query tab, delete ``select ""`` and paste the following query beneath the import statement ``import go``.
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import go
|
||||
|
||||
from Method m, Variable recv, Write w, Field f
|
||||
where
|
||||
recv = m.getReceiver() and
|
||||
@@ -52,34 +42,17 @@ Running the query
|
||||
not recv.getType() instanceof PointerType
|
||||
select w, "This update to " + f + " has no effect, because " + recv + " is not a pointer."
|
||||
|
||||
LGTM checks whether your query compiles and, if all is well, the **Run** button changes to green to indicate that you can go ahead and run the query.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/run-quick-query-2.rst
|
||||
|
||||
#. Click **Run**.
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-go-query-results-1.png
|
||||
:align: center
|
||||
|
||||
The name of the project you are querying, and the ID of the most recently analyzed commit to the project, are listed below the query box. To the right of this is an icon that indicates the progress of the query operation:
|
||||
If any matching code is found, click a link in the ``w`` column to open the file and highlight the matching location.
|
||||
|
||||
.. image:: ../images/query-progress.png
|
||||
:align: center
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-go-query-results-2.png
|
||||
:align: center
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Your query is always run against the most recently analyzed commit to the selected project.
|
||||
|
||||
The query will take a few moments to return results. When the query completes, the results are displayed below the project name. The query results are listed in two columns, corresponding to the two expressions in the ``select`` clause of the query. The first column corresponds to ``w``, which is the location in the source code where the receiver ``recv`` is modified. The second column is the alert message.
|
||||
|
||||
➤ `Example query results <https://lgtm.com/query/6221190009056970603/>`__
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
An ellipsis (…) at the bottom of the table indicates that the entire list is not displayed—click it to show more results.
|
||||
|
||||
#. If any matching code is found, click a link in the ``w`` column to view it in the code viewer.
|
||||
|
||||
The matching ``w`` is highlighted with a yellow background in the code viewer. If any code in the file also matches a query from the standard query library for that language, you will see a red alert message at the appropriate point within the code.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/note-store-quick-query.rst
|
||||
|
||||
About the query structure
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -140,14 +113,24 @@ To exclude these values:
|
||||
not recv.getType() instanceof PointerType and
|
||||
not exists(ReturnStmt ret | ret.getExpr() = recv.getARead().asExpr())
|
||||
|
||||
#. Click **Run**.
|
||||
#. Re-run the query.
|
||||
|
||||
There are now fewer results because value methods that return their receiver variable are no longer reported.
|
||||
|
||||
➤ `See this in the query console <https://lgtm.com/query/9110448975027954322/>`__
|
||||
|
||||
Further reading
|
||||
---------------
|
||||
|
||||
.. include:: ../reusables/go-further-reading.rst
|
||||
.. include:: ../reusables/codeql-ref-tools-further-reading.rst
|
||||
|
||||
.. Article-specific substitutions for the reusables used in docs/codeql/reusables/vs-code-basic-instructions
|
||||
|
||||
.. |language-text| replace:: Go
|
||||
|
||||
.. |language-code| replace:: ``go``
|
||||
|
||||
.. |example-url| replace:: https://github.com/go-gorm/gorm
|
||||
|
||||
.. |image-quick-query| image:: ../images/codeql-for-visual-studio-code/quick-query-tab-go.png
|
||||
|
||||
.. |result-col-1| replace:: The first column corresponds to ``w``, which is the location in the source code where the receiver ``recv`` is modified.
|
||||
|
||||
@@ -1,100 +1,90 @@
|
||||
.. _basic-query-for-java-code:
|
||||
|
||||
Basic query for Java code
|
||||
=========================
|
||||
Basic query for Java and Kotlin code
|
||||
====================================
|
||||
|
||||
Learn to write and run a simple CodeQL query using LGTM.
|
||||
Learn to write and run a simple CodeQL query using Visual Studio Code with the CodeQL extension.
|
||||
|
||||
.. include:: ../reusables/vs-code-basic-instructions/setup-to-run-queries.rst
|
||||
|
||||
About the query
|
||||
---------------
|
||||
|
||||
The query we're going to run performs a basic search of the code for ``if`` statements that are redundant, in the sense that they have an empty then branch. For example, code such as:
|
||||
The query we're going to run searches for inefficient tests for empty strings. For example, Java code such as:
|
||||
|
||||
.. code-block:: java
|
||||
|
||||
if (error) { }
|
||||
public class TestJava {
|
||||
void myJavaFun(String s) {
|
||||
boolean b = s.equals("");
|
||||
}
|
||||
}
|
||||
|
||||
Running the query
|
||||
-----------------
|
||||
or Kotlin code such as:
|
||||
|
||||
#. In the main search box on LGTM.com, search for the project you want to query. For tips, see `Searching <https://lgtm.com/help/lgtm/searching>`__.
|
||||
.. code-block:: kotlin
|
||||
|
||||
#. Click the project in the search results.
|
||||
void myKotlinFun(s: String) {
|
||||
var b = s.equals("")
|
||||
}
|
||||
|
||||
#. Click **Query this project**.
|
||||
In either case, replacing ``s.equals("")`` with ``s.isEmpty()``
|
||||
would be more efficient.
|
||||
|
||||
This opens the query console. (For information about using this, see `Using the query console <https://lgtm.com/help/lgtm/using-query-console>`__.)
|
||||
.. include:: ../reusables/vs-code-basic-instructions/find-database.rst
|
||||
|
||||
.. pull-quote::
|
||||
Running a quick query
|
||||
---------------------
|
||||
|
||||
Note
|
||||
.. include:: ../reusables/vs-code-basic-instructions/run-quick-query-1.rst
|
||||
|
||||
Alternatively, you can go straight to the query console by clicking **Query console** (at the top of any page), selecting **Java** from the **Language** drop-down list, then choosing one or more projects to query from those displayed in the **Project** drop-down list.
|
||||
|
||||
#. Copy the following query into the text box in the query console:
|
||||
#. In the quick query tab, delete ``select ""`` and paste the following query beneath the import statement ``import java``.
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import java
|
||||
from MethodAccess ma
|
||||
where
|
||||
ma.getMethod().hasName("equals") and
|
||||
ma.getArgument(0).(StringLiteral).getValue() = ""
|
||||
select ma, "This comparison to empty string is inefficient, use isEmpty() instead."
|
||||
|
||||
from IfStmt ifstmt, Block block
|
||||
where ifstmt.getThen() = block and
|
||||
block.getNumStmt() = 0
|
||||
select ifstmt, "This 'if' statement is redundant."
|
||||
Note that CodeQL treats Java and Kotlin as part of the same language, so even though this query starts with ``import java``, it will work for both Java and Kotlin code.
|
||||
|
||||
LGTM checks whether your query compiles and, if all is well, the **Run** button changes to green to indicate that you can go ahead and run the query.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/run-quick-query-2.rst
|
||||
|
||||
#. Click **Run**.
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-java-query-results-1.png
|
||||
:align: center
|
||||
|
||||
The name of the project you are querying, and the ID of the most recently analyzed commit to the project, are listed below the query box. To the right of this is an icon that indicates the progress of the query operation:
|
||||
If any matching code is found, click a link in the ``ma`` column to view the ``.equals`` expression in the code viewer.
|
||||
|
||||
.. image:: ../images/query-progress.png
|
||||
:align: center
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-java-query-results-2.png
|
||||
:align: center
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Your query is always run against the most recently analyzed commit to the selected project.
|
||||
|
||||
The query will take a few moments to return results. When the query completes, the results are displayed below the project name. The query results are listed in two columns, corresponding to the two expressions in the ``select`` clause of the query. The first column corresponds to the expression ``ifstmt`` and is linked to the location in the source code of the project where ``ifstmt`` occurs. The second column is the alert message.
|
||||
|
||||
➤ `Example query results <https://lgtm.com/query/3235645104630320782/>`__
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
An ellipsis (…) at the bottom of the table indicates that the entire list is not displayed—click it to show more results.
|
||||
|
||||
#. If any matching code is found, click a link in the ``ifstmt`` column to view the ``if`` statement in the code viewer.
|
||||
|
||||
The matching ``if`` statement is highlighted with a yellow background in the code viewer. If any code in the file also matches a query from the standard query library for that language, you will see a red alert message at the appropriate point within the code.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/note-store-quick-query.rst
|
||||
|
||||
About the query structure
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
After the initial ``import`` statement, this simple query comprises three parts that serve similar purposes to the FROM, WHERE, and SELECT parts of an SQL query.
|
||||
|
||||
+---------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------+
|
||||
| Query part | Purpose | Details |
|
||||
+===============================================================+===================================================================================================================+========================================================================================================================+
|
||||
| ``import java`` | Imports the standard CodeQL libraries for Java. | Every query begins with one or more ``import`` statements. |
|
||||
+---------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------+
|
||||
| ``from IfStmt ifstmt, Block block`` | Defines the variables for the query. | We use: |
|
||||
| | Declarations are of the form: | |
|
||||
| | ``<type> <variable name>`` | - an ``IfStmt`` variable for ``if`` statements |
|
||||
| | | - a ``Block`` variable for the then block |
|
||||
+---------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------+
|
||||
| ``where ifstmt.getThen() = block and block.getNumStmt() = 0`` | Defines a condition on the variables. | ``ifstmt.getThen() = block`` relates the two variables. The block must be the ``then`` branch of the ``if`` statement. |
|
||||
| | | |
|
||||
| | | ``block.getNumStmt() = 0`` states that the block must be empty (that is, it contains no statements). |
|
||||
+---------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------+
|
||||
| ``select ifstmt, "This 'if' statement is redundant."`` | Defines what to report for each match. | Reports the resulting ``if`` statement with a string that explains the problem. |
|
||||
| | | |
|
||||
| | ``select`` statements for queries that are used to find instances of poor coding practice are always in the form: | |
|
||||
| | ``select <program element>, "<alert message>"`` | |
|
||||
+---------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------+
|
||||
+--------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+
|
||||
| Query part | Purpose | Details |
|
||||
+==================================================================================================+===================================================================================================================+===================================================================================================+
|
||||
| ``import java`` | Imports the standard CodeQL libraries for Java and Kotlin. | Every query begins with one or more ``import`` statements. |
|
||||
+--------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+
|
||||
| ``from MethodAccess ma`` | Defines the variables for the query. | We use: |
|
||||
| | Declarations are of the form: | |
|
||||
| | ``<type> <variable name>`` | - a ``MethodAccess`` variable for call expressions |
|
||||
+--------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+
|
||||
| ``where ma.getMethod().hasName("equals") and ma.getArgument(0).(StringLiteral).getValue() = ""`` | Defines a condition on the variables. | ``ma.getMethod().hasName("equals")`` restricts ``ma`` to only calls to methods call ``equals``. |
|
||||
| | | |
|
||||
| | | ``ma.getArgument(0).(StringLiteral).getValue() = ""`` says the argument must be literal ``""``. |
|
||||
+--------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+
|
||||
| ``select ma, "This comparison to empty string is inefficient, use isEmpty() instead."`` | Defines what to report for each match. | Reports the resulting ``.equals`` expression with a string that explains the problem. |
|
||||
| | | |
|
||||
| | ``select`` statements for queries that are used to find instances of poor coding practice are always in the form: | |
|
||||
| | ``select <program element>, "<alert message>"`` | |
|
||||
+--------------------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+
|
||||
|
||||
Extend the query
|
||||
----------------
|
||||
@@ -104,44 +94,51 @@ Query writing is an inherently iterative process. You write a simple query and t
|
||||
Remove false positive results
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Browsing the results of our basic query shows that it could be improved. Among the results you are likely to find examples of ``if`` statements with an ``else`` branch, where an empty ``then`` branch does serve a purpose. For example:
|
||||
Browsing the results of our basic query shows that it could be improved. For example, you may find results for code like:
|
||||
|
||||
.. code-block:: java
|
||||
|
||||
if (...) {
|
||||
...
|
||||
} else if ("-verbose".equals(option)) {
|
||||
// nothing to do - handled earlier
|
||||
} else {
|
||||
error("unrecognized option");
|
||||
}
|
||||
public class TestJava {
|
||||
void myJavaFun(Object o) {
|
||||
boolean b = o.equals("");
|
||||
}
|
||||
}
|
||||
|
||||
In this case, identifying the ``if`` statement with the empty ``then`` branch as redundant is a false positive. One solution to this is to modify the query to ignore empty ``then`` branches if the ``if`` statement has an ``else`` branch.
|
||||
|
||||
To exclude ``if`` statements that have an ``else`` branch:
|
||||
In this case, it is not possible to simply use ``o.isEmpty()`` instead, as ``o`` has type ``Object`` rather than ``String``. One solution to this is to modify the query to only return results where the expression being tested has type ``String``:
|
||||
|
||||
#. Extend the where clause to include the following extra condition:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
and not exists(ifstmt.getElse())
|
||||
ma.getQualifier().getType() instanceof TypeString
|
||||
|
||||
The ``where`` clause is now:
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
where ifstmt.getThen() = block and
|
||||
block.getNumStmt() = 0 and
|
||||
not exists(ifstmt.getElse())
|
||||
where
|
||||
ma.getQualifier().getType() instanceof TypeString and
|
||||
ma.getMethod().hasName("equals") and
|
||||
ma.getArgument(0).(StringLiteral).getValue() = ""
|
||||
|
||||
#. Click **Run**.
|
||||
#. Re-run the query.
|
||||
|
||||
There are now fewer results because ``if`` statements with an ``else`` branch are no longer included.
|
||||
|
||||
➤ `See this in the query console <https://lgtm.com/query/6382189874776576029/>`__
|
||||
There are now fewer results because ``.equals`` expressions with different types are no longer included.
|
||||
|
||||
Further reading
|
||||
---------------
|
||||
|
||||
.. include:: ../reusables/java-further-reading.rst
|
||||
.. include:: ../reusables/codeql-ref-tools-further-reading.rst
|
||||
|
||||
.. Article-specific substitutions for the reusables used in docs/codeql/reusables/vs-code-basic-instructions
|
||||
|
||||
.. |language-text| replace:: Java
|
||||
|
||||
.. |language-code| replace:: ``java``
|
||||
|
||||
.. |example-url| replace:: https://github.com/apache/activemq
|
||||
|
||||
.. |image-quick-query| image:: ../images/codeql-for-visual-studio-code/quick-query-tab-java.png
|
||||
|
||||
.. |result-col-1| replace:: The first column corresponds to the expression ``ma`` and is linked to the location in the source code of the project where ``ma`` occurs.
|
||||
@@ -3,7 +3,9 @@
|
||||
Basic query for JavaScript code
|
||||
===============================
|
||||
|
||||
Learn to write and run a simple CodeQL query using LGTM.
|
||||
Learn to write and run a simple CodeQL query using Visual Studio Code with the CodeQL extension.
|
||||
|
||||
.. include:: ../reusables/vs-code-basic-instructions/setup-to-run-queries.rst
|
||||
|
||||
About the query
|
||||
---------------
|
||||
@@ -12,62 +14,33 @@ In JavaScript, any expression can be turned into an expression statement. While
|
||||
|
||||
The query you will run finds instances of this problem. The query searches for expressions ``e`` that are pure—that is, their evaluation does not lead to any side effects—but appear as an expression statement.
|
||||
|
||||
Running the query
|
||||
-----------------
|
||||
.. include:: ../reusables/vs-code-basic-instructions/find-database.rst
|
||||
|
||||
#. In the main search box on LGTM.com, search for the project you want to query. For tips, see `Searching <https://lgtm.com/help/lgtm/searching>`__.
|
||||
Running a quick query
|
||||
---------------------
|
||||
|
||||
#. Click the project in the search results.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/run-quick-query-1.rst
|
||||
|
||||
#. Click **Query this project**.
|
||||
|
||||
This opens the query console. (For information about using this, see `Using the query console <https://lgtm.com/help/lgtm/using-query-console>`__.)
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Alternatively, you can go straight to the query console by clicking **Query console** (at the top of any page), selecting **JavaScript** from the **Language** drop-down list, then choosing one or more projects to query from those displayed in the **Project** drop-down list.
|
||||
|
||||
#. Copy the following query into the text box in the query console:
|
||||
#. In the quick query tab, delete ``select ""`` and paste the following query beneath the import statement ``import javascript``.
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import javascript
|
||||
|
||||
from Expr e
|
||||
where e.isPure() and
|
||||
e.getParent() instanceof ExprStmt
|
||||
select e, "This expression has no effect."
|
||||
|
||||
LGTM checks whether your query compiles and, if all is well, the **Run** button changes to green to indicate that you can go ahead and run the query.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/run-quick-query-2.rst
|
||||
|
||||
#. Click **Run**.
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-js-query-results-1.png
|
||||
:align: center
|
||||
|
||||
The name of the project you are querying, and the ID of the most recently analyzed commit to the project, are listed below the query box. To the right of this is an icon that indicates the progress of the query operation:
|
||||
If any matching code is found, click one of the links in the ``e`` column to open the file and highlight the matching expression.
|
||||
|
||||
.. image:: ../images/query-progress.png
|
||||
:align: center
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-js-query-results-2.png
|
||||
:align: center
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Your query is always run against the most recently analyzed commit to the selected project.
|
||||
|
||||
The query will take a few moments to return results. When the query completes, the results are displayed below the project name. The query results are listed in two columns, corresponding to the two expressions in the ``select`` clause of the query. The first column corresponds to the expression ``e`` and is linked to the location in the source code of the project where ``e`` occurs. The second column is the alert message.
|
||||
|
||||
➤ `Example query results <https://lgtm.com/query/5137013631828816943/>`__
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
An ellipsis (…) at the bottom of the table indicates that the entire list is not displayed—click it to show more results.
|
||||
|
||||
#. If any matching code is found, click one of the links in the ``e`` column to view the expression in the code viewer.
|
||||
|
||||
The matching statement is highlighted with a yellow background in the code viewer. If any code in the file also matches a query from the standard query library for that language, you will see a red alert message at the appropriate point within the code.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/note-store-quick-query.rst
|
||||
|
||||
About the query structure
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -119,11 +92,14 @@ To remove directives from the results:
|
||||
e.getParent() instanceof ExprStmt and
|
||||
not e.getParent() instanceof Directive
|
||||
|
||||
#. Click **Run**.
|
||||
#. Re-run the query.
|
||||
|
||||
There are now fewer results as ``use strict`` directives are no longer reported.
|
||||
|
||||
The improved query finds several results on the example project including `this result <https://lgtm.com/projects/g/ajaxorg/ace/rev/ad50673d7137c09d1a5a6f0ef83633a149f9e3d1/files/lib/ace/keyboard/vim.js#L320>`__:
|
||||
The improved query finds several results on the example project including the result below:
|
||||
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-js-query-results-1.png
|
||||
:align: center
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
@@ -136,3 +112,15 @@ Further reading
|
||||
|
||||
.. include:: ../reusables/javascript-further-reading.rst
|
||||
.. include:: ../reusables/codeql-ref-tools-further-reading.rst
|
||||
|
||||
.. Article-specific substitutions for the reusables used in docs/codeql/reusables/vs-code-basic-instructions
|
||||
|
||||
.. |language-text| replace:: JavaScript/TypeScript
|
||||
|
||||
.. |language-code| replace:: ``javascript``
|
||||
|
||||
.. |example-url| replace:: https://github.com/ajaxorg/ace
|
||||
|
||||
.. |image-quick-query| image:: ../images/codeql-for-visual-studio-code/quick-query-tab-js.png
|
||||
|
||||
.. |result-col-1| replace:: The first column corresponds to the expression ``e`` and is linked to the location in the source code of the project where ``e`` occurs.
|
||||
@@ -3,7 +3,9 @@
|
||||
Basic query for Python code
|
||||
===========================
|
||||
|
||||
Learn to write and run a simple CodeQL query using LGTM.
|
||||
Learn to write and run a simple CodeQL query using Visual Studio Code with the CodeQL extension.
|
||||
|
||||
.. include:: ../reusables/vs-code-basic-instructions/setup-to-run-queries.rst
|
||||
|
||||
About the query
|
||||
---------------
|
||||
@@ -14,62 +16,33 @@ The query we're going to run performs a basic search of the code for ``if`` stat
|
||||
|
||||
if error: pass
|
||||
|
||||
Running the query
|
||||
-----------------
|
||||
.. include:: ../reusables/vs-code-basic-instructions/find-database.rst
|
||||
|
||||
#. In the main search box on LGTM.com, search for the project you want to query. For tips, see `Searching <https://lgtm.com/help/lgtm/searching>`__.
|
||||
Running a quick query
|
||||
---------------------
|
||||
|
||||
#. Click the project in the search results.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/run-quick-query-1.rst
|
||||
|
||||
#. Click **Query this project**.
|
||||
|
||||
This opens the query console. (For information about using this, see `Using the query console <https://lgtm.com/help/lgtm/using-query-console>`__.)
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Alternatively, you can go straight to the query console by clicking **Query console** (at the top of any page), selecting **Python** from the **Language** drop-down list, then choosing one or more projects to query from those displayed in the **Project** drop-down list.
|
||||
|
||||
#. Copy the following query into the text box in the query console:
|
||||
#. In the quick query tab, delete ``select ""`` and paste the following query beneath the import statement ``import python``.
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
import python
|
||||
|
||||
from If ifstmt, Stmt pass
|
||||
where pass = ifstmt.getStmt(0) and
|
||||
pass instanceof Pass
|
||||
select ifstmt, "This 'if' statement is redundant."
|
||||
|
||||
LGTM checks whether your query compiles and, if all is well, the **Run** button changes to green to indicate that you can go ahead and run the query.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/run-quick-query-2.rst
|
||||
|
||||
#. Click **Run**.
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-python-query-results-1.png
|
||||
:align: center
|
||||
|
||||
The name of the project you are querying, and the ID of the most recently analyzed commit to the project, are listed below the query box. To the right of this is an icon that indicates the progress of the query operation:
|
||||
If any matching code is found, click a link in the ``ifstmt`` column to open the file and highlight the matching ``if`` statement.
|
||||
|
||||
.. image:: ../images/query-progress.png
|
||||
:align: center
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-python-query-results-2.png
|
||||
:align: center
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Your query is always run against the most recently analyzed commit to the selected project.
|
||||
|
||||
The query will take a few moments to return results. When the query completes, the results are displayed below the project name. The query results are listed in two columns, corresponding to the two expressions in the ``select`` clause of the query. The first column corresponds to the expression ``ifstmt`` and is linked to the location in the source code of the project where ``ifstmt`` occurs. The second column is the alert message.
|
||||
|
||||
➤ `Example query results <https://lgtm.com/query/3592297537117272922/>`__
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
An ellipsis (…) at the bottom of the table indicates that the entire list is not displayed—click it to show more results.
|
||||
|
||||
#. If any matching code is found, click a link in the ``ifstmt`` column to view the ``if`` statement in the code viewer.
|
||||
|
||||
The matching ``if`` statement is highlighted with a yellow background in the code viewer. If any code in the file also matches a query from the standard query library for that language, you will see a red alert message at the appropriate point within the code.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/note-store-quick-query.rst
|
||||
|
||||
About the query structure
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -133,14 +106,24 @@ To exclude ``if`` statements that have an ``else`` branch:
|
||||
pass instanceof Pass and
|
||||
not exists(ifstmt.getOrelse())
|
||||
|
||||
#. Click **Run**.
|
||||
#. Re-run the query.
|
||||
|
||||
There are now fewer results because ``if`` statements with an ``else`` branch are no longer included.
|
||||
|
||||
➤ `See this in the query console <https://lgtm.com/query/3424727946018612474/>`__
|
||||
|
||||
Further reading
|
||||
---------------
|
||||
|
||||
.. include:: ../reusables/python-further-reading.rst
|
||||
.. include:: ../reusables/codeql-ref-tools-further-reading.rst
|
||||
|
||||
.. Article-specific substitutions for the reusables used in docs/codeql/reusables/vs-code-basic-instructions
|
||||
|
||||
.. |language-text| replace:: Python
|
||||
|
||||
.. |language-code| replace:: ``python``
|
||||
|
||||
.. |example-url| replace:: https://github.com/saltstack/salt
|
||||
|
||||
.. |image-quick-query| image:: ../images/codeql-for-visual-studio-code/quick-query-tab-python.png
|
||||
|
||||
.. |result-col-1| replace:: The first column corresponds to the expression ``ifstmt`` and is linked to the location in the source code of the project where ``ifstmt`` occurs.
|
||||
@@ -3,7 +3,9 @@
|
||||
Basic query for Ruby code
|
||||
=========================
|
||||
|
||||
Learn to write and run a simple CodeQL query.
|
||||
Learn to write and run a simple CodeQL query using Visual Studio Code with the CodeQL extension.
|
||||
|
||||
.. include:: ../reusables/vs-code-basic-instructions/setup-to-run-queries.rst
|
||||
|
||||
About the query
|
||||
---------------
|
||||
@@ -15,24 +17,14 @@ The query we're going to run performs a basic search of the code for ``if`` expr
|
||||
if error
|
||||
# Handle the error
|
||||
|
||||
Running the query
|
||||
-----------------
|
||||
.. include:: ../reusables/vs-code-basic-instructions/find-database.rst
|
||||
|
||||
#. In the main search box on LGTM.com, search for the project you want to query. For tips, see `Searching <https://lgtm.com/help/lgtm/searching>`__.
|
||||
Running a quick query
|
||||
---------------------
|
||||
|
||||
#. Click the project in the search results.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/run-quick-query-1.rst
|
||||
|
||||
#. Click **Query this project**.
|
||||
|
||||
This opens the query console. (For information about using this, see `Using the query console <https://lgtm.com/help/lgtm/using-query-console>`__.)
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Alternatively, you can go straight to the query console by clicking **Query console** (at the top of any page), selecting **Ruby** from the **Language** drop-down list, then choosing one or more projects to query from those displayed in the **Project** drop-down list.
|
||||
|
||||
#. Copy the following query into the text box in the query console:
|
||||
#. In the quick query tab, delete the content and paste in the following query.
|
||||
|
||||
.. code-block:: ql
|
||||
|
||||
@@ -40,37 +32,20 @@ Running the query
|
||||
|
||||
from IfExpr ifexpr
|
||||
where
|
||||
not exists(ifexpr.getThen())
|
||||
not exists(ifexpr.getThen())
|
||||
select ifexpr, "This 'if' expression is redundant."
|
||||
|
||||
LGTM checks whether your query compiles and, if all is well, the **Run** button changes to green to indicate that you can go ahead and run the query.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/run-quick-query-2.rst
|
||||
|
||||
#. Click **Run**.
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-ruby-query-results-1.png
|
||||
:align: center
|
||||
|
||||
The name of the project you are querying, and the ID of the most recently analyzed commit to the project, are listed below the query box. To the right of this is an icon that indicates the progress of the query operation:
|
||||
If any matching code is found, click a link in the ``ifexpr`` column to open the file and highlight the matching ``if`` statement.
|
||||
|
||||
.. image:: ../images/query-progress.png
|
||||
:align: center
|
||||
.. image:: ../images/codeql-for-visual-studio-code/basic-ruby-query-results-2.png
|
||||
:align: center
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
Your query is always run against the most recently analyzed commit to the selected project.
|
||||
|
||||
The query will take a few moments to return results. When the query completes, the results are displayed below the project name. The query results are listed in two columns, corresponding to the two expressions in the ``select`` clause of the query. The first column corresponds to the expression ``ifexpr`` and is linked to the location in the source code of the project where ``ifexpr`` occurs. The second column is the alert message.
|
||||
|
||||
➤ `Example query results <https://lgtm.com/query/4416853782037269427/>`__
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
|
||||
An ellipsis (…) at the bottom of the table indicates that the entire list is not displayed—click it to show more results.
|
||||
|
||||
#. If any matching code is found, click a link in the ``ifexpr`` column to view the ``if`` statement in the code viewer.
|
||||
|
||||
The matching ``if`` expression is highlighted with a yellow background in the code viewer. If any code in the file also matches a query from the standard query library for that language, you will see a red alert message at the appropriate point within the code.
|
||||
.. include:: ../reusables/vs-code-basic-instructions/note-store-quick-query.rst
|
||||
|
||||
About the query structure
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -131,14 +106,24 @@ To exclude ``if`` statements that have an ``else`` branch:
|
||||
not exists(ifexpr.getThen()) and
|
||||
not exists(ifexpr.getElse())
|
||||
|
||||
#. Click **Run**.
|
||||
#. Re-run the query.
|
||||
|
||||
There are now fewer results because ``if`` expressions with an ``else`` branch are no longer included.
|
||||
|
||||
➤ `See this in the query console <https://lgtm.com/query/4694253275631320752/>`__
|
||||
|
||||
Further reading
|
||||
---------------
|
||||
|
||||
.. include:: ../reusables/ruby-further-reading.rst
|
||||
.. include:: ../reusables/codeql-ref-tools-further-reading.rst
|
||||
|
||||
.. Article-specific substitutions for the reusables used in docs/codeql/reusables/vs-code-basic-instructions
|
||||
|
||||
.. |language-text| replace:: Ruby
|
||||
|
||||
.. |language-code| replace:: ``ruby``
|
||||
|
||||
.. |example-url| replace:: https://github.com/discourse/discourse
|
||||
|
||||
.. |image-quick-query| image:: ../images/codeql-for-visual-studio-code/quick-query-tab-ruby.png
|
||||
|
||||
.. |result-col-1| replace:: The first column corresponds to the expression ``ifexpr`` and is linked to the location in the source code of the project where ``ifexpr`` occurs.
|
||||
|
||||
@@ -21,7 +21,7 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat
|
||||
hash-consing-and-value-numbering
|
||||
|
||||
|
||||
- :doc:`Basic query for C and C++ code <basic-query-for-cpp-code>`: Learn to write and run a simple CodeQL query using LGTM.
|
||||
- :doc:`Basic query for C and C++ code <basic-query-for-cpp-code>`: Learn to write and run a simple CodeQL query.
|
||||
|
||||
- :doc:`CodeQL library for C and C++ <codeql-library-for-cpp>`: When analyzing C or C++ code, you can use the large collection of classes in the CodeQL library for C and C++.
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat
|
||||
codeql-library-for-csharp
|
||||
analyzing-data-flow-in-csharp
|
||||
|
||||
- :doc:`Basic query for C# code <basic-query-for-csharp-code>`: Learn to write and run a simple CodeQL query using LGTM.
|
||||
- :doc:`Basic query for C# code <basic-query-for-csharp-code>`: Learn to write and run a simple CodeQL query.
|
||||
|
||||
- :doc:`CodeQL library for C# <codeql-library-for-csharp>`: When you're analyzing a C# program, you can make use of the large collection of classes in the CodeQL library for C#.
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat
|
||||
abstract-syntax-tree-classes-for-working-with-go-programs
|
||||
modeling-data-flow-in-go-libraries
|
||||
|
||||
- :doc:`Basic query for Go code <basic-query-for-go-code>`: Learn to write and run a simple CodeQL query using LGTM.
|
||||
- :doc:`Basic query for Go code <basic-query-for-go-code>`: Learn to write and run a simple CodeQL query.
|
||||
|
||||
- :doc:`CodeQL library for Go <codeql-library-for-go>`: When you're analyzing a Go program, you can make use of the large collection of classes in the CodeQL library for Go.
|
||||
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
.. _codeql-for-java:
|
||||
|
||||
CodeQL for Java
|
||||
===============
|
||||
CodeQL for Java and Kotlin
|
||||
==========================
|
||||
|
||||
Experiment and learn how to write effective and efficient queries for CodeQL databases generated from Java codebases.
|
||||
Experiment and learn how to write effective and efficient queries for CodeQL databases generated from Java and Kotlin codebases.
|
||||
|
||||
.. include:: ../reusables/kotlin-beta-note.rst
|
||||
|
||||
|
||||
.. pull-quote:: Enabling Kotlin support
|
||||
|
||||
CodeQL treats Java and Kotlin as parts of the same language, so to enable Kotlin support you should enable ``java`` as a language.
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
@@ -19,7 +26,7 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat
|
||||
working-with-source-locations
|
||||
abstract-syntax-tree-classes-for-working-with-java-programs
|
||||
|
||||
- :doc:`Basic query for Java code <basic-query-for-java-code>`: Learn to write and run a simple CodeQL query using LGTM.
|
||||
- :doc:`Basic query for Java code <basic-query-for-java-code>`: Learn to write and run a simple CodeQL query.
|
||||
|
||||
- :doc:`CodeQL library for Java <codeql-library-for-java>`: When analyzing Java code, you can use the large collection of classes in the CodeQL library for Java.
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat
|
||||
abstract-syntax-tree-classes-for-working-with-javascript-and-typescript-programs
|
||||
data-flow-cheat-sheet-for-javascript
|
||||
|
||||
- :doc:`Basic query for JavaScript code <basic-query-for-javascript-code>`: Learn to write and run a simple CodeQL query using LGTM.
|
||||
- :doc:`Basic query for JavaScript code <basic-query-for-javascript-code>`: Learn to write and run a simple CodeQL query.
|
||||
|
||||
- :doc:`CodeQL library for JavaScript <codeql-library-for-javascript>`: When you're analyzing a JavaScript program, you can make use of the large collection of classes in the CodeQL library for JavaScript.
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat
|
||||
expressions-and-statements-in-python
|
||||
analyzing-control-flow-in-python
|
||||
|
||||
- :doc:`Basic query for Python code <basic-query-for-python-code>`: Learn to write and run a simple CodeQL query using LGTM.
|
||||
- :doc:`Basic query for Python code <basic-query-for-python-code>`: Learn to write and run a simple CodeQL query.
|
||||
|
||||
- :doc:`CodeQL library for Python <codeql-library-for-python>`: When you need to analyze a Python program, you can make use of the large collection of classes in the CodeQL library for Python.
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ Experiment and learn how to write effective and efficient queries for CodeQL dat
|
||||
analyzing-data-flow-in-ruby
|
||||
using-api-graphs-in-ruby
|
||||
|
||||
- :doc:`Basic query for Ruby code <basic-query-for-ruby-code>`: Learn to write and run a simple CodeQL query using LGTM.
|
||||
- :doc:`Basic query for Ruby code <basic-query-for-ruby-code>`: Learn to write and run a simple CodeQL query.
|
||||
|
||||
- :doc:`CodeQL library for Ruby <codeql-library-for-ruby>`: When you're analyzing a Ruby program, you can make use of the large collection of classes in the CodeQL library for Ruby.
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ For example, the following query finds all variables of type ``int`` in the prog
|
||||
pt.hasName("int")
|
||||
select v
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/860076406167044435/>`__. You're likely to get many results when you run this query because most projects contain many variables of type ``int``.
|
||||
You're likely to get many results when you run this query because most projects contain many variables of type ``int``.
|
||||
|
||||
Reference types are also categorized according to their declaration scope:
|
||||
|
||||
@@ -87,7 +87,7 @@ For instance, this query finds all top-level types whose name is not the same as
|
||||
where tl.getName() != tl.getCompilationUnit().getName()
|
||||
select tl
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/4340983612585284460/>`__. This pattern is seen in many projects. When we ran it on the LGTM.com demo projects, most of the projects had at least one instance of this problem in the source code. There were many more instances in the files referenced by the source code.
|
||||
You will typically see this pattern in the source code of a repository, with many more instances in the files referenced by the source code.
|
||||
|
||||
Several more specialized classes are available as well:
|
||||
|
||||
@@ -109,7 +109,7 @@ As an example, we can write a query that finds all nested classes that directly
|
||||
where nc.getASupertype() instanceof TypeObject
|
||||
select nc
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/8482509736206423238/>`__. You're likely to get many results when you run this query because many projects include nested classes that extend ``Object`` directly.
|
||||
You're likely to get many results when you run this query because many projects include nested classes that extend ``Object`` directly.
|
||||
|
||||
Generics
|
||||
~~~~~~~~
|
||||
@@ -143,8 +143,6 @@ For instance, we could use the following query to find all parameterized instanc
|
||||
pt.getSourceDeclaration() = map
|
||||
select pt
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/7863873821043873550/>`__. None of the LGTM.com demo projects contain parameterized instances of ``java.util.Map`` in their source code, but they all have results in reference files.
|
||||
|
||||
In general, generic types may restrict which types a type parameter can be bound to. For instance, a type of maps from strings to numbers could be declared as follows:
|
||||
|
||||
.. code-block:: java
|
||||
@@ -166,8 +164,6 @@ As an example, the following query finds all type variables with type bound ``Nu
|
||||
tb.getType().hasQualifiedName("java.lang", "Number")
|
||||
select tv
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/6740696080876162817/>`__. When we ran it on the LGTM.com demo projects, the *neo4j/neo4j*, *hibernate/hibernate-orm* and *apache/hadoop* projects all contained examples of this pattern.
|
||||
|
||||
For dealing with legacy code that is unaware of generics, every generic type has a "raw" version without any type parameters. In the CodeQL libraries, raw types are represented using class ``RawType``, which has the expected subclasses ``RawClass`` and ``RawInterface``. Again, there is a predicate ``getSourceDeclaration`` for obtaining the corresponding generic type. As an example, we can find variables of (raw) type ``Map``:
|
||||
|
||||
.. code-block:: ql
|
||||
@@ -179,8 +175,6 @@ For dealing with legacy code that is unaware of generics, every generic type has
|
||||
rt.getSourceDeclaration().hasQualifiedName("java.util", "Map")
|
||||
select v
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/4032913402499547882/>`__. Many projects have variables of raw type ``Map``.
|
||||
|
||||
For example, in the following code snippet this query would find ``m1``, but not ``m2``:
|
||||
|
||||
.. code-block:: java
|
||||
@@ -230,7 +224,7 @@ For example, the following query finds all expressions whose parents are ``retur
|
||||
where e.getParent() instanceof ReturnStmt
|
||||
select e
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/1947757851560375919/>`__. Many projects have examples of ``return`` statements with child expressions.
|
||||
Many projects have examples of ``return`` statements with child expressions.
|
||||
|
||||
Therefore, if the program contains a return statement ``return x + y;``, this query will return ``x + y``.
|
||||
|
||||
@@ -244,7 +238,7 @@ As another example, the following query finds statements whose parent is an ``if
|
||||
where s.getParent() instanceof IfStmt
|
||||
select s
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/1989464153689219612/>`__. Many projects have examples of ``if`` statements with child statements.
|
||||
Many projects have examples of ``if`` statements with child statements.
|
||||
|
||||
This query will find both ``then`` branches and ``else`` branches of all ``if`` statements in the program.
|
||||
|
||||
@@ -258,8 +252,6 @@ Finally, here is a query that finds method bodies:
|
||||
where s.getParent() instanceof Method
|
||||
select s
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/1016821702972128245/>`__. Most projects have many method bodies.
|
||||
|
||||
As these examples show, the parent node of an expression is not always an expression: it may also be a statement, for example, an ``IfStmt``. Similarly, the parent node of a statement is not always a statement: it may also be a method or a constructor. To capture this, the QL Java library provides two abstract class ``ExprParent`` and ``StmtParent``, the former representing any node that may be the parent node of an expression, and the latter any node that may be the parent node of a statement.
|
||||
|
||||
For more information on working with AST classes, see the :doc:`article on overflow-prone comparisons in Java <overflow-prone-comparisons-in-java>`.
|
||||
@@ -278,7 +270,7 @@ For annotations, class ``Annotatable`` is a superclass of all program elements t
|
||||
from Constructor c
|
||||
select c.getAnAnnotation()
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/3206112561297137365/>`__. The LGTM.com demo projects all use annotations, you can see examples where they are used to suppress warnings and mark code as deprecated.
|
||||
You may see examples where annotations are used to suppress warnings or to mark code as deprecated.
|
||||
|
||||
These annotations are represented by class ``Annotation``. An annotation is simply an expression whose type is an ``AnnotationType``. For example, you can amend this query so that it only reports deprecated constructors:
|
||||
|
||||
@@ -292,7 +284,7 @@ These annotations are represented by class ``Annotation``. An annotation is simp
|
||||
anntp.hasQualifiedName("java.lang", "Deprecated")
|
||||
select ann
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/5393027107459215059/>`__. Only constructors with the ``@Deprecated`` annotation are reported this time.
|
||||
Only constructors with the ``@Deprecated`` annotation are reported this time.
|
||||
|
||||
For more information on working with annotations, see the :doc:`article on annotations <annotations-in-java>`.
|
||||
|
||||
@@ -307,7 +299,7 @@ For Javadoc, class ``Element`` has a member predicate ``getDoc`` that returns a
|
||||
jdoc = f.getDoc().getJavadoc()
|
||||
select jdoc
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/6022769142134600659/>`__. You can see this pattern in many projects.
|
||||
You can see this pattern in many projects.
|
||||
|
||||
Class ``Javadoc`` represents an entire Javadoc comment as a tree of ``JavadocElement`` nodes, which can be traversed using member predicates ``getAChild`` and ``getParent``. For instance, you could edit the query so that it finds all ``@author`` tags in Javadoc comments on private fields:
|
||||
|
||||
@@ -321,8 +313,6 @@ Class ``Javadoc`` represents an entire Javadoc comment as a tree of ``JavadocEle
|
||||
at.getParent+() = jdoc
|
||||
select at
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/2510220694395289111/>`__. None of the LGTM.com demo projects uses the ``@author`` tag on private fields.
|
||||
|
||||
.. pull-quote::
|
||||
|
||||
Note
|
||||
@@ -349,7 +339,7 @@ For example, the following query finds methods with a `cyclomatic complexity <ht
|
||||
mc.getCyclomaticComplexity() > 40
|
||||
select m
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/6566950741051181919/>`__. Most large projects include some methods with a very high cyclomatic complexity. These methods are likely to be difficult to understand and test.
|
||||
Most large projects include some methods with a very high cyclomatic complexity. These methods are likely to be difficult to understand and test.
|
||||
|
||||
Call graph
|
||||
----------
|
||||
@@ -369,8 +359,6 @@ We can use predicate ``Call.getCallee`` to find out which method or constructor
|
||||
m.hasName("println")
|
||||
select c
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/5861255162551917595/>`__. The LGTM.com demo projects all include many calls to methods of this name.
|
||||
|
||||
Conversely, ``Callable.getAReference`` returns a ``Call`` that refers to it. So we can find methods and constructors that are never called using this query:
|
||||
|
||||
.. code-block:: ql
|
||||
@@ -381,7 +369,7 @@ Conversely, ``Callable.getAReference`` returns a ``Call`` that refers to it. So
|
||||
where not exists(c.getAReference())
|
||||
select c
|
||||
|
||||
➤ `See this in the query console on LGTM.com <https://lgtm.com/query/7261739919657747703/>`__. The LGTM.com demo projects all appear to have many methods that are not called directly, but this is unlikely to be the whole story. To explore this area further, see ":doc:`Navigating the call graph <navigating-the-call-graph>`."
|
||||
Codebases often have many methods that are not called directly, but this is unlikely to be the whole story. To explore this area further, see ":doc:`Navigating the call graph <navigating-the-call-graph>`."
|
||||
|
||||
For more information about callables and calls, see the :doc:`article on the call graph <navigating-the-call-graph>`.
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user