mirror of
https://github.com/github/codeql.git
synced 2026-05-20 14:17:11 +02:00
Compare commits
367 Commits
post-relea
...
codeql-cli
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
712d71856b | ||
|
|
59da2cdf69 | ||
|
|
6664a3814a | ||
|
|
fa40d59332 | ||
|
|
a62f181d42 | ||
|
|
de4458346f | ||
|
|
dc27089714 | ||
|
|
7732c0885f | ||
|
|
0669ef505e | ||
|
|
372f099850 | ||
|
|
b18f7a9bd7 | ||
|
|
c0b61d7f73 | ||
|
|
124aac23c6 | ||
|
|
4ae92667e1 | ||
|
|
ba23393c0d | ||
|
|
a6eba04793 | ||
|
|
88bb8a2704 | ||
|
|
d699ca9aa8 | ||
|
|
7ff2ee695d | ||
|
|
efc9e67ec2 | ||
|
|
fad95d8935 | ||
|
|
f32d464c0f | ||
|
|
327cf444f4 | ||
|
|
f3c0eadbce | ||
|
|
58f36e4b31 | ||
|
|
90e49508a3 | ||
|
|
a4bea05fa7 | ||
|
|
be1e75471e | ||
|
|
1cab177f8a | ||
|
|
0e0c3e3937 | ||
|
|
6301e726ee | ||
|
|
1cd37dddf5 | ||
|
|
07a4f5f748 | ||
|
|
679aad138e | ||
|
|
42bf866fb3 | ||
|
|
9604ed883c | ||
|
|
d804893a49 | ||
|
|
03fb244545 | ||
|
|
a6360215f3 | ||
|
|
0ca9852cc8 | ||
|
|
e1d290d4c0 | ||
|
|
1857de1f33 | ||
|
|
b80a84c156 | ||
|
|
6a1aea740f | ||
|
|
c9a87234ef | ||
|
|
66c1629974 | ||
|
|
b6c5b4d213 | ||
|
|
d8857c7ce8 | ||
|
|
a46787ea07 | ||
|
|
bd9b96e154 | ||
|
|
8ee020f79c | ||
|
|
6e167040f5 | ||
|
|
657cd89286 | ||
|
|
afa58f5676 | ||
|
|
13f7fd88f1 | ||
|
|
634ed91904 | ||
|
|
cf42427f54 | ||
|
|
f7f3890b40 | ||
|
|
70f76d06c7 | ||
|
|
45c0d4a3b2 | ||
|
|
7e5bfa5aa0 | ||
|
|
271b23ba8f | ||
|
|
0c3daabc51 | ||
|
|
753d886b0d | ||
|
|
6d247bfdf9 | ||
|
|
e7209d1ee1 | ||
|
|
75f3ebf051 | ||
|
|
9f69c75c50 | ||
|
|
2cd70b96cd | ||
|
|
1a1a7413c2 | ||
|
|
d60b90acd3 | ||
|
|
e879ca7a3b | ||
|
|
15b4b218c8 | ||
|
|
bbab0e582a | ||
|
|
9e61dfb41f | ||
|
|
5a26346ba5 | ||
|
|
5376eb89b3 | ||
|
|
df482a9603 | ||
|
|
470256da85 | ||
|
|
8bba3eb2b6 | ||
|
|
f08f07e19e | ||
|
|
d0a19fffee | ||
|
|
7e99426141 | ||
|
|
2bf5966fe3 | ||
|
|
fd4915a564 | ||
|
|
9d288c90a5 | ||
|
|
a7b3f1370f | ||
|
|
d0aa307bd3 | ||
|
|
b887165005 | ||
|
|
3689481c18 | ||
|
|
660e52f2bf | ||
|
|
e9e3ef3ea2 | ||
|
|
799c945299 | ||
|
|
95f8f85aa2 | ||
|
|
aacba0b522 | ||
|
|
513fe09dbb | ||
|
|
d17c055139 | ||
|
|
44a615839d | ||
|
|
f08eb8e616 | ||
|
|
69f42b9c74 | ||
|
|
38250b0821 | ||
|
|
cbc96dba8a | ||
|
|
522a4bb9fa | ||
|
|
8e11c2c476 | ||
|
|
992801b7cb | ||
|
|
9ffa236c51 | ||
|
|
c0c40cc05b | ||
|
|
3a3c7fc59e | ||
|
|
f209ff4f76 | ||
|
|
b7f7c5ba20 | ||
|
|
f63ffb0630 | ||
|
|
069cf9d17f | ||
|
|
cbd21edc99 | ||
|
|
2f85735b6a | ||
|
|
69ba2e6f8c | ||
|
|
d46564caa6 | ||
|
|
f6a8b9a7e5 | ||
|
|
b871342e83 | ||
|
|
13347cd102 | ||
|
|
9f4b965202 | ||
|
|
d70d1fbf81 | ||
|
|
a43704ab43 | ||
|
|
063398f24d | ||
|
|
60f3ff8c33 | ||
|
|
8bcbf8e30f | ||
|
|
8517eff0f7 | ||
|
|
b49ca6a24c | ||
|
|
a18aad8536 | ||
|
|
38d0bb4a60 | ||
|
|
1d321c692b | ||
|
|
ede1503cc6 | ||
|
|
283173ad02 | ||
|
|
3145e8f9b7 | ||
|
|
1956405d17 | ||
|
|
5735bb698d | ||
|
|
0e33f730b1 | ||
|
|
ea7063f3c6 | ||
|
|
490872173a | ||
|
|
07ca1c2ec0 | ||
|
|
e7c298d903 | ||
|
|
b502ca1ea7 | ||
|
|
a716482c1f | ||
|
|
59bac04d8f | ||
|
|
ffc858e34d | ||
|
|
bf0ecded04 | ||
|
|
7437cd4d85 | ||
|
|
f85a47d41f | ||
|
|
a2dc505c26 | ||
|
|
5183290439 | ||
|
|
322e39446d | ||
|
|
016727d6b6 | ||
|
|
b2c1b55c0c | ||
|
|
b17a93eaad | ||
|
|
4d797d6b3d | ||
|
|
da43984ba4 | ||
|
|
ee23799a59 | ||
|
|
6c739b67fa | ||
|
|
3c59aa319e | ||
|
|
7cd9369d91 | ||
|
|
33a9f86f54 | ||
|
|
dd33f4f4d2 | ||
|
|
6f42153eac | ||
|
|
4e68a4670b | ||
|
|
4765772725 | ||
|
|
243b92b28c | ||
|
|
60c0bcf8f7 | ||
|
|
c39fe59a04 | ||
|
|
7ae1047fda | ||
|
|
ff9ed0d4fb | ||
|
|
5dbbb86d46 | ||
|
|
728e3abee5 | ||
|
|
36569f997f | ||
|
|
6b1ac73a46 | ||
|
|
de1269f18f | ||
|
|
c46ede02e6 | ||
|
|
6adfea2365 | ||
|
|
daf6a4ce07 | ||
|
|
f68a40f82b | ||
|
|
fac2769d85 | ||
|
|
0e31439b7e | ||
|
|
2a3b5fc2b2 | ||
|
|
d0840afb80 | ||
|
|
9f48ae656f | ||
|
|
0805daaa56 | ||
|
|
51998294ad | ||
|
|
4ae99592a3 | ||
|
|
205233b42f | ||
|
|
3e1ebb954f | ||
|
|
0cec59e043 | ||
|
|
8ffa195538 | ||
|
|
5a2ef8321c | ||
|
|
4128f56aa9 | ||
|
|
6c6113b85b | ||
|
|
802faf1197 | ||
|
|
7ad52e1365 | ||
|
|
f00b62df76 | ||
|
|
90baef83ee | ||
|
|
8eb041c172 | ||
|
|
520f598d49 | ||
|
|
d9704d7b39 | ||
|
|
42f6dfc197 | ||
|
|
404f4a81a7 | ||
|
|
50dd4e7ee7 | ||
|
|
f2800abee4 | ||
|
|
7f44cebed7 | ||
|
|
4138296ec6 | ||
|
|
991d659cb2 | ||
|
|
976faf97d1 | ||
|
|
19c34be1ea | ||
|
|
102b5e05e1 | ||
|
|
2b349b3024 | ||
|
|
2c4ccb79a1 | ||
|
|
3043ac850c | ||
|
|
f6c36b469a | ||
|
|
f190d60912 | ||
|
|
eccba57536 | ||
|
|
7aa6c62050 | ||
|
|
05415768c9 | ||
|
|
f10f053c36 | ||
|
|
913d8361ba | ||
|
|
4609b2060a | ||
|
|
8f3be9fbfd | ||
|
|
edf7724579 | ||
|
|
37644d30d2 | ||
|
|
6327fced6f | ||
|
|
ad281c0365 | ||
|
|
a8f673ffa4 | ||
|
|
e08c734c40 | ||
|
|
55c17f453f | ||
|
|
87b968f337 | ||
|
|
9f8326a3fa | ||
|
|
a077345227 | ||
|
|
73f2f52ed8 | ||
|
|
739906b60c | ||
|
|
9e10aee8a1 | ||
|
|
cc2914be3c | ||
|
|
de53727ab3 | ||
|
|
0a3d62c92a | ||
|
|
148da611c6 | ||
|
|
aad55ffbd6 | ||
|
|
75f9a947b3 | ||
|
|
ed706d9bc1 | ||
|
|
e41cd810d3 | ||
|
|
93e291cb3e | ||
|
|
cde853c095 | ||
|
|
6742beae1b | ||
|
|
31374b485c | ||
|
|
e410244fe0 | ||
|
|
bb8f4bb7c1 | ||
|
|
ae6501d906 | ||
|
|
08be8edbce | ||
|
|
4b221bd964 | ||
|
|
186ba428cf | ||
|
|
1243d40bb2 | ||
|
|
35a67845cf | ||
|
|
59b71df2d6 | ||
|
|
0b4d0d2772 | ||
|
|
bab8cfb62a | ||
|
|
a5b6889478 | ||
|
|
5dd2d20176 | ||
|
|
7d6664f14d | ||
|
|
540ecf3c21 | ||
|
|
755085e9fe | ||
|
|
2589034242 | ||
|
|
830908b5c8 | ||
|
|
3e914ef2ff | ||
|
|
fc05825c73 | ||
|
|
8a6a8fc28a | ||
|
|
0619453c2f | ||
|
|
b40c77d419 | ||
|
|
3f218c903b | ||
|
|
8f270b665c | ||
|
|
c91b6f7ce9 | ||
|
|
f4555ed1a2 | ||
|
|
66e086f92f | ||
|
|
1e026ef45e | ||
|
|
cbd7434a7e | ||
|
|
b68538376c | ||
|
|
3bcf6d68ce | ||
|
|
f8a62c4c82 | ||
|
|
58f92764f7 | ||
|
|
fd23fa94a5 | ||
|
|
e79b8f3e23 | ||
|
|
d2d5cce787 | ||
|
|
14590436f9 | ||
|
|
50d3592ad3 | ||
|
|
a91208fd2c | ||
|
|
36f14b31bc | ||
|
|
82602014ad | ||
|
|
88fb1a18cb | ||
|
|
fdcc144a98 | ||
|
|
591aeff906 | ||
|
|
19bbe6d276 | ||
|
|
d1a7feebc4 | ||
|
|
d946802057 | ||
|
|
57399b733e | ||
|
|
0e890fd788 | ||
|
|
eef3905c46 | ||
|
|
9ce248c829 | ||
|
|
c13cad7e87 | ||
|
|
d79337774d | ||
|
|
db04a0dadf | ||
|
|
74158f1e3a | ||
|
|
09a11f4166 | ||
|
|
6c3aabe1df | ||
|
|
c3e495efe9 | ||
|
|
03b6ee3833 | ||
|
|
6ff8d4de5c | ||
|
|
f96968975b | ||
|
|
e98ab5d2c2 | ||
|
|
e9ce29664e | ||
|
|
1d358c5f77 | ||
|
|
f5b40731d6 | ||
|
|
e801d9636a | ||
|
|
8b0bc677f4 | ||
|
|
dca1e34cd8 | ||
|
|
16e1e97ff0 | ||
|
|
af4c3122ca | ||
|
|
078a2aa03b | ||
|
|
ec0bd24b64 | ||
|
|
5b560b12e9 | ||
|
|
04a3f76a8b | ||
|
|
d36a7ed10e | ||
|
|
99c8b291b2 | ||
|
|
b8732859de | ||
|
|
31400df0d4 | ||
|
|
69690a2509 | ||
|
|
4438f8c58c | ||
|
|
4c5faaf985 | ||
|
|
8abaf1247a | ||
|
|
5ffbf563b8 | ||
|
|
72a03257e7 | ||
|
|
5eb814fd8b | ||
|
|
7869733ab5 | ||
|
|
88b6bd9478 | ||
|
|
ce2b86b9e3 | ||
|
|
2eae6a3e9a | ||
|
|
6afcbce421 | ||
|
|
5d0dfe8c04 | ||
|
|
e7524dea69 | ||
|
|
1411804e58 | ||
|
|
d493cfdf3a | ||
|
|
baafd9f8ba | ||
|
|
70081defdc | ||
|
|
62ae702e07 | ||
|
|
e9df860431 | ||
|
|
6060f2e3e3 | ||
|
|
c369b28a2a | ||
|
|
f39872e649 | ||
|
|
089d030bc2 | ||
|
|
df6ba43cca | ||
|
|
f63c768d9f | ||
|
|
6d27585b92 | ||
|
|
418adb824c | ||
|
|
fd73f4094f | ||
|
|
1ec935dee6 | ||
|
|
bd940712de | ||
|
|
9a74f18ac5 | ||
|
|
ce004e9c1e | ||
|
|
12a3251649 | ||
|
|
9d50511ea4 | ||
|
|
5deb996b33 | ||
|
|
91efb61e97 | ||
|
|
0325c07bd9 | ||
|
|
ffa77f0a76 | ||
|
|
588dedc265 | ||
|
|
1a04ad98bc |
2
.github/workflows/ruby-dataset-measure.yml
vendored
2
.github/workflows/ruby-dataset-measure.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
repo: [rails/rails, discourse/discourse, spree/spree]
|
||||
repo: [rails/rails, discourse/discourse, spree/spree, ruby/ruby]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
lgtm,codescanning
|
||||
* The QL library `semmle.code.cpp.commons.Exclusions` now contains a predicate
|
||||
`isFromSystemMacroDefinition` for identifying code that originates from a
|
||||
macro outside the project being analyzed.
|
||||
@@ -1,2 +0,0 @@
|
||||
lgtm,codescanning
|
||||
* A new query `cpp/non-https-url` has been added for C/C++. The query flags uses of `http` URLs that might be better replaced with `https`.
|
||||
@@ -1,3 +1,5 @@
|
||||
## 0.0.5
|
||||
|
||||
## 0.0.4
|
||||
|
||||
### New Features
|
||||
|
||||
1
cpp/ql/lib/change-notes/released/0.0.5.md
Normal file
1
cpp/ql/lib/change-notes/released/0.0.5.md
Normal file
@@ -0,0 +1 @@
|
||||
## 0.0.5
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.0.4
|
||||
lastReleaseVersion: 0.0.5
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
name: codeql/cpp-all
|
||||
version: 0.0.5-dev
|
||||
version: 0.0.5
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
library: true
|
||||
dependencies:
|
||||
codeql/cpp-upgrades: 0.0.3
|
||||
codeql/cpp-upgrades: ^0.0.3
|
||||
|
||||
@@ -626,9 +626,9 @@ library class ExprEvaluator extends int {
|
||||
// All assignments must have the same int value
|
||||
result =
|
||||
unique(Expr value |
|
||||
value = v.getAnAssignedValue() and not ignoreVariableAssignment(e, v, value)
|
||||
value = v.getAnAssignedValue() and not this.ignoreVariableAssignment(e, v, value)
|
||||
|
|
||||
getValueInternalNonSubExpr(value)
|
||||
this.getValueInternalNonSubExpr(value)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
private import cpp
|
||||
private import semmle.code.cpp.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.cpp.dataflow.internal.DataFlowUtil
|
||||
|
||||
/**
|
||||
* Gets a function that might be called by `call`.
|
||||
@@ -63,3 +65,17 @@ predicate mayBenefitFromCallContext(Call call, Function f) { none() }
|
||||
* restricted to those `call`s for which a context might make a difference.
|
||||
*/
|
||||
Function viableImplInCallContext(Call call, Call ctx) { none() }
|
||||
|
||||
/** A parameter position represented by an integer. */
|
||||
class ParameterPosition extends int {
|
||||
ParameterPosition() { any(ParameterNode p).isParameterOf(_, this) }
|
||||
}
|
||||
|
||||
/** An argument position represented by an integer. */
|
||||
class ArgumentPosition extends int {
|
||||
ArgumentPosition() { any(ArgumentNode a).argumentOf(_, this) }
|
||||
}
|
||||
|
||||
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
|
||||
pragma[inline]
|
||||
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
|
||||
|
||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
||||
private class ParamNodeEx extends NodeEx {
|
||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||
|
||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||
}
|
||||
|
||||
int getPosition() { this.isParameterOf(_, result) }
|
||||
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||
|
||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||
}
|
||||
@@ -1012,6 +1012,9 @@ private module Stage2 {
|
||||
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||
|
||||
bindingset[node, ap]
|
||||
private predicate filter(NodeEx node, Ap ap) { any() }
|
||||
|
||||
bindingset[ap, contentType]
|
||||
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||
|
||||
@@ -1020,6 +1023,13 @@ private module Stage2 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughOutOfCall(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||
@@ -1042,6 +1052,13 @@ private module Stage2 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
flowCand(node, _, config) and
|
||||
sourceNode(node, config) and
|
||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||
@@ -1112,7 +1129,7 @@ private module Stage2 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -1189,7 +1206,7 @@ private module Stage2 {
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1430,7 +1447,7 @@ private module Stage2 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2125,7 +2142,7 @@ private module Stage3 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2891,7 +2908,7 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2975,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
|
||||
int getParameterPos() { p.isParameterOf(_, result) }
|
||||
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||
|
||||
ParamNodeEx getParamNode() { result = p }
|
||||
|
||||
@@ -3622,39 +3639,40 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||
AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ArgNode arg |
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
arg.argumentOf(call, apos) and
|
||||
ap = mid.getAp() and
|
||||
apa = ap.getApprox() and
|
||||
config = mid.getConfiguration()
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
p.isParameterOf(callable, pos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoCallable0(
|
||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||
AccessPath ap, Configuration config
|
||||
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa |
|
||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
callable = resolveCall(call, outercc) and
|
||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
||||
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3669,9 +3687,9 @@ private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
(
|
||||
sc = TSummaryCtxSome(p, ap)
|
||||
or
|
||||
@@ -3695,7 +3713,7 @@ private predicate paramFlowsThrough(
|
||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
||||
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||
mid.getNodeEx() = ret and
|
||||
kind = ret.getKind() and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -4424,24 +4442,25 @@ private module FlowExploration {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate partialPathIntoArg(
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ArgNode arg |
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
arg.argumentOf(call, apos) and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathIntoCallable0(
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
||||
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||
callable = resolveCall(call, outercc)
|
||||
}
|
||||
|
||||
@@ -4450,9 +4469,9 @@ private module FlowExploration {
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
sc1 = TSummaryCtx1Param(p) and
|
||||
sc2 = TSummaryCtx2Some(ap)
|
||||
|
|
||||
@@ -4616,22 +4635,23 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathFlowsThrough(
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||
RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||
mid.getNodeEx() = p and
|
||||
p.getPosition() = pos and
|
||||
p.getPosition() = ppos and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable0(
|
||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
||||
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||
@@ -4644,7 +4664,7 @@ private module FlowExploration {
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, int pos |
|
||||
exists(DataFlowCall call, ArgumentPosition pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||
)
|
||||
|
||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
||||
private class ParamNodeEx extends NodeEx {
|
||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||
|
||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||
}
|
||||
|
||||
int getPosition() { this.isParameterOf(_, result) }
|
||||
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||
|
||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||
}
|
||||
@@ -1012,6 +1012,9 @@ private module Stage2 {
|
||||
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||
|
||||
bindingset[node, ap]
|
||||
private predicate filter(NodeEx node, Ap ap) { any() }
|
||||
|
||||
bindingset[ap, contentType]
|
||||
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||
|
||||
@@ -1020,6 +1023,13 @@ private module Stage2 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughOutOfCall(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||
@@ -1042,6 +1052,13 @@ private module Stage2 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
flowCand(node, _, config) and
|
||||
sourceNode(node, config) and
|
||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||
@@ -1112,7 +1129,7 @@ private module Stage2 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -1189,7 +1206,7 @@ private module Stage2 {
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1430,7 +1447,7 @@ private module Stage2 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2125,7 +2142,7 @@ private module Stage3 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2891,7 +2908,7 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2975,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
|
||||
int getParameterPos() { p.isParameterOf(_, result) }
|
||||
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||
|
||||
ParamNodeEx getParamNode() { result = p }
|
||||
|
||||
@@ -3622,39 +3639,40 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||
AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ArgNode arg |
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
arg.argumentOf(call, apos) and
|
||||
ap = mid.getAp() and
|
||||
apa = ap.getApprox() and
|
||||
config = mid.getConfiguration()
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
p.isParameterOf(callable, pos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoCallable0(
|
||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||
AccessPath ap, Configuration config
|
||||
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa |
|
||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
callable = resolveCall(call, outercc) and
|
||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
||||
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3669,9 +3687,9 @@ private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
(
|
||||
sc = TSummaryCtxSome(p, ap)
|
||||
or
|
||||
@@ -3695,7 +3713,7 @@ private predicate paramFlowsThrough(
|
||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
||||
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||
mid.getNodeEx() = ret and
|
||||
kind = ret.getKind() and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -4424,24 +4442,25 @@ private module FlowExploration {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate partialPathIntoArg(
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ArgNode arg |
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
arg.argumentOf(call, apos) and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathIntoCallable0(
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
||||
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||
callable = resolveCall(call, outercc)
|
||||
}
|
||||
|
||||
@@ -4450,9 +4469,9 @@ private module FlowExploration {
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
sc1 = TSummaryCtx1Param(p) and
|
||||
sc2 = TSummaryCtx2Some(ap)
|
||||
|
|
||||
@@ -4616,22 +4635,23 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathFlowsThrough(
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||
RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||
mid.getNodeEx() = p and
|
||||
p.getPosition() = pos and
|
||||
p.getPosition() = ppos and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable0(
|
||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
||||
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||
@@ -4644,7 +4664,7 @@ private module FlowExploration {
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, int pos |
|
||||
exists(DataFlowCall call, ArgumentPosition pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||
)
|
||||
|
||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
||||
private class ParamNodeEx extends NodeEx {
|
||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||
|
||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||
}
|
||||
|
||||
int getPosition() { this.isParameterOf(_, result) }
|
||||
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||
|
||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||
}
|
||||
@@ -1012,6 +1012,9 @@ private module Stage2 {
|
||||
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||
|
||||
bindingset[node, ap]
|
||||
private predicate filter(NodeEx node, Ap ap) { any() }
|
||||
|
||||
bindingset[ap, contentType]
|
||||
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||
|
||||
@@ -1020,6 +1023,13 @@ private module Stage2 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughOutOfCall(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||
@@ -1042,6 +1052,13 @@ private module Stage2 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
flowCand(node, _, config) and
|
||||
sourceNode(node, config) and
|
||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||
@@ -1112,7 +1129,7 @@ private module Stage2 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -1189,7 +1206,7 @@ private module Stage2 {
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1430,7 +1447,7 @@ private module Stage2 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2125,7 +2142,7 @@ private module Stage3 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2891,7 +2908,7 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2975,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
|
||||
int getParameterPos() { p.isParameterOf(_, result) }
|
||||
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||
|
||||
ParamNodeEx getParamNode() { result = p }
|
||||
|
||||
@@ -3622,39 +3639,40 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||
AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ArgNode arg |
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
arg.argumentOf(call, apos) and
|
||||
ap = mid.getAp() and
|
||||
apa = ap.getApprox() and
|
||||
config = mid.getConfiguration()
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
p.isParameterOf(callable, pos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoCallable0(
|
||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||
AccessPath ap, Configuration config
|
||||
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa |
|
||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
callable = resolveCall(call, outercc) and
|
||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
||||
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3669,9 +3687,9 @@ private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
(
|
||||
sc = TSummaryCtxSome(p, ap)
|
||||
or
|
||||
@@ -3695,7 +3713,7 @@ private predicate paramFlowsThrough(
|
||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
||||
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||
mid.getNodeEx() = ret and
|
||||
kind = ret.getKind() and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -4424,24 +4442,25 @@ private module FlowExploration {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate partialPathIntoArg(
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ArgNode arg |
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
arg.argumentOf(call, apos) and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathIntoCallable0(
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
||||
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||
callable = resolveCall(call, outercc)
|
||||
}
|
||||
|
||||
@@ -4450,9 +4469,9 @@ private module FlowExploration {
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
sc1 = TSummaryCtx1Param(p) and
|
||||
sc2 = TSummaryCtx2Some(ap)
|
||||
|
|
||||
@@ -4616,22 +4635,23 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathFlowsThrough(
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||
RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||
mid.getNodeEx() = p and
|
||||
p.getPosition() = pos and
|
||||
p.getPosition() = ppos and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable0(
|
||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
||||
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||
@@ -4644,7 +4664,7 @@ private module FlowExploration {
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, int pos |
|
||||
exists(DataFlowCall call, ArgumentPosition pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||
)
|
||||
|
||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
||||
private class ParamNodeEx extends NodeEx {
|
||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||
|
||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||
}
|
||||
|
||||
int getPosition() { this.isParameterOf(_, result) }
|
||||
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||
|
||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||
}
|
||||
@@ -1012,6 +1012,9 @@ private module Stage2 {
|
||||
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||
|
||||
bindingset[node, ap]
|
||||
private predicate filter(NodeEx node, Ap ap) { any() }
|
||||
|
||||
bindingset[ap, contentType]
|
||||
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||
|
||||
@@ -1020,6 +1023,13 @@ private module Stage2 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughOutOfCall(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||
@@ -1042,6 +1052,13 @@ private module Stage2 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
flowCand(node, _, config) and
|
||||
sourceNode(node, config) and
|
||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||
@@ -1112,7 +1129,7 @@ private module Stage2 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -1189,7 +1206,7 @@ private module Stage2 {
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1430,7 +1447,7 @@ private module Stage2 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2125,7 +2142,7 @@ private module Stage3 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2891,7 +2908,7 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2975,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
|
||||
int getParameterPos() { p.isParameterOf(_, result) }
|
||||
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||
|
||||
ParamNodeEx getParamNode() { result = p }
|
||||
|
||||
@@ -3622,39 +3639,40 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||
AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ArgNode arg |
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
arg.argumentOf(call, apos) and
|
||||
ap = mid.getAp() and
|
||||
apa = ap.getApprox() and
|
||||
config = mid.getConfiguration()
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
p.isParameterOf(callable, pos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoCallable0(
|
||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||
AccessPath ap, Configuration config
|
||||
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa |
|
||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
callable = resolveCall(call, outercc) and
|
||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
||||
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3669,9 +3687,9 @@ private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
(
|
||||
sc = TSummaryCtxSome(p, ap)
|
||||
or
|
||||
@@ -3695,7 +3713,7 @@ private predicate paramFlowsThrough(
|
||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
||||
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||
mid.getNodeEx() = ret and
|
||||
kind = ret.getKind() and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -4424,24 +4442,25 @@ private module FlowExploration {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate partialPathIntoArg(
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ArgNode arg |
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
arg.argumentOf(call, apos) and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathIntoCallable0(
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
||||
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||
callable = resolveCall(call, outercc)
|
||||
}
|
||||
|
||||
@@ -4450,9 +4469,9 @@ private module FlowExploration {
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
sc1 = TSummaryCtx1Param(p) and
|
||||
sc2 = TSummaryCtx2Some(ap)
|
||||
|
|
||||
@@ -4616,22 +4635,23 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathFlowsThrough(
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||
RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||
mid.getNodeEx() = p and
|
||||
p.getPosition() = pos and
|
||||
p.getPosition() = ppos and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable0(
|
||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
||||
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||
@@ -4644,7 +4664,7 @@ private module FlowExploration {
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, int pos |
|
||||
exists(DataFlowCall call, ArgumentPosition pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||
)
|
||||
|
||||
@@ -62,6 +62,18 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
|
||||
tupleLimit = 1000
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `arg` is an argument of `call` with an argument position that matches
|
||||
* parameter position `ppos`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
predicate argumentPositionMatch(DataFlowCall call, ArgNode arg, ParameterPosition ppos) {
|
||||
exists(ArgumentPosition apos |
|
||||
arg.argumentOf(call, apos) and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a simple data-flow analysis for resolving lambda calls. The analysis
|
||||
* currently excludes read-steps, store-steps, and flow-through.
|
||||
@@ -71,25 +83,27 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
|
||||
* calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly.
|
||||
*/
|
||||
private module LambdaFlow {
|
||||
private predicate viableParamNonLambda(DataFlowCall call, int i, ParamNode p) {
|
||||
p.isParameterOf(viableCallable(call), i)
|
||||
pragma[noinline]
|
||||
private predicate viableParamNonLambda(DataFlowCall call, ParameterPosition ppos, ParamNode p) {
|
||||
p.isParameterOf(viableCallable(call), ppos)
|
||||
}
|
||||
|
||||
private predicate viableParamLambda(DataFlowCall call, int i, ParamNode p) {
|
||||
p.isParameterOf(viableCallableLambda(call, _), i)
|
||||
pragma[noinline]
|
||||
private predicate viableParamLambda(DataFlowCall call, ParameterPosition ppos, ParamNode p) {
|
||||
p.isParameterOf(viableCallableLambda(call, _), ppos)
|
||||
}
|
||||
|
||||
private predicate viableParamArgNonLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||
exists(int i |
|
||||
viableParamNonLambda(call, i, p) and
|
||||
arg.argumentOf(call, i)
|
||||
exists(ParameterPosition ppos |
|
||||
viableParamNonLambda(call, ppos, p) and
|
||||
argumentPositionMatch(call, arg, ppos)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate viableParamArgLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||
exists(int i |
|
||||
viableParamLambda(call, i, p) and
|
||||
arg.argumentOf(call, i)
|
||||
exists(ParameterPosition ppos |
|
||||
viableParamLambda(call, ppos, p) and
|
||||
argumentPositionMatch(call, arg, ppos)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -322,7 +336,7 @@ private module Cached {
|
||||
or
|
||||
exists(ArgNode arg |
|
||||
result.(PostUpdateNode).getPreUpdateNode() = arg and
|
||||
arg.argumentOf(call, k.(ParamUpdateReturnKind).getPosition())
|
||||
arg.argumentOf(call, k.(ParamUpdateReturnKind).getAMatchingArgumentPosition())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -330,7 +344,7 @@ private module Cached {
|
||||
predicate returnNodeExt(Node n, ReturnKindExt k) {
|
||||
k = TValueReturn(n.(ReturnNode).getKind())
|
||||
or
|
||||
exists(ParamNode p, int pos |
|
||||
exists(ParamNode p, ParameterPosition pos |
|
||||
parameterValueFlowsToPreUpdate(p, n) and
|
||||
p.isParameterOf(_, pos) and
|
||||
k = TParamUpdate(pos)
|
||||
@@ -352,11 +366,13 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
predicate parameterNode(Node p, DataFlowCallable c, int pos) { isParameterNode(p, c, pos) }
|
||||
predicate parameterNode(Node p, DataFlowCallable c, ParameterPosition pos) {
|
||||
isParameterNode(p, c, pos)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate argumentNode(Node n, DataFlowCall call, int pos) {
|
||||
n.(ArgumentNode).argumentOf(call, pos)
|
||||
predicate argumentNode(Node n, DataFlowCall call, ArgumentPosition pos) {
|
||||
isArgumentNode(n, call, pos)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -374,12 +390,12 @@ private module Cached {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `p` is the `i`th parameter of a viable dispatch target of `call`.
|
||||
* The instance parameter is considered to have index `-1`.
|
||||
* Holds if `p` is the parameter of a viable dispatch target of `call`,
|
||||
* and `p` has position `ppos`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate viableParam(DataFlowCall call, int i, ParamNode p) {
|
||||
p.isParameterOf(viableCallableExt(call), i)
|
||||
private predicate viableParam(DataFlowCall call, ParameterPosition ppos, ParamNode p) {
|
||||
p.isParameterOf(viableCallableExt(call), ppos)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -388,9 +404,9 @@ private module Cached {
|
||||
*/
|
||||
cached
|
||||
predicate viableParamArg(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||
exists(int i |
|
||||
viableParam(call, i, p) and
|
||||
arg.argumentOf(call, i) and
|
||||
exists(ParameterPosition ppos |
|
||||
viableParam(call, ppos, p) and
|
||||
argumentPositionMatch(call, arg, ppos) and
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
|
||||
)
|
||||
}
|
||||
@@ -862,7 +878,7 @@ private module Cached {
|
||||
cached
|
||||
newtype TReturnKindExt =
|
||||
TValueReturn(ReturnKind kind) or
|
||||
TParamUpdate(int pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
|
||||
TParamUpdate(ParameterPosition pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
|
||||
|
||||
cached
|
||||
newtype TBooleanOption =
|
||||
@@ -1054,9 +1070,9 @@ class ParamNode extends Node {
|
||||
|
||||
/**
|
||||
* Holds if this node is the parameter of callable `c` at the specified
|
||||
* (zero-based) position.
|
||||
* position.
|
||||
*/
|
||||
predicate isParameterOf(DataFlowCallable c, int i) { parameterNode(this, c, i) }
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) { parameterNode(this, c, pos) }
|
||||
}
|
||||
|
||||
/** A data-flow node that represents a call argument. */
|
||||
@@ -1064,7 +1080,9 @@ class ArgNode extends Node {
|
||||
ArgNode() { argumentNode(this, _, _) }
|
||||
|
||||
/** Holds if this argument occurs at the given position in the given call. */
|
||||
final predicate argumentOf(DataFlowCall call, int pos) { argumentNode(this, call, pos) }
|
||||
final predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
|
||||
argumentNode(this, call, pos)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1110,11 +1128,14 @@ class ValueReturnKind extends ReturnKindExt, TValueReturn {
|
||||
}
|
||||
|
||||
class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
|
||||
private int pos;
|
||||
private ParameterPosition pos;
|
||||
|
||||
ParamUpdateReturnKind() { this = TParamUpdate(pos) }
|
||||
|
||||
int getPosition() { result = pos }
|
||||
ParameterPosition getPosition() { result = pos }
|
||||
|
||||
pragma[nomagic]
|
||||
ArgumentPosition getAMatchingArgumentPosition() { parameterMatch(pos, result) }
|
||||
|
||||
override string toString() { result = "param update " + pos }
|
||||
}
|
||||
|
||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
||||
private class ParamNodeEx extends NodeEx {
|
||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||
|
||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||
}
|
||||
|
||||
int getPosition() { this.isParameterOf(_, result) }
|
||||
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||
|
||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||
}
|
||||
@@ -1012,6 +1012,9 @@ private module Stage2 {
|
||||
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||
|
||||
bindingset[node, ap]
|
||||
private predicate filter(NodeEx node, Ap ap) { any() }
|
||||
|
||||
bindingset[ap, contentType]
|
||||
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||
|
||||
@@ -1020,6 +1023,13 @@ private module Stage2 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughOutOfCall(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||
@@ -1042,6 +1052,13 @@ private module Stage2 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
flowCand(node, _, config) and
|
||||
sourceNode(node, config) and
|
||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||
@@ -1112,7 +1129,7 @@ private module Stage2 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -1189,7 +1206,7 @@ private module Stage2 {
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1430,7 +1447,7 @@ private module Stage2 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2125,7 +2142,7 @@ private module Stage3 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2891,7 +2908,7 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2975,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
|
||||
int getParameterPos() { p.isParameterOf(_, result) }
|
||||
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||
|
||||
ParamNodeEx getParamNode() { result = p }
|
||||
|
||||
@@ -3622,39 +3639,40 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||
AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ArgNode arg |
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
arg.argumentOf(call, apos) and
|
||||
ap = mid.getAp() and
|
||||
apa = ap.getApprox() and
|
||||
config = mid.getConfiguration()
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
p.isParameterOf(callable, pos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoCallable0(
|
||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||
AccessPath ap, Configuration config
|
||||
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa |
|
||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
callable = resolveCall(call, outercc) and
|
||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
||||
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3669,9 +3687,9 @@ private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
(
|
||||
sc = TSummaryCtxSome(p, ap)
|
||||
or
|
||||
@@ -3695,7 +3713,7 @@ private predicate paramFlowsThrough(
|
||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
||||
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||
mid.getNodeEx() = ret and
|
||||
kind = ret.getKind() and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -4424,24 +4442,25 @@ private module FlowExploration {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate partialPathIntoArg(
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ArgNode arg |
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
arg.argumentOf(call, apos) and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathIntoCallable0(
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
||||
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||
callable = resolveCall(call, outercc)
|
||||
}
|
||||
|
||||
@@ -4450,9 +4469,9 @@ private module FlowExploration {
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
sc1 = TSummaryCtx1Param(p) and
|
||||
sc2 = TSummaryCtx2Some(ap)
|
||||
|
|
||||
@@ -4616,22 +4635,23 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathFlowsThrough(
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||
RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||
mid.getNodeEx() = p and
|
||||
p.getPosition() = pos and
|
||||
p.getPosition() = ppos and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable0(
|
||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
||||
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||
@@ -4644,7 +4664,7 @@ private module FlowExploration {
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, int pos |
|
||||
exists(DataFlowCall call, ArgumentPosition pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||
)
|
||||
|
||||
@@ -8,7 +8,14 @@ private import DataFlowImplConsistency
|
||||
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() }
|
||||
|
||||
/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */
|
||||
predicate isParameterNode(ParameterNode p, DataFlowCallable c, int pos) { p.isParameterOf(c, pos) }
|
||||
predicate isParameterNode(ParameterNode p, DataFlowCallable c, ParameterPosition pos) {
|
||||
p.isParameterOf(c, pos)
|
||||
}
|
||||
|
||||
/** Holds if `arg` is an `ArgumentNode` of `c` with position `pos`. */
|
||||
predicate isArgumentNode(ArgumentNode arg, DataFlowCall c, ArgumentPosition pos) {
|
||||
arg.argumentOf(c, pos)
|
||||
}
|
||||
|
||||
/** Gets the instance argument of a non-static call. */
|
||||
private Node getInstanceArgument(Call call) {
|
||||
|
||||
@@ -2,6 +2,7 @@ private import cpp
|
||||
private import semmle.code.cpp.ir.IR
|
||||
private import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
||||
private import DataFlowImplCommon as DataFlowImplCommon
|
||||
|
||||
/**
|
||||
@@ -266,3 +267,17 @@ Function viableImplInCallContext(CallInstruction call, CallInstruction ctx) {
|
||||
result = ctx.getArgument(i).getUnconvertedResultExpression().(FunctionAccess).getTarget()
|
||||
)
|
||||
}
|
||||
|
||||
/** A parameter position represented by an integer. */
|
||||
class ParameterPosition extends int {
|
||||
ParameterPosition() { any(ParameterNode p).isParameterOf(_, this) }
|
||||
}
|
||||
|
||||
/** An argument position represented by an integer. */
|
||||
class ArgumentPosition extends int {
|
||||
ArgumentPosition() { any(ArgumentNode a).argumentOf(_, this) }
|
||||
}
|
||||
|
||||
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
|
||||
pragma[inline]
|
||||
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
|
||||
|
||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
||||
private class ParamNodeEx extends NodeEx {
|
||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||
|
||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||
}
|
||||
|
||||
int getPosition() { this.isParameterOf(_, result) }
|
||||
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||
|
||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||
}
|
||||
@@ -1012,6 +1012,9 @@ private module Stage2 {
|
||||
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||
|
||||
bindingset[node, ap]
|
||||
private predicate filter(NodeEx node, Ap ap) { any() }
|
||||
|
||||
bindingset[ap, contentType]
|
||||
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||
|
||||
@@ -1020,6 +1023,13 @@ private module Stage2 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughOutOfCall(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||
@@ -1042,6 +1052,13 @@ private module Stage2 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
flowCand(node, _, config) and
|
||||
sourceNode(node, config) and
|
||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||
@@ -1112,7 +1129,7 @@ private module Stage2 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -1189,7 +1206,7 @@ private module Stage2 {
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1430,7 +1447,7 @@ private module Stage2 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2125,7 +2142,7 @@ private module Stage3 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2891,7 +2908,7 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2975,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
|
||||
int getParameterPos() { p.isParameterOf(_, result) }
|
||||
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||
|
||||
ParamNodeEx getParamNode() { result = p }
|
||||
|
||||
@@ -3622,39 +3639,40 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||
AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ArgNode arg |
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
arg.argumentOf(call, apos) and
|
||||
ap = mid.getAp() and
|
||||
apa = ap.getApprox() and
|
||||
config = mid.getConfiguration()
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
p.isParameterOf(callable, pos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoCallable0(
|
||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||
AccessPath ap, Configuration config
|
||||
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa |
|
||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
callable = resolveCall(call, outercc) and
|
||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
||||
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3669,9 +3687,9 @@ private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
(
|
||||
sc = TSummaryCtxSome(p, ap)
|
||||
or
|
||||
@@ -3695,7 +3713,7 @@ private predicate paramFlowsThrough(
|
||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
||||
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||
mid.getNodeEx() = ret and
|
||||
kind = ret.getKind() and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -4424,24 +4442,25 @@ private module FlowExploration {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate partialPathIntoArg(
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ArgNode arg |
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
arg.argumentOf(call, apos) and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathIntoCallable0(
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
||||
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||
callable = resolveCall(call, outercc)
|
||||
}
|
||||
|
||||
@@ -4450,9 +4469,9 @@ private module FlowExploration {
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
sc1 = TSummaryCtx1Param(p) and
|
||||
sc2 = TSummaryCtx2Some(ap)
|
||||
|
|
||||
@@ -4616,22 +4635,23 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathFlowsThrough(
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||
RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||
mid.getNodeEx() = p and
|
||||
p.getPosition() = pos and
|
||||
p.getPosition() = ppos and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable0(
|
||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
||||
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||
@@ -4644,7 +4664,7 @@ private module FlowExploration {
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, int pos |
|
||||
exists(DataFlowCall call, ArgumentPosition pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||
)
|
||||
|
||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
||||
private class ParamNodeEx extends NodeEx {
|
||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||
|
||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||
}
|
||||
|
||||
int getPosition() { this.isParameterOf(_, result) }
|
||||
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||
|
||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||
}
|
||||
@@ -1012,6 +1012,9 @@ private module Stage2 {
|
||||
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||
|
||||
bindingset[node, ap]
|
||||
private predicate filter(NodeEx node, Ap ap) { any() }
|
||||
|
||||
bindingset[ap, contentType]
|
||||
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||
|
||||
@@ -1020,6 +1023,13 @@ private module Stage2 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughOutOfCall(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||
@@ -1042,6 +1052,13 @@ private module Stage2 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
flowCand(node, _, config) and
|
||||
sourceNode(node, config) and
|
||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||
@@ -1112,7 +1129,7 @@ private module Stage2 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -1189,7 +1206,7 @@ private module Stage2 {
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1430,7 +1447,7 @@ private module Stage2 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2125,7 +2142,7 @@ private module Stage3 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2891,7 +2908,7 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2975,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
|
||||
int getParameterPos() { p.isParameterOf(_, result) }
|
||||
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||
|
||||
ParamNodeEx getParamNode() { result = p }
|
||||
|
||||
@@ -3622,39 +3639,40 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||
AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ArgNode arg |
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
arg.argumentOf(call, apos) and
|
||||
ap = mid.getAp() and
|
||||
apa = ap.getApprox() and
|
||||
config = mid.getConfiguration()
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
p.isParameterOf(callable, pos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoCallable0(
|
||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||
AccessPath ap, Configuration config
|
||||
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa |
|
||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
callable = resolveCall(call, outercc) and
|
||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
||||
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3669,9 +3687,9 @@ private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
(
|
||||
sc = TSummaryCtxSome(p, ap)
|
||||
or
|
||||
@@ -3695,7 +3713,7 @@ private predicate paramFlowsThrough(
|
||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
||||
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||
mid.getNodeEx() = ret and
|
||||
kind = ret.getKind() and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -4424,24 +4442,25 @@ private module FlowExploration {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate partialPathIntoArg(
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ArgNode arg |
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
arg.argumentOf(call, apos) and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathIntoCallable0(
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
||||
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||
callable = resolveCall(call, outercc)
|
||||
}
|
||||
|
||||
@@ -4450,9 +4469,9 @@ private module FlowExploration {
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
sc1 = TSummaryCtx1Param(p) and
|
||||
sc2 = TSummaryCtx2Some(ap)
|
||||
|
|
||||
@@ -4616,22 +4635,23 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathFlowsThrough(
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||
RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||
mid.getNodeEx() = p and
|
||||
p.getPosition() = pos and
|
||||
p.getPosition() = ppos and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable0(
|
||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
||||
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||
@@ -4644,7 +4664,7 @@ private module FlowExploration {
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, int pos |
|
||||
exists(DataFlowCall call, ArgumentPosition pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||
)
|
||||
|
||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
||||
private class ParamNodeEx extends NodeEx {
|
||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||
|
||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||
}
|
||||
|
||||
int getPosition() { this.isParameterOf(_, result) }
|
||||
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||
|
||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||
}
|
||||
@@ -1012,6 +1012,9 @@ private module Stage2 {
|
||||
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||
|
||||
bindingset[node, ap]
|
||||
private predicate filter(NodeEx node, Ap ap) { any() }
|
||||
|
||||
bindingset[ap, contentType]
|
||||
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||
|
||||
@@ -1020,6 +1023,13 @@ private module Stage2 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughOutOfCall(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||
@@ -1042,6 +1052,13 @@ private module Stage2 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
flowCand(node, _, config) and
|
||||
sourceNode(node, config) and
|
||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||
@@ -1112,7 +1129,7 @@ private module Stage2 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -1189,7 +1206,7 @@ private module Stage2 {
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1430,7 +1447,7 @@ private module Stage2 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2125,7 +2142,7 @@ private module Stage3 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2891,7 +2908,7 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2975,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
|
||||
int getParameterPos() { p.isParameterOf(_, result) }
|
||||
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||
|
||||
ParamNodeEx getParamNode() { result = p }
|
||||
|
||||
@@ -3622,39 +3639,40 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||
AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ArgNode arg |
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
arg.argumentOf(call, apos) and
|
||||
ap = mid.getAp() and
|
||||
apa = ap.getApprox() and
|
||||
config = mid.getConfiguration()
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
p.isParameterOf(callable, pos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoCallable0(
|
||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||
AccessPath ap, Configuration config
|
||||
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa |
|
||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
callable = resolveCall(call, outercc) and
|
||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
||||
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3669,9 +3687,9 @@ private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
(
|
||||
sc = TSummaryCtxSome(p, ap)
|
||||
or
|
||||
@@ -3695,7 +3713,7 @@ private predicate paramFlowsThrough(
|
||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
||||
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||
mid.getNodeEx() = ret and
|
||||
kind = ret.getKind() and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -4424,24 +4442,25 @@ private module FlowExploration {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate partialPathIntoArg(
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ArgNode arg |
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
arg.argumentOf(call, apos) and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathIntoCallable0(
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
||||
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||
callable = resolveCall(call, outercc)
|
||||
}
|
||||
|
||||
@@ -4450,9 +4469,9 @@ private module FlowExploration {
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
sc1 = TSummaryCtx1Param(p) and
|
||||
sc2 = TSummaryCtx2Some(ap)
|
||||
|
|
||||
@@ -4616,22 +4635,23 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathFlowsThrough(
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||
RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||
mid.getNodeEx() = p and
|
||||
p.getPosition() = pos and
|
||||
p.getPosition() = ppos and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable0(
|
||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
||||
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||
@@ -4644,7 +4664,7 @@ private module FlowExploration {
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, int pos |
|
||||
exists(DataFlowCall call, ArgumentPosition pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||
)
|
||||
|
||||
@@ -256,11 +256,11 @@ private class ArgNodeEx extends NodeEx {
|
||||
private class ParamNodeEx extends NodeEx {
|
||||
ParamNodeEx() { this.asNode() instanceof ParamNode }
|
||||
|
||||
predicate isParameterOf(DataFlowCallable c, int i) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, i)
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
this.asNode().(ParamNode).isParameterOf(c, pos)
|
||||
}
|
||||
|
||||
int getPosition() { this.isParameterOf(_, result) }
|
||||
ParameterPosition getPosition() { this.isParameterOf(_, result) }
|
||||
|
||||
predicate allowParameterReturnInSelf() { allowParameterReturnInSelfCached(this.asNode()) }
|
||||
}
|
||||
@@ -1012,6 +1012,9 @@ private module Stage2 {
|
||||
|
||||
private predicate flowIntoCall = flowIntoCallNodeCand1/5;
|
||||
|
||||
bindingset[node, ap]
|
||||
private predicate filter(NodeEx node, Ap ap) { any() }
|
||||
|
||||
bindingset[ap, contentType]
|
||||
private predicate typecheckStore(Ap ap, DataFlowType contentType) { any() }
|
||||
|
||||
@@ -1020,6 +1023,13 @@ private module Stage2 {
|
||||
PrevStage::revFlow(node, _, _, apa, config)
|
||||
}
|
||||
|
||||
bindingset[result, apa]
|
||||
private ApApprox unbindApa(ApApprox apa) {
|
||||
exists(ApApprox apa0 |
|
||||
apa = pragma[only_bind_into](apa0) and result = pragma[only_bind_into](apa0)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate flowThroughOutOfCall(
|
||||
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
|
||||
@@ -1042,6 +1052,13 @@ private module Stage2 {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
fwdFlow0(node, cc, argAp, ap, config) and
|
||||
flowCand(node, unbindApa(getApprox(ap)), config) and
|
||||
filter(node, ap)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
|
||||
flowCand(node, _, config) and
|
||||
sourceNode(node, config) and
|
||||
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
|
||||
@@ -1112,7 +1129,7 @@ private module Stage2 {
|
||||
) {
|
||||
exists(DataFlowType contentType |
|
||||
fwdFlow(node1, cc, argAp, ap1, config) and
|
||||
PrevStage::storeStepCand(node1, getApprox(ap1), tc, node2, contentType, config) and
|
||||
PrevStage::storeStepCand(node1, unbindApa(getApprox(ap1)), tc, node2, contentType, config) and
|
||||
typecheckStore(ap1, contentType)
|
||||
)
|
||||
}
|
||||
@@ -1189,7 +1206,7 @@ private module Stage2 {
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
fwdFlowIn(call, p, cc, _, argAp, ap, config) and
|
||||
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
|
||||
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1430,7 +1447,7 @@ private module Stage2 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2125,7 +2142,7 @@ private module Stage3 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2891,7 +2908,7 @@ private module Stage4 {
|
||||
}
|
||||
|
||||
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, int pos |
|
||||
exists(RetNodeEx ret, Ap ap0, ReturnKindExt kind, ParameterPosition pos |
|
||||
parameterFlow(p, ap, ap0, c, config) and
|
||||
c = ret.getEnclosingCallable() and
|
||||
revFlow(pragma[only_bind_into](ret), true, apSome(_), pragma[only_bind_into](ap0),
|
||||
@@ -2975,7 +2992,7 @@ private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
|
||||
|
||||
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
|
||||
|
||||
int getParameterPos() { p.isParameterOf(_, result) }
|
||||
ParameterPosition getParameterPos() { p.isParameterOf(_, result) }
|
||||
|
||||
ParamNodeEx getParamNode() { result = p }
|
||||
|
||||
@@ -3622,39 +3639,40 @@ private predicate pathOutOfCallable(PathNodeMid mid, NodeEx out, CallContext cc)
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate pathIntoArg(
|
||||
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
PathNodeMid mid, ParameterPosition ppos, CallContext cc, DataFlowCall call, AccessPath ap,
|
||||
AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ArgNode arg |
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
arg.argumentOf(call, apos) and
|
||||
ap = mid.getAp() and
|
||||
apa = ap.getApprox() and
|
||||
config = mid.getConfiguration()
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate parameterCand(
|
||||
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
|
||||
DataFlowCallable callable, ParameterPosition pos, AccessPathApprox apa, Configuration config
|
||||
) {
|
||||
exists(ParamNodeEx p |
|
||||
Stage4::revFlow(p, _, _, apa, config) and
|
||||
p.isParameterOf(callable, i)
|
||||
p.isParameterOf(callable, pos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate pathIntoCallable0(
|
||||
PathNodeMid mid, DataFlowCallable callable, int i, CallContext outercc, DataFlowCall call,
|
||||
AccessPath ap, Configuration config
|
||||
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, AccessPath ap, Configuration config
|
||||
) {
|
||||
exists(AccessPathApprox apa |
|
||||
pathIntoArg(mid, pragma[only_bind_into](i), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pathIntoArg(mid, pragma[only_bind_into](pos), outercc, call, ap, pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config)) and
|
||||
callable = resolveCall(call, outercc) and
|
||||
parameterCand(callable, pragma[only_bind_into](i), pragma[only_bind_into](apa),
|
||||
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa),
|
||||
pragma[only_bind_into](config))
|
||||
)
|
||||
}
|
||||
@@ -3669,9 +3687,9 @@ private predicate pathIntoCallable(
|
||||
PathNodeMid mid, ParamNodeEx p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
|
||||
DataFlowCall call, Configuration config
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
exists(ParameterPosition pos, DataFlowCallable callable, AccessPath ap |
|
||||
pathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
(
|
||||
sc = TSummaryCtxSome(p, ap)
|
||||
or
|
||||
@@ -3695,7 +3713,7 @@ private predicate paramFlowsThrough(
|
||||
ReturnKindExt kind, CallContextCall cc, SummaryCtxSome sc, AccessPath ap, AccessPathApprox apa,
|
||||
Configuration config
|
||||
) {
|
||||
exists(PathNodeMid mid, RetNodeEx ret, int pos |
|
||||
exists(PathNodeMid mid, RetNodeEx ret, ParameterPosition pos |
|
||||
mid.getNodeEx() = ret and
|
||||
kind = ret.getKind() and
|
||||
cc = mid.getCallContext() and
|
||||
@@ -4424,24 +4442,25 @@ private module FlowExploration {
|
||||
|
||||
pragma[noinline]
|
||||
private predicate partialPathIntoArg(
|
||||
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
PartialPathNodeFwd mid, ParameterPosition ppos, CallContext cc, DataFlowCall call,
|
||||
PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(ArgNode arg |
|
||||
exists(ArgNode arg, ArgumentPosition apos |
|
||||
arg = mid.getNodeEx().asNode() and
|
||||
cc = mid.getCallContext() and
|
||||
arg.argumentOf(call, i) and
|
||||
arg.argumentOf(call, apos) and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathIntoCallable0(
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, int i, CallContext outercc,
|
||||
PartialPathNodeFwd mid, DataFlowCallable callable, ParameterPosition pos, CallContext outercc,
|
||||
DataFlowCall call, PartialAccessPath ap, Configuration config
|
||||
) {
|
||||
partialPathIntoArg(mid, i, outercc, call, ap, config) and
|
||||
partialPathIntoArg(mid, pos, outercc, call, ap, config) and
|
||||
callable = resolveCall(call, outercc)
|
||||
}
|
||||
|
||||
@@ -4450,9 +4469,9 @@ private module FlowExploration {
|
||||
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(int i, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, i, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, i) and
|
||||
exists(ParameterPosition pos, DataFlowCallable callable |
|
||||
partialPathIntoCallable0(mid, callable, pos, outercc, call, ap, config) and
|
||||
p.isParameterOf(callable, pos) and
|
||||
sc1 = TSummaryCtx1Param(p) and
|
||||
sc2 = TSummaryCtx2Some(ap)
|
||||
|
|
||||
@@ -4616,22 +4635,23 @@ private module FlowExploration {
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathFlowsThrough(
|
||||
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
ArgumentPosition apos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2,
|
||||
RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p |
|
||||
exists(PartialPathNodeRev mid, ParamNodeEx p, ParameterPosition ppos |
|
||||
mid.getNodeEx() = p and
|
||||
p.getPosition() = pos and
|
||||
p.getPosition() = ppos and
|
||||
sc1 = mid.getSummaryCtx1() and
|
||||
sc2 = mid.getSummaryCtx2() and
|
||||
ap = mid.getAp() and
|
||||
config = mid.getConfiguration()
|
||||
config = mid.getConfiguration() and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revPartialPathThroughCallable0(
|
||||
DataFlowCall call, PartialPathNodeRev mid, int pos, RevPartialAccessPath ap,
|
||||
DataFlowCall call, PartialPathNodeRev mid, ArgumentPosition pos, RevPartialAccessPath ap,
|
||||
Configuration config
|
||||
) {
|
||||
exists(TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2 |
|
||||
@@ -4644,7 +4664,7 @@ private module FlowExploration {
|
||||
private predicate revPartialPathThroughCallable(
|
||||
PartialPathNodeRev mid, ArgNodeEx node, RevPartialAccessPath ap, Configuration config
|
||||
) {
|
||||
exists(DataFlowCall call, int pos |
|
||||
exists(DataFlowCall call, ArgumentPosition pos |
|
||||
revPartialPathThroughCallable0(call, mid, pos, ap, config) and
|
||||
node.asNode().(ArgNode).argumentOf(call, pos)
|
||||
)
|
||||
|
||||
@@ -62,6 +62,18 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
|
||||
tupleLimit = 1000
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `arg` is an argument of `call` with an argument position that matches
|
||||
* parameter position `ppos`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
predicate argumentPositionMatch(DataFlowCall call, ArgNode arg, ParameterPosition ppos) {
|
||||
exists(ArgumentPosition apos |
|
||||
arg.argumentOf(call, apos) and
|
||||
parameterMatch(ppos, apos)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a simple data-flow analysis for resolving lambda calls. The analysis
|
||||
* currently excludes read-steps, store-steps, and flow-through.
|
||||
@@ -71,25 +83,27 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
|
||||
* calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly.
|
||||
*/
|
||||
private module LambdaFlow {
|
||||
private predicate viableParamNonLambda(DataFlowCall call, int i, ParamNode p) {
|
||||
p.isParameterOf(viableCallable(call), i)
|
||||
pragma[noinline]
|
||||
private predicate viableParamNonLambda(DataFlowCall call, ParameterPosition ppos, ParamNode p) {
|
||||
p.isParameterOf(viableCallable(call), ppos)
|
||||
}
|
||||
|
||||
private predicate viableParamLambda(DataFlowCall call, int i, ParamNode p) {
|
||||
p.isParameterOf(viableCallableLambda(call, _), i)
|
||||
pragma[noinline]
|
||||
private predicate viableParamLambda(DataFlowCall call, ParameterPosition ppos, ParamNode p) {
|
||||
p.isParameterOf(viableCallableLambda(call, _), ppos)
|
||||
}
|
||||
|
||||
private predicate viableParamArgNonLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||
exists(int i |
|
||||
viableParamNonLambda(call, i, p) and
|
||||
arg.argumentOf(call, i)
|
||||
exists(ParameterPosition ppos |
|
||||
viableParamNonLambda(call, ppos, p) and
|
||||
argumentPositionMatch(call, arg, ppos)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate viableParamArgLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||
exists(int i |
|
||||
viableParamLambda(call, i, p) and
|
||||
arg.argumentOf(call, i)
|
||||
exists(ParameterPosition ppos |
|
||||
viableParamLambda(call, ppos, p) and
|
||||
argumentPositionMatch(call, arg, ppos)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -322,7 +336,7 @@ private module Cached {
|
||||
or
|
||||
exists(ArgNode arg |
|
||||
result.(PostUpdateNode).getPreUpdateNode() = arg and
|
||||
arg.argumentOf(call, k.(ParamUpdateReturnKind).getPosition())
|
||||
arg.argumentOf(call, k.(ParamUpdateReturnKind).getAMatchingArgumentPosition())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -330,7 +344,7 @@ private module Cached {
|
||||
predicate returnNodeExt(Node n, ReturnKindExt k) {
|
||||
k = TValueReturn(n.(ReturnNode).getKind())
|
||||
or
|
||||
exists(ParamNode p, int pos |
|
||||
exists(ParamNode p, ParameterPosition pos |
|
||||
parameterValueFlowsToPreUpdate(p, n) and
|
||||
p.isParameterOf(_, pos) and
|
||||
k = TParamUpdate(pos)
|
||||
@@ -352,11 +366,13 @@ private module Cached {
|
||||
}
|
||||
|
||||
cached
|
||||
predicate parameterNode(Node p, DataFlowCallable c, int pos) { isParameterNode(p, c, pos) }
|
||||
predicate parameterNode(Node p, DataFlowCallable c, ParameterPosition pos) {
|
||||
isParameterNode(p, c, pos)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate argumentNode(Node n, DataFlowCall call, int pos) {
|
||||
n.(ArgumentNode).argumentOf(call, pos)
|
||||
predicate argumentNode(Node n, DataFlowCall call, ArgumentPosition pos) {
|
||||
isArgumentNode(n, call, pos)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -374,12 +390,12 @@ private module Cached {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `p` is the `i`th parameter of a viable dispatch target of `call`.
|
||||
* The instance parameter is considered to have index `-1`.
|
||||
* Holds if `p` is the parameter of a viable dispatch target of `call`,
|
||||
* and `p` has position `ppos`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate viableParam(DataFlowCall call, int i, ParamNode p) {
|
||||
p.isParameterOf(viableCallableExt(call), i)
|
||||
private predicate viableParam(DataFlowCall call, ParameterPosition ppos, ParamNode p) {
|
||||
p.isParameterOf(viableCallableExt(call), ppos)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -388,9 +404,9 @@ private module Cached {
|
||||
*/
|
||||
cached
|
||||
predicate viableParamArg(DataFlowCall call, ParamNode p, ArgNode arg) {
|
||||
exists(int i |
|
||||
viableParam(call, i, p) and
|
||||
arg.argumentOf(call, i) and
|
||||
exists(ParameterPosition ppos |
|
||||
viableParam(call, ppos, p) and
|
||||
argumentPositionMatch(call, arg, ppos) and
|
||||
compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
|
||||
)
|
||||
}
|
||||
@@ -862,7 +878,7 @@ private module Cached {
|
||||
cached
|
||||
newtype TReturnKindExt =
|
||||
TValueReturn(ReturnKind kind) or
|
||||
TParamUpdate(int pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
|
||||
TParamUpdate(ParameterPosition pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
|
||||
|
||||
cached
|
||||
newtype TBooleanOption =
|
||||
@@ -1054,9 +1070,9 @@ class ParamNode extends Node {
|
||||
|
||||
/**
|
||||
* Holds if this node is the parameter of callable `c` at the specified
|
||||
* (zero-based) position.
|
||||
* position.
|
||||
*/
|
||||
predicate isParameterOf(DataFlowCallable c, int i) { parameterNode(this, c, i) }
|
||||
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) { parameterNode(this, c, pos) }
|
||||
}
|
||||
|
||||
/** A data-flow node that represents a call argument. */
|
||||
@@ -1064,7 +1080,9 @@ class ArgNode extends Node {
|
||||
ArgNode() { argumentNode(this, _, _) }
|
||||
|
||||
/** Holds if this argument occurs at the given position in the given call. */
|
||||
final predicate argumentOf(DataFlowCall call, int pos) { argumentNode(this, call, pos) }
|
||||
final predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
|
||||
argumentNode(this, call, pos)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1110,11 +1128,14 @@ class ValueReturnKind extends ReturnKindExt, TValueReturn {
|
||||
}
|
||||
|
||||
class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
|
||||
private int pos;
|
||||
private ParameterPosition pos;
|
||||
|
||||
ParamUpdateReturnKind() { this = TParamUpdate(pos) }
|
||||
|
||||
int getPosition() { result = pos }
|
||||
ParameterPosition getPosition() { result = pos }
|
||||
|
||||
pragma[nomagic]
|
||||
ArgumentPosition getAMatchingArgumentPosition() { parameterMatch(pos, result) }
|
||||
|
||||
override string toString() { result = "param update " + pos }
|
||||
}
|
||||
|
||||
@@ -8,7 +8,14 @@ private import DataFlowImplConsistency
|
||||
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() }
|
||||
|
||||
/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */
|
||||
predicate isParameterNode(ParameterNode p, DataFlowCallable c, int pos) { p.isParameterOf(c, pos) }
|
||||
predicate isParameterNode(ParameterNode p, DataFlowCallable c, ParameterPosition pos) {
|
||||
p.isParameterOf(c, pos)
|
||||
}
|
||||
|
||||
/** Holds if `arg` is an `ArgumentNode` of `c` with position `pos`. */
|
||||
predicate isArgumentNode(ArgumentNode arg, DataFlowCall c, ArgumentPosition pos) {
|
||||
arg.argumentOf(c, pos)
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node that occurs as the argument of a call and is passed as-is
|
||||
|
||||
@@ -452,7 +452,7 @@ class SsaPhiNode extends Node, TSsaPhiNode {
|
||||
|
||||
/** Holds if this phi node has input from the `rnk`'th write operation in block `block`. */
|
||||
final predicate hasInputAtRankInBlock(IRBlock block, int rnk) {
|
||||
hasInputAtRankInBlock(block, rnk, _)
|
||||
this.hasInputAtRankInBlock(block, rnk, _)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -307,7 +307,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe
|
||||
final override string toString() { result = tag.toString() }
|
||||
|
||||
final override Instruction getAnyDef() {
|
||||
result = unique(Instruction defInstr | hasDefinition(defInstr, _))
|
||||
result = unique(Instruction defInstr | this.hasDefinition(defInstr, _))
|
||||
}
|
||||
|
||||
final override Overlap getDefinitionOverlap() { this.hasDefinition(_, result) }
|
||||
|
||||
@@ -307,7 +307,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe
|
||||
final override string toString() { result = tag.toString() }
|
||||
|
||||
final override Instruction getAnyDef() {
|
||||
result = unique(Instruction defInstr | hasDefinition(defInstr, _))
|
||||
result = unique(Instruction defInstr | this.hasDefinition(defInstr, _))
|
||||
}
|
||||
|
||||
final override Overlap getDefinitionOverlap() { this.hasDefinition(_, result) }
|
||||
|
||||
@@ -307,7 +307,7 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOpe
|
||||
final override string toString() { result = tag.toString() }
|
||||
|
||||
final override Instruction getAnyDef() {
|
||||
result = unique(Instruction defInstr | hasDefinition(defInstr, _))
|
||||
result = unique(Instruction defInstr | this.hasDefinition(defInstr, _))
|
||||
}
|
||||
|
||||
final override Overlap getDefinitionOverlap() { this.hasDefinition(_, result) }
|
||||
|
||||
@@ -18,12 +18,12 @@ class SuppressionComment extends Comment {
|
||||
(
|
||||
this instanceof CppStyleComment and
|
||||
// strip the beginning slashes
|
||||
text = getContents().suffix(2)
|
||||
text = this.getContents().suffix(2)
|
||||
or
|
||||
this instanceof CStyleComment and
|
||||
// strip both the beginning /* and the end */ the comment
|
||||
exists(string text0 |
|
||||
text0 = getContents().suffix(2) and
|
||||
text0 = this.getContents().suffix(2) and
|
||||
text = text0.prefix(text0.length() - 2)
|
||||
) and
|
||||
// The /* */ comment must be a single-line comment
|
||||
|
||||
@@ -153,12 +153,12 @@ class ExtClass extends Class {
|
||||
}
|
||||
|
||||
predicate hasLocationInfo(string path, int startline, int startcol, int endline, int endcol) {
|
||||
if hasOneVariableGroup()
|
||||
if this.hasOneVariableGroup()
|
||||
then
|
||||
exists(VariableDeclarationGroup vdg | vdg.getClass() = this |
|
||||
vdg.hasLocationInfo(path, startline, startcol, endline, endcol)
|
||||
)
|
||||
else getLocation().hasLocationInfo(path, startline, startcol, endline, endcol)
|
||||
else this.getLocation().hasLocationInfo(path, startline, startcol, endline, endcol)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,16 @@ predicate reachableThing(Thing t) {
|
||||
exists(Thing mid | reachableThing(mid) and mid.callsOrAccesses() = t)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate callsOrAccessesPlus(Thing thing1, FunctionToRemove thing2) {
|
||||
thing1.callsOrAccesses() = thing2
|
||||
or
|
||||
exists(Thing mid |
|
||||
thing1.callsOrAccesses() = mid and
|
||||
callsOrAccessesPlus(mid, thing2)
|
||||
)
|
||||
}
|
||||
|
||||
class Thing extends Locatable {
|
||||
Thing() {
|
||||
this instanceof Function or
|
||||
@@ -81,7 +91,7 @@ class FunctionToRemove extends Function {
|
||||
}
|
||||
|
||||
Thing getOther() {
|
||||
result.callsOrAccesses+() = this and
|
||||
callsOrAccessesPlus(result, this) and
|
||||
this != result and
|
||||
// We will already be reporting the enclosing function of a
|
||||
// local variable, so don't also report the variable
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
## 0.0.5
|
||||
|
||||
### New Queries
|
||||
|
||||
* A new query `cpp/certificate-not-checked` has been added for C/C++. The query flags unsafe use of OpenSSL and similar libraries.
|
||||
* A new query `cpp/certificate-result-conflation` has been added for C/C++. The query flags unsafe use of OpenSSL and similar libraries.
|
||||
|
||||
## 0.0.4
|
||||
|
||||
### New Queries
|
||||
|
||||
@@ -103,9 +103,9 @@ class CallWithBufferSize extends FunctionCall {
|
||||
// `upperBound(e)` defaults to `exprMaxVal(e)` when `e` isn't analyzable. So to get a meaningful
|
||||
// result in this case we pick the minimum value obtainable from dataflow and range analysis.
|
||||
result =
|
||||
upperBound(statedSizeExpr())
|
||||
upperBound(this.statedSizeExpr())
|
||||
.minimum(min(Expr statedSizeSrc |
|
||||
DataFlow::localExprFlow(statedSizeSrc, statedSizeExpr())
|
||||
DataFlow::localExprFlow(statedSizeSrc, this.statedSizeExpr())
|
||||
|
|
||||
statedSizeSrc.getValue().toInt()
|
||||
))
|
||||
|
||||
@@ -22,7 +22,7 @@ abstract class LockOperation extends FunctionCall {
|
||||
ControlFlowNode getAReachedNode() {
|
||||
result = this
|
||||
or
|
||||
exists(ControlFlowNode mid | mid = getAReachedNode() |
|
||||
exists(ControlFlowNode mid | mid = this.getAReachedNode() |
|
||||
not mid != this.getMatchingUnlock() and
|
||||
result = mid.getASuccessor()
|
||||
)
|
||||
|
||||
@@ -156,8 +156,8 @@ abstract class LeapYearFieldAccess extends YearFieldAccess {
|
||||
//
|
||||
// https://aa.usno.navy.mil/faq/docs/calendars.php
|
||||
this.isUsedInMod4Operation() and
|
||||
additionalModulusCheckForLeapYear(400) and
|
||||
additionalModulusCheckForLeapYear(100)
|
||||
this.additionalModulusCheckForLeapYear(400) and
|
||||
this.additionalModulusCheckForLeapYear(100)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,17 +176,17 @@ class StructTmLeapYearFieldAccess extends LeapYearFieldAccess {
|
||||
|
||||
override predicate isUsedInCorrectLeapYearCheck() {
|
||||
this.isUsedInMod4Operation() and
|
||||
additionalModulusCheckForLeapYear(400) and
|
||||
additionalModulusCheckForLeapYear(100) and
|
||||
this.additionalModulusCheckForLeapYear(400) and
|
||||
this.additionalModulusCheckForLeapYear(100) and
|
||||
// tm_year represents years since 1900
|
||||
(
|
||||
additionalAdditionOrSubstractionCheckForLeapYear(1900)
|
||||
this.additionalAdditionOrSubstractionCheckForLeapYear(1900)
|
||||
or
|
||||
// some systems may use 2000 for 2-digit year conversions
|
||||
additionalAdditionOrSubstractionCheckForLeapYear(2000)
|
||||
this.additionalAdditionOrSubstractionCheckForLeapYear(2000)
|
||||
or
|
||||
// converting from/to Unix epoch
|
||||
additionalAdditionOrSubstractionCheckForLeapYear(1970)
|
||||
this.additionalAdditionOrSubstractionCheckForLeapYear(1970)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ class LoopWithAlloca extends Stmt {
|
||||
or
|
||||
// `e == 0`
|
||||
exists(EQExpr eq |
|
||||
conditionRequires(eq, truth.booleanNot()) and
|
||||
this.conditionRequires(eq, truth.booleanNot()) and
|
||||
eq.getAnOperand().getValue().toInt() = 0 and
|
||||
e = eq.getAnOperand() and
|
||||
not exists(e.getValue())
|
||||
@@ -65,7 +65,7 @@ class LoopWithAlloca extends Stmt {
|
||||
or
|
||||
// `e != 0`
|
||||
exists(NEExpr eq |
|
||||
conditionRequires(eq, truth) and
|
||||
this.conditionRequires(eq, truth) and
|
||||
eq.getAnOperand().getValue().toInt() = 0 and
|
||||
e = eq.getAnOperand() and
|
||||
not exists(e.getValue())
|
||||
@@ -73,7 +73,7 @@ class LoopWithAlloca extends Stmt {
|
||||
or
|
||||
// `(bool)e == true`
|
||||
exists(EQExpr eq |
|
||||
conditionRequires(eq, truth) and
|
||||
this.conditionRequires(eq, truth) and
|
||||
eq.getAnOperand().getValue().toInt() = 1 and
|
||||
e = eq.getAnOperand() and
|
||||
e.getUnspecifiedType() instanceof BoolType and
|
||||
@@ -82,7 +82,7 @@ class LoopWithAlloca extends Stmt {
|
||||
or
|
||||
// `(bool)e != true`
|
||||
exists(NEExpr eq |
|
||||
conditionRequires(eq, truth.booleanNot()) and
|
||||
this.conditionRequires(eq, truth.booleanNot()) and
|
||||
eq.getAnOperand().getValue().toInt() = 1 and
|
||||
e = eq.getAnOperand() and
|
||||
e.getUnspecifiedType() instanceof BoolType and
|
||||
@@ -90,7 +90,7 @@ class LoopWithAlloca extends Stmt {
|
||||
)
|
||||
or
|
||||
exists(NotExpr notExpr |
|
||||
conditionRequires(notExpr, truth.booleanNot()) and
|
||||
this.conditionRequires(notExpr, truth.booleanNot()) and
|
||||
e = notExpr.getOperand()
|
||||
)
|
||||
or
|
||||
@@ -98,7 +98,7 @@ class LoopWithAlloca extends Stmt {
|
||||
// requires both of its operand to be true as well.
|
||||
exists(LogicalAndExpr andExpr |
|
||||
truth = true and
|
||||
conditionRequires(andExpr, truth) and
|
||||
this.conditionRequires(andExpr, truth) and
|
||||
e = andExpr.getAnOperand()
|
||||
)
|
||||
or
|
||||
@@ -106,7 +106,7 @@ class LoopWithAlloca extends Stmt {
|
||||
// it requires both of its operand to be false as well.
|
||||
exists(LogicalOrExpr orExpr |
|
||||
truth = false and
|
||||
conditionRequires(orExpr, truth) and
|
||||
this.conditionRequires(orExpr, truth) and
|
||||
e = orExpr.getAnOperand()
|
||||
)
|
||||
}
|
||||
@@ -141,9 +141,9 @@ class LoopWithAlloca extends Stmt {
|
||||
* `conditionRequiresInequality`.
|
||||
*/
|
||||
private Variable getAControllingVariable() {
|
||||
conditionRequires(result.getAnAccess(), _)
|
||||
this.conditionRequires(result.getAnAccess(), _)
|
||||
or
|
||||
conditionRequiresInequality(result.getAnAccess(), _, _)
|
||||
this.conditionRequiresInequality(result.getAnAccess(), _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -61,72 +61,72 @@ class PointerArithmeticAccess extends BufferAccess, Expr {
|
||||
* A pair of buffer accesses through a call to memcpy.
|
||||
*/
|
||||
class MemCpy extends BufferAccess, FunctionCall {
|
||||
MemCpy() { getTarget().hasName("memcpy") }
|
||||
MemCpy() { this.getTarget().hasName("memcpy") }
|
||||
|
||||
override Expr getPointer() {
|
||||
result = getArgument(0) or
|
||||
result = getArgument(1)
|
||||
result = this.getArgument(0) or
|
||||
result = this.getArgument(1)
|
||||
}
|
||||
|
||||
override Expr getAccessedLength() { result = getArgument(2) }
|
||||
override Expr getAccessedLength() { result = this.getArgument(2) }
|
||||
}
|
||||
|
||||
class StrncpySizeExpr extends BufferAccess, FunctionCall {
|
||||
StrncpySizeExpr() { getTarget().hasName("strncpy") }
|
||||
StrncpySizeExpr() { this.getTarget().hasName("strncpy") }
|
||||
|
||||
override Expr getPointer() {
|
||||
result = getArgument(0) or
|
||||
result = getArgument(1)
|
||||
result = this.getArgument(0) or
|
||||
result = this.getArgument(1)
|
||||
}
|
||||
|
||||
override Expr getAccessedLength() { result = getArgument(2) }
|
||||
override Expr getAccessedLength() { result = this.getArgument(2) }
|
||||
}
|
||||
|
||||
class RecvSizeExpr extends BufferAccess, FunctionCall {
|
||||
RecvSizeExpr() { getTarget().hasName("recv") }
|
||||
RecvSizeExpr() { this.getTarget().hasName("recv") }
|
||||
|
||||
override Expr getPointer() { result = getArgument(1) }
|
||||
override Expr getPointer() { result = this.getArgument(1) }
|
||||
|
||||
override Expr getAccessedLength() { result = getArgument(2) }
|
||||
override Expr getAccessedLength() { result = this.getArgument(2) }
|
||||
}
|
||||
|
||||
class SendSizeExpr extends BufferAccess, FunctionCall {
|
||||
SendSizeExpr() { getTarget().hasName("send") }
|
||||
SendSizeExpr() { this.getTarget().hasName("send") }
|
||||
|
||||
override Expr getPointer() { result = getArgument(1) }
|
||||
override Expr getPointer() { result = this.getArgument(1) }
|
||||
|
||||
override Expr getAccessedLength() { result = getArgument(2) }
|
||||
override Expr getAccessedLength() { result = this.getArgument(2) }
|
||||
}
|
||||
|
||||
class SnprintfSizeExpr extends BufferAccess, FunctionCall {
|
||||
SnprintfSizeExpr() { getTarget().hasName("snprintf") }
|
||||
SnprintfSizeExpr() { this.getTarget().hasName("snprintf") }
|
||||
|
||||
override Expr getPointer() { result = getArgument(0) }
|
||||
override Expr getPointer() { result = this.getArgument(0) }
|
||||
|
||||
override Expr getAccessedLength() { result = getArgument(1) }
|
||||
override Expr getAccessedLength() { result = this.getArgument(1) }
|
||||
}
|
||||
|
||||
class MemcmpSizeExpr extends BufferAccess, FunctionCall {
|
||||
MemcmpSizeExpr() { getTarget().hasName("Memcmp") }
|
||||
MemcmpSizeExpr() { this.getTarget().hasName("Memcmp") }
|
||||
|
||||
override Expr getPointer() {
|
||||
result = getArgument(0) or
|
||||
result = getArgument(1)
|
||||
result = this.getArgument(0) or
|
||||
result = this.getArgument(1)
|
||||
}
|
||||
|
||||
override Expr getAccessedLength() { result = getArgument(2) }
|
||||
override Expr getAccessedLength() { result = this.getArgument(2) }
|
||||
}
|
||||
|
||||
class MallocSizeExpr extends BufferAccess, FunctionCall {
|
||||
MallocSizeExpr() { getTarget().hasName("malloc") }
|
||||
MallocSizeExpr() { this.getTarget().hasName("malloc") }
|
||||
|
||||
override Expr getPointer() { none() }
|
||||
|
||||
override Expr getAccessedLength() { result = getArgument(0) }
|
||||
override Expr getAccessedLength() { result = this.getArgument(0) }
|
||||
}
|
||||
|
||||
class NetworkFunctionCall extends FunctionCall {
|
||||
NetworkFunctionCall() { getTarget().hasName(["ntohd", "ntohf", "ntohl", "ntohll", "ntohs"]) }
|
||||
NetworkFunctionCall() { this.getTarget().hasName(["ntohd", "ntohf", "ntohl", "ntohll", "ntohs"]) }
|
||||
}
|
||||
|
||||
class NetworkToBufferSizeConfiguration extends DataFlow::Configuration {
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
* @description Using the TLS or SSLv23 protocol from the boost::asio library, but not disabling deprecated protocols, or disabling minimum-recommended protocols.
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @security-severity 7.5
|
||||
* @id cpp/boost/tls-settings-misconfiguration
|
||||
* @tags security
|
||||
* external/cwe/cwe-326
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
* @description Using a deprecated hard-coded protocol using the boost::asio library.
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @security-severity 7.5
|
||||
* @id cpp/boost/use-of-deprecated-hardcoded-security-protocol
|
||||
* @tags security
|
||||
* external/cwe/cwe-327
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
@@ -13,7 +13,7 @@ import cpp
|
||||
|
||||
class MacroFunctionCall extends MacroInvocation {
|
||||
MacroFunctionCall() {
|
||||
not exists(getParentInvocation()) and
|
||||
not exists(this.getParentInvocation()) and
|
||||
this.getMacro().getHead().matches("%(%")
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import semmle.code.cpp.commons.Assertions
|
||||
|
||||
class MacroFunctionCall extends MacroInvocation {
|
||||
MacroFunctionCall() {
|
||||
not exists(getParentInvocation()) and
|
||||
not exists(this.getParentInvocation()) and
|
||||
this.getMacro().getHead().matches("%(%")
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ class ExternalAPIDataNode extends DataFlow::Node {
|
||||
int getIndex() { result = i }
|
||||
|
||||
/** Gets the description of the function being called. */
|
||||
string getFunctionDescription() { result = getExternalFunction().toString() }
|
||||
string getFunctionDescription() { result = this.getExternalFunction().toString() }
|
||||
}
|
||||
|
||||
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalAPIDataNode`s. */
|
||||
|
||||
@@ -38,7 +38,7 @@ class ExternalAPIDataNode extends DataFlow::Node {
|
||||
int getIndex() { result = i }
|
||||
|
||||
/** Gets the description of the function being called. */
|
||||
string getFunctionDescription() { result = getExternalFunction().toString() }
|
||||
string getFunctionDescription() { result = this.getExternalFunction().toString() }
|
||||
}
|
||||
|
||||
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalAPIDataNode`s. */
|
||||
|
||||
@@ -42,7 +42,7 @@ class VarargsFunction extends Function {
|
||||
}
|
||||
|
||||
private int trailingArgValueCount(string value) {
|
||||
result = strictcount(FunctionCall fc | trailingArgValue(fc) = value)
|
||||
result = strictcount(FunctionCall fc | this.trailingArgValue(fc) = value)
|
||||
}
|
||||
|
||||
string nonTrailingVarArgValue(FunctionCall fc, int index) {
|
||||
@@ -58,11 +58,11 @@ class VarargsFunction extends Function {
|
||||
|
||||
string normalTerminator(int cnt) {
|
||||
result = ["0", "-1"] and
|
||||
cnt = trailingArgValueCount(result) and
|
||||
2 * cnt > totalCount() and
|
||||
cnt = this.trailingArgValueCount(result) and
|
||||
2 * cnt > this.totalCount() and
|
||||
not exists(FunctionCall fc, int index |
|
||||
// terminator value is used in a non-terminating position
|
||||
nonTrailingVarArgValue(fc, index) = result
|
||||
this.nonTrailingVarArgValue(fc, index) = result
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ class TaintSource extends VariableAccess {
|
||||
definitionUsePair(_, this, va)
|
||||
or
|
||||
exists(VariableAccess mid, Expr def |
|
||||
sourceReaches(mid) and
|
||||
this.sourceReaches(mid) and
|
||||
exprDefinition(_, def, mid) and
|
||||
definitionUsePair(_, def, va)
|
||||
)
|
||||
@@ -53,11 +53,11 @@ class TaintSource extends VariableAccess {
|
||||
* from `va`, possibly using intermediate reassignments.
|
||||
*/
|
||||
private predicate reachesSink(VariableAccess va, VariableAccess sink) {
|
||||
isSink(sink) and
|
||||
this.isSink(sink) and
|
||||
va = sink
|
||||
or
|
||||
exists(VariableAccess mid, Expr def |
|
||||
reachesSink(mid, sink) and
|
||||
this.reachesSink(mid, sink) and
|
||||
exprDefinition(_, def, va) and
|
||||
definitionUsePair(_, def, mid)
|
||||
)
|
||||
@@ -71,15 +71,15 @@ class TaintSource extends VariableAccess {
|
||||
* this source to `sink` found via `tainted(source, sink)`.)
|
||||
*/
|
||||
predicate reaches(VariableAccess sink) {
|
||||
isSink(sink) and
|
||||
this.isSink(sink) and
|
||||
not exists(VariableAccess va |
|
||||
va != this and
|
||||
va != sink and
|
||||
mayAddNullTerminator(_, va)
|
||||
|
|
||||
sourceReaches(va)
|
||||
this.sourceReaches(va)
|
||||
or
|
||||
reachesSink(va, sink)
|
||||
this.reachesSink(va, sink)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
28
cpp/ql/src/Security/CWE/CWE-295/SSLResultConflation.qhelp
Normal file
28
cpp/ql/src/Security/CWE/CWE-295/SSLResultConflation.qhelp
Normal file
@@ -0,0 +1,28 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>When checking the result of SSL certificate verification, accepting any error code may allow an attacker to impersonate someone who is trusted.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>When checking an SSL certificate with <code>SSL_get_verify_result</code>, only <code>X509_V_OK</code> is a success code. If there is any other result the certificate should not be accepted.</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
|
||||
<p>In this example the error code <code>X509_V_ERR_CERT_HAS_EXPIRED</code> is treated the same as an OK result. An expired certificate should not be accepted as it is more likely to be compromised than a valid certificate.</p>
|
||||
|
||||
<sample src="SSLResultConflationBad.cpp" />
|
||||
|
||||
<p>In the corrected example, only a result of <code>X509_V_OK</code> is accepted.</p>
|
||||
|
||||
<sample src="SSLResultConflationGood.cpp" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
50
cpp/ql/src/Security/CWE/CWE-295/SSLResultConflation.ql
Normal file
50
cpp/ql/src/Security/CWE/CWE-295/SSLResultConflation.ql
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* @name Certificate result conflation
|
||||
* @description Only accept SSL certificates that pass certificate verification.
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @security-severity 7.5
|
||||
* @precision medium
|
||||
* @id cpp/certificate-result-conflation
|
||||
* @tags security
|
||||
* external/cwe/cwe-295
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.Guards
|
||||
import semmle.code.cpp.dataflow.DataFlow
|
||||
|
||||
/**
|
||||
* A call to `SSL_get_verify_result`.
|
||||
*/
|
||||
class SSLGetVerifyResultCall extends FunctionCall {
|
||||
SSLGetVerifyResultCall() { getTarget().getName() = "SSL_get_verify_result" }
|
||||
}
|
||||
|
||||
/**
|
||||
* Data flow from a call to `SSL_get_verify_result` to a guard condition
|
||||
* that references the result.
|
||||
*/
|
||||
class VerifyResultConfig extends DataFlow::Configuration {
|
||||
VerifyResultConfig() { this = "VerifyResultConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr() instanceof SSLGetVerifyResultCall
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(GuardCondition guard | guard.getAChild*() = sink.asExpr())
|
||||
}
|
||||
}
|
||||
|
||||
from
|
||||
VerifyResultConfig config, DataFlow::Node source, DataFlow::Node sink1, DataFlow::Node sink2,
|
||||
GuardCondition guard, Expr c1, Expr c2, boolean testIsTrue
|
||||
where
|
||||
config.hasFlow(source, sink1) and
|
||||
config.hasFlow(source, sink2) and
|
||||
guard.comparesEq(sink1.asExpr(), c1, 0, false, testIsTrue) and // (value != c1) => testIsTrue
|
||||
guard.comparesEq(sink2.asExpr(), c2, 0, false, testIsTrue) and // (value != c2) => testIsTrue
|
||||
c1.getValue().toInt() = 0 and
|
||||
c2.getValue().toInt() != 0
|
||||
select guard, "This expression conflates OK and non-OK results from $@.", source, source.toString()
|
||||
13
cpp/ql/src/Security/CWE/CWE-295/SSLResultConflationBad.cpp
Normal file
13
cpp/ql/src/Security/CWE/CWE-295/SSLResultConflationBad.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
// ...
|
||||
|
||||
if (cert = SSL_get_peer_certificate(ssl))
|
||||
{
|
||||
result = SSL_get_verify_result(ssl);
|
||||
|
||||
if ((result == X509_V_OK) || (result == X509_V_ERR_CERT_HAS_EXPIRED)) // BAD (conflates OK and a non-OK codes)
|
||||
{
|
||||
do_ok();
|
||||
} else {
|
||||
do_error();
|
||||
}
|
||||
}
|
||||
13
cpp/ql/src/Security/CWE/CWE-295/SSLResultConflationGood.cpp
Normal file
13
cpp/ql/src/Security/CWE/CWE-295/SSLResultConflationGood.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
// ...
|
||||
|
||||
if (cert = SSL_get_peer_certificate(ssl))
|
||||
{
|
||||
result = SSL_get_verify_result(ssl);
|
||||
|
||||
if (result == X509_V_OK) // GOOD
|
||||
{
|
||||
do_ok();
|
||||
} else {
|
||||
do_error();
|
||||
}
|
||||
}
|
||||
28
cpp/ql/src/Security/CWE/CWE-295/SSLResultNotChecked.qhelp
Normal file
28
cpp/ql/src/Security/CWE/CWE-295/SSLResultNotChecked.qhelp
Normal file
@@ -0,0 +1,28 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>After fetching an SSL certificate, always check the result of certificate verification.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>Always check the result of SSL certificate verification. A certificate that has been revoked may indicate that data is coming from an attacker, whereas a certificate that has expired or was self-signed may indicate an increased likelihood that the data is malicious.</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
|
||||
<p>In this example, the <code>SSL_get_peer_certificate</code> function is used to get the certificate of a peer. However it is unsafe to use that information without checking if the certificate is valid.</p>
|
||||
|
||||
<sample src="SSLResultNotCheckedBad.cpp" />
|
||||
|
||||
<p>In the corrected example, we use <code>SSL_get_verify_result</code> to check that certificate verification was successful.</p>
|
||||
|
||||
<sample src="SSLResultNotCheckedGood.cpp" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
120
cpp/ql/src/Security/CWE/CWE-295/SSLResultNotChecked.ql
Normal file
120
cpp/ql/src/Security/CWE/CWE-295/SSLResultNotChecked.ql
Normal file
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* @name Certificate not checked
|
||||
* @description Always check the result of certificate verification after fetching an SSL certificate.
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @security-severity 7.5
|
||||
* @precision medium
|
||||
* @id cpp/certificate-not-checked
|
||||
* @tags security
|
||||
* external/cwe/cwe-295
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
import semmle.code.cpp.controlflow.IRGuards
|
||||
|
||||
/**
|
||||
* A call to `SSL_get_peer_certificate`.
|
||||
*/
|
||||
class SSLGetPeerCertificateCall extends FunctionCall {
|
||||
SSLGetPeerCertificateCall() {
|
||||
getTarget().getName() = "SSL_get_peer_certificate" // SSL_get_peer_certificate(ssl)
|
||||
}
|
||||
|
||||
Expr getSSLArgument() { result = getArgument(0) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `SSL_get_verify_result`.
|
||||
*/
|
||||
class SSLGetVerifyResultCall extends FunctionCall {
|
||||
SSLGetVerifyResultCall() {
|
||||
getTarget().getName() = "SSL_get_verify_result" // SSL_get_peer_certificate(ssl)
|
||||
}
|
||||
|
||||
Expr getSSLArgument() { result = getArgument(0) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the SSL object passed into `SSL_get_peer_certificate` is checked with
|
||||
* `SSL_get_verify_result` entering `node`.
|
||||
*/
|
||||
predicate resultIsChecked(SSLGetPeerCertificateCall getCertCall, ControlFlowNode node) {
|
||||
exists(Expr ssl, SSLGetVerifyResultCall check |
|
||||
ssl = globalValueNumber(getCertCall.getSSLArgument()).getAnExpr() and
|
||||
ssl = check.getSSLArgument() and
|
||||
node = check
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the certificate returned by `SSL_get_peer_certificate` is found to be
|
||||
* `0` on the edge `node1` to `node2`.
|
||||
*/
|
||||
predicate certIsZero(
|
||||
SSLGetPeerCertificateCall getCertCall, ControlFlowNode node1, ControlFlowNode node2
|
||||
) {
|
||||
exists(Expr cert | cert = globalValueNumber(getCertCall).getAnExpr() |
|
||||
exists(GuardCondition guard, Expr zero |
|
||||
zero.getValue().toInt() = 0 and
|
||||
node1 = guard and
|
||||
(
|
||||
// if (cert == zero) {
|
||||
guard.comparesEq(cert, zero, 0, true, true) and
|
||||
node2 = guard.getATrueSuccessor()
|
||||
or
|
||||
// if (cert != zero) { }
|
||||
guard.comparesEq(cert, zero, 0, false, true) and
|
||||
node2 = guard.getAFalseSuccessor()
|
||||
)
|
||||
)
|
||||
or
|
||||
(
|
||||
// if (cert) { }
|
||||
node1 = cert
|
||||
or
|
||||
// if (!cert) {
|
||||
node1.(NotExpr).getAChild() = cert
|
||||
) and
|
||||
node2 = node1.getASuccessor() and
|
||||
not cert.(GuardCondition).controls(node2, true) // cert may be false
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the SSL object passed into `SSL_get_peer_certificate` has not been checked with
|
||||
* `SSL_get_verify_result` at `node`. Note that this is only computed at the call to
|
||||
* `SSL_get_peer_certificate` and at the start and end of `BasicBlock`s.
|
||||
*/
|
||||
predicate certNotChecked(SSLGetPeerCertificateCall getCertCall, ControlFlowNode node) {
|
||||
// cert is not checked at the call to `SSL_get_peer_certificate`
|
||||
node = getCertCall
|
||||
or
|
||||
exists(BasicBlock bb, int pos |
|
||||
// flow to end of a `BasicBlock`
|
||||
certNotChecked(getCertCall, bb.getNode(pos)) and
|
||||
node = bb.getEnd() and
|
||||
// check for barrier node
|
||||
not exists(int pos2 |
|
||||
pos2 > pos and
|
||||
resultIsChecked(getCertCall, bb.getNode(pos2))
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(BasicBlock pred, BasicBlock bb |
|
||||
// flow from the end of one `BasicBlock` to the beginning of a successor
|
||||
certNotChecked(getCertCall, pred.getEnd()) and
|
||||
bb = pred.getASuccessor() and
|
||||
node = bb.getStart() and
|
||||
// check for barrier bb
|
||||
not certIsZero(getCertCall, pred.getEnd(), bb.getStart())
|
||||
)
|
||||
}
|
||||
|
||||
from SSLGetPeerCertificateCall getCertCall, ControlFlowNode node
|
||||
where
|
||||
certNotChecked(getCertCall, node) and
|
||||
node instanceof Function // (function exit)
|
||||
select getCertCall,
|
||||
"This " + getCertCall.toString() + " is not followed by a call to SSL_get_verify_result."
|
||||
@@ -0,0 +1,5 @@
|
||||
// ...
|
||||
|
||||
X509 *cert = SSL_get_peer_certificate(ssl); // BAD (SSL_get_verify_result is never called)
|
||||
|
||||
// ...
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user