Compare commits

...

52 Commits

Author SHA1 Message Date
Philip Ginsbach
065d8a60af use new meaning of super keyword 2021-05-13 11:36:01 +01:00
Philip Ginsbach
8cdd8b6ae0 use instanceof extensions in javascript 2021-05-12 18:58:45 +01:00
Erik Krogh Kristensen
0194af9432 convert field based range pattern to casting based range pattern 2021-05-12 16:49:43 +02:00
Anders Schack-Mulligen
7974e3ad38 Merge pull request #5883 from zbazztian/consider-boxed-booleans-to-avoid-xxe-fps
Consider boxed booleans to avoid false positives for XXE.ql
2021-05-12 12:51:22 +02:00
Sebastian Bauersfeld
b05512a958 Add change notes. 2021-05-12 16:58:24 +07:00
Sebastian Bauersfeld
bf4d88175c Consider boxed booleans to avoid false positives for XXE.ql 2021-05-12 16:40:00 +07:00
Geoffrey White
8f152b7380 Merge pull request #5877 from MathiasVP/detect-more-abs-in-overflow-library
C++: Detect more uses of `abs`
2021-05-12 10:02:12 +01:00
Tom Hvitved
fc121e1cbd Merge pull request #5865 from tamasvajk/feature/remove-base-class-dependency-id
C#: Remove base class from type IDs in trap files
2021-05-12 10:30:31 +02:00
Anders Schack-Mulligen
a247ae4357 Merge pull request #5843 from JLLeitschuh/feat/JLL/improve_kryo_support
[Java] Fix Kryo FP & Kryo 5 Support
2021-05-12 09:52:24 +02:00
Anders Schack-Mulligen
74ae2e0857 Merge pull request #5773 from hvitved/dataflow/aggressive-caching
Data flow: Cache most language-dependent predicates
2021-05-12 09:41:55 +02:00
Tamas Vajk
8e371fd05a Adjust expected IR test file 2021-05-11 21:54:05 +02:00
Mathias Vorreiter Pedersen
948f1d8e34 C++: Add testcase with INTMAX_MIN. 2021-05-11 19:43:21 +02:00
Geoffrey White
d7e560c611 Merge pull request #5767 from ihsinme/ihsinme-patch-268
CPP: Add query for CWE-1126: Declaration of Variable with Unnecessarily Wide Scope
2021-05-11 15:24:25 +01:00
Mathias Vorreiter Pedersen
3e21f479a9 C++: Add change-note. 2021-05-11 14:58:48 +02:00
Tom Hvitved
d66506b0a3 Data flow: Rename {Argument,Parameter}NodeExt to {Arg,Param}Node 2021-05-11 14:40:10 +02:00
Mathias Vorreiter Pedersen
48e783184c C++: Fix false positive by recognizing more absolute value functions in Overflow.qll 2021-05-11 14:30:28 +02:00
Jonathan Leitschuh
0d9a85ca6b Update java/change-notes/2021-05-05-kryo-improvements.md
Co-authored-by: Anders Schack-Mulligen <aschackmull@users.noreply.github.com>
2021-05-11 08:29:50 -04:00
Mathias Vorreiter Pedersen
24d8abd2c2 C++: Add false positive testcase when an absolute value is used in comparison. 2021-05-11 14:27:53 +02:00
Tamas Vajk
717070c7e4 Fix/cleanup passed and default arguments values 2021-05-11 13:11:35 +02:00
Jonathan Leitschuh
d27316eb3e Apply suggestions from code review
Co-authored-by: Marcono1234 <Marcono1234@users.noreply.github.com>
2021-05-10 11:55:31 -04:00
Tamas Vajk
dd86da3f24 C#: Remove base class from type IDs in trap files 2021-05-10 17:06:10 +02:00
Tamas Vajk
31ac6442e8 C#: Fix default parameter value generation in case of error symbols 2021-05-10 17:03:08 +02:00
ihsinme
9e5a38debd Update DeclarationOfVariableWithUnnecessarilyWideScope.expected 2021-05-10 14:17:40 +03:00
ihsinme
d3c6093f37 Update test.c 2021-05-10 14:16:38 +03:00
ihsinme
c8f2937df9 Update DeclarationOfVariableWithUnnecessarilyWideScope.ql 2021-05-10 14:16:11 +03:00
Jonathan Leitschuh
67e9f06304 [Java] Fix Kryo FP & Kryo 5 Support
Closes #4992
2021-05-05 17:38:34 -04:00
ihsinme
976ccda135 Update DeclarationOfVariableWithUnnecessarilyWideScope.ql 2021-05-05 23:34:21 +03:00
ihsinme
b277082462 Update DeclarationOfVariableWithUnnecessarilyWideScope.qhelp 2021-05-05 23:28:04 +03:00
ihsinme
bb97507ebc Update test.c 2021-05-02 22:59:56 +03:00
ihsinme
21f43252e6 Update DeclarationOfVariableWithUnnecessarilyWideScope.expected 2021-05-02 22:59:04 +03:00
ihsinme
0935c5a0f2 Update DeclarationOfVariableWithUnnecessarilyWideScope.ql 2021-05-02 22:58:30 +03:00
ihsinme
8c3980d80b Update cpp/ql/src/experimental/Security/CWE/CWE-1126/DeclarationOfVariableWithUnnecessarilyWideScope.c
Co-authored-by: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
2021-05-02 22:54:43 +03:00
Tom Hvitved
c35a2b959a Python: Update data-flow caching 2021-04-28 14:49:05 +02:00
Tom Hvitved
e8347c2c20 C++: Update data-flow caching 2021-04-28 14:49:05 +02:00
Tom Hvitved
bd0a196a39 Java: Update data-flow caching 2021-04-27 19:06:39 +02:00
Tom Hvitved
befc80b3cb C#: Update data-flow caching 2021-04-27 19:06:39 +02:00
Tom Hvitved
914184f3dd Data flow: Sync files 2021-04-27 19:06:39 +02:00
Tom Hvitved
0c8886967b Data flow: Cache nodeIsHidden 2021-04-27 19:05:11 +02:00
Tom Hvitved
1112c0f994 Data flow: Cache ParameterNode 2021-04-27 19:05:11 +02:00
Tom Hvitved
7d4feaca2f Data flow: Cache ArgumentNode 2021-04-27 19:05:11 +02:00
Tom Hvitved
ade99c2c2b Data flow: Cache Cast(ing)Node 2021-04-27 19:05:11 +02:00
Tom Hvitved
346af4f97a Data flow: Cache ReturnNodeExt 2021-04-27 19:05:10 +02:00
Tom Hvitved
9738de2cb9 Data flow: Cache OutNodeExt 2021-04-27 19:05:10 +02:00
Tom Hvitved
23113c4ff7 Data flow: Cache isUnreachableInCall 2021-04-27 19:05:10 +02:00
Tom Hvitved
1bf0e01a83 Data flow: Cache clearsContent 2021-04-27 19:05:10 +02:00
Tom Hvitved
4009c01558 Data flow: Cache readStep 2021-04-27 19:05:10 +02:00
Tom Hvitved
96aa182893 Data flow: Cache jumpStep 2021-04-27 19:05:10 +02:00
Tom Hvitved
8bfeae768f Data flow: Cache simpleLocalFlowStep 2021-04-27 19:05:10 +02:00
Tom Hvitved
1a56f0b79c Data flow: Cache getNodeType 2021-04-27 19:05:10 +02:00
Tom Hvitved
044c92016b Data flow: Cache enclosing callable predicates 2021-04-27 19:05:09 +02:00
ihsinme
98f7f70814 Add files via upload 2021-04-25 22:35:40 +03:00
ihsinme
50c63a88c3 Add files via upload 2021-04-25 22:34:41 +03:00
90 changed files with 8048 additions and 3420 deletions

View File

@@ -0,0 +1,2 @@
lgtm
* The `cpp/tainted-arithmetic`, `cpp/arithmetic-with-extreme-values`, and `cpp/uncontrolled-arithmetic` queries now recognize more functions as returning the absolute value of their input. As a result, they produce fewer false positives.

View File

@@ -0,0 +1,14 @@
while(intIndex > 2)
{
...
intIndex--;
...
} // GOOD: correct cycle
...
while(intIndex > 2)
{
...
int intIndex;
intIndex--;
...
} // BAD: the variable used in the condition does not change.

View File

@@ -0,0 +1,26 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Using variables with the same name is dangerous. However, such a situation inside the while loop can create an infinite loop exhausting resources. Requires the attention of developers.</p>
</overview>
<recommendation>
<p>We recommend not to use local variables inside a loop if their names are the same as the variables in the condition of this loop.</p>
</recommendation>
<example>
<p>The following example demonstrates an erroneous and corrected use of a local variable within a loop.</p>
<sample src="DeclarationOfVariableWithUnnecessarilyWideScope.c" />
</example>
<references>
<li>
CERT C Coding Standard:
<a href="https://wiki.sei.cmu.edu/confluence/display/c/DCL01-C.+Do+not+reuse+variable+names+in+subscopes">DCL01-C. Do not reuse variable names in subscopes</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,60 @@
/**
* @name Errors When Using Variable Declaration Inside Loop
* @description Using variables with the same name is dangerous.
* However, such a situation inside the while loop can create an infinite loop exhausting resources.
* Requires the attention of developers.
* @kind problem
* @id cpp/errors-when-using-variable-declaration-inside-loop
* @problem.severity warning
* @precision medium
* @tags correctness
* security
* external/cwe/cwe-1126
*/
import cpp
/**
* Errors when using a variable declaration inside a loop.
*/
class DangerousWhileLoop extends WhileStmt {
Expr exp;
Declaration dl;
DangerousWhileLoop() {
this = dl.getParentScope().(BlockStmt).getParent*() and
exp = this.getCondition().getAChild*() and
not exp instanceof PointerFieldAccess and
not exp instanceof ValueFieldAccess and
exp.(VariableAccess).getTarget().getName() = dl.getName() and
not exp.getParent*() instanceof FunctionCall
}
Declaration getDeclaration() { result = dl }
/** Holds when there are changes to the variables involved in the condition. */
predicate isUseThisVariable() {
exists(Variable v |
this.getCondition().getAChild*().(VariableAccess).getTarget() = v and
(
exists(Assignment aexp |
this = aexp.getEnclosingStmt().getParentStmt*() and
(
aexp.getLValue().(ArrayExpr).getArrayBase().(VariableAccess).getTarget() = v
or
aexp.getLValue().(VariableAccess).getTarget() = v
)
)
or
exists(CrementOperation crm |
this = crm.getEnclosingStmt().getParentStmt*() and
crm.getOperand().(VariableAccess).getTarget() = v
)
)
)
}
}
from DangerousWhileLoop lp
where not lp.isUseThisVariable()
select lp.getDeclaration(), "A variable with this name is used in the $@ condition.", lp, "loop"

View File

@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`. * Holds if data can flow in one local step from `node1` to `node2`.
*/ */
private predicate localFlowStep(Node node1, Node node2, Configuration config) { private predicate localFlowStep(Node node1, Node node2, Configuration config) {
( simpleLocalFlowStepExt(node1, node2) and
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts. * Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/ */
private predicate jumpStep(Node node1, Node node2, Configuration config) { private predicate jumpStep(Node node1, Node node2, Configuration config) {
jumpStep(node1, node2) and jumpStepCached(node1, node2) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) { private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
exists(ArgumentNode arg | exists(ArgNode arg |
fwdFlow(arg, cc, config) and fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg) viableParamArg(call, _, arg)
) )
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic] pragma[nomagic]
predicate viableParamArgNodeCandFwd1( predicate viableParamArgNodeCandFwd1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
viableParamArg(call, p, arg) and viableParamArg(call, p, arg) and
fwdFlow(arg, config) fwdFlow(arg, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config exists(ParamNode p |
) {
exists(ParameterNode p |
revFlow(p, toReturn, config) and revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config) viableParamArgNodeCandFwd1(call, p, arg, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config) revFlowIn(call, arg, true, config)
} }
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a * Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic] pragma[nomagic]
private predicate viableParamArgNodeCand1( private predicate viableParamArgNodeCand1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config) Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) { ) {
viableParamArgNodeCand1(call, p, arg, config) and viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, arg, p, config) and flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j | exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config) PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
) )
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand2( private predicate flowIntoCallNodeCand2(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/ */
private class FlowCheckNode extends Node { private class FlowCheckNode extends Node {
FlowCheckNode() { FlowCheckNode() {
this instanceof CastNode or castNode(this) or
clearsContent(this, _) clearsContentCached(this, _)
} }
} }
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or config.isSource(node) or
jumpStep(_, node, config) or jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or additionalJumpStep(_, node, config) or
node instanceof ParameterNode or node instanceof ParamNode or
node instanceof OutNodeExt or node instanceof OutNodeExt or
store(_, _, node, _) or store(_, _, node, _) or
read(_, _, node) or read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc LocalCallContext cc
) { ) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
( (
localFlowEntry(node1, pragma[only_bind_into](config)) and localFlowEntry(node1, pragma[only_bind_into](config)) and
( (
localFlowStepNodeCand1(node1, node2, config) and localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and preservesValue = true and
t = getNodeType(node1) t = getNodeDataFlowType(node1)
or or
additionalLocalFlowStepNodeCand2(node1, node2, config) and additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) t = getNodeDataFlowType(node2)
) and ) and
node1 != node2 and node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
or or
exists(Node mid | exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and not mid instanceof FlowCheckNode and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) and t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
) )
) )
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() } private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap] bindingset[node, ap]
private predicate filter(Node node, Ap ap) { private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and not ap.isClearedAt(node) and
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() if node instanceof CastingNode
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
} }
bindingset[ap, contentType] bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() } private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCall( private predicate flowIntoCall(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx = private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParameterNode p, AccessPath ap) { TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _) Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
} }
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */ /** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
private ParameterNode p; private ParamNode p;
private AccessPath ap; private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) } SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and config.isSource(node) and
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
// ... or a step from an existing PathNode to another node. // ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid | exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() } Configuration getConfiguration() { none() }
private predicate isHidden() { private predicate isHidden() {
nodeIsHidden(this.getNode()) and hiddenNode(this.getNode()) and
not this.isSource() and not this.isSource() and
not this instanceof PathNodeSink not this instanceof PathNodeSink
} }
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and mid.getAp() instanceof AccessPathNil and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx() sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg( private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand( private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i) p.isParameterOf(callable, i)
) )
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively. * respectively.
*/ */
private predicate pathIntoCallable( private predicate pathIntoCallable(
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call DataFlowCall call
) { ) {
exists(int i, DataFlowCallable callable, AccessPath ap | exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 = private newtype TSummaryCtx1 =
TSummaryCtx1None() or TSummaryCtx1None() or
TSummaryCtx1Param(ParameterNode p) TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 = private newtype TSummaryCtx2 =
TSummaryCtx2None() or TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
exists(config.explorationLimit()) exists(config.explorationLimit())
or or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or or
exists(PartialPathNodeRev mid | exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit() distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
) )
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid | exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not clearsContent(node, ap.getHead().getContent()) and not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode if node instanceof CastingNode
then compatibleTypes(getNodeType(node), ap.getType()) then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any() else any()
) )
} }
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
( (
localFlowStep(mid.getNode(), node, config) and localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
) )
or or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
or or
partialPathStoreStep(mid, _, _, node, ap) and partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getNodeType(node)) compatibleTypes(ap.getType(), getNodeDataFlowType(node))
) )
or or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap, PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
} }
private predicate partialPathIntoCallable( private predicate partialPathIntoCallable(
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc, PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap, TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc, DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 | exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config) paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
) )
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config) apConsRev(ap, c, ap0, config)
) )
or or
exists(ParameterNode p | exists(ParamNode p |
mid.getNode() = p and mid.getNode() = p and
viableParamArg(_, p, node) and viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap, int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(PartialPathNodeRev mid, ParameterNode p | exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and mid.getNode() = p and
p.isParameterOf(_, pos) and p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic] pragma[nomagic]
private predicate revPartialPathThroughCallable( private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) { ) {
exists(DataFlowCall call, int pos | exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and revPartialPathThroughCallable0(call, mid, pos, ap, config) and

View File

@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`. * Holds if data can flow in one local step from `node1` to `node2`.
*/ */
private predicate localFlowStep(Node node1, Node node2, Configuration config) { private predicate localFlowStep(Node node1, Node node2, Configuration config) {
( simpleLocalFlowStepExt(node1, node2) and
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts. * Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/ */
private predicate jumpStep(Node node1, Node node2, Configuration config) { private predicate jumpStep(Node node1, Node node2, Configuration config) {
jumpStep(node1, node2) and jumpStepCached(node1, node2) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) { private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
exists(ArgumentNode arg | exists(ArgNode arg |
fwdFlow(arg, cc, config) and fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg) viableParamArg(call, _, arg)
) )
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic] pragma[nomagic]
predicate viableParamArgNodeCandFwd1( predicate viableParamArgNodeCandFwd1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
viableParamArg(call, p, arg) and viableParamArg(call, p, arg) and
fwdFlow(arg, config) fwdFlow(arg, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config exists(ParamNode p |
) {
exists(ParameterNode p |
revFlow(p, toReturn, config) and revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config) viableParamArgNodeCandFwd1(call, p, arg, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config) revFlowIn(call, arg, true, config)
} }
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a * Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic] pragma[nomagic]
private predicate viableParamArgNodeCand1( private predicate viableParamArgNodeCand1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config) Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) { ) {
viableParamArgNodeCand1(call, p, arg, config) and viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, arg, p, config) and flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j | exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config) PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
) )
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand2( private predicate flowIntoCallNodeCand2(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/ */
private class FlowCheckNode extends Node { private class FlowCheckNode extends Node {
FlowCheckNode() { FlowCheckNode() {
this instanceof CastNode or castNode(this) or
clearsContent(this, _) clearsContentCached(this, _)
} }
} }
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or config.isSource(node) or
jumpStep(_, node, config) or jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or additionalJumpStep(_, node, config) or
node instanceof ParameterNode or node instanceof ParamNode or
node instanceof OutNodeExt or node instanceof OutNodeExt or
store(_, _, node, _) or store(_, _, node, _) or
read(_, _, node) or read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc LocalCallContext cc
) { ) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
( (
localFlowEntry(node1, pragma[only_bind_into](config)) and localFlowEntry(node1, pragma[only_bind_into](config)) and
( (
localFlowStepNodeCand1(node1, node2, config) and localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and preservesValue = true and
t = getNodeType(node1) t = getNodeDataFlowType(node1)
or or
additionalLocalFlowStepNodeCand2(node1, node2, config) and additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) t = getNodeDataFlowType(node2)
) and ) and
node1 != node2 and node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
or or
exists(Node mid | exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and not mid instanceof FlowCheckNode and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) and t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
) )
) )
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() } private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap] bindingset[node, ap]
private predicate filter(Node node, Ap ap) { private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and not ap.isClearedAt(node) and
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() if node instanceof CastingNode
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
} }
bindingset[ap, contentType] bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() } private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCall( private predicate flowIntoCall(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx = private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParameterNode p, AccessPath ap) { TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _) Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
} }
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */ /** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
private ParameterNode p; private ParamNode p;
private AccessPath ap; private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) } SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and config.isSource(node) and
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
// ... or a step from an existing PathNode to another node. // ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid | exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() } Configuration getConfiguration() { none() }
private predicate isHidden() { private predicate isHidden() {
nodeIsHidden(this.getNode()) and hiddenNode(this.getNode()) and
not this.isSource() and not this.isSource() and
not this instanceof PathNodeSink not this instanceof PathNodeSink
} }
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and mid.getAp() instanceof AccessPathNil and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx() sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg( private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand( private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i) p.isParameterOf(callable, i)
) )
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively. * respectively.
*/ */
private predicate pathIntoCallable( private predicate pathIntoCallable(
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call DataFlowCall call
) { ) {
exists(int i, DataFlowCallable callable, AccessPath ap | exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 = private newtype TSummaryCtx1 =
TSummaryCtx1None() or TSummaryCtx1None() or
TSummaryCtx1Param(ParameterNode p) TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 = private newtype TSummaryCtx2 =
TSummaryCtx2None() or TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
exists(config.explorationLimit()) exists(config.explorationLimit())
or or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or or
exists(PartialPathNodeRev mid | exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit() distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
) )
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid | exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not clearsContent(node, ap.getHead().getContent()) and not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode if node instanceof CastingNode
then compatibleTypes(getNodeType(node), ap.getType()) then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any() else any()
) )
} }
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
( (
localFlowStep(mid.getNode(), node, config) and localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
) )
or or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
or or
partialPathStoreStep(mid, _, _, node, ap) and partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getNodeType(node)) compatibleTypes(ap.getType(), getNodeDataFlowType(node))
) )
or or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap, PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
} }
private predicate partialPathIntoCallable( private predicate partialPathIntoCallable(
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc, PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap, TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc, DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 | exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config) paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
) )
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config) apConsRev(ap, c, ap0, config)
) )
or or
exists(ParameterNode p | exists(ParamNode p |
mid.getNode() = p and mid.getNode() = p and
viableParamArg(_, p, node) and viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap, int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(PartialPathNodeRev mid, ParameterNode p | exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and mid.getNode() = p and
p.isParameterOf(_, pos) and p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic] pragma[nomagic]
private predicate revPartialPathThroughCallable( private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) { ) {
exists(DataFlowCall call, int pos | exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and revPartialPathThroughCallable0(call, mid, pos, ap, config) and

View File

@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`. * Holds if data can flow in one local step from `node1` to `node2`.
*/ */
private predicate localFlowStep(Node node1, Node node2, Configuration config) { private predicate localFlowStep(Node node1, Node node2, Configuration config) {
( simpleLocalFlowStepExt(node1, node2) and
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts. * Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/ */
private predicate jumpStep(Node node1, Node node2, Configuration config) { private predicate jumpStep(Node node1, Node node2, Configuration config) {
jumpStep(node1, node2) and jumpStepCached(node1, node2) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) { private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
exists(ArgumentNode arg | exists(ArgNode arg |
fwdFlow(arg, cc, config) and fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg) viableParamArg(call, _, arg)
) )
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic] pragma[nomagic]
predicate viableParamArgNodeCandFwd1( predicate viableParamArgNodeCandFwd1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
viableParamArg(call, p, arg) and viableParamArg(call, p, arg) and
fwdFlow(arg, config) fwdFlow(arg, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config exists(ParamNode p |
) {
exists(ParameterNode p |
revFlow(p, toReturn, config) and revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config) viableParamArgNodeCandFwd1(call, p, arg, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config) revFlowIn(call, arg, true, config)
} }
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a * Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic] pragma[nomagic]
private predicate viableParamArgNodeCand1( private predicate viableParamArgNodeCand1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config) Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) { ) {
viableParamArgNodeCand1(call, p, arg, config) and viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, arg, p, config) and flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j | exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config) PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
) )
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand2( private predicate flowIntoCallNodeCand2(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/ */
private class FlowCheckNode extends Node { private class FlowCheckNode extends Node {
FlowCheckNode() { FlowCheckNode() {
this instanceof CastNode or castNode(this) or
clearsContent(this, _) clearsContentCached(this, _)
} }
} }
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or config.isSource(node) or
jumpStep(_, node, config) or jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or additionalJumpStep(_, node, config) or
node instanceof ParameterNode or node instanceof ParamNode or
node instanceof OutNodeExt or node instanceof OutNodeExt or
store(_, _, node, _) or store(_, _, node, _) or
read(_, _, node) or read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc LocalCallContext cc
) { ) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
( (
localFlowEntry(node1, pragma[only_bind_into](config)) and localFlowEntry(node1, pragma[only_bind_into](config)) and
( (
localFlowStepNodeCand1(node1, node2, config) and localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and preservesValue = true and
t = getNodeType(node1) t = getNodeDataFlowType(node1)
or or
additionalLocalFlowStepNodeCand2(node1, node2, config) and additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) t = getNodeDataFlowType(node2)
) and ) and
node1 != node2 and node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
or or
exists(Node mid | exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and not mid instanceof FlowCheckNode and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) and t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
) )
) )
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() } private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap] bindingset[node, ap]
private predicate filter(Node node, Ap ap) { private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and not ap.isClearedAt(node) and
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() if node instanceof CastingNode
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
} }
bindingset[ap, contentType] bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() } private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCall( private predicate flowIntoCall(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx = private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParameterNode p, AccessPath ap) { TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _) Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
} }
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */ /** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
private ParameterNode p; private ParamNode p;
private AccessPath ap; private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) } SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and config.isSource(node) and
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
// ... or a step from an existing PathNode to another node. // ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid | exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() } Configuration getConfiguration() { none() }
private predicate isHidden() { private predicate isHidden() {
nodeIsHidden(this.getNode()) and hiddenNode(this.getNode()) and
not this.isSource() and not this.isSource() and
not this instanceof PathNodeSink not this instanceof PathNodeSink
} }
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and mid.getAp() instanceof AccessPathNil and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx() sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg( private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand( private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i) p.isParameterOf(callable, i)
) )
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively. * respectively.
*/ */
private predicate pathIntoCallable( private predicate pathIntoCallable(
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call DataFlowCall call
) { ) {
exists(int i, DataFlowCallable callable, AccessPath ap | exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 = private newtype TSummaryCtx1 =
TSummaryCtx1None() or TSummaryCtx1None() or
TSummaryCtx1Param(ParameterNode p) TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 = private newtype TSummaryCtx2 =
TSummaryCtx2None() or TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
exists(config.explorationLimit()) exists(config.explorationLimit())
or or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or or
exists(PartialPathNodeRev mid | exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit() distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
) )
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid | exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not clearsContent(node, ap.getHead().getContent()) and not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode if node instanceof CastingNode
then compatibleTypes(getNodeType(node), ap.getType()) then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any() else any()
) )
} }
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
( (
localFlowStep(mid.getNode(), node, config) and localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
) )
or or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
or or
partialPathStoreStep(mid, _, _, node, ap) and partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getNodeType(node)) compatibleTypes(ap.getType(), getNodeDataFlowType(node))
) )
or or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap, PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
} }
private predicate partialPathIntoCallable( private predicate partialPathIntoCallable(
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc, PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap, TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc, DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 | exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config) paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
) )
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config) apConsRev(ap, c, ap0, config)
) )
or or
exists(ParameterNode p | exists(ParamNode p |
mid.getNode() = p and mid.getNode() = p and
viableParamArg(_, p, node) and viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap, int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(PartialPathNodeRev mid, ParameterNode p | exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and mid.getNode() = p and
p.isParameterOf(_, pos) and p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic] pragma[nomagic]
private predicate revPartialPathThroughCallable( private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) { ) {
exists(DataFlowCall call, int pos | exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and revPartialPathThroughCallable0(call, mid, pos, ap, config) and

View File

@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`. * Holds if data can flow in one local step from `node1` to `node2`.
*/ */
private predicate localFlowStep(Node node1, Node node2, Configuration config) { private predicate localFlowStep(Node node1, Node node2, Configuration config) {
( simpleLocalFlowStepExt(node1, node2) and
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts. * Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/ */
private predicate jumpStep(Node node1, Node node2, Configuration config) { private predicate jumpStep(Node node1, Node node2, Configuration config) {
jumpStep(node1, node2) and jumpStepCached(node1, node2) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) { private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
exists(ArgumentNode arg | exists(ArgNode arg |
fwdFlow(arg, cc, config) and fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg) viableParamArg(call, _, arg)
) )
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic] pragma[nomagic]
predicate viableParamArgNodeCandFwd1( predicate viableParamArgNodeCandFwd1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
viableParamArg(call, p, arg) and viableParamArg(call, p, arg) and
fwdFlow(arg, config) fwdFlow(arg, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config exists(ParamNode p |
) {
exists(ParameterNode p |
revFlow(p, toReturn, config) and revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config) viableParamArgNodeCandFwd1(call, p, arg, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config) revFlowIn(call, arg, true, config)
} }
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a * Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic] pragma[nomagic]
private predicate viableParamArgNodeCand1( private predicate viableParamArgNodeCand1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config) Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) { ) {
viableParamArgNodeCand1(call, p, arg, config) and viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, arg, p, config) and flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j | exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config) PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
) )
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand2( private predicate flowIntoCallNodeCand2(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/ */
private class FlowCheckNode extends Node { private class FlowCheckNode extends Node {
FlowCheckNode() { FlowCheckNode() {
this instanceof CastNode or castNode(this) or
clearsContent(this, _) clearsContentCached(this, _)
} }
} }
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or config.isSource(node) or
jumpStep(_, node, config) or jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or additionalJumpStep(_, node, config) or
node instanceof ParameterNode or node instanceof ParamNode or
node instanceof OutNodeExt or node instanceof OutNodeExt or
store(_, _, node, _) or store(_, _, node, _) or
read(_, _, node) or read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc LocalCallContext cc
) { ) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
( (
localFlowEntry(node1, pragma[only_bind_into](config)) and localFlowEntry(node1, pragma[only_bind_into](config)) and
( (
localFlowStepNodeCand1(node1, node2, config) and localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and preservesValue = true and
t = getNodeType(node1) t = getNodeDataFlowType(node1)
or or
additionalLocalFlowStepNodeCand2(node1, node2, config) and additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) t = getNodeDataFlowType(node2)
) and ) and
node1 != node2 and node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
or or
exists(Node mid | exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and not mid instanceof FlowCheckNode and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) and t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
) )
) )
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() } private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap] bindingset[node, ap]
private predicate filter(Node node, Ap ap) { private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and not ap.isClearedAt(node) and
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() if node instanceof CastingNode
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
} }
bindingset[ap, contentType] bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() } private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCall( private predicate flowIntoCall(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx = private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParameterNode p, AccessPath ap) { TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _) Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
} }
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */ /** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
private ParameterNode p; private ParamNode p;
private AccessPath ap; private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) } SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and config.isSource(node) and
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
// ... or a step from an existing PathNode to another node. // ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid | exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() } Configuration getConfiguration() { none() }
private predicate isHidden() { private predicate isHidden() {
nodeIsHidden(this.getNode()) and hiddenNode(this.getNode()) and
not this.isSource() and not this.isSource() and
not this instanceof PathNodeSink not this instanceof PathNodeSink
} }
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and mid.getAp() instanceof AccessPathNil and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx() sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg( private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand( private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i) p.isParameterOf(callable, i)
) )
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively. * respectively.
*/ */
private predicate pathIntoCallable( private predicate pathIntoCallable(
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call DataFlowCall call
) { ) {
exists(int i, DataFlowCallable callable, AccessPath ap | exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 = private newtype TSummaryCtx1 =
TSummaryCtx1None() or TSummaryCtx1None() or
TSummaryCtx1Param(ParameterNode p) TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 = private newtype TSummaryCtx2 =
TSummaryCtx2None() or TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
exists(config.explorationLimit()) exists(config.explorationLimit())
or or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or or
exists(PartialPathNodeRev mid | exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit() distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
) )
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid | exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not clearsContent(node, ap.getHead().getContent()) and not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode if node instanceof CastingNode
then compatibleTypes(getNodeType(node), ap.getType()) then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any() else any()
) )
} }
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
( (
localFlowStep(mid.getNode(), node, config) and localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
) )
or or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
or or
partialPathStoreStep(mid, _, _, node, ap) and partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getNodeType(node)) compatibleTypes(ap.getType(), getNodeDataFlowType(node))
) )
or or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap, PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
} }
private predicate partialPathIntoCallable( private predicate partialPathIntoCallable(
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc, PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap, TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc, DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 | exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config) paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
) )
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config) apConsRev(ap, c, ap0, config)
) )
or or
exists(ParameterNode p | exists(ParamNode p |
mid.getNode() = p and mid.getNode() = p and
viableParamArg(_, p, node) and viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap, int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(PartialPathNodeRev mid, ParameterNode p | exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and mid.getNode() = p and
p.isParameterOf(_, pos) and p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic] pragma[nomagic]
private predicate revPartialPathThroughCallable( private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) { ) {
exists(DataFlowCall call, int pos | exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and revPartialPathThroughCallable0(call, mid, pos, ap, config) and

View File

@@ -35,22 +35,22 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
* calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly. * calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly.
*/ */
private module LambdaFlow { private module LambdaFlow {
private predicate viableParamNonLambda(DataFlowCall call, int i, ParameterNode p) { private predicate viableParamNonLambda(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallable(call), i) p.isParameterOf(viableCallable(call), i)
} }
private predicate viableParamLambda(DataFlowCall call, int i, ParameterNode p) { private predicate viableParamLambda(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallableLambda(call, _), i) p.isParameterOf(viableCallableLambda(call, _), i)
} }
private predicate viableParamArgNonLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) { private predicate viableParamArgNonLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i | exists(int i |
viableParamNonLambda(call, i, p) and viableParamNonLambda(call, i, p) and
arg.argumentOf(call, i) arg.argumentOf(call, i)
) )
} }
private predicate viableParamArgLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) { private predicate viableParamArgLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i | exists(int i |
viableParamLambda(call, i, p) and viableParamLambda(call, i, p) and
arg.argumentOf(call, i) arg.argumentOf(call, i)
@@ -118,8 +118,8 @@ private module LambdaFlow {
boolean toJump, DataFlowCallOption lastCall boolean toJump, DataFlowCallOption lastCall
) { ) {
revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and
if node instanceof CastNode or node instanceof ArgumentNode or node instanceof ReturnNode if castNode(node) or node instanceof ArgNode or node instanceof ReturnNode
then compatibleTypes(t, getNodeType(node)) then compatibleTypes(t, getNodeDataFlowType(node))
else any() else any()
} }
@@ -129,7 +129,7 @@ private module LambdaFlow {
boolean toJump, DataFlowCallOption lastCall boolean toJump, DataFlowCallOption lastCall
) { ) {
lambdaCall(lambdaCall, kind, node) and lambdaCall(lambdaCall, kind, node) and
t = getNodeType(node) and t = getNodeDataFlowType(node) and
toReturn = false and toReturn = false and
toJump = false and toJump = false and
lastCall = TDataFlowCallNone() lastCall = TDataFlowCallNone()
@@ -146,7 +146,7 @@ private module LambdaFlow {
getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid) getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid)
| |
preservesValue = false and preservesValue = false and
t = getNodeType(node) t = getNodeDataFlowType(node)
or or
preservesValue = true and preservesValue = true and
t = t0 t = t0
@@ -160,7 +160,7 @@ private module LambdaFlow {
toJump = true and toJump = true and
lastCall = TDataFlowCallNone() lastCall = TDataFlowCallNone()
| |
jumpStep(node, mid) and jumpStepCached(node, mid) and
t = t0 t = t0
or or
exists(boolean preservesValue | exists(boolean preservesValue |
@@ -168,7 +168,7 @@ private module LambdaFlow {
getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid) getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid)
| |
preservesValue = false and preservesValue = false and
t = getNodeType(node) t = getNodeDataFlowType(node)
or or
preservesValue = true and preservesValue = true and
t = t0 t = t0
@@ -176,7 +176,7 @@ private module LambdaFlow {
) )
or or
// flow into a callable // flow into a callable
exists(ParameterNode p, DataFlowCallOption lastCall0, DataFlowCall call | exists(ParamNode p, DataFlowCallOption lastCall0, DataFlowCall call |
revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and
( (
if lastCall0 = TDataFlowCallNone() and toJump = false if lastCall0 = TDataFlowCallNone() and toJump = false
@@ -227,7 +227,7 @@ private module LambdaFlow {
pragma[nomagic] pragma[nomagic]
predicate revLambdaFlowIn( predicate revLambdaFlowIn(
DataFlowCall lambdaCall, LambdaCallKind kind, ParameterNode p, DataFlowType t, boolean toJump, DataFlowCall lambdaCall, LambdaCallKind kind, ParamNode p, DataFlowType t, boolean toJump,
DataFlowCallOption lastCall DataFlowCallOption lastCall
) { ) {
revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall) revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall)
@@ -242,6 +242,89 @@ private DataFlowCallable viableCallableExt(DataFlowCall call) {
cached cached
private module Cached { private module Cached {
/**
* If needed, call this predicate from `DataFlowImplSpecific.qll` in order to
* force a stage-dependency on the `DataFlowImplCommon.qll` stage and therby
* collapsing the two stages.
*/
cached
predicate forceCachingInSameStage() { any() }
cached
predicate nodeEnclosingCallable(Node n, DataFlowCallable c) { c = n.getEnclosingCallable() }
cached
predicate callEnclosingCallable(DataFlowCall call, DataFlowCallable c) {
c = call.getEnclosingCallable()
}
cached
predicate nodeDataFlowType(Node n, DataFlowType t) { t = getNodeType(n) }
cached
predicate jumpStepCached(Node node1, Node node2) { jumpStep(node1, node2) }
cached
predicate clearsContentCached(Node n, Content c) { clearsContent(n, c) }
cached
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
cached
predicate outNodeExt(Node n) {
n instanceof OutNode
or
n.(PostUpdateNode).getPreUpdateNode() instanceof ArgNode
}
cached
predicate hiddenNode(Node n) { nodeIsHidden(n) }
cached
OutNodeExt getAnOutNodeExt(DataFlowCall call, ReturnKindExt k) {
result = getAnOutNode(call, k.(ValueReturnKind).getKind())
or
exists(ArgNode arg |
result.(PostUpdateNode).getPreUpdateNode() = arg and
arg.argumentOf(call, k.(ParamUpdateReturnKind).getPosition())
)
}
cached
predicate returnNodeExt(Node n, ReturnKindExt k) {
k = TValueReturn(n.(ReturnNode).getKind())
or
exists(ParamNode p, int pos |
parameterValueFlowsToPreUpdate(p, n) and
p.isParameterOf(_, pos) and
k = TParamUpdate(pos)
)
}
cached
predicate castNode(Node n) { n instanceof CastNode }
cached
predicate castingNode(Node n) {
castNode(n) or
n instanceof ParamNode or
n instanceof OutNodeExt or
// For reads, `x.f`, we want to check that the tracked type after the read (which
// is obtained by popping the head of the access path stack) is compatible with
// the type of `x.f`.
read(_, _, n)
}
cached
predicate parameterNode(Node n, DataFlowCallable c, int i) {
n.(ParameterNode).isParameterOf(c, i)
}
cached
predicate argumentNode(Node n, DataFlowCall call, int pos) {
n.(ArgumentNode).argumentOf(call, pos)
}
/** /**
* Gets a viable target for the lambda call `call`. * Gets a viable target for the lambda call `call`.
* *
@@ -261,7 +344,7 @@ private module Cached {
* The instance parameter is considered to have index `-1`. * The instance parameter is considered to have index `-1`.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate viableParam(DataFlowCall call, int i, ParameterNode p) { private predicate viableParam(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallableExt(call), i) p.isParameterOf(viableCallableExt(call), i)
} }
@@ -270,11 +353,11 @@ private module Cached {
* dispatch into account. * dispatch into account.
*/ */
cached cached
predicate viableParamArg(DataFlowCall call, ParameterNode p, ArgumentNode arg) { predicate viableParamArg(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i | exists(int i |
viableParam(call, i, p) and viableParam(call, i, p) and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
compatibleTypes(getNodeType(arg), getNodeType(p)) compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
) )
} }
@@ -312,7 +395,7 @@ private module Cached {
* `read` indicates whether it is contents of `p` that can flow to `node`. * `read` indicates whether it is contents of `p` that can flow to `node`.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate parameterValueFlowCand(ParameterNode p, Node node, boolean read) { private predicate parameterValueFlowCand(ParamNode p, Node node, boolean read) {
p = node and p = node and
read = false read = false
or or
@@ -325,30 +408,30 @@ private module Cached {
// read // read
exists(Node mid | exists(Node mid |
parameterValueFlowCand(p, mid, false) and parameterValueFlowCand(p, mid, false) and
readStep(mid, _, node) and read(mid, _, node) and
read = true read = true
) )
or or
// flow through: no prior read // flow through: no prior read
exists(ArgumentNode arg | exists(ArgNode arg |
parameterValueFlowArgCand(p, arg, false) and parameterValueFlowArgCand(p, arg, false) and
argumentValueFlowsThroughCand(arg, node, read) argumentValueFlowsThroughCand(arg, node, read)
) )
or or
// flow through: no read inside method // flow through: no read inside method
exists(ArgumentNode arg | exists(ArgNode arg |
parameterValueFlowArgCand(p, arg, read) and parameterValueFlowArgCand(p, arg, read) and
argumentValueFlowsThroughCand(arg, node, false) argumentValueFlowsThroughCand(arg, node, false)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate parameterValueFlowArgCand(ParameterNode p, ArgumentNode arg, boolean read) { private predicate parameterValueFlowArgCand(ParamNode p, ArgNode arg, boolean read) {
parameterValueFlowCand(p, arg, read) parameterValueFlowCand(p, arg, read)
} }
pragma[nomagic] pragma[nomagic]
predicate parameterValueFlowsToPreUpdateCand(ParameterNode p, PostUpdateNode n) { predicate parameterValueFlowsToPreUpdateCand(ParamNode p, PostUpdateNode n) {
parameterValueFlowCand(p, n.getPreUpdateNode(), false) parameterValueFlowCand(p, n.getPreUpdateNode(), false)
} }
@@ -360,7 +443,7 @@ private module Cached {
* `read` indicates whether it is contents of `p` that can flow to the return * `read` indicates whether it is contents of `p` that can flow to the return
* node. * node.
*/ */
predicate parameterValueFlowReturnCand(ParameterNode p, ReturnKind kind, boolean read) { predicate parameterValueFlowReturnCand(ParamNode p, ReturnKind kind, boolean read) {
exists(ReturnNode ret | exists(ReturnNode ret |
parameterValueFlowCand(p, ret, read) and parameterValueFlowCand(p, ret, read) and
kind = ret.getKind() kind = ret.getKind()
@@ -369,9 +452,9 @@ private module Cached {
pragma[nomagic] pragma[nomagic]
private predicate argumentValueFlowsThroughCand0( private predicate argumentValueFlowsThroughCand0(
DataFlowCall call, ArgumentNode arg, ReturnKind kind, boolean read DataFlowCall call, ArgNode arg, ReturnKind kind, boolean read
) { ) {
exists(ParameterNode param | viableParamArg(call, param, arg) | exists(ParamNode param | viableParamArg(call, param, arg) |
parameterValueFlowReturnCand(param, kind, read) parameterValueFlowReturnCand(param, kind, read)
) )
} }
@@ -382,14 +465,14 @@ private module Cached {
* *
* `read` indicates whether it is contents of `arg` that can flow to `out`. * `read` indicates whether it is contents of `arg` that can flow to `out`.
*/ */
predicate argumentValueFlowsThroughCand(ArgumentNode arg, Node out, boolean read) { predicate argumentValueFlowsThroughCand(ArgNode arg, Node out, boolean read) {
exists(DataFlowCall call, ReturnKind kind | exists(DataFlowCall call, ReturnKind kind |
argumentValueFlowsThroughCand0(call, arg, kind, read) and argumentValueFlowsThroughCand0(call, arg, kind, read) and
out = getAnOutNode(call, kind) out = getAnOutNode(call, kind)
) )
} }
predicate cand(ParameterNode p, Node n) { predicate cand(ParamNode p, Node n) {
parameterValueFlowCand(p, n, _) and parameterValueFlowCand(p, n, _) and
( (
parameterValueFlowReturnCand(p, _, _) parameterValueFlowReturnCand(p, _, _)
@@ -416,21 +499,21 @@ private module Cached {
* If a read step was taken, then `read` captures the `Content`, the * If a read step was taken, then `read` captures the `Content`, the
* container type, and the content type. * container type, and the content type.
*/ */
predicate parameterValueFlow(ParameterNode p, Node node, ReadStepTypesOption read) { predicate parameterValueFlow(ParamNode p, Node node, ReadStepTypesOption read) {
parameterValueFlow0(p, node, read) and parameterValueFlow0(p, node, read) and
if node instanceof CastingNode if node instanceof CastingNode
then then
// normal flow through // normal flow through
read = TReadStepTypesNone() and read = TReadStepTypesNone() and
compatibleTypes(getNodeType(p), getNodeType(node)) compatibleTypes(getNodeDataFlowType(p), getNodeDataFlowType(node))
or or
// getter // getter
compatibleTypes(read.getContentType(), getNodeType(node)) compatibleTypes(read.getContentType(), getNodeDataFlowType(node))
else any() else any()
} }
pragma[nomagic] pragma[nomagic]
private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) { private predicate parameterValueFlow0(ParamNode p, Node node, ReadStepTypesOption read) {
p = node and p = node and
Cand::cand(p, _) and Cand::cand(p, _) and
read = TReadStepTypesNone() read = TReadStepTypesNone()
@@ -447,7 +530,7 @@ private module Cached {
readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, readStepWithTypes(mid, read.getContainerType(), read.getContent(), node,
read.getContentType()) and read.getContentType()) and
Cand::parameterValueFlowReturnCand(p, _, true) and Cand::parameterValueFlowReturnCand(p, _, true) and
compatibleTypes(getNodeType(p), read.getContainerType()) compatibleTypes(getNodeDataFlowType(p), read.getContainerType())
) )
or or
parameterValueFlow0_0(TReadStepTypesNone(), p, node, read) parameterValueFlow0_0(TReadStepTypesNone(), p, node, read)
@@ -455,34 +538,32 @@ private module Cached {
pragma[nomagic] pragma[nomagic]
private predicate parameterValueFlow0_0( private predicate parameterValueFlow0_0(
ReadStepTypesOption mustBeNone, ParameterNode p, Node node, ReadStepTypesOption read ReadStepTypesOption mustBeNone, ParamNode p, Node node, ReadStepTypesOption read
) { ) {
// flow through: no prior read // flow through: no prior read
exists(ArgumentNode arg | exists(ArgNode arg |
parameterValueFlowArg(p, arg, mustBeNone) and parameterValueFlowArg(p, arg, mustBeNone) and
argumentValueFlowsThrough(arg, read, node) argumentValueFlowsThrough(arg, read, node)
) )
or or
// flow through: no read inside method // flow through: no read inside method
exists(ArgumentNode arg | exists(ArgNode arg |
parameterValueFlowArg(p, arg, read) and parameterValueFlowArg(p, arg, read) and
argumentValueFlowsThrough(arg, mustBeNone, node) argumentValueFlowsThrough(arg, mustBeNone, node)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate parameterValueFlowArg( private predicate parameterValueFlowArg(ParamNode p, ArgNode arg, ReadStepTypesOption read) {
ParameterNode p, ArgumentNode arg, ReadStepTypesOption read
) {
parameterValueFlow(p, arg, read) and parameterValueFlow(p, arg, read) and
Cand::argumentValueFlowsThroughCand(arg, _, _) Cand::argumentValueFlowsThroughCand(arg, _, _)
} }
pragma[nomagic] pragma[nomagic]
private predicate argumentValueFlowsThrough0( private predicate argumentValueFlowsThrough0(
DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read DataFlowCall call, ArgNode arg, ReturnKind kind, ReadStepTypesOption read
) { ) {
exists(ParameterNode param | viableParamArg(call, param, arg) | exists(ParamNode param | viableParamArg(call, param, arg) |
parameterValueFlowReturn(param, kind, read) parameterValueFlowReturn(param, kind, read)
) )
} }
@@ -496,18 +577,18 @@ private module Cached {
* container type, and the content type. * container type, and the content type.
*/ */
pragma[nomagic] pragma[nomagic]
predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) { predicate argumentValueFlowsThrough(ArgNode arg, ReadStepTypesOption read, Node out) {
exists(DataFlowCall call, ReturnKind kind | exists(DataFlowCall call, ReturnKind kind |
argumentValueFlowsThrough0(call, arg, kind, read) and argumentValueFlowsThrough0(call, arg, kind, read) and
out = getAnOutNode(call, kind) out = getAnOutNode(call, kind)
| |
// normal flow through // normal flow through
read = TReadStepTypesNone() and read = TReadStepTypesNone() and
compatibleTypes(getNodeType(arg), getNodeType(out)) compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(out))
or or
// getter // getter
compatibleTypes(getNodeType(arg), read.getContainerType()) and compatibleTypes(getNodeDataFlowType(arg), read.getContainerType()) and
compatibleTypes(read.getContentType(), getNodeType(out)) compatibleTypes(read.getContentType(), getNodeDataFlowType(out))
) )
} }
@@ -516,7 +597,7 @@ private module Cached {
* value-preserving steps and a single read step, not taking call * value-preserving steps and a single read step, not taking call
* contexts into account, thus representing a getter-step. * contexts into account, thus representing a getter-step.
*/ */
predicate getterStep(ArgumentNode arg, Content c, Node out) { predicate getterStep(ArgNode arg, Content c, Node out) {
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out) argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
} }
@@ -529,7 +610,7 @@ private module Cached {
* container type, and the content type. * container type, and the content type.
*/ */
private predicate parameterValueFlowReturn( private predicate parameterValueFlowReturn(
ParameterNode p, ReturnKind kind, ReadStepTypesOption read ParamNode p, ReturnKind kind, ReadStepTypesOption read
) { ) {
exists(ReturnNode ret | exists(ReturnNode ret |
parameterValueFlow(p, ret, read) and parameterValueFlow(p, ret, read) and
@@ -553,7 +634,7 @@ private module Cached {
private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) { private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) {
mayBenefitFromCallContext(call, callable) mayBenefitFromCallContext(call, callable)
or or
callable = call.getEnclosingCallable() and callEnclosingCallable(call, callable) and
exists(viableCallableLambda(call, TDataFlowCallSome(_))) exists(viableCallableLambda(call, TDataFlowCallSome(_)))
} }
@@ -611,7 +692,7 @@ private module Cached {
mayBenefitFromCallContextExt(call, _) and mayBenefitFromCallContextExt(call, _) and
c = viableCallableExt(call) and c = viableCallableExt(call) and
ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContextExt(call, ctx)) and ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContextExt(call, ctx)) and
tgts = strictcount(DataFlowCall ctx | viableCallableExt(ctx) = call.getEnclosingCallable()) and tgts = strictcount(DataFlowCall ctx | callEnclosingCallable(call, viableCallableExt(ctx))) and
ctxtgts < tgts ctxtgts < tgts
) )
} }
@@ -635,8 +716,7 @@ private module Cached {
* Holds if `p` can flow to the pre-update node associated with post-update * Holds if `p` can flow to the pre-update node associated with post-update
* node `n`, in the same callable, using only value-preserving steps. * node `n`, in the same callable, using only value-preserving steps.
*/ */
cached private predicate parameterValueFlowsToPreUpdate(ParamNode p, PostUpdateNode n) {
predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) {
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone()) parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
} }
@@ -644,9 +724,9 @@ private module Cached {
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
) { ) {
storeStep(node1, c, node2) and storeStep(node1, c, node2) and
readStep(_, c, _) and read(_, c, _) and
contentType = getNodeType(node1) and contentType = getNodeDataFlowType(node1) and
containerType = getNodeType(node2) containerType = getNodeDataFlowType(node2)
or or
exists(Node n1, Node n2 | exists(Node n1, Node n2 |
n1 = node1.(PostUpdateNode).getPreUpdateNode() and n1 = node1.(PostUpdateNode).getPreUpdateNode() and
@@ -654,12 +734,15 @@ private module Cached {
| |
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1) argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
or or
readStep(n2, c, n1) and read(n2, c, n1) and
contentType = getNodeType(n1) and contentType = getNodeDataFlowType(n1) and
containerType = getNodeType(n2) containerType = getNodeDataFlowType(n2)
) )
} }
cached
predicate read(Node node1, Content c, Node node2) { readStep(node1, c, node2) }
/** /**
* Holds if data can flow from `node1` to `node2` via a direct assignment to * Holds if data can flow from `node1` to `node2` via a direct assignment to
* `f`. * `f`.
@@ -678,8 +761,9 @@ private module Cached {
* are aliases. A typical example is a function returning `this`, implementing a fluent * are aliases. A typical example is a function returning `this`, implementing a fluent
* interface. * interface.
*/ */
cached private predicate reverseStepThroughInputOutputAlias(
predicate reverseStepThroughInputOutputAlias(PostUpdateNode fromNode, PostUpdateNode toNode) { PostUpdateNode fromNode, PostUpdateNode toNode
) {
exists(Node fromPre, Node toPre | exists(Node fromPre, Node toPre |
fromPre = fromNode.getPreUpdateNode() and fromPre = fromNode.getPreUpdateNode() and
toPre = toNode.getPreUpdateNode() toPre = toNode.getPreUpdateNode()
@@ -688,14 +772,20 @@ private module Cached {
// Does the language-specific simpleLocalFlowStep already model flow // Does the language-specific simpleLocalFlowStep already model flow
// from function input to output? // from function input to output?
fromPre = getAnOutNode(c, _) and fromPre = getAnOutNode(c, _) and
toPre.(ArgumentNode).argumentOf(c, _) and toPre.(ArgNode).argumentOf(c, _) and
simpleLocalFlowStep(toPre.(ArgumentNode), fromPre) simpleLocalFlowStep(toPre.(ArgNode), fromPre)
) )
or or
argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre) argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre)
) )
} }
cached
predicate simpleLocalFlowStepExt(Node node1, Node node2) {
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
}
/** /**
* Holds if the call context `call` either improves virtual dispatch in * Holds if the call context `call` either improves virtual dispatch in
* `callable` or if it allows us to prune unreachable nodes in `callable`. * `callable` or if it allows us to prune unreachable nodes in `callable`.
@@ -704,7 +794,7 @@ private module Cached {
predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) { predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
reducedViableImplInCallContext(_, callable, call) reducedViableImplInCallContext(_, callable, call)
or or
exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCall(n, call)) exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call))
} }
cached cached
@@ -726,12 +816,12 @@ private module Cached {
cached cached
newtype TLocalFlowCallContext = newtype TLocalFlowCallContext =
TAnyLocalCall() or TAnyLocalCall() or
TSpecificLocalCall(DataFlowCall call) { isUnreachableInCall(_, call) } TSpecificLocalCall(DataFlowCall call) { isUnreachableInCallCached(_, call) }
cached cached
newtype TReturnKindExt = newtype TReturnKindExt =
TValueReturn(ReturnKind kind) or TValueReturn(ReturnKind kind) or
TParamUpdate(int pos) { exists(ParameterNode p | p.isParameterOf(_, pos)) } TParamUpdate(int pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
cached cached
newtype TBooleanOption = newtype TBooleanOption =
@@ -761,23 +851,15 @@ private module Cached {
* A `Node` at which a cast can occur such that the type should be checked. * A `Node` at which a cast can occur such that the type should be checked.
*/ */
class CastingNode extends Node { class CastingNode extends Node {
CastingNode() { CastingNode() { castingNode(this) }
this instanceof ParameterNode or
this instanceof CastNode or
this instanceof OutNodeExt or
// For reads, `x.f`, we want to check that the tracked type after the read (which
// is obtained by popping the head of the access path stack) is compatible with
// the type of `x.f`.
readStep(_, _, this)
}
} }
private predicate readStepWithTypes( private predicate readStepWithTypes(
Node n1, DataFlowType container, Content c, Node n2, DataFlowType content Node n1, DataFlowType container, Content c, Node n2, DataFlowType content
) { ) {
readStep(n1, c, n2) and read(n1, c, n2) and
container = getNodeType(n1) and container = getNodeDataFlowType(n1) and
content = getNodeType(n2) content = getNodeDataFlowType(n2)
} }
private newtype TReadStepTypesOption = private newtype TReadStepTypesOption =
@@ -854,7 +936,7 @@ class CallContextSomeCall extends CallContextCall, TSomeCall {
override string toString() { result = "CcSomeCall" } override string toString() { result = "CcSomeCall" }
override predicate relevantFor(DataFlowCallable callable) { override predicate relevantFor(DataFlowCallable callable) {
exists(ParameterNode p | getNodeEnclosingCallable(p) = callable) exists(ParamNode p | getNodeEnclosingCallable(p) = callable)
} }
override predicate matchesCall(DataFlowCall call) { any() } override predicate matchesCall(DataFlowCall call) { any() }
@@ -866,7 +948,7 @@ class CallContextReturn extends CallContextNoCall, TReturn {
} }
override predicate relevantFor(DataFlowCallable callable) { override predicate relevantFor(DataFlowCallable callable) {
exists(DataFlowCall call | this = TReturn(_, call) and call.getEnclosingCallable() = callable) exists(DataFlowCall call | this = TReturn(_, call) and callEnclosingCallable(call, callable))
} }
} }
@@ -899,7 +981,7 @@ class LocalCallContextSpecificCall extends LocalCallContext, TSpecificLocalCall
} }
private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) { private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) {
exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCall(n, call)) exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCallCached(n, call))
} }
/** /**
@@ -913,26 +995,37 @@ LocalCallContext getLocalCallContext(CallContext ctx, DataFlowCallable callable)
else result instanceof LocalCallContextAny else result instanceof LocalCallContextAny
} }
/**
* The value of a parameter at function entry, viewed as a node in a data
* flow graph.
*/
class ParamNode extends Node {
ParamNode() { parameterNode(this, _, _) }
/**
* Holds if this node is the parameter of callable `c` at the specified
* (zero-based) position.
*/
predicate isParameterOf(DataFlowCallable c, int i) { parameterNode(this, c, i) }
}
/** A data-flow node that represents a call argument. */
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) }
}
/** /**
* A node from which flow can return to the caller. This is either a regular * A node from which flow can return to the caller. This is either a regular
* `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter. * `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter.
*/ */
class ReturnNodeExt extends Node { class ReturnNodeExt extends Node {
ReturnNodeExt() { ReturnNodeExt() { returnNodeExt(this, _) }
this instanceof ReturnNode or
parameterValueFlowsToPreUpdate(_, this)
}
/** Gets the kind of this returned value. */ /** Gets the kind of this returned value. */
ReturnKindExt getKind() { ReturnKindExt getKind() { returnNodeExt(this, result) }
result = TValueReturn(this.(ReturnNode).getKind())
or
exists(ParameterNode p, int pos |
parameterValueFlowsToPreUpdate(p, this) and
p.isParameterOf(_, pos) and
result = TParamUpdate(pos)
)
}
} }
/** /**
@@ -940,11 +1033,7 @@ class ReturnNodeExt extends Node {
* or a post-update node associated with a call argument. * or a post-update node associated with a call argument.
*/ */
class OutNodeExt extends Node { class OutNodeExt extends Node {
OutNodeExt() { OutNodeExt() { outNodeExt(this) }
this instanceof OutNode
or
this.(PostUpdateNode).getPreUpdateNode() instanceof ArgumentNode
}
} }
/** /**
@@ -957,7 +1046,7 @@ abstract class ReturnKindExt extends TReturnKindExt {
abstract string toString(); abstract string toString();
/** Gets a node corresponding to data flow out of `call`. */ /** Gets a node corresponding to data flow out of `call`. */
abstract OutNodeExt getAnOutNode(DataFlowCall call); final OutNodeExt getAnOutNode(DataFlowCall call) { result = getAnOutNodeExt(call, this) }
} }
class ValueReturnKind extends ReturnKindExt, TValueReturn { class ValueReturnKind extends ReturnKindExt, TValueReturn {
@@ -968,10 +1057,6 @@ class ValueReturnKind extends ReturnKindExt, TValueReturn {
ReturnKind getKind() { result = kind } ReturnKind getKind() { result = kind }
override string toString() { result = kind.toString() } override string toString() { result = kind.toString() }
override OutNodeExt getAnOutNode(DataFlowCall call) {
result = getAnOutNode(call, this.getKind())
}
} }
class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate { class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
@@ -982,13 +1067,6 @@ class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
int getPosition() { result = pos } int getPosition() { result = pos }
override string toString() { result = "param update " + pos } override string toString() { result = "param update " + pos }
override OutNodeExt getAnOutNode(DataFlowCall call) {
exists(ArgumentNode arg |
result.(PostUpdateNode).getPreUpdateNode() = arg and
arg.argumentOf(call, this.getPosition())
)
}
} }
/** A callable tagged with a relevant return kind. */ /** A callable tagged with a relevant return kind. */
@@ -1015,10 +1093,13 @@ class ReturnPosition extends TReturnPosition0 {
*/ */
pragma[inline] pragma[inline]
DataFlowCallable getNodeEnclosingCallable(Node n) { DataFlowCallable getNodeEnclosingCallable(Node n) {
exists(Node n0 | nodeEnclosingCallable(pragma[only_bind_out](n), pragma[only_bind_into](result))
pragma[only_bind_into](n0) = n and }
pragma[only_bind_into](result) = n0.getEnclosingCallable()
) /** Gets the type of `n` used for type pruning. */
pragma[inline]
DataFlowType getNodeDataFlowType(Node n) {
nodeDataFlowType(pragma[only_bind_out](n), pragma[only_bind_into](result))
} }
pragma[noinline] pragma[noinline]
@@ -1042,7 +1123,7 @@ predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall
cc instanceof CallContextAny and callable = viableCallableExt(call) cc instanceof CallContextAny and callable = viableCallableExt(call)
or or
exists(DataFlowCallable c0, DataFlowCall call0 | exists(DataFlowCallable c0, DataFlowCall call0 |
call0.getEnclosingCallable() = callable and callEnclosingCallable(call0, callable) and
cc = TReturn(c0, call0) and cc = TReturn(c0, call0) and
c0 = prunedViableImplInCallContextReverse(call0, call) c0 = prunedViableImplInCallContextReverse(call0, call)
) )
@@ -1063,8 +1144,6 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
result = viableCallableExt(call) and cc instanceof CallContextReturn result = viableCallableExt(call) and cc instanceof CallContextReturn
} }
predicate read = readStep/3;
/** An optional Boolean value. */ /** An optional Boolean value. */
class BooleanOption extends TBooleanOption { class BooleanOption extends TBooleanOption {
string toString() { string toString() {
@@ -1116,7 +1195,7 @@ abstract class AccessPathFront extends TAccessPathFront {
TypedContent getHead() { this = TFrontHead(result) } TypedContent getHead() { this = TFrontHead(result) }
predicate isClearedAt(Node n) { clearsContent(n, getHead().getContent()) } predicate isClearedAt(Node n) { clearsContentCached(n, getHead().getContent()) }
} }
class AccessPathFrontNil extends AccessPathFront, TFrontNil { class AccessPathFrontNil extends AccessPathFront, TFrontNil {

View File

@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`. * Holds if data can flow in one local step from `node1` to `node2`.
*/ */
private predicate localFlowStep(Node node1, Node node2, Configuration config) { private predicate localFlowStep(Node node1, Node node2, Configuration config) {
( simpleLocalFlowStepExt(node1, node2) and
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts. * Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/ */
private predicate jumpStep(Node node1, Node node2, Configuration config) { private predicate jumpStep(Node node1, Node node2, Configuration config) {
jumpStep(node1, node2) and jumpStepCached(node1, node2) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) { private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
exists(ArgumentNode arg | exists(ArgNode arg |
fwdFlow(arg, cc, config) and fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg) viableParamArg(call, _, arg)
) )
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic] pragma[nomagic]
predicate viableParamArgNodeCandFwd1( predicate viableParamArgNodeCandFwd1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
viableParamArg(call, p, arg) and viableParamArg(call, p, arg) and
fwdFlow(arg, config) fwdFlow(arg, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config exists(ParamNode p |
) {
exists(ParameterNode p |
revFlow(p, toReturn, config) and revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config) viableParamArgNodeCandFwd1(call, p, arg, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config) revFlowIn(call, arg, true, config)
} }
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a * Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic] pragma[nomagic]
private predicate viableParamArgNodeCand1( private predicate viableParamArgNodeCand1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config) Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) { ) {
viableParamArgNodeCand1(call, p, arg, config) and viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, arg, p, config) and flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j | exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config) PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
) )
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand2( private predicate flowIntoCallNodeCand2(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/ */
private class FlowCheckNode extends Node { private class FlowCheckNode extends Node {
FlowCheckNode() { FlowCheckNode() {
this instanceof CastNode or castNode(this) or
clearsContent(this, _) clearsContentCached(this, _)
} }
} }
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or config.isSource(node) or
jumpStep(_, node, config) or jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or additionalJumpStep(_, node, config) or
node instanceof ParameterNode or node instanceof ParamNode or
node instanceof OutNodeExt or node instanceof OutNodeExt or
store(_, _, node, _) or store(_, _, node, _) or
read(_, _, node) or read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc LocalCallContext cc
) { ) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
( (
localFlowEntry(node1, pragma[only_bind_into](config)) and localFlowEntry(node1, pragma[only_bind_into](config)) and
( (
localFlowStepNodeCand1(node1, node2, config) and localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and preservesValue = true and
t = getNodeType(node1) t = getNodeDataFlowType(node1)
or or
additionalLocalFlowStepNodeCand2(node1, node2, config) and additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) t = getNodeDataFlowType(node2)
) and ) and
node1 != node2 and node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
or or
exists(Node mid | exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and not mid instanceof FlowCheckNode and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) and t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
) )
) )
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() } private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap] bindingset[node, ap]
private predicate filter(Node node, Ap ap) { private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and not ap.isClearedAt(node) and
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() if node instanceof CastingNode
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
} }
bindingset[ap, contentType] bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() } private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCall( private predicate flowIntoCall(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx = private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParameterNode p, AccessPath ap) { TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _) Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
} }
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */ /** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
private ParameterNode p; private ParamNode p;
private AccessPath ap; private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) } SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and config.isSource(node) and
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
// ... or a step from an existing PathNode to another node. // ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid | exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() } Configuration getConfiguration() { none() }
private predicate isHidden() { private predicate isHidden() {
nodeIsHidden(this.getNode()) and hiddenNode(this.getNode()) and
not this.isSource() and not this.isSource() and
not this instanceof PathNodeSink not this instanceof PathNodeSink
} }
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and mid.getAp() instanceof AccessPathNil and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx() sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg( private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand( private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i) p.isParameterOf(callable, i)
) )
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively. * respectively.
*/ */
private predicate pathIntoCallable( private predicate pathIntoCallable(
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call DataFlowCall call
) { ) {
exists(int i, DataFlowCallable callable, AccessPath ap | exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 = private newtype TSummaryCtx1 =
TSummaryCtx1None() or TSummaryCtx1None() or
TSummaryCtx1Param(ParameterNode p) TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 = private newtype TSummaryCtx2 =
TSummaryCtx2None() or TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
exists(config.explorationLimit()) exists(config.explorationLimit())
or or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or or
exists(PartialPathNodeRev mid | exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit() distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
) )
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid | exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not clearsContent(node, ap.getHead().getContent()) and not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode if node instanceof CastingNode
then compatibleTypes(getNodeType(node), ap.getType()) then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any() else any()
) )
} }
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
( (
localFlowStep(mid.getNode(), node, config) and localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
) )
or or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
or or
partialPathStoreStep(mid, _, _, node, ap) and partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getNodeType(node)) compatibleTypes(ap.getType(), getNodeDataFlowType(node))
) )
or or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap, PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
} }
private predicate partialPathIntoCallable( private predicate partialPathIntoCallable(
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc, PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap, TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc, DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 | exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config) paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
) )
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config) apConsRev(ap, c, ap0, config)
) )
or or
exists(ParameterNode p | exists(ParamNode p |
mid.getNode() = p and mid.getNode() = p and
viableParamArg(_, p, node) and viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap, int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(PartialPathNodeRev mid, ParameterNode p | exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and mid.getNode() = p and
p.isParameterOf(_, pos) and p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic] pragma[nomagic]
private predicate revPartialPathThroughCallable( private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) { ) {
exists(DataFlowCall call, int pos | exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and revPartialPathThroughCallable0(call, mid, pos, ap, config) and

View File

@@ -526,7 +526,6 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) {
* This is the local flow predicate that's used as a building block in global * This is the local flow predicate that's used as a building block in global
* data flow. It may have less flow than the `localFlowStep` predicate. * data flow. It may have less flow than the `localFlowStep` predicate.
*/ */
cached
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
// Expr -> Expr // Expr -> Expr
exprToExprStep_nocfg(nodeFrom.asExpr(), nodeTo.asExpr()) exprToExprStep_nocfg(nodeFrom.asExpr(), nodeTo.asExpr())

View File

@@ -45,6 +45,7 @@ predicate defaultTaintSanitizer(DataFlow::Node node) { none() }
* local data flow steps. That is, `nodeFrom` and `nodeTo` are likely to represent * local data flow steps. That is, `nodeFrom` and `nodeTo` are likely to represent
* different objects. * different objects.
*/ */
cached
predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
// Taint can flow through expressions that alter the value but preserve // Taint can flow through expressions that alter the value but preserve
// more than one bit of it _or_ expressions that follow data through // more than one bit of it _or_ expressions that follow data through

View File

@@ -165,105 +165,132 @@ private predicate nodeIsBarrierEqualityCandidate(
any(IRGuardCondition guard).ensuresEq(access, _, _, node.asInstruction().getBlock(), true) any(IRGuardCondition guard).ensuresEq(access, _, _, node.asInstruction().getBlock(), true)
} }
private predicate nodeIsBarrier(DataFlow::Node node) { cached
exists(Variable checkedVar | private module Cached {
readsVariable(node.asInstruction(), checkedVar) and cached
hasUpperBoundsCheck(checkedVar) predicate nodeIsBarrier(DataFlow::Node node) {
) exists(Variable checkedVar |
or readsVariable(node.asInstruction(), checkedVar) and
exists(Variable checkedVar, Operand access | hasUpperBoundsCheck(checkedVar)
/* )
* This node is guarded by a condition that forces the accessed variable
* to equal something else. For example:
* ```
* x = taintsource()
* if (x == 10) {
* taintsink(x); // not considered tainted
* }
* ```
*/
nodeIsBarrierEqualityCandidate(node, access, checkedVar) and
readsVariable(access.getDef(), checkedVar)
)
}
private predicate nodeIsBarrierIn(DataFlow::Node node) {
// don't use dataflow into taint sources, as this leads to duplicate results.
exists(Expr source | isUserInput(source, _) |
node = DataFlow::exprNode(source)
or or
// This case goes together with the similar (but not identical) rule in exists(Variable checkedVar, Operand access |
// `getNodeForSource`. /*
node = DataFlow::definitionByReferenceNodeFromArgument(source) * This node is guarded by a condition that forces the accessed variable
) * to equal something else. For example:
or * ```
// don't use dataflow into binary instructions if both operands are unpredictable * x = taintsource()
exists(BinaryInstruction iTo | * if (x == 10) {
iTo = node.asInstruction() and * taintsink(x); // not considered tainted
not predictableInstruction(iTo.getLeft()) and * }
not predictableInstruction(iTo.getRight()) and * ```
// propagate taint from either the pointer or the offset, regardless of predictability */
not iTo instanceof PointerArithmeticInstruction
) nodeIsBarrierEqualityCandidate(node, access, checkedVar) and
or readsVariable(access.getDef(), checkedVar)
// don't use dataflow through calls to pure functions if two or more operands )
// are unpredictable }
exists(Instruction iFrom1, Instruction iFrom2, CallInstruction iTo |
iTo = node.asInstruction() and cached
isPureFunction(iTo.getStaticCallTarget().getName()) and predicate nodeIsBarrierIn(DataFlow::Node node) {
iFrom1 = iTo.getAnArgument() and // don't use dataflow into taint sources, as this leads to duplicate results.
iFrom2 = iTo.getAnArgument() and exists(Expr source | isUserInput(source, _) |
not predictableInstruction(iFrom1) and node = DataFlow::exprNode(source)
not predictableInstruction(iFrom2) and or
iFrom1 != iFrom2 // This case goes together with the similar (but not identical) rule in
) // `getNodeForSource`.
node = DataFlow::definitionByReferenceNodeFromArgument(source)
)
or
// don't use dataflow into binary instructions if both operands are unpredictable
exists(BinaryInstruction iTo |
iTo = node.asInstruction() and
not predictableInstruction(iTo.getLeft()) and
not predictableInstruction(iTo.getRight()) and
// propagate taint from either the pointer or the offset, regardless of predictability
not iTo instanceof PointerArithmeticInstruction
)
or
// don't use dataflow through calls to pure functions if two or more operands
// are unpredictable
exists(Instruction iFrom1, Instruction iFrom2, CallInstruction iTo |
iTo = node.asInstruction() and
isPureFunction(iTo.getStaticCallTarget().getName()) and
iFrom1 = iTo.getAnArgument() and
iFrom2 = iTo.getAnArgument() and
not predictableInstruction(iFrom1) and
not predictableInstruction(iFrom2) and
iFrom1 != iFrom2
)
}
cached
Element adjustedSink(DataFlow::Node sink) {
// TODO: is it more appropriate to use asConvertedExpr here and avoid
// `getConversion*`? Or will that cause us to miss some cases where there's
// flow to a conversion (like a `ReferenceDereferenceExpr`) and we want to
// pretend there was flow to the converted `Expr` for the sake of
// compatibility.
sink.asExpr().getConversion*() = result
or
// For compatibility, send flow from arguments to parameters, even for
// functions with no body.
exists(FunctionCall call, int i |
sink.asExpr() = call.getArgument(i) and
result = resolveCall(call).getParameter(i)
)
or
// For compatibility, send flow into a `Variable` if there is flow to any
// Load or Store of that variable.
exists(CopyInstruction copy |
copy.getSourceValue() = sink.asInstruction() and
(
readsVariable(copy, result) or
writesVariable(copy, result)
) and
not hasUpperBoundsCheck(result)
)
or
// For compatibility, send flow into a `NotExpr` even if it's part of a
// short-circuiting condition and thus might get skipped.
result.(NotExpr).getOperand() = sink.asExpr()
or
// Taint postfix and prefix crement operations when their operand is tainted.
result.(CrementOperation).getAnOperand() = sink.asExpr()
or
// Taint `e1 += e2`, `e &= e2` and friends when `e1` or `e2` is tainted.
result.(AssignOperation).getAnOperand() = sink.asExpr()
or
result =
sink.asOperand()
.(SideEffectOperand)
.getUse()
.(ReadSideEffectInstruction)
.getArgumentDef()
.getUnconvertedResultExpression()
}
/**
* Step to return value of a modeled function when an input taints the
* dereference of the return value.
*/
cached
predicate additionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) {
exists(CallInstruction call, Function func, FunctionInput modelIn, FunctionOutput modelOut |
n1.asOperand() = callInput(call, modelIn) and
(
func.(TaintFunction).hasTaintFlow(modelIn, modelOut)
or
func.(DataFlowFunction).hasDataFlow(modelIn, modelOut)
) and
call.getStaticCallTarget() = func and
modelOut.isReturnValueDeref() and
call = n2.asInstruction()
)
}
} }
private Element adjustedSink(DataFlow::Node sink) { private import Cached
// TODO: is it more appropriate to use asConvertedExpr here and avoid
// `getConversion*`? Or will that cause us to miss some cases where there's
// flow to a conversion (like a `ReferenceDereferenceExpr`) and we want to
// pretend there was flow to the converted `Expr` for the sake of
// compatibility.
sink.asExpr().getConversion*() = result
or
// For compatibility, send flow from arguments to parameters, even for
// functions with no body.
exists(FunctionCall call, int i |
sink.asExpr() = call.getArgument(i) and
result = resolveCall(call).getParameter(i)
)
or
// For compatibility, send flow into a `Variable` if there is flow to any
// Load or Store of that variable.
exists(CopyInstruction copy |
copy.getSourceValue() = sink.asInstruction() and
(
readsVariable(copy, result) or
writesVariable(copy, result)
) and
not hasUpperBoundsCheck(result)
)
or
// For compatibility, send flow into a `NotExpr` even if it's part of a
// short-circuiting condition and thus might get skipped.
result.(NotExpr).getOperand() = sink.asExpr()
or
// Taint postfix and prefix crement operations when their operand is tainted.
result.(CrementOperation).getAnOperand() = sink.asExpr()
or
// Taint `e1 += e2`, `e &= e2` and friends when `e1` or `e2` is tainted.
result.(AssignOperation).getAnOperand() = sink.asExpr()
or
result =
sink.asOperand()
.(SideEffectOperand)
.getUse()
.(ReadSideEffectInstruction)
.getArgumentDef()
.getUnconvertedResultExpression()
}
/** /**
* Holds if `tainted` may contain taint from `source`. * Holds if `tainted` may contain taint from `source`.
@@ -402,19 +429,7 @@ module TaintedWithPath {
readsVariable(n2.asInstruction(), n1.asVariable().(GlobalOrNamespaceVariable)) readsVariable(n2.asInstruction(), n1.asVariable().(GlobalOrNamespaceVariable))
) )
or or
// Step to return value of a modeled function when an input taints the additionalTaintStep(n1, n2)
// dereference of the return value
exists(CallInstruction call, Function func, FunctionInput modelIn, FunctionOutput modelOut |
n1.asOperand() = callInput(call, modelIn) and
(
func.(TaintFunction).hasTaintFlow(modelIn, modelOut)
or
func.(DataFlowFunction).hasDataFlow(modelIn, modelOut)
) and
call.getStaticCallTarget() = func and
modelOut.isReturnValueDeref() and
call = n2.asInstruction()
)
} }
override predicate isSanitizer(DataFlow::Node node) { override predicate isSanitizer(DataFlow::Node node) {

View File

@@ -2,11 +2,14 @@ private import cpp
private import semmle.code.cpp.ir.IR private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.DataFlow 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.DataFlowPrivate
private import DataFlowImplCommon as DataFlowImplCommon
/** /**
* Gets a function that might be called by `call`. * Gets a function that might be called by `call`.
*/ */
cached
Function viableCallable(CallInstruction call) { Function viableCallable(CallInstruction call) {
DataFlowImplCommon::forceCachingInSameStage() and
result = call.getStaticCallTarget() result = call.getStaticCallTarget()
or or
// If the target of the call does not have a body in the snapshot, it might // If the target of the call does not have a body in the snapshot, it might
@@ -43,7 +46,6 @@ private module VirtualDispatch {
abstract DataFlow::Node getDispatchValue(); abstract DataFlow::Node getDispatchValue();
/** Gets a candidate target for this call. */ /** Gets a candidate target for this call. */
cached
abstract Function resolve(); abstract Function resolve();
/** /**

View File

@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`. * Holds if data can flow in one local step from `node1` to `node2`.
*/ */
private predicate localFlowStep(Node node1, Node node2, Configuration config) { private predicate localFlowStep(Node node1, Node node2, Configuration config) {
( simpleLocalFlowStepExt(node1, node2) and
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts. * Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/ */
private predicate jumpStep(Node node1, Node node2, Configuration config) { private predicate jumpStep(Node node1, Node node2, Configuration config) {
jumpStep(node1, node2) and jumpStepCached(node1, node2) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) { private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
exists(ArgumentNode arg | exists(ArgNode arg |
fwdFlow(arg, cc, config) and fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg) viableParamArg(call, _, arg)
) )
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic] pragma[nomagic]
predicate viableParamArgNodeCandFwd1( predicate viableParamArgNodeCandFwd1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
viableParamArg(call, p, arg) and viableParamArg(call, p, arg) and
fwdFlow(arg, config) fwdFlow(arg, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config exists(ParamNode p |
) {
exists(ParameterNode p |
revFlow(p, toReturn, config) and revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config) viableParamArgNodeCandFwd1(call, p, arg, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config) revFlowIn(call, arg, true, config)
} }
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a * Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic] pragma[nomagic]
private predicate viableParamArgNodeCand1( private predicate viableParamArgNodeCand1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config) Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) { ) {
viableParamArgNodeCand1(call, p, arg, config) and viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, arg, p, config) and flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j | exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config) PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
) )
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand2( private predicate flowIntoCallNodeCand2(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/ */
private class FlowCheckNode extends Node { private class FlowCheckNode extends Node {
FlowCheckNode() { FlowCheckNode() {
this instanceof CastNode or castNode(this) or
clearsContent(this, _) clearsContentCached(this, _)
} }
} }
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or config.isSource(node) or
jumpStep(_, node, config) or jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or additionalJumpStep(_, node, config) or
node instanceof ParameterNode or node instanceof ParamNode or
node instanceof OutNodeExt or node instanceof OutNodeExt or
store(_, _, node, _) or store(_, _, node, _) or
read(_, _, node) or read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc LocalCallContext cc
) { ) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
( (
localFlowEntry(node1, pragma[only_bind_into](config)) and localFlowEntry(node1, pragma[only_bind_into](config)) and
( (
localFlowStepNodeCand1(node1, node2, config) and localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and preservesValue = true and
t = getNodeType(node1) t = getNodeDataFlowType(node1)
or or
additionalLocalFlowStepNodeCand2(node1, node2, config) and additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) t = getNodeDataFlowType(node2)
) and ) and
node1 != node2 and node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
or or
exists(Node mid | exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and not mid instanceof FlowCheckNode and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) and t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
) )
) )
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() } private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap] bindingset[node, ap]
private predicate filter(Node node, Ap ap) { private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and not ap.isClearedAt(node) and
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() if node instanceof CastingNode
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
} }
bindingset[ap, contentType] bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() } private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCall( private predicate flowIntoCall(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx = private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParameterNode p, AccessPath ap) { TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _) Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
} }
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */ /** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
private ParameterNode p; private ParamNode p;
private AccessPath ap; private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) } SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and config.isSource(node) and
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
// ... or a step from an existing PathNode to another node. // ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid | exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() } Configuration getConfiguration() { none() }
private predicate isHidden() { private predicate isHidden() {
nodeIsHidden(this.getNode()) and hiddenNode(this.getNode()) and
not this.isSource() and not this.isSource() and
not this instanceof PathNodeSink not this instanceof PathNodeSink
} }
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and mid.getAp() instanceof AccessPathNil and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx() sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg( private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand( private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i) p.isParameterOf(callable, i)
) )
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively. * respectively.
*/ */
private predicate pathIntoCallable( private predicate pathIntoCallable(
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call DataFlowCall call
) { ) {
exists(int i, DataFlowCallable callable, AccessPath ap | exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 = private newtype TSummaryCtx1 =
TSummaryCtx1None() or TSummaryCtx1None() or
TSummaryCtx1Param(ParameterNode p) TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 = private newtype TSummaryCtx2 =
TSummaryCtx2None() or TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
exists(config.explorationLimit()) exists(config.explorationLimit())
or or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or or
exists(PartialPathNodeRev mid | exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit() distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
) )
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid | exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not clearsContent(node, ap.getHead().getContent()) and not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode if node instanceof CastingNode
then compatibleTypes(getNodeType(node), ap.getType()) then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any() else any()
) )
} }
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
( (
localFlowStep(mid.getNode(), node, config) and localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
) )
or or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
or or
partialPathStoreStep(mid, _, _, node, ap) and partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getNodeType(node)) compatibleTypes(ap.getType(), getNodeDataFlowType(node))
) )
or or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap, PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
} }
private predicate partialPathIntoCallable( private predicate partialPathIntoCallable(
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc, PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap, TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc, DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 | exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config) paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
) )
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config) apConsRev(ap, c, ap0, config)
) )
or or
exists(ParameterNode p | exists(ParamNode p |
mid.getNode() = p and mid.getNode() = p and
viableParamArg(_, p, node) and viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap, int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(PartialPathNodeRev mid, ParameterNode p | exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and mid.getNode() = p and
p.isParameterOf(_, pos) and p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic] pragma[nomagic]
private predicate revPartialPathThroughCallable( private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) { ) {
exists(DataFlowCall call, int pos | exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and revPartialPathThroughCallable0(call, mid, pos, ap, config) and

View File

@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`. * Holds if data can flow in one local step from `node1` to `node2`.
*/ */
private predicate localFlowStep(Node node1, Node node2, Configuration config) { private predicate localFlowStep(Node node1, Node node2, Configuration config) {
( simpleLocalFlowStepExt(node1, node2) and
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts. * Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/ */
private predicate jumpStep(Node node1, Node node2, Configuration config) { private predicate jumpStep(Node node1, Node node2, Configuration config) {
jumpStep(node1, node2) and jumpStepCached(node1, node2) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) { private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
exists(ArgumentNode arg | exists(ArgNode arg |
fwdFlow(arg, cc, config) and fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg) viableParamArg(call, _, arg)
) )
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic] pragma[nomagic]
predicate viableParamArgNodeCandFwd1( predicate viableParamArgNodeCandFwd1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
viableParamArg(call, p, arg) and viableParamArg(call, p, arg) and
fwdFlow(arg, config) fwdFlow(arg, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config exists(ParamNode p |
) {
exists(ParameterNode p |
revFlow(p, toReturn, config) and revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config) viableParamArgNodeCandFwd1(call, p, arg, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config) revFlowIn(call, arg, true, config)
} }
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a * Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic] pragma[nomagic]
private predicate viableParamArgNodeCand1( private predicate viableParamArgNodeCand1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config) Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) { ) {
viableParamArgNodeCand1(call, p, arg, config) and viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, arg, p, config) and flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j | exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config) PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
) )
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand2( private predicate flowIntoCallNodeCand2(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/ */
private class FlowCheckNode extends Node { private class FlowCheckNode extends Node {
FlowCheckNode() { FlowCheckNode() {
this instanceof CastNode or castNode(this) or
clearsContent(this, _) clearsContentCached(this, _)
} }
} }
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or config.isSource(node) or
jumpStep(_, node, config) or jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or additionalJumpStep(_, node, config) or
node instanceof ParameterNode or node instanceof ParamNode or
node instanceof OutNodeExt or node instanceof OutNodeExt or
store(_, _, node, _) or store(_, _, node, _) or
read(_, _, node) or read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc LocalCallContext cc
) { ) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
( (
localFlowEntry(node1, pragma[only_bind_into](config)) and localFlowEntry(node1, pragma[only_bind_into](config)) and
( (
localFlowStepNodeCand1(node1, node2, config) and localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and preservesValue = true and
t = getNodeType(node1) t = getNodeDataFlowType(node1)
or or
additionalLocalFlowStepNodeCand2(node1, node2, config) and additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) t = getNodeDataFlowType(node2)
) and ) and
node1 != node2 and node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
or or
exists(Node mid | exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and not mid instanceof FlowCheckNode and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) and t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
) )
) )
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() } private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap] bindingset[node, ap]
private predicate filter(Node node, Ap ap) { private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and not ap.isClearedAt(node) and
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() if node instanceof CastingNode
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
} }
bindingset[ap, contentType] bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() } private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCall( private predicate flowIntoCall(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx = private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParameterNode p, AccessPath ap) { TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _) Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
} }
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */ /** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
private ParameterNode p; private ParamNode p;
private AccessPath ap; private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) } SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and config.isSource(node) and
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
// ... or a step from an existing PathNode to another node. // ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid | exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() } Configuration getConfiguration() { none() }
private predicate isHidden() { private predicate isHidden() {
nodeIsHidden(this.getNode()) and hiddenNode(this.getNode()) and
not this.isSource() and not this.isSource() and
not this instanceof PathNodeSink not this instanceof PathNodeSink
} }
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and mid.getAp() instanceof AccessPathNil and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx() sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg( private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand( private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i) p.isParameterOf(callable, i)
) )
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively. * respectively.
*/ */
private predicate pathIntoCallable( private predicate pathIntoCallable(
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call DataFlowCall call
) { ) {
exists(int i, DataFlowCallable callable, AccessPath ap | exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 = private newtype TSummaryCtx1 =
TSummaryCtx1None() or TSummaryCtx1None() or
TSummaryCtx1Param(ParameterNode p) TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 = private newtype TSummaryCtx2 =
TSummaryCtx2None() or TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
exists(config.explorationLimit()) exists(config.explorationLimit())
or or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or or
exists(PartialPathNodeRev mid | exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit() distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
) )
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid | exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not clearsContent(node, ap.getHead().getContent()) and not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode if node instanceof CastingNode
then compatibleTypes(getNodeType(node), ap.getType()) then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any() else any()
) )
} }
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
( (
localFlowStep(mid.getNode(), node, config) and localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
) )
or or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
or or
partialPathStoreStep(mid, _, _, node, ap) and partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getNodeType(node)) compatibleTypes(ap.getType(), getNodeDataFlowType(node))
) )
or or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap, PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
} }
private predicate partialPathIntoCallable( private predicate partialPathIntoCallable(
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc, PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap, TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc, DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 | exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config) paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
) )
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config) apConsRev(ap, c, ap0, config)
) )
or or
exists(ParameterNode p | exists(ParamNode p |
mid.getNode() = p and mid.getNode() = p and
viableParamArg(_, p, node) and viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap, int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(PartialPathNodeRev mid, ParameterNode p | exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and mid.getNode() = p and
p.isParameterOf(_, pos) and p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic] pragma[nomagic]
private predicate revPartialPathThroughCallable( private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) { ) {
exists(DataFlowCall call, int pos | exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and revPartialPathThroughCallable0(call, mid, pos, ap, config) and

View File

@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`. * Holds if data can flow in one local step from `node1` to `node2`.
*/ */
private predicate localFlowStep(Node node1, Node node2, Configuration config) { private predicate localFlowStep(Node node1, Node node2, Configuration config) {
( simpleLocalFlowStepExt(node1, node2) and
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts. * Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/ */
private predicate jumpStep(Node node1, Node node2, Configuration config) { private predicate jumpStep(Node node1, Node node2, Configuration config) {
jumpStep(node1, node2) and jumpStepCached(node1, node2) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) { private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
exists(ArgumentNode arg | exists(ArgNode arg |
fwdFlow(arg, cc, config) and fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg) viableParamArg(call, _, arg)
) )
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic] pragma[nomagic]
predicate viableParamArgNodeCandFwd1( predicate viableParamArgNodeCandFwd1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
viableParamArg(call, p, arg) and viableParamArg(call, p, arg) and
fwdFlow(arg, config) fwdFlow(arg, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config exists(ParamNode p |
) {
exists(ParameterNode p |
revFlow(p, toReturn, config) and revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config) viableParamArgNodeCandFwd1(call, p, arg, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config) revFlowIn(call, arg, true, config)
} }
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a * Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic] pragma[nomagic]
private predicate viableParamArgNodeCand1( private predicate viableParamArgNodeCand1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config) Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) { ) {
viableParamArgNodeCand1(call, p, arg, config) and viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, arg, p, config) and flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j | exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config) PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
) )
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand2( private predicate flowIntoCallNodeCand2(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/ */
private class FlowCheckNode extends Node { private class FlowCheckNode extends Node {
FlowCheckNode() { FlowCheckNode() {
this instanceof CastNode or castNode(this) or
clearsContent(this, _) clearsContentCached(this, _)
} }
} }
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or config.isSource(node) or
jumpStep(_, node, config) or jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or additionalJumpStep(_, node, config) or
node instanceof ParameterNode or node instanceof ParamNode or
node instanceof OutNodeExt or node instanceof OutNodeExt or
store(_, _, node, _) or store(_, _, node, _) or
read(_, _, node) or read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc LocalCallContext cc
) { ) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
( (
localFlowEntry(node1, pragma[only_bind_into](config)) and localFlowEntry(node1, pragma[only_bind_into](config)) and
( (
localFlowStepNodeCand1(node1, node2, config) and localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and preservesValue = true and
t = getNodeType(node1) t = getNodeDataFlowType(node1)
or or
additionalLocalFlowStepNodeCand2(node1, node2, config) and additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) t = getNodeDataFlowType(node2)
) and ) and
node1 != node2 and node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
or or
exists(Node mid | exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and not mid instanceof FlowCheckNode and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) and t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
) )
) )
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() } private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap] bindingset[node, ap]
private predicate filter(Node node, Ap ap) { private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and not ap.isClearedAt(node) and
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() if node instanceof CastingNode
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
} }
bindingset[ap, contentType] bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() } private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCall( private predicate flowIntoCall(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx = private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParameterNode p, AccessPath ap) { TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _) Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
} }
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */ /** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
private ParameterNode p; private ParamNode p;
private AccessPath ap; private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) } SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and config.isSource(node) and
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
// ... or a step from an existing PathNode to another node. // ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid | exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() } Configuration getConfiguration() { none() }
private predicate isHidden() { private predicate isHidden() {
nodeIsHidden(this.getNode()) and hiddenNode(this.getNode()) and
not this.isSource() and not this.isSource() and
not this instanceof PathNodeSink not this instanceof PathNodeSink
} }
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and mid.getAp() instanceof AccessPathNil and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx() sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg( private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand( private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i) p.isParameterOf(callable, i)
) )
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively. * respectively.
*/ */
private predicate pathIntoCallable( private predicate pathIntoCallable(
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call DataFlowCall call
) { ) {
exists(int i, DataFlowCallable callable, AccessPath ap | exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 = private newtype TSummaryCtx1 =
TSummaryCtx1None() or TSummaryCtx1None() or
TSummaryCtx1Param(ParameterNode p) TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 = private newtype TSummaryCtx2 =
TSummaryCtx2None() or TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
exists(config.explorationLimit()) exists(config.explorationLimit())
or or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or or
exists(PartialPathNodeRev mid | exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit() distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
) )
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid | exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not clearsContent(node, ap.getHead().getContent()) and not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode if node instanceof CastingNode
then compatibleTypes(getNodeType(node), ap.getType()) then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any() else any()
) )
} }
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
( (
localFlowStep(mid.getNode(), node, config) and localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
) )
or or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
or or
partialPathStoreStep(mid, _, _, node, ap) and partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getNodeType(node)) compatibleTypes(ap.getType(), getNodeDataFlowType(node))
) )
or or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap, PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
} }
private predicate partialPathIntoCallable( private predicate partialPathIntoCallable(
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc, PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap, TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc, DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 | exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config) paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
) )
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config) apConsRev(ap, c, ap0, config)
) )
or or
exists(ParameterNode p | exists(ParamNode p |
mid.getNode() = p and mid.getNode() = p and
viableParamArg(_, p, node) and viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap, int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(PartialPathNodeRev mid, ParameterNode p | exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and mid.getNode() = p and
p.isParameterOf(_, pos) and p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic] pragma[nomagic]
private predicate revPartialPathThroughCallable( private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) { ) {
exists(DataFlowCall call, int pos | exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and revPartialPathThroughCallable0(call, mid, pos, ap, config) and

View File

@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`. * Holds if data can flow in one local step from `node1` to `node2`.
*/ */
private predicate localFlowStep(Node node1, Node node2, Configuration config) { private predicate localFlowStep(Node node1, Node node2, Configuration config) {
( simpleLocalFlowStepExt(node1, node2) and
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts. * Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/ */
private predicate jumpStep(Node node1, Node node2, Configuration config) { private predicate jumpStep(Node node1, Node node2, Configuration config) {
jumpStep(node1, node2) and jumpStepCached(node1, node2) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) { private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
exists(ArgumentNode arg | exists(ArgNode arg |
fwdFlow(arg, cc, config) and fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg) viableParamArg(call, _, arg)
) )
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic] pragma[nomagic]
predicate viableParamArgNodeCandFwd1( predicate viableParamArgNodeCandFwd1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
viableParamArg(call, p, arg) and viableParamArg(call, p, arg) and
fwdFlow(arg, config) fwdFlow(arg, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config exists(ParamNode p |
) {
exists(ParameterNode p |
revFlow(p, toReturn, config) and revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config) viableParamArgNodeCandFwd1(call, p, arg, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config) revFlowIn(call, arg, true, config)
} }
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a * Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic] pragma[nomagic]
private predicate viableParamArgNodeCand1( private predicate viableParamArgNodeCand1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config) Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) { ) {
viableParamArgNodeCand1(call, p, arg, config) and viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, arg, p, config) and flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j | exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config) PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
) )
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand2( private predicate flowIntoCallNodeCand2(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/ */
private class FlowCheckNode extends Node { private class FlowCheckNode extends Node {
FlowCheckNode() { FlowCheckNode() {
this instanceof CastNode or castNode(this) or
clearsContent(this, _) clearsContentCached(this, _)
} }
} }
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or config.isSource(node) or
jumpStep(_, node, config) or jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or additionalJumpStep(_, node, config) or
node instanceof ParameterNode or node instanceof ParamNode or
node instanceof OutNodeExt or node instanceof OutNodeExt or
store(_, _, node, _) or store(_, _, node, _) or
read(_, _, node) or read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc LocalCallContext cc
) { ) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
( (
localFlowEntry(node1, pragma[only_bind_into](config)) and localFlowEntry(node1, pragma[only_bind_into](config)) and
( (
localFlowStepNodeCand1(node1, node2, config) and localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and preservesValue = true and
t = getNodeType(node1) t = getNodeDataFlowType(node1)
or or
additionalLocalFlowStepNodeCand2(node1, node2, config) and additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) t = getNodeDataFlowType(node2)
) and ) and
node1 != node2 and node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
or or
exists(Node mid | exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and not mid instanceof FlowCheckNode and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) and t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
) )
) )
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() } private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap] bindingset[node, ap]
private predicate filter(Node node, Ap ap) { private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and not ap.isClearedAt(node) and
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() if node instanceof CastingNode
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
} }
bindingset[ap, contentType] bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() } private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCall( private predicate flowIntoCall(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx = private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParameterNode p, AccessPath ap) { TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _) Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
} }
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */ /** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
private ParameterNode p; private ParamNode p;
private AccessPath ap; private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) } SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and config.isSource(node) and
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
// ... or a step from an existing PathNode to another node. // ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid | exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() } Configuration getConfiguration() { none() }
private predicate isHidden() { private predicate isHidden() {
nodeIsHidden(this.getNode()) and hiddenNode(this.getNode()) and
not this.isSource() and not this.isSource() and
not this instanceof PathNodeSink not this instanceof PathNodeSink
} }
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and mid.getAp() instanceof AccessPathNil and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx() sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg( private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand( private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i) p.isParameterOf(callable, i)
) )
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively. * respectively.
*/ */
private predicate pathIntoCallable( private predicate pathIntoCallable(
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call DataFlowCall call
) { ) {
exists(int i, DataFlowCallable callable, AccessPath ap | exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 = private newtype TSummaryCtx1 =
TSummaryCtx1None() or TSummaryCtx1None() or
TSummaryCtx1Param(ParameterNode p) TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 = private newtype TSummaryCtx2 =
TSummaryCtx2None() or TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
exists(config.explorationLimit()) exists(config.explorationLimit())
or or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or or
exists(PartialPathNodeRev mid | exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit() distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
) )
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid | exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not clearsContent(node, ap.getHead().getContent()) and not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode if node instanceof CastingNode
then compatibleTypes(getNodeType(node), ap.getType()) then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any() else any()
) )
} }
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
( (
localFlowStep(mid.getNode(), node, config) and localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
) )
or or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
or or
partialPathStoreStep(mid, _, _, node, ap) and partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getNodeType(node)) compatibleTypes(ap.getType(), getNodeDataFlowType(node))
) )
or or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap, PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
} }
private predicate partialPathIntoCallable( private predicate partialPathIntoCallable(
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc, PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap, TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc, DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 | exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config) paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
) )
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config) apConsRev(ap, c, ap0, config)
) )
or or
exists(ParameterNode p | exists(ParamNode p |
mid.getNode() = p and mid.getNode() = p and
viableParamArg(_, p, node) and viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap, int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(PartialPathNodeRev mid, ParameterNode p | exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and mid.getNode() = p and
p.isParameterOf(_, pos) and p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic] pragma[nomagic]
private predicate revPartialPathThroughCallable( private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) { ) {
exists(DataFlowCall call, int pos | exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and revPartialPathThroughCallable0(call, mid, pos, ap, config) and

View File

@@ -35,22 +35,22 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
* calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly. * calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly.
*/ */
private module LambdaFlow { private module LambdaFlow {
private predicate viableParamNonLambda(DataFlowCall call, int i, ParameterNode p) { private predicate viableParamNonLambda(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallable(call), i) p.isParameterOf(viableCallable(call), i)
} }
private predicate viableParamLambda(DataFlowCall call, int i, ParameterNode p) { private predicate viableParamLambda(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallableLambda(call, _), i) p.isParameterOf(viableCallableLambda(call, _), i)
} }
private predicate viableParamArgNonLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) { private predicate viableParamArgNonLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i | exists(int i |
viableParamNonLambda(call, i, p) and viableParamNonLambda(call, i, p) and
arg.argumentOf(call, i) arg.argumentOf(call, i)
) )
} }
private predicate viableParamArgLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) { private predicate viableParamArgLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i | exists(int i |
viableParamLambda(call, i, p) and viableParamLambda(call, i, p) and
arg.argumentOf(call, i) arg.argumentOf(call, i)
@@ -118,8 +118,8 @@ private module LambdaFlow {
boolean toJump, DataFlowCallOption lastCall boolean toJump, DataFlowCallOption lastCall
) { ) {
revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and
if node instanceof CastNode or node instanceof ArgumentNode or node instanceof ReturnNode if castNode(node) or node instanceof ArgNode or node instanceof ReturnNode
then compatibleTypes(t, getNodeType(node)) then compatibleTypes(t, getNodeDataFlowType(node))
else any() else any()
} }
@@ -129,7 +129,7 @@ private module LambdaFlow {
boolean toJump, DataFlowCallOption lastCall boolean toJump, DataFlowCallOption lastCall
) { ) {
lambdaCall(lambdaCall, kind, node) and lambdaCall(lambdaCall, kind, node) and
t = getNodeType(node) and t = getNodeDataFlowType(node) and
toReturn = false and toReturn = false and
toJump = false and toJump = false and
lastCall = TDataFlowCallNone() lastCall = TDataFlowCallNone()
@@ -146,7 +146,7 @@ private module LambdaFlow {
getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid) getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid)
| |
preservesValue = false and preservesValue = false and
t = getNodeType(node) t = getNodeDataFlowType(node)
or or
preservesValue = true and preservesValue = true and
t = t0 t = t0
@@ -160,7 +160,7 @@ private module LambdaFlow {
toJump = true and toJump = true and
lastCall = TDataFlowCallNone() lastCall = TDataFlowCallNone()
| |
jumpStep(node, mid) and jumpStepCached(node, mid) and
t = t0 t = t0
or or
exists(boolean preservesValue | exists(boolean preservesValue |
@@ -168,7 +168,7 @@ private module LambdaFlow {
getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid) getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid)
| |
preservesValue = false and preservesValue = false and
t = getNodeType(node) t = getNodeDataFlowType(node)
or or
preservesValue = true and preservesValue = true and
t = t0 t = t0
@@ -176,7 +176,7 @@ private module LambdaFlow {
) )
or or
// flow into a callable // flow into a callable
exists(ParameterNode p, DataFlowCallOption lastCall0, DataFlowCall call | exists(ParamNode p, DataFlowCallOption lastCall0, DataFlowCall call |
revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and
( (
if lastCall0 = TDataFlowCallNone() and toJump = false if lastCall0 = TDataFlowCallNone() and toJump = false
@@ -227,7 +227,7 @@ private module LambdaFlow {
pragma[nomagic] pragma[nomagic]
predicate revLambdaFlowIn( predicate revLambdaFlowIn(
DataFlowCall lambdaCall, LambdaCallKind kind, ParameterNode p, DataFlowType t, boolean toJump, DataFlowCall lambdaCall, LambdaCallKind kind, ParamNode p, DataFlowType t, boolean toJump,
DataFlowCallOption lastCall DataFlowCallOption lastCall
) { ) {
revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall) revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall)
@@ -242,6 +242,89 @@ private DataFlowCallable viableCallableExt(DataFlowCall call) {
cached cached
private module Cached { private module Cached {
/**
* If needed, call this predicate from `DataFlowImplSpecific.qll` in order to
* force a stage-dependency on the `DataFlowImplCommon.qll` stage and therby
* collapsing the two stages.
*/
cached
predicate forceCachingInSameStage() { any() }
cached
predicate nodeEnclosingCallable(Node n, DataFlowCallable c) { c = n.getEnclosingCallable() }
cached
predicate callEnclosingCallable(DataFlowCall call, DataFlowCallable c) {
c = call.getEnclosingCallable()
}
cached
predicate nodeDataFlowType(Node n, DataFlowType t) { t = getNodeType(n) }
cached
predicate jumpStepCached(Node node1, Node node2) { jumpStep(node1, node2) }
cached
predicate clearsContentCached(Node n, Content c) { clearsContent(n, c) }
cached
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
cached
predicate outNodeExt(Node n) {
n instanceof OutNode
or
n.(PostUpdateNode).getPreUpdateNode() instanceof ArgNode
}
cached
predicate hiddenNode(Node n) { nodeIsHidden(n) }
cached
OutNodeExt getAnOutNodeExt(DataFlowCall call, ReturnKindExt k) {
result = getAnOutNode(call, k.(ValueReturnKind).getKind())
or
exists(ArgNode arg |
result.(PostUpdateNode).getPreUpdateNode() = arg and
arg.argumentOf(call, k.(ParamUpdateReturnKind).getPosition())
)
}
cached
predicate returnNodeExt(Node n, ReturnKindExt k) {
k = TValueReturn(n.(ReturnNode).getKind())
or
exists(ParamNode p, int pos |
parameterValueFlowsToPreUpdate(p, n) and
p.isParameterOf(_, pos) and
k = TParamUpdate(pos)
)
}
cached
predicate castNode(Node n) { n instanceof CastNode }
cached
predicate castingNode(Node n) {
castNode(n) or
n instanceof ParamNode or
n instanceof OutNodeExt or
// For reads, `x.f`, we want to check that the tracked type after the read (which
// is obtained by popping the head of the access path stack) is compatible with
// the type of `x.f`.
read(_, _, n)
}
cached
predicate parameterNode(Node n, DataFlowCallable c, int i) {
n.(ParameterNode).isParameterOf(c, i)
}
cached
predicate argumentNode(Node n, DataFlowCall call, int pos) {
n.(ArgumentNode).argumentOf(call, pos)
}
/** /**
* Gets a viable target for the lambda call `call`. * Gets a viable target for the lambda call `call`.
* *
@@ -261,7 +344,7 @@ private module Cached {
* The instance parameter is considered to have index `-1`. * The instance parameter is considered to have index `-1`.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate viableParam(DataFlowCall call, int i, ParameterNode p) { private predicate viableParam(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallableExt(call), i) p.isParameterOf(viableCallableExt(call), i)
} }
@@ -270,11 +353,11 @@ private module Cached {
* dispatch into account. * dispatch into account.
*/ */
cached cached
predicate viableParamArg(DataFlowCall call, ParameterNode p, ArgumentNode arg) { predicate viableParamArg(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i | exists(int i |
viableParam(call, i, p) and viableParam(call, i, p) and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
compatibleTypes(getNodeType(arg), getNodeType(p)) compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
) )
} }
@@ -312,7 +395,7 @@ private module Cached {
* `read` indicates whether it is contents of `p` that can flow to `node`. * `read` indicates whether it is contents of `p` that can flow to `node`.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate parameterValueFlowCand(ParameterNode p, Node node, boolean read) { private predicate parameterValueFlowCand(ParamNode p, Node node, boolean read) {
p = node and p = node and
read = false read = false
or or
@@ -325,30 +408,30 @@ private module Cached {
// read // read
exists(Node mid | exists(Node mid |
parameterValueFlowCand(p, mid, false) and parameterValueFlowCand(p, mid, false) and
readStep(mid, _, node) and read(mid, _, node) and
read = true read = true
) )
or or
// flow through: no prior read // flow through: no prior read
exists(ArgumentNode arg | exists(ArgNode arg |
parameterValueFlowArgCand(p, arg, false) and parameterValueFlowArgCand(p, arg, false) and
argumentValueFlowsThroughCand(arg, node, read) argumentValueFlowsThroughCand(arg, node, read)
) )
or or
// flow through: no read inside method // flow through: no read inside method
exists(ArgumentNode arg | exists(ArgNode arg |
parameterValueFlowArgCand(p, arg, read) and parameterValueFlowArgCand(p, arg, read) and
argumentValueFlowsThroughCand(arg, node, false) argumentValueFlowsThroughCand(arg, node, false)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate parameterValueFlowArgCand(ParameterNode p, ArgumentNode arg, boolean read) { private predicate parameterValueFlowArgCand(ParamNode p, ArgNode arg, boolean read) {
parameterValueFlowCand(p, arg, read) parameterValueFlowCand(p, arg, read)
} }
pragma[nomagic] pragma[nomagic]
predicate parameterValueFlowsToPreUpdateCand(ParameterNode p, PostUpdateNode n) { predicate parameterValueFlowsToPreUpdateCand(ParamNode p, PostUpdateNode n) {
parameterValueFlowCand(p, n.getPreUpdateNode(), false) parameterValueFlowCand(p, n.getPreUpdateNode(), false)
} }
@@ -360,7 +443,7 @@ private module Cached {
* `read` indicates whether it is contents of `p` that can flow to the return * `read` indicates whether it is contents of `p` that can flow to the return
* node. * node.
*/ */
predicate parameterValueFlowReturnCand(ParameterNode p, ReturnKind kind, boolean read) { predicate parameterValueFlowReturnCand(ParamNode p, ReturnKind kind, boolean read) {
exists(ReturnNode ret | exists(ReturnNode ret |
parameterValueFlowCand(p, ret, read) and parameterValueFlowCand(p, ret, read) and
kind = ret.getKind() kind = ret.getKind()
@@ -369,9 +452,9 @@ private module Cached {
pragma[nomagic] pragma[nomagic]
private predicate argumentValueFlowsThroughCand0( private predicate argumentValueFlowsThroughCand0(
DataFlowCall call, ArgumentNode arg, ReturnKind kind, boolean read DataFlowCall call, ArgNode arg, ReturnKind kind, boolean read
) { ) {
exists(ParameterNode param | viableParamArg(call, param, arg) | exists(ParamNode param | viableParamArg(call, param, arg) |
parameterValueFlowReturnCand(param, kind, read) parameterValueFlowReturnCand(param, kind, read)
) )
} }
@@ -382,14 +465,14 @@ private module Cached {
* *
* `read` indicates whether it is contents of `arg` that can flow to `out`. * `read` indicates whether it is contents of `arg` that can flow to `out`.
*/ */
predicate argumentValueFlowsThroughCand(ArgumentNode arg, Node out, boolean read) { predicate argumentValueFlowsThroughCand(ArgNode arg, Node out, boolean read) {
exists(DataFlowCall call, ReturnKind kind | exists(DataFlowCall call, ReturnKind kind |
argumentValueFlowsThroughCand0(call, arg, kind, read) and argumentValueFlowsThroughCand0(call, arg, kind, read) and
out = getAnOutNode(call, kind) out = getAnOutNode(call, kind)
) )
} }
predicate cand(ParameterNode p, Node n) { predicate cand(ParamNode p, Node n) {
parameterValueFlowCand(p, n, _) and parameterValueFlowCand(p, n, _) and
( (
parameterValueFlowReturnCand(p, _, _) parameterValueFlowReturnCand(p, _, _)
@@ -416,21 +499,21 @@ private module Cached {
* If a read step was taken, then `read` captures the `Content`, the * If a read step was taken, then `read` captures the `Content`, the
* container type, and the content type. * container type, and the content type.
*/ */
predicate parameterValueFlow(ParameterNode p, Node node, ReadStepTypesOption read) { predicate parameterValueFlow(ParamNode p, Node node, ReadStepTypesOption read) {
parameterValueFlow0(p, node, read) and parameterValueFlow0(p, node, read) and
if node instanceof CastingNode if node instanceof CastingNode
then then
// normal flow through // normal flow through
read = TReadStepTypesNone() and read = TReadStepTypesNone() and
compatibleTypes(getNodeType(p), getNodeType(node)) compatibleTypes(getNodeDataFlowType(p), getNodeDataFlowType(node))
or or
// getter // getter
compatibleTypes(read.getContentType(), getNodeType(node)) compatibleTypes(read.getContentType(), getNodeDataFlowType(node))
else any() else any()
} }
pragma[nomagic] pragma[nomagic]
private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) { private predicate parameterValueFlow0(ParamNode p, Node node, ReadStepTypesOption read) {
p = node and p = node and
Cand::cand(p, _) and Cand::cand(p, _) and
read = TReadStepTypesNone() read = TReadStepTypesNone()
@@ -447,7 +530,7 @@ private module Cached {
readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, readStepWithTypes(mid, read.getContainerType(), read.getContent(), node,
read.getContentType()) and read.getContentType()) and
Cand::parameterValueFlowReturnCand(p, _, true) and Cand::parameterValueFlowReturnCand(p, _, true) and
compatibleTypes(getNodeType(p), read.getContainerType()) compatibleTypes(getNodeDataFlowType(p), read.getContainerType())
) )
or or
parameterValueFlow0_0(TReadStepTypesNone(), p, node, read) parameterValueFlow0_0(TReadStepTypesNone(), p, node, read)
@@ -455,34 +538,32 @@ private module Cached {
pragma[nomagic] pragma[nomagic]
private predicate parameterValueFlow0_0( private predicate parameterValueFlow0_0(
ReadStepTypesOption mustBeNone, ParameterNode p, Node node, ReadStepTypesOption read ReadStepTypesOption mustBeNone, ParamNode p, Node node, ReadStepTypesOption read
) { ) {
// flow through: no prior read // flow through: no prior read
exists(ArgumentNode arg | exists(ArgNode arg |
parameterValueFlowArg(p, arg, mustBeNone) and parameterValueFlowArg(p, arg, mustBeNone) and
argumentValueFlowsThrough(arg, read, node) argumentValueFlowsThrough(arg, read, node)
) )
or or
// flow through: no read inside method // flow through: no read inside method
exists(ArgumentNode arg | exists(ArgNode arg |
parameterValueFlowArg(p, arg, read) and parameterValueFlowArg(p, arg, read) and
argumentValueFlowsThrough(arg, mustBeNone, node) argumentValueFlowsThrough(arg, mustBeNone, node)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate parameterValueFlowArg( private predicate parameterValueFlowArg(ParamNode p, ArgNode arg, ReadStepTypesOption read) {
ParameterNode p, ArgumentNode arg, ReadStepTypesOption read
) {
parameterValueFlow(p, arg, read) and parameterValueFlow(p, arg, read) and
Cand::argumentValueFlowsThroughCand(arg, _, _) Cand::argumentValueFlowsThroughCand(arg, _, _)
} }
pragma[nomagic] pragma[nomagic]
private predicate argumentValueFlowsThrough0( private predicate argumentValueFlowsThrough0(
DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read DataFlowCall call, ArgNode arg, ReturnKind kind, ReadStepTypesOption read
) { ) {
exists(ParameterNode param | viableParamArg(call, param, arg) | exists(ParamNode param | viableParamArg(call, param, arg) |
parameterValueFlowReturn(param, kind, read) parameterValueFlowReturn(param, kind, read)
) )
} }
@@ -496,18 +577,18 @@ private module Cached {
* container type, and the content type. * container type, and the content type.
*/ */
pragma[nomagic] pragma[nomagic]
predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) { predicate argumentValueFlowsThrough(ArgNode arg, ReadStepTypesOption read, Node out) {
exists(DataFlowCall call, ReturnKind kind | exists(DataFlowCall call, ReturnKind kind |
argumentValueFlowsThrough0(call, arg, kind, read) and argumentValueFlowsThrough0(call, arg, kind, read) and
out = getAnOutNode(call, kind) out = getAnOutNode(call, kind)
| |
// normal flow through // normal flow through
read = TReadStepTypesNone() and read = TReadStepTypesNone() and
compatibleTypes(getNodeType(arg), getNodeType(out)) compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(out))
or or
// getter // getter
compatibleTypes(getNodeType(arg), read.getContainerType()) and compatibleTypes(getNodeDataFlowType(arg), read.getContainerType()) and
compatibleTypes(read.getContentType(), getNodeType(out)) compatibleTypes(read.getContentType(), getNodeDataFlowType(out))
) )
} }
@@ -516,7 +597,7 @@ private module Cached {
* value-preserving steps and a single read step, not taking call * value-preserving steps and a single read step, not taking call
* contexts into account, thus representing a getter-step. * contexts into account, thus representing a getter-step.
*/ */
predicate getterStep(ArgumentNode arg, Content c, Node out) { predicate getterStep(ArgNode arg, Content c, Node out) {
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out) argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
} }
@@ -529,7 +610,7 @@ private module Cached {
* container type, and the content type. * container type, and the content type.
*/ */
private predicate parameterValueFlowReturn( private predicate parameterValueFlowReturn(
ParameterNode p, ReturnKind kind, ReadStepTypesOption read ParamNode p, ReturnKind kind, ReadStepTypesOption read
) { ) {
exists(ReturnNode ret | exists(ReturnNode ret |
parameterValueFlow(p, ret, read) and parameterValueFlow(p, ret, read) and
@@ -553,7 +634,7 @@ private module Cached {
private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) { private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) {
mayBenefitFromCallContext(call, callable) mayBenefitFromCallContext(call, callable)
or or
callable = call.getEnclosingCallable() and callEnclosingCallable(call, callable) and
exists(viableCallableLambda(call, TDataFlowCallSome(_))) exists(viableCallableLambda(call, TDataFlowCallSome(_)))
} }
@@ -611,7 +692,7 @@ private module Cached {
mayBenefitFromCallContextExt(call, _) and mayBenefitFromCallContextExt(call, _) and
c = viableCallableExt(call) and c = viableCallableExt(call) and
ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContextExt(call, ctx)) and ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContextExt(call, ctx)) and
tgts = strictcount(DataFlowCall ctx | viableCallableExt(ctx) = call.getEnclosingCallable()) and tgts = strictcount(DataFlowCall ctx | callEnclosingCallable(call, viableCallableExt(ctx))) and
ctxtgts < tgts ctxtgts < tgts
) )
} }
@@ -635,8 +716,7 @@ private module Cached {
* Holds if `p` can flow to the pre-update node associated with post-update * Holds if `p` can flow to the pre-update node associated with post-update
* node `n`, in the same callable, using only value-preserving steps. * node `n`, in the same callable, using only value-preserving steps.
*/ */
cached private predicate parameterValueFlowsToPreUpdate(ParamNode p, PostUpdateNode n) {
predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) {
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone()) parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
} }
@@ -644,9 +724,9 @@ private module Cached {
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
) { ) {
storeStep(node1, c, node2) and storeStep(node1, c, node2) and
readStep(_, c, _) and read(_, c, _) and
contentType = getNodeType(node1) and contentType = getNodeDataFlowType(node1) and
containerType = getNodeType(node2) containerType = getNodeDataFlowType(node2)
or or
exists(Node n1, Node n2 | exists(Node n1, Node n2 |
n1 = node1.(PostUpdateNode).getPreUpdateNode() and n1 = node1.(PostUpdateNode).getPreUpdateNode() and
@@ -654,12 +734,15 @@ private module Cached {
| |
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1) argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
or or
readStep(n2, c, n1) and read(n2, c, n1) and
contentType = getNodeType(n1) and contentType = getNodeDataFlowType(n1) and
containerType = getNodeType(n2) containerType = getNodeDataFlowType(n2)
) )
} }
cached
predicate read(Node node1, Content c, Node node2) { readStep(node1, c, node2) }
/** /**
* Holds if data can flow from `node1` to `node2` via a direct assignment to * Holds if data can flow from `node1` to `node2` via a direct assignment to
* `f`. * `f`.
@@ -678,8 +761,9 @@ private module Cached {
* are aliases. A typical example is a function returning `this`, implementing a fluent * are aliases. A typical example is a function returning `this`, implementing a fluent
* interface. * interface.
*/ */
cached private predicate reverseStepThroughInputOutputAlias(
predicate reverseStepThroughInputOutputAlias(PostUpdateNode fromNode, PostUpdateNode toNode) { PostUpdateNode fromNode, PostUpdateNode toNode
) {
exists(Node fromPre, Node toPre | exists(Node fromPre, Node toPre |
fromPre = fromNode.getPreUpdateNode() and fromPre = fromNode.getPreUpdateNode() and
toPre = toNode.getPreUpdateNode() toPre = toNode.getPreUpdateNode()
@@ -688,14 +772,20 @@ private module Cached {
// Does the language-specific simpleLocalFlowStep already model flow // Does the language-specific simpleLocalFlowStep already model flow
// from function input to output? // from function input to output?
fromPre = getAnOutNode(c, _) and fromPre = getAnOutNode(c, _) and
toPre.(ArgumentNode).argumentOf(c, _) and toPre.(ArgNode).argumentOf(c, _) and
simpleLocalFlowStep(toPre.(ArgumentNode), fromPre) simpleLocalFlowStep(toPre.(ArgNode), fromPre)
) )
or or
argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre) argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre)
) )
} }
cached
predicate simpleLocalFlowStepExt(Node node1, Node node2) {
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
}
/** /**
* Holds if the call context `call` either improves virtual dispatch in * Holds if the call context `call` either improves virtual dispatch in
* `callable` or if it allows us to prune unreachable nodes in `callable`. * `callable` or if it allows us to prune unreachable nodes in `callable`.
@@ -704,7 +794,7 @@ private module Cached {
predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) { predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
reducedViableImplInCallContext(_, callable, call) reducedViableImplInCallContext(_, callable, call)
or or
exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCall(n, call)) exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call))
} }
cached cached
@@ -726,12 +816,12 @@ private module Cached {
cached cached
newtype TLocalFlowCallContext = newtype TLocalFlowCallContext =
TAnyLocalCall() or TAnyLocalCall() or
TSpecificLocalCall(DataFlowCall call) { isUnreachableInCall(_, call) } TSpecificLocalCall(DataFlowCall call) { isUnreachableInCallCached(_, call) }
cached cached
newtype TReturnKindExt = newtype TReturnKindExt =
TValueReturn(ReturnKind kind) or TValueReturn(ReturnKind kind) or
TParamUpdate(int pos) { exists(ParameterNode p | p.isParameterOf(_, pos)) } TParamUpdate(int pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
cached cached
newtype TBooleanOption = newtype TBooleanOption =
@@ -761,23 +851,15 @@ private module Cached {
* A `Node` at which a cast can occur such that the type should be checked. * A `Node` at which a cast can occur such that the type should be checked.
*/ */
class CastingNode extends Node { class CastingNode extends Node {
CastingNode() { CastingNode() { castingNode(this) }
this instanceof ParameterNode or
this instanceof CastNode or
this instanceof OutNodeExt or
// For reads, `x.f`, we want to check that the tracked type after the read (which
// is obtained by popping the head of the access path stack) is compatible with
// the type of `x.f`.
readStep(_, _, this)
}
} }
private predicate readStepWithTypes( private predicate readStepWithTypes(
Node n1, DataFlowType container, Content c, Node n2, DataFlowType content Node n1, DataFlowType container, Content c, Node n2, DataFlowType content
) { ) {
readStep(n1, c, n2) and read(n1, c, n2) and
container = getNodeType(n1) and container = getNodeDataFlowType(n1) and
content = getNodeType(n2) content = getNodeDataFlowType(n2)
} }
private newtype TReadStepTypesOption = private newtype TReadStepTypesOption =
@@ -854,7 +936,7 @@ class CallContextSomeCall extends CallContextCall, TSomeCall {
override string toString() { result = "CcSomeCall" } override string toString() { result = "CcSomeCall" }
override predicate relevantFor(DataFlowCallable callable) { override predicate relevantFor(DataFlowCallable callable) {
exists(ParameterNode p | getNodeEnclosingCallable(p) = callable) exists(ParamNode p | getNodeEnclosingCallable(p) = callable)
} }
override predicate matchesCall(DataFlowCall call) { any() } override predicate matchesCall(DataFlowCall call) { any() }
@@ -866,7 +948,7 @@ class CallContextReturn extends CallContextNoCall, TReturn {
} }
override predicate relevantFor(DataFlowCallable callable) { override predicate relevantFor(DataFlowCallable callable) {
exists(DataFlowCall call | this = TReturn(_, call) and call.getEnclosingCallable() = callable) exists(DataFlowCall call | this = TReturn(_, call) and callEnclosingCallable(call, callable))
} }
} }
@@ -899,7 +981,7 @@ class LocalCallContextSpecificCall extends LocalCallContext, TSpecificLocalCall
} }
private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) { private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) {
exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCall(n, call)) exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCallCached(n, call))
} }
/** /**
@@ -913,26 +995,37 @@ LocalCallContext getLocalCallContext(CallContext ctx, DataFlowCallable callable)
else result instanceof LocalCallContextAny else result instanceof LocalCallContextAny
} }
/**
* The value of a parameter at function entry, viewed as a node in a data
* flow graph.
*/
class ParamNode extends Node {
ParamNode() { parameterNode(this, _, _) }
/**
* Holds if this node is the parameter of callable `c` at the specified
* (zero-based) position.
*/
predicate isParameterOf(DataFlowCallable c, int i) { parameterNode(this, c, i) }
}
/** A data-flow node that represents a call argument. */
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) }
}
/** /**
* A node from which flow can return to the caller. This is either a regular * A node from which flow can return to the caller. This is either a regular
* `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter. * `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter.
*/ */
class ReturnNodeExt extends Node { class ReturnNodeExt extends Node {
ReturnNodeExt() { ReturnNodeExt() { returnNodeExt(this, _) }
this instanceof ReturnNode or
parameterValueFlowsToPreUpdate(_, this)
}
/** Gets the kind of this returned value. */ /** Gets the kind of this returned value. */
ReturnKindExt getKind() { ReturnKindExt getKind() { returnNodeExt(this, result) }
result = TValueReturn(this.(ReturnNode).getKind())
or
exists(ParameterNode p, int pos |
parameterValueFlowsToPreUpdate(p, this) and
p.isParameterOf(_, pos) and
result = TParamUpdate(pos)
)
}
} }
/** /**
@@ -940,11 +1033,7 @@ class ReturnNodeExt extends Node {
* or a post-update node associated with a call argument. * or a post-update node associated with a call argument.
*/ */
class OutNodeExt extends Node { class OutNodeExt extends Node {
OutNodeExt() { OutNodeExt() { outNodeExt(this) }
this instanceof OutNode
or
this.(PostUpdateNode).getPreUpdateNode() instanceof ArgumentNode
}
} }
/** /**
@@ -957,7 +1046,7 @@ abstract class ReturnKindExt extends TReturnKindExt {
abstract string toString(); abstract string toString();
/** Gets a node corresponding to data flow out of `call`. */ /** Gets a node corresponding to data flow out of `call`. */
abstract OutNodeExt getAnOutNode(DataFlowCall call); final OutNodeExt getAnOutNode(DataFlowCall call) { result = getAnOutNodeExt(call, this) }
} }
class ValueReturnKind extends ReturnKindExt, TValueReturn { class ValueReturnKind extends ReturnKindExt, TValueReturn {
@@ -968,10 +1057,6 @@ class ValueReturnKind extends ReturnKindExt, TValueReturn {
ReturnKind getKind() { result = kind } ReturnKind getKind() { result = kind }
override string toString() { result = kind.toString() } override string toString() { result = kind.toString() }
override OutNodeExt getAnOutNode(DataFlowCall call) {
result = getAnOutNode(call, this.getKind())
}
} }
class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate { class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
@@ -982,13 +1067,6 @@ class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
int getPosition() { result = pos } int getPosition() { result = pos }
override string toString() { result = "param update " + pos } override string toString() { result = "param update " + pos }
override OutNodeExt getAnOutNode(DataFlowCall call) {
exists(ArgumentNode arg |
result.(PostUpdateNode).getPreUpdateNode() = arg and
arg.argumentOf(call, this.getPosition())
)
}
} }
/** A callable tagged with a relevant return kind. */ /** A callable tagged with a relevant return kind. */
@@ -1015,10 +1093,13 @@ class ReturnPosition extends TReturnPosition0 {
*/ */
pragma[inline] pragma[inline]
DataFlowCallable getNodeEnclosingCallable(Node n) { DataFlowCallable getNodeEnclosingCallable(Node n) {
exists(Node n0 | nodeEnclosingCallable(pragma[only_bind_out](n), pragma[only_bind_into](result))
pragma[only_bind_into](n0) = n and }
pragma[only_bind_into](result) = n0.getEnclosingCallable()
) /** Gets the type of `n` used for type pruning. */
pragma[inline]
DataFlowType getNodeDataFlowType(Node n) {
nodeDataFlowType(pragma[only_bind_out](n), pragma[only_bind_into](result))
} }
pragma[noinline] pragma[noinline]
@@ -1042,7 +1123,7 @@ predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall
cc instanceof CallContextAny and callable = viableCallableExt(call) cc instanceof CallContextAny and callable = viableCallableExt(call)
or or
exists(DataFlowCallable c0, DataFlowCall call0 | exists(DataFlowCallable c0, DataFlowCall call0 |
call0.getEnclosingCallable() = callable and callEnclosingCallable(call0, callable) and
cc = TReturn(c0, call0) and cc = TReturn(c0, call0) and
c0 = prunedViableImplInCallContextReverse(call0, call) c0 = prunedViableImplInCallContextReverse(call0, call)
) )
@@ -1063,8 +1144,6 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
result = viableCallableExt(call) and cc instanceof CallContextReturn result = viableCallableExt(call) and cc instanceof CallContextReturn
} }
predicate read = readStep/3;
/** An optional Boolean value. */ /** An optional Boolean value. */
class BooleanOption extends TBooleanOption { class BooleanOption extends TBooleanOption {
string toString() { string toString() {
@@ -1116,7 +1195,7 @@ abstract class AccessPathFront extends TAccessPathFront {
TypedContent getHead() { this = TFrontHead(result) } TypedContent getHead() { this = TFrontHead(result) }
predicate isClearedAt(Node n) { clearsContent(n, getHead().getContent()) } predicate isClearedAt(Node n) { clearsContentCached(n, getHead().getContent()) }
} }
class AccessPathFrontNil extends AccessPathFront, TFrontNil { class AccessPathFrontNil extends AccessPathFront, TFrontNil {

View File

@@ -12,10 +12,20 @@ private import semmle.code.cpp.controlflow.IRGuards
private import semmle.code.cpp.models.interfaces.DataFlow private import semmle.code.cpp.models.interfaces.DataFlow
cached cached
private newtype TIRDataFlowNode = private module Cached {
TInstructionNode(Instruction i) or cached
TOperandNode(Operand op) or newtype TIRDataFlowNode =
TVariableNode(Variable var) TInstructionNode(Instruction i) or
TOperandNode(Operand op) or
TVariableNode(Variable var)
cached
predicate localFlowStepCached(Node nodeFrom, Node nodeTo) {
simpleLocalFlowStep(nodeFrom, nodeTo)
}
}
private import Cached
/** /**
* A node in a data flow graph. * A node in a data flow graph.
@@ -590,7 +600,7 @@ Node uninitializedNode(LocalVariable v) { none() }
* Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local * Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local
* (intra-procedural) step. * (intra-procedural) step.
*/ */
predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFrom, nodeTo) } predicate localFlowStep = localFlowStepCached/2;
/** /**
* INTERNAL: do not use. * INTERNAL: do not use.
@@ -598,7 +608,6 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFr
* This is the local flow predicate that's used as a building block in global * This is the local flow predicate that's used as a building block in global
* data flow. It may have less flow than the `localFlowStep` predicate. * data flow. It may have less flow than the `localFlowStep` predicate.
*/ */
cached
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
// Operand -> Instruction flow // Operand -> Instruction flow
simpleInstructionLocalFlowStep(nodeFrom.asOperand(), nodeTo.asInstruction()) simpleInstructionLocalFlowStep(nodeFrom.asOperand(), nodeTo.asInstruction())

View File

@@ -12,7 +12,7 @@ import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
* Holds if the value of `use` is guarded using `abs`. * Holds if the value of `use` is guarded using `abs`.
*/ */
predicate guardedAbs(Operation e, Expr use) { predicate guardedAbs(Operation e, Expr use) {
exists(FunctionCall fc | fc.getTarget().getName() = "abs" | exists(FunctionCall fc | fc.getTarget().getName() = ["abs", "labs", "llabs", "imaxabs"] |
fc.getArgument(0).getAChild*() = use and fc.getArgument(0).getAChild*() = use and
guardedLesser(e, fc) guardedLesser(e, fc)
) )

View File

@@ -0,0 +1 @@
| test.c:14:9:14:16 | intIndex | A variable with this name is used in the $@ condition. | test.c:11:3:16:3 | while (...) ... | loop |

View File

@@ -0,0 +1 @@
experimental/Security/CWE/CWE-1126/DeclarationOfVariableWithUnnecessarilyWideScope.ql

View File

@@ -0,0 +1,59 @@
void workFunction_0(char *s) {
int intIndex = 10;
int intGuard;
char buf[80];
while(intIndex > 2) // GOOD
{
buf[intIndex] = 1;
intIndex--;
}
intIndex = 10;
while(intIndex > 2)
{
buf[intIndex] = 1;
int intIndex; // BAD
intIndex--;
}
intIndex = 10;
intGuard = 20;
while(intIndex < intGuard--) // GOOD
{
buf[intIndex] = 1;
int intIndex;
intIndex--;
}
intIndex = 10;
intGuard = 20;
while(intIndex < intGuard) // GOOD
{
buf[intIndex] = 1;
int intIndex;
intIndex++;
intGuard--;
}
intIndex = 10;
intGuard = 20;
while(intIndex < intGuard) // GOOD
{
buf[intIndex] = 1;
int intIndex;
intIndex--;
intGuard -= 4;
}
intIndex = 10;
while(intIndex > 2) // GOOD
{
buf[intIndex] = 1;
intIndex -= 2;
int intIndex;
intIndex--;
}
intIndex = 10;
while(intIndex > 2) // GOOD
{
buf[intIndex] = 1;
--intIndex;
int intIndex;
intIndex--;
}
}

View File

@@ -18,3 +18,25 @@ void useTaintedInt()
y = getTaintedInt(); y = getTaintedInt();
y = y * 1024; // BAD: arithmetic on a tainted value y = y * 1024; // BAD: arithmetic on a tainted value
} }
typedef long long int intmax_t;
intmax_t imaxabs(intmax_t j);
void useTaintedIntWithGuard() {
int tainted = getTaintedInt();
if(imaxabs(tainted) <= 100) {
int product = tainted * tainted; // GOOD: can't underflow/overflow
}
}
#define INTMAX_MIN (-0x7fffffffffffffff - 1)
void useTaintedIntWithGuardIntMaxMin() {
intmax_t tainted = getTaintedInt();
if(imaxabs(tainted) <= INTMAX_MIN) {
int product = tainted * tainted; // BAD: imaxabs(INTMAX_MIN) == INTMAX_MIN [NOT DETECTED]
}
}

View File

@@ -170,7 +170,8 @@ namespace Semmle.Extraction.CSharp.Entities
public static Expression? CreateGenerated(Context cx, IParameterSymbol parameter, IExpressionParentEntity parent, public static Expression? CreateGenerated(Context cx, IParameterSymbol parameter, IExpressionParentEntity parent,
int childIndex, Extraction.Entities.Location location) int childIndex, Extraction.Entities.Location location)
{ {
if (!parameter.HasExplicitDefaultValue) if (!parameter.HasExplicitDefaultValue ||
parameter.Type is IErrorTypeSymbol)
{ {
return null; return null;
} }

View File

@@ -13,7 +13,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(EscapingTextWriter trapFile) public override void WriteId(EscapingTextWriter trapFile)
{ {
Symbol.BuildTypeId(Context, trapFile, Symbol); Symbol.BuildTypeId(Context, trapFile, Symbol, constructUnderlyingTupleType: false);
trapFile.Write(";functionpointertype"); trapFile.Write(";functionpointertype");
} }

View File

@@ -32,7 +32,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(EscapingTextWriter trapFile) public override void WriteId(EscapingTextWriter trapFile)
{ {
Symbol.BuildTypeId(Context, trapFile, Symbol); Symbol.BuildTypeId(Context, trapFile, Symbol, constructUnderlyingTupleType: false);
trapFile.Write(";tuple"); trapFile.Write(";tuple");
} }

View File

@@ -81,22 +81,45 @@ namespace Semmle.Extraction.CSharp.Entities
Symbol.BuildDisplayName(Context, trapFile, constructUnderlyingTupleType); Symbol.BuildDisplayName(Context, trapFile, constructUnderlyingTupleType);
trapFile.WriteLine("\")"); trapFile.WriteLine("\")");
var baseTypes = GetBaseTypeDeclarations();
// Visit base types // Visit base types
var baseTypes = new List<Type>();
if (Symbol.GetNonObjectBaseType(Context) is INamedTypeSymbol @base) if (Symbol.GetNonObjectBaseType(Context) is INamedTypeSymbol @base)
{ {
var baseKey = Create(Context, @base); var bts = GetBaseTypeDeclarations(baseTypes, @base);
trapFile.extend(this, baseKey.TypeRef);
if (Symbol.TypeKind != TypeKind.Struct) Context.PopulateLater(() =>
baseTypes.Add(baseKey); {
var baseKey = Create(Context, @base);
trapFile.extend(this, baseKey.TypeRef);
if (Symbol.TypeKind != TypeKind.Struct)
{
foreach (var bt in bts)
{
TypeMention.Create(Context, bt.Type, this, baseKey);
}
}
});
} }
// Visit implemented interfaces
if (!(base.Symbol is IArrayTypeSymbol)) if (!(base.Symbol is IArrayTypeSymbol))
{ {
foreach (var t in base.Symbol.Interfaces.Select(i => Create(Context, i))) foreach (var i in base.Symbol.Interfaces)
{ {
trapFile.implement(this, t.TypeRef); var bts = GetBaseTypeDeclarations(baseTypes, i);
baseTypes.Add(t);
Context.PopulateLater(() =>
{
var interfaceKey = Create(Context, i);
trapFile.implement(this, interfaceKey.TypeRef);
foreach (var bt in bts)
{
TypeMention.Create(Context, bt.Type, this, interfaceKey);
}
});
} }
} }
@@ -145,23 +168,30 @@ namespace Semmle.Extraction.CSharp.Entities
} }
Modifier.ExtractModifiers(Context, trapFile, this, Symbol); Modifier.ExtractModifiers(Context, trapFile, this, Symbol);
}
if (IsSourceDeclaration && Symbol.FromSource()) private IEnumerable<BaseTypeSyntax> GetBaseTypeDeclarations()
{
if (!IsSourceDeclaration || !Symbol.FromSource())
{ {
var declSyntaxReferences = Symbol.DeclaringSyntaxReferences.Select(d => d.GetSyntax()).ToArray(); return Enumerable.Empty<BaseTypeSyntax>();
var baseLists = declSyntaxReferences.OfType<ClassDeclarationSyntax>().Select(c => c.BaseList);
baseLists = baseLists.Concat(declSyntaxReferences.OfType<InterfaceDeclarationSyntax>().Select(c => c.BaseList));
baseLists = baseLists.Concat(declSyntaxReferences.OfType<StructDeclarationSyntax>().Select(c => c.BaseList));
baseLists
.Where(bl => bl is not null)
.SelectMany(bl => bl!.Types)
.Zip(
baseTypes.Where(bt => bt.Symbol.SpecialType != SpecialType.System_Object),
(s, t) => TypeMention.Create(Context, s.Type, this, t))
.Enumerate();
} }
var declSyntaxReferences = Symbol.DeclaringSyntaxReferences.Select(d => d.GetSyntax()).ToArray();
var baseLists = declSyntaxReferences.OfType<ClassDeclarationSyntax>().Select(c => c.BaseList);
baseLists = baseLists.Concat(declSyntaxReferences.OfType<InterfaceDeclarationSyntax>().Select(c => c.BaseList));
baseLists = baseLists.Concat(declSyntaxReferences.OfType<StructDeclarationSyntax>().Select(c => c.BaseList));
return baseLists
.Where(bl => bl is not null)
.SelectMany(bl => bl!.Types)
.ToList();
}
private IEnumerable<BaseTypeSyntax> GetBaseTypeDeclarations(IEnumerable<BaseTypeSyntax> baseTypes, INamedTypeSymbol type)
{
return baseTypes.Where(bt => SymbolEqualityComparer.Default.Equals(Context.GetModel(bt).GetTypeInfo(bt.Type).Type, type));
} }
private void ExtractParametersForDelegateLikeType(TextWriter trapFile, IMethodSymbol invokeMethod, Action<Type> storeReturnType) private void ExtractParametersForDelegateLikeType(TextWriter trapFile, IMethodSymbol invokeMethod, Action<Type> storeReturnType)

View File

@@ -121,8 +121,6 @@ namespace Semmle.Extraction.CSharp
named = named.TupleUnderlyingType; named = named.TupleUnderlyingType;
if (IdDependsOnImpl(named.ContainingType)) if (IdDependsOnImpl(named.ContainingType))
return true; return true;
if (IdDependsOnImpl(named.GetNonObjectBaseType(cx)))
return true;
if (IdDependsOnImpl(named.ConstructedFrom)) if (IdDependsOnImpl(named.ConstructedFrom))
return true; return true;
return named.TypeArguments.Any(IdDependsOnImpl); return named.TypeArguments.Any(IdDependsOnImpl);
@@ -160,10 +158,7 @@ namespace Semmle.Extraction.CSharp
/// <param name="trapFile">The trap builder used to store the result.</param> /// <param name="trapFile">The trap builder used to store the result.</param>
/// <param name="symbolBeingDefined">The outer symbol being defined (to avoid recursive ids).</param> /// <param name="symbolBeingDefined">The outer symbol being defined (to avoid recursive ids).</param>
/// <param name="constructUnderlyingTupleType">Whether to build a type ID for the underlying `System.ValueTuple` struct in the case of tuple types.</param> /// <param name="constructUnderlyingTupleType">Whether to build a type ID for the underlying `System.ValueTuple` struct in the case of tuple types.</param>
public static void BuildTypeId(this ITypeSymbol type, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined, bool constructUnderlyingTupleType = false) => public static void BuildTypeId(this ITypeSymbol type, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined, bool constructUnderlyingTupleType)
type.BuildTypeId(cx, trapFile, symbolBeingDefined, true, constructUnderlyingTupleType);
private static void BuildTypeId(this ITypeSymbol type, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined, bool addBaseClass, bool constructUnderlyingTupleType)
{ {
using (cx.StackGuard) using (cx.StackGuard)
{ {
@@ -171,7 +166,7 @@ namespace Semmle.Extraction.CSharp
{ {
case TypeKind.Array: case TypeKind.Array:
var array = (IArrayTypeSymbol)type; var array = (IArrayTypeSymbol)type;
array.ElementType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass); array.ElementType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
array.BuildArraySuffix(trapFile); array.BuildArraySuffix(trapFile);
return; return;
case TypeKind.Class: case TypeKind.Class:
@@ -181,16 +176,16 @@ namespace Semmle.Extraction.CSharp
case TypeKind.Delegate: case TypeKind.Delegate:
case TypeKind.Error: case TypeKind.Error:
var named = (INamedTypeSymbol)type; var named = (INamedTypeSymbol)type;
named.BuildNamedTypeId(cx, trapFile, symbolBeingDefined, addBaseClass, constructUnderlyingTupleType); named.BuildNamedTypeId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType);
return; return;
case TypeKind.Pointer: case TypeKind.Pointer:
var ptr = (IPointerTypeSymbol)type; var ptr = (IPointerTypeSymbol)type;
ptr.PointedAtType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass); ptr.PointedAtType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
trapFile.Write('*'); trapFile.Write('*');
return; return;
case TypeKind.TypeParameter: case TypeKind.TypeParameter:
var tp = (ITypeParameterSymbol)type; var tp = (ITypeParameterSymbol)type;
tp.ContainingSymbol.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass); tp.ContainingSymbol.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
trapFile.Write('_'); trapFile.Write('_');
trapFile.Write(tp.Name); trapFile.Write(tp.Name);
return; return;
@@ -207,7 +202,7 @@ namespace Semmle.Extraction.CSharp
} }
} }
private static void BuildOrWriteId(this ISymbol? symbol, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined, bool addBaseClass, bool constructUnderlyingTupleType = false) private static void BuildOrWriteId(this ISymbol? symbol, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined, bool constructUnderlyingTupleType)
{ {
if (symbol is null) if (symbol is null)
{ {
@@ -232,7 +227,7 @@ namespace Semmle.Extraction.CSharp
if (SymbolEqualityComparer.Default.Equals(symbol, symbolBeingDefined)) if (SymbolEqualityComparer.Default.Equals(symbol, symbolBeingDefined))
trapFile.Write("__self__"); trapFile.Write("__self__");
else if (symbol is ITypeSymbol type && type.IdDependsOn(cx, symbolBeingDefined)) else if (symbol is ITypeSymbol type && type.IdDependsOn(cx, symbolBeingDefined))
type.BuildTypeId(cx, trapFile, symbolBeingDefined, addBaseClass, constructUnderlyingTupleType); type.BuildTypeId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType);
else if (symbol is INamedTypeSymbol namedType && namedType.IsTupleType && constructUnderlyingTupleType) else if (symbol is INamedTypeSymbol namedType && namedType.IsTupleType && constructUnderlyingTupleType)
trapFile.WriteSubId(NamedType.CreateNamedTypeFromTupleType(cx, namedType)); trapFile.WriteSubId(NamedType.CreateNamedTypeFromTupleType(cx, namedType));
else else
@@ -250,7 +245,7 @@ namespace Semmle.Extraction.CSharp
/// <paramref name="symbol" />. /// <paramref name="symbol" />.
/// </summary> /// </summary>
public static void BuildOrWriteId(this ISymbol? symbol, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined) => public static void BuildOrWriteId(this ISymbol? symbol, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined) =>
symbol.BuildOrWriteId(cx, trapFile, symbolBeingDefined, true); symbol.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
/// <summary> /// <summary>
/// Constructs an array suffix string for this array type symbol. /// Constructs an array suffix string for this array type symbol.
@@ -287,7 +282,7 @@ namespace Semmle.Extraction.CSharp
BuildFunctionPointerSignature(funptr, trapFile, s => s.BuildOrWriteId(cx, trapFile, symbolBeingDefined)); BuildFunctionPointerSignature(funptr, trapFile, s => s.BuildOrWriteId(cx, trapFile, symbolBeingDefined));
} }
private static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined, bool addBaseClass, bool constructUnderlyingTupleType) private static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, EscapingTextWriter trapFile, ISymbol symbolBeingDefined, bool constructUnderlyingTupleType)
{ {
if (!constructUnderlyingTupleType && named.IsTupleType) if (!constructUnderlyingTupleType && named.IsTupleType)
{ {
@@ -297,7 +292,7 @@ namespace Semmle.Extraction.CSharp
{ {
trapFile.Write((f.CorrespondingTupleField ?? f).Name); trapFile.Write((f.CorrespondingTupleField ?? f).Name);
trapFile.Write(":"); trapFile.Write(":");
f.Type.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass); f.Type.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
} }
); );
trapFile.Write(")"); trapFile.Write(")");
@@ -308,7 +303,7 @@ namespace Semmle.Extraction.CSharp
{ {
if (named.ContainingType is not null) if (named.ContainingType is not null)
{ {
named.ContainingType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass); named.ContainingType.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false);
trapFile.Write('.'); trapFile.Write('.');
} }
else if (named.ContainingNamespace is not null) else if (named.ContainingNamespace is not null)
@@ -333,35 +328,17 @@ namespace Semmle.Extraction.CSharp
} }
else else
{ {
named.ConstructedFrom.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass, constructUnderlyingTupleType); named.ConstructedFrom.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType);
trapFile.Write('<'); trapFile.Write('<');
// Encode the nullability of the type arguments in the label. // Encode the nullability of the type arguments in the label.
// Type arguments with different nullability can result in // Type arguments with different nullability can result in
// a constructed type with different nullability of its members and methods, // a constructed type with different nullability of its members and methods,
// so we need to create a distinct database entity for it. // so we need to create a distinct database entity for it.
trapFile.BuildList(",", named.GetAnnotatedTypeArguments(), trapFile.BuildList(",", named.GetAnnotatedTypeArguments(),
ta => ta.Symbol.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass) ta => ta.Symbol.BuildOrWriteId(cx, trapFile, symbolBeingDefined, constructUnderlyingTupleType: false)
); );
trapFile.Write('>'); trapFile.Write('>');
} }
if (addBaseClass && named.GetNonObjectBaseType(cx) is INamedTypeSymbol @base)
{
// We need to limit unfolding of base classes. For example, in
//
// ```csharp
// class C1<T> { }
// class C2<T> : C1<C3<T>> { }
// class C3<T> : C1<C2<T>> { }
// class C4 : C3<C4> { }
// ```
//
// when we generate the label for `C4`, the base class `C3<C4>` has itself `C1<C2<C4>>` as
// a base class, which in turn has `C1<C3<C4>>` as a base class. The latter has the original
// base class `C3<C4>` as a type argument, which would lead to infinite unfolding.
trapFile.Write(" : ");
@base.BuildOrWriteId(cx, trapFile, symbolBeingDefined, addBaseClass: false);
}
} }
private static void BuildNamespace(this INamespaceSymbol ns, Context cx, EscapingTextWriter trapFile) private static void BuildNamespace(this INamespaceSymbol ns, Context cx, EscapingTextWriter trapFile)

View File

@@ -47,44 +47,6 @@ module Stages {
} }
} }
cached
module DataFlowStage {
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
private import semmle.code.csharp.dataflow.internal.DataFlowImplCommon
private import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate
cached
predicate forceCachingInSameStage() { any() }
cached
private predicate forceCachingInSameStageRev() {
defaultAdditionalTaintStep(_, _)
or
any(ArgumentNode n).argumentOf(_, _)
or
exists(any(DataFlow::Node n).getEnclosingCallable())
or
exists(any(DataFlow::Node n).getControlFlowNode())
or
exists(any(DataFlow::Node n).getType())
or
exists(any(NodeImpl n).getDataFlowType())
or
exists(any(DataFlow::Node n).getLocation())
or
exists(any(DataFlow::Node n).toString())
or
exists(any(OutNode n).getCall(_))
or
exists(CallContext cc)
or
exists(any(DataFlowCall c).getEnclosingCallable())
or
forceCachingInSameStageRev()
}
}
cached cached
module UnificationStage { module UnificationStage {
private import semmle.code.csharp.Unification private import semmle.code.csharp.Unification

View File

@@ -1,10 +1,10 @@
private import csharp private import csharp
private import cil private import cil
private import dotnet private import dotnet
private import DataFlowImplCommon as DataFlowImplCommon
private import DataFlowPublic private import DataFlowPublic
private import DataFlowPrivate private import DataFlowPrivate
private import FlowSummaryImpl as FlowSummaryImpl private import FlowSummaryImpl as FlowSummaryImpl
private import semmle.code.csharp.Caching
private import semmle.code.csharp.dataflow.FlowSummary private import semmle.code.csharp.dataflow.FlowSummary
private import semmle.code.csharp.dispatch.Dispatch private import semmle.code.csharp.dispatch.Dispatch
private import semmle.code.csharp.frameworks.system.Collections private import semmle.code.csharp.frameworks.system.Collections
@@ -68,31 +68,30 @@ private predicate transitiveCapturedCallTarget(ControlFlow::Nodes::ElementNode c
) )
} }
cached newtype TReturnKind =
private module Cached { TNormalReturnKind() or
cached TOutReturnKind(int i) { i = any(Parameter p | p.isOut()).getPosition() } or
newtype TReturnKind = TRefReturnKind(int i) { i = any(Parameter p | p.isRef()).getPosition() } or
TNormalReturnKind() { Stages::DataFlowStage::forceCachingInSameStage() } or TImplicitCapturedReturnKind(LocalScopeVariable v) {
TOutReturnKind(int i) { i = any(Parameter p | p.isOut()).getPosition() } or exists(Ssa::ExplicitDefinition def | def.isCapturedVariableDefinitionFlowOut(_, _) |
TRefReturnKind(int i) { i = any(Parameter p | p.isRef()).getPosition() } or v = def.getSourceVariable().getAssignable()
TImplicitCapturedReturnKind(LocalScopeVariable v) { )
exists(Ssa::ExplicitDefinition def | def.isCapturedVariableDefinitionFlowOut(_, _) | } or
v = def.getSourceVariable().getAssignable() TJumpReturnKind(DataFlowCallable target, ReturnKind rk) {
) rk instanceof NormalReturnKind and
} or (
TJumpReturnKind(DataFlowCallable target, ReturnKind rk) { target instanceof Constructor or
rk instanceof NormalReturnKind and not target.getReturnType() instanceof VoidType
( )
target instanceof Constructor or or
not target.getReturnType() instanceof VoidType exists(target.getParameter(rk.(OutRefReturnKind).getPosition()))
) }
or
exists(target.getParameter(rk.(OutRefReturnKind).getPosition()))
}
private module Cached {
cached cached
newtype TDataFlowCall = newtype TDataFlowCall =
TNonDelegateCall(ControlFlow::Nodes::ElementNode cfn, DispatchCall dc) { TNonDelegateCall(ControlFlow::Nodes::ElementNode cfn, DispatchCall dc) {
DataFlowImplCommon::forceCachingInSameStage() and
cfn.getElement() = dc.getCall() cfn.getElement() = dc.getCall()
} or } or
TExplicitDelegateLikeCall(ControlFlow::Nodes::ElementNode cfn, DelegateLikeCall dc) { TExplicitDelegateLikeCall(ControlFlow::Nodes::ElementNode cfn, DelegateLikeCall dc) {
@@ -246,7 +245,6 @@ abstract class DataFlowCall extends TDataFlowCall {
abstract DataFlow::Node getNode(); abstract DataFlow::Node getNode();
/** Gets the enclosing callable of this call. */ /** Gets the enclosing callable of this call. */
cached
abstract DataFlowCallable getEnclosingCallable(); abstract DataFlowCallable getEnclosingCallable();
/** Gets the underlying expression, if any. */ /** Gets the underlying expression, if any. */
@@ -280,10 +278,7 @@ class NonDelegateDataFlowCall extends DataFlowCall, TNonDelegateCall {
override DataFlow::ExprNode getNode() { result.getControlFlowNode() = cfn } override DataFlow::ExprNode getNode() { result.getControlFlowNode() = cfn }
override DataFlowCallable getEnclosingCallable() { override DataFlowCallable getEnclosingCallable() { result = cfn.getEnclosingCallable() }
Stages::DataFlowStage::forceCachingInSameStage() and
result = cfn.getEnclosingCallable()
}
override string toString() { result = cfn.toString() } override string toString() { result = cfn.toString() }

View File

@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`. * Holds if data can flow in one local step from `node1` to `node2`.
*/ */
private predicate localFlowStep(Node node1, Node node2, Configuration config) { private predicate localFlowStep(Node node1, Node node2, Configuration config) {
( simpleLocalFlowStepExt(node1, node2) and
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts. * Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/ */
private predicate jumpStep(Node node1, Node node2, Configuration config) { private predicate jumpStep(Node node1, Node node2, Configuration config) {
jumpStep(node1, node2) and jumpStepCached(node1, node2) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) { private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
exists(ArgumentNode arg | exists(ArgNode arg |
fwdFlow(arg, cc, config) and fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg) viableParamArg(call, _, arg)
) )
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic] pragma[nomagic]
predicate viableParamArgNodeCandFwd1( predicate viableParamArgNodeCandFwd1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
viableParamArg(call, p, arg) and viableParamArg(call, p, arg) and
fwdFlow(arg, config) fwdFlow(arg, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config exists(ParamNode p |
) {
exists(ParameterNode p |
revFlow(p, toReturn, config) and revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config) viableParamArgNodeCandFwd1(call, p, arg, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config) revFlowIn(call, arg, true, config)
} }
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a * Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic] pragma[nomagic]
private predicate viableParamArgNodeCand1( private predicate viableParamArgNodeCand1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config) Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) { ) {
viableParamArgNodeCand1(call, p, arg, config) and viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, arg, p, config) and flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j | exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config) PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
) )
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand2( private predicate flowIntoCallNodeCand2(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/ */
private class FlowCheckNode extends Node { private class FlowCheckNode extends Node {
FlowCheckNode() { FlowCheckNode() {
this instanceof CastNode or castNode(this) or
clearsContent(this, _) clearsContentCached(this, _)
} }
} }
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or config.isSource(node) or
jumpStep(_, node, config) or jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or additionalJumpStep(_, node, config) or
node instanceof ParameterNode or node instanceof ParamNode or
node instanceof OutNodeExt or node instanceof OutNodeExt or
store(_, _, node, _) or store(_, _, node, _) or
read(_, _, node) or read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc LocalCallContext cc
) { ) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
( (
localFlowEntry(node1, pragma[only_bind_into](config)) and localFlowEntry(node1, pragma[only_bind_into](config)) and
( (
localFlowStepNodeCand1(node1, node2, config) and localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and preservesValue = true and
t = getNodeType(node1) t = getNodeDataFlowType(node1)
or or
additionalLocalFlowStepNodeCand2(node1, node2, config) and additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) t = getNodeDataFlowType(node2)
) and ) and
node1 != node2 and node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
or or
exists(Node mid | exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and not mid instanceof FlowCheckNode and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) and t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
) )
) )
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() } private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap] bindingset[node, ap]
private predicate filter(Node node, Ap ap) { private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and not ap.isClearedAt(node) and
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() if node instanceof CastingNode
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
} }
bindingset[ap, contentType] bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() } private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCall( private predicate flowIntoCall(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx = private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParameterNode p, AccessPath ap) { TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _) Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
} }
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */ /** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
private ParameterNode p; private ParamNode p;
private AccessPath ap; private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) } SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and config.isSource(node) and
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
// ... or a step from an existing PathNode to another node. // ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid | exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() } Configuration getConfiguration() { none() }
private predicate isHidden() { private predicate isHidden() {
nodeIsHidden(this.getNode()) and hiddenNode(this.getNode()) and
not this.isSource() and not this.isSource() and
not this instanceof PathNodeSink not this instanceof PathNodeSink
} }
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and mid.getAp() instanceof AccessPathNil and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx() sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg( private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand( private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i) p.isParameterOf(callable, i)
) )
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively. * respectively.
*/ */
private predicate pathIntoCallable( private predicate pathIntoCallable(
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call DataFlowCall call
) { ) {
exists(int i, DataFlowCallable callable, AccessPath ap | exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 = private newtype TSummaryCtx1 =
TSummaryCtx1None() or TSummaryCtx1None() or
TSummaryCtx1Param(ParameterNode p) TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 = private newtype TSummaryCtx2 =
TSummaryCtx2None() or TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
exists(config.explorationLimit()) exists(config.explorationLimit())
or or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or or
exists(PartialPathNodeRev mid | exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit() distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
) )
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid | exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not clearsContent(node, ap.getHead().getContent()) and not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode if node instanceof CastingNode
then compatibleTypes(getNodeType(node), ap.getType()) then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any() else any()
) )
} }
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
( (
localFlowStep(mid.getNode(), node, config) and localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
) )
or or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
or or
partialPathStoreStep(mid, _, _, node, ap) and partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getNodeType(node)) compatibleTypes(ap.getType(), getNodeDataFlowType(node))
) )
or or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap, PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
} }
private predicate partialPathIntoCallable( private predicate partialPathIntoCallable(
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc, PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap, TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc, DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 | exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config) paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
) )
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config) apConsRev(ap, c, ap0, config)
) )
or or
exists(ParameterNode p | exists(ParamNode p |
mid.getNode() = p and mid.getNode() = p and
viableParamArg(_, p, node) and viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap, int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(PartialPathNodeRev mid, ParameterNode p | exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and mid.getNode() = p and
p.isParameterOf(_, pos) and p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic] pragma[nomagic]
private predicate revPartialPathThroughCallable( private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) { ) {
exists(DataFlowCall call, int pos | exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and revPartialPathThroughCallable0(call, mid, pos, ap, config) and

View File

@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`. * Holds if data can flow in one local step from `node1` to `node2`.
*/ */
private predicate localFlowStep(Node node1, Node node2, Configuration config) { private predicate localFlowStep(Node node1, Node node2, Configuration config) {
( simpleLocalFlowStepExt(node1, node2) and
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts. * Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/ */
private predicate jumpStep(Node node1, Node node2, Configuration config) { private predicate jumpStep(Node node1, Node node2, Configuration config) {
jumpStep(node1, node2) and jumpStepCached(node1, node2) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) { private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
exists(ArgumentNode arg | exists(ArgNode arg |
fwdFlow(arg, cc, config) and fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg) viableParamArg(call, _, arg)
) )
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic] pragma[nomagic]
predicate viableParamArgNodeCandFwd1( predicate viableParamArgNodeCandFwd1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
viableParamArg(call, p, arg) and viableParamArg(call, p, arg) and
fwdFlow(arg, config) fwdFlow(arg, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config exists(ParamNode p |
) {
exists(ParameterNode p |
revFlow(p, toReturn, config) and revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config) viableParamArgNodeCandFwd1(call, p, arg, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config) revFlowIn(call, arg, true, config)
} }
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a * Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic] pragma[nomagic]
private predicate viableParamArgNodeCand1( private predicate viableParamArgNodeCand1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config) Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) { ) {
viableParamArgNodeCand1(call, p, arg, config) and viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, arg, p, config) and flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j | exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config) PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
) )
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand2( private predicate flowIntoCallNodeCand2(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/ */
private class FlowCheckNode extends Node { private class FlowCheckNode extends Node {
FlowCheckNode() { FlowCheckNode() {
this instanceof CastNode or castNode(this) or
clearsContent(this, _) clearsContentCached(this, _)
} }
} }
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or config.isSource(node) or
jumpStep(_, node, config) or jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or additionalJumpStep(_, node, config) or
node instanceof ParameterNode or node instanceof ParamNode or
node instanceof OutNodeExt or node instanceof OutNodeExt or
store(_, _, node, _) or store(_, _, node, _) or
read(_, _, node) or read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc LocalCallContext cc
) { ) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
( (
localFlowEntry(node1, pragma[only_bind_into](config)) and localFlowEntry(node1, pragma[only_bind_into](config)) and
( (
localFlowStepNodeCand1(node1, node2, config) and localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and preservesValue = true and
t = getNodeType(node1) t = getNodeDataFlowType(node1)
or or
additionalLocalFlowStepNodeCand2(node1, node2, config) and additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) t = getNodeDataFlowType(node2)
) and ) and
node1 != node2 and node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
or or
exists(Node mid | exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and not mid instanceof FlowCheckNode and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) and t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
) )
) )
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() } private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap] bindingset[node, ap]
private predicate filter(Node node, Ap ap) { private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and not ap.isClearedAt(node) and
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() if node instanceof CastingNode
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
} }
bindingset[ap, contentType] bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() } private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCall( private predicate flowIntoCall(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx = private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParameterNode p, AccessPath ap) { TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _) Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
} }
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */ /** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
private ParameterNode p; private ParamNode p;
private AccessPath ap; private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) } SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and config.isSource(node) and
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
// ... or a step from an existing PathNode to another node. // ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid | exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() } Configuration getConfiguration() { none() }
private predicate isHidden() { private predicate isHidden() {
nodeIsHidden(this.getNode()) and hiddenNode(this.getNode()) and
not this.isSource() and not this.isSource() and
not this instanceof PathNodeSink not this instanceof PathNodeSink
} }
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and mid.getAp() instanceof AccessPathNil and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx() sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg( private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand( private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i) p.isParameterOf(callable, i)
) )
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively. * respectively.
*/ */
private predicate pathIntoCallable( private predicate pathIntoCallable(
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call DataFlowCall call
) { ) {
exists(int i, DataFlowCallable callable, AccessPath ap | exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 = private newtype TSummaryCtx1 =
TSummaryCtx1None() or TSummaryCtx1None() or
TSummaryCtx1Param(ParameterNode p) TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 = private newtype TSummaryCtx2 =
TSummaryCtx2None() or TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
exists(config.explorationLimit()) exists(config.explorationLimit())
or or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or or
exists(PartialPathNodeRev mid | exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit() distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
) )
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid | exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not clearsContent(node, ap.getHead().getContent()) and not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode if node instanceof CastingNode
then compatibleTypes(getNodeType(node), ap.getType()) then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any() else any()
) )
} }
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
( (
localFlowStep(mid.getNode(), node, config) and localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
) )
or or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
or or
partialPathStoreStep(mid, _, _, node, ap) and partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getNodeType(node)) compatibleTypes(ap.getType(), getNodeDataFlowType(node))
) )
or or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap, PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
} }
private predicate partialPathIntoCallable( private predicate partialPathIntoCallable(
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc, PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap, TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc, DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 | exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config) paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
) )
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config) apConsRev(ap, c, ap0, config)
) )
or or
exists(ParameterNode p | exists(ParamNode p |
mid.getNode() = p and mid.getNode() = p and
viableParamArg(_, p, node) and viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap, int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(PartialPathNodeRev mid, ParameterNode p | exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and mid.getNode() = p and
p.isParameterOf(_, pos) and p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic] pragma[nomagic]
private predicate revPartialPathThroughCallable( private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) { ) {
exists(DataFlowCall call, int pos | exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and revPartialPathThroughCallable0(call, mid, pos, ap, config) and

View File

@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`. * Holds if data can flow in one local step from `node1` to `node2`.
*/ */
private predicate localFlowStep(Node node1, Node node2, Configuration config) { private predicate localFlowStep(Node node1, Node node2, Configuration config) {
( simpleLocalFlowStepExt(node1, node2) and
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts. * Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/ */
private predicate jumpStep(Node node1, Node node2, Configuration config) { private predicate jumpStep(Node node1, Node node2, Configuration config) {
jumpStep(node1, node2) and jumpStepCached(node1, node2) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) { private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
exists(ArgumentNode arg | exists(ArgNode arg |
fwdFlow(arg, cc, config) and fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg) viableParamArg(call, _, arg)
) )
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic] pragma[nomagic]
predicate viableParamArgNodeCandFwd1( predicate viableParamArgNodeCandFwd1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
viableParamArg(call, p, arg) and viableParamArg(call, p, arg) and
fwdFlow(arg, config) fwdFlow(arg, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config exists(ParamNode p |
) {
exists(ParameterNode p |
revFlow(p, toReturn, config) and revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config) viableParamArgNodeCandFwd1(call, p, arg, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config) revFlowIn(call, arg, true, config)
} }
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a * Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic] pragma[nomagic]
private predicate viableParamArgNodeCand1( private predicate viableParamArgNodeCand1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config) Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) { ) {
viableParamArgNodeCand1(call, p, arg, config) and viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, arg, p, config) and flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j | exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config) PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
) )
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand2( private predicate flowIntoCallNodeCand2(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/ */
private class FlowCheckNode extends Node { private class FlowCheckNode extends Node {
FlowCheckNode() { FlowCheckNode() {
this instanceof CastNode or castNode(this) or
clearsContent(this, _) clearsContentCached(this, _)
} }
} }
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or config.isSource(node) or
jumpStep(_, node, config) or jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or additionalJumpStep(_, node, config) or
node instanceof ParameterNode or node instanceof ParamNode or
node instanceof OutNodeExt or node instanceof OutNodeExt or
store(_, _, node, _) or store(_, _, node, _) or
read(_, _, node) or read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc LocalCallContext cc
) { ) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
( (
localFlowEntry(node1, pragma[only_bind_into](config)) and localFlowEntry(node1, pragma[only_bind_into](config)) and
( (
localFlowStepNodeCand1(node1, node2, config) and localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and preservesValue = true and
t = getNodeType(node1) t = getNodeDataFlowType(node1)
or or
additionalLocalFlowStepNodeCand2(node1, node2, config) and additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) t = getNodeDataFlowType(node2)
) and ) and
node1 != node2 and node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
or or
exists(Node mid | exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and not mid instanceof FlowCheckNode and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) and t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
) )
) )
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() } private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap] bindingset[node, ap]
private predicate filter(Node node, Ap ap) { private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and not ap.isClearedAt(node) and
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() if node instanceof CastingNode
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
} }
bindingset[ap, contentType] bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() } private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCall( private predicate flowIntoCall(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx = private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParameterNode p, AccessPath ap) { TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _) Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
} }
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */ /** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
private ParameterNode p; private ParamNode p;
private AccessPath ap; private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) } SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and config.isSource(node) and
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
// ... or a step from an existing PathNode to another node. // ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid | exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() } Configuration getConfiguration() { none() }
private predicate isHidden() { private predicate isHidden() {
nodeIsHidden(this.getNode()) and hiddenNode(this.getNode()) and
not this.isSource() and not this.isSource() and
not this instanceof PathNodeSink not this instanceof PathNodeSink
} }
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and mid.getAp() instanceof AccessPathNil and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx() sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg( private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand( private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i) p.isParameterOf(callable, i)
) )
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively. * respectively.
*/ */
private predicate pathIntoCallable( private predicate pathIntoCallable(
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call DataFlowCall call
) { ) {
exists(int i, DataFlowCallable callable, AccessPath ap | exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 = private newtype TSummaryCtx1 =
TSummaryCtx1None() or TSummaryCtx1None() or
TSummaryCtx1Param(ParameterNode p) TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 = private newtype TSummaryCtx2 =
TSummaryCtx2None() or TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
exists(config.explorationLimit()) exists(config.explorationLimit())
or or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or or
exists(PartialPathNodeRev mid | exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit() distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
) )
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid | exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not clearsContent(node, ap.getHead().getContent()) and not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode if node instanceof CastingNode
then compatibleTypes(getNodeType(node), ap.getType()) then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any() else any()
) )
} }
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
( (
localFlowStep(mid.getNode(), node, config) and localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
) )
or or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
or or
partialPathStoreStep(mid, _, _, node, ap) and partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getNodeType(node)) compatibleTypes(ap.getType(), getNodeDataFlowType(node))
) )
or or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap, PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
} }
private predicate partialPathIntoCallable( private predicate partialPathIntoCallable(
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc, PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap, TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc, DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 | exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config) paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
) )
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config) apConsRev(ap, c, ap0, config)
) )
or or
exists(ParameterNode p | exists(ParamNode p |
mid.getNode() = p and mid.getNode() = p and
viableParamArg(_, p, node) and viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap, int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(PartialPathNodeRev mid, ParameterNode p | exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and mid.getNode() = p and
p.isParameterOf(_, pos) and p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic] pragma[nomagic]
private predicate revPartialPathThroughCallable( private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) { ) {
exists(DataFlowCall call, int pos | exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and revPartialPathThroughCallable0(call, mid, pos, ap, config) and

View File

@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`. * Holds if data can flow in one local step from `node1` to `node2`.
*/ */
private predicate localFlowStep(Node node1, Node node2, Configuration config) { private predicate localFlowStep(Node node1, Node node2, Configuration config) {
( simpleLocalFlowStepExt(node1, node2) and
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts. * Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/ */
private predicate jumpStep(Node node1, Node node2, Configuration config) { private predicate jumpStep(Node node1, Node node2, Configuration config) {
jumpStep(node1, node2) and jumpStepCached(node1, node2) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) { private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
exists(ArgumentNode arg | exists(ArgNode arg |
fwdFlow(arg, cc, config) and fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg) viableParamArg(call, _, arg)
) )
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic] pragma[nomagic]
predicate viableParamArgNodeCandFwd1( predicate viableParamArgNodeCandFwd1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
viableParamArg(call, p, arg) and viableParamArg(call, p, arg) and
fwdFlow(arg, config) fwdFlow(arg, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config exists(ParamNode p |
) {
exists(ParameterNode p |
revFlow(p, toReturn, config) and revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config) viableParamArgNodeCandFwd1(call, p, arg, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config) revFlowIn(call, arg, true, config)
} }
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a * Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic] pragma[nomagic]
private predicate viableParamArgNodeCand1( private predicate viableParamArgNodeCand1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config) Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) { ) {
viableParamArgNodeCand1(call, p, arg, config) and viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, arg, p, config) and flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j | exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config) PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
) )
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand2( private predicate flowIntoCallNodeCand2(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/ */
private class FlowCheckNode extends Node { private class FlowCheckNode extends Node {
FlowCheckNode() { FlowCheckNode() {
this instanceof CastNode or castNode(this) or
clearsContent(this, _) clearsContentCached(this, _)
} }
} }
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or config.isSource(node) or
jumpStep(_, node, config) or jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or additionalJumpStep(_, node, config) or
node instanceof ParameterNode or node instanceof ParamNode or
node instanceof OutNodeExt or node instanceof OutNodeExt or
store(_, _, node, _) or store(_, _, node, _) or
read(_, _, node) or read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc LocalCallContext cc
) { ) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
( (
localFlowEntry(node1, pragma[only_bind_into](config)) and localFlowEntry(node1, pragma[only_bind_into](config)) and
( (
localFlowStepNodeCand1(node1, node2, config) and localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and preservesValue = true and
t = getNodeType(node1) t = getNodeDataFlowType(node1)
or or
additionalLocalFlowStepNodeCand2(node1, node2, config) and additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) t = getNodeDataFlowType(node2)
) and ) and
node1 != node2 and node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
or or
exists(Node mid | exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and not mid instanceof FlowCheckNode and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) and t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
) )
) )
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() } private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap] bindingset[node, ap]
private predicate filter(Node node, Ap ap) { private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and not ap.isClearedAt(node) and
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() if node instanceof CastingNode
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
} }
bindingset[ap, contentType] bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() } private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCall( private predicate flowIntoCall(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx = private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParameterNode p, AccessPath ap) { TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _) Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
} }
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */ /** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
private ParameterNode p; private ParamNode p;
private AccessPath ap; private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) } SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and config.isSource(node) and
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
// ... or a step from an existing PathNode to another node. // ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid | exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() } Configuration getConfiguration() { none() }
private predicate isHidden() { private predicate isHidden() {
nodeIsHidden(this.getNode()) and hiddenNode(this.getNode()) and
not this.isSource() and not this.isSource() and
not this instanceof PathNodeSink not this instanceof PathNodeSink
} }
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and mid.getAp() instanceof AccessPathNil and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx() sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg( private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand( private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i) p.isParameterOf(callable, i)
) )
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively. * respectively.
*/ */
private predicate pathIntoCallable( private predicate pathIntoCallable(
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call DataFlowCall call
) { ) {
exists(int i, DataFlowCallable callable, AccessPath ap | exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 = private newtype TSummaryCtx1 =
TSummaryCtx1None() or TSummaryCtx1None() or
TSummaryCtx1Param(ParameterNode p) TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 = private newtype TSummaryCtx2 =
TSummaryCtx2None() or TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
exists(config.explorationLimit()) exists(config.explorationLimit())
or or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or or
exists(PartialPathNodeRev mid | exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit() distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
) )
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid | exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not clearsContent(node, ap.getHead().getContent()) and not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode if node instanceof CastingNode
then compatibleTypes(getNodeType(node), ap.getType()) then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any() else any()
) )
} }
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
( (
localFlowStep(mid.getNode(), node, config) and localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
) )
or or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
or or
partialPathStoreStep(mid, _, _, node, ap) and partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getNodeType(node)) compatibleTypes(ap.getType(), getNodeDataFlowType(node))
) )
or or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap, PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
} }
private predicate partialPathIntoCallable( private predicate partialPathIntoCallable(
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc, PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap, TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc, DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 | exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config) paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
) )
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config) apConsRev(ap, c, ap0, config)
) )
or or
exists(ParameterNode p | exists(ParamNode p |
mid.getNode() = p and mid.getNode() = p and
viableParamArg(_, p, node) and viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap, int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(PartialPathNodeRev mid, ParameterNode p | exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and mid.getNode() = p and
p.isParameterOf(_, pos) and p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic] pragma[nomagic]
private predicate revPartialPathThroughCallable( private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) { ) {
exists(DataFlowCall call, int pos | exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and revPartialPathThroughCallable0(call, mid, pos, ap, config) and

View File

@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`. * Holds if data can flow in one local step from `node1` to `node2`.
*/ */
private predicate localFlowStep(Node node1, Node node2, Configuration config) { private predicate localFlowStep(Node node1, Node node2, Configuration config) {
( simpleLocalFlowStepExt(node1, node2) and
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts. * Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/ */
private predicate jumpStep(Node node1, Node node2, Configuration config) { private predicate jumpStep(Node node1, Node node2, Configuration config) {
jumpStep(node1, node2) and jumpStepCached(node1, node2) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) { private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
exists(ArgumentNode arg | exists(ArgNode arg |
fwdFlow(arg, cc, config) and fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg) viableParamArg(call, _, arg)
) )
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic] pragma[nomagic]
predicate viableParamArgNodeCandFwd1( predicate viableParamArgNodeCandFwd1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
viableParamArg(call, p, arg) and viableParamArg(call, p, arg) and
fwdFlow(arg, config) fwdFlow(arg, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config exists(ParamNode p |
) {
exists(ParameterNode p |
revFlow(p, toReturn, config) and revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config) viableParamArgNodeCandFwd1(call, p, arg, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config) revFlowIn(call, arg, true, config)
} }
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a * Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic] pragma[nomagic]
private predicate viableParamArgNodeCand1( private predicate viableParamArgNodeCand1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config) Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) { ) {
viableParamArgNodeCand1(call, p, arg, config) and viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, arg, p, config) and flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j | exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config) PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
) )
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand2( private predicate flowIntoCallNodeCand2(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/ */
private class FlowCheckNode extends Node { private class FlowCheckNode extends Node {
FlowCheckNode() { FlowCheckNode() {
this instanceof CastNode or castNode(this) or
clearsContent(this, _) clearsContentCached(this, _)
} }
} }
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or config.isSource(node) or
jumpStep(_, node, config) or jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or additionalJumpStep(_, node, config) or
node instanceof ParameterNode or node instanceof ParamNode or
node instanceof OutNodeExt or node instanceof OutNodeExt or
store(_, _, node, _) or store(_, _, node, _) or
read(_, _, node) or read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc LocalCallContext cc
) { ) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
( (
localFlowEntry(node1, pragma[only_bind_into](config)) and localFlowEntry(node1, pragma[only_bind_into](config)) and
( (
localFlowStepNodeCand1(node1, node2, config) and localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and preservesValue = true and
t = getNodeType(node1) t = getNodeDataFlowType(node1)
or or
additionalLocalFlowStepNodeCand2(node1, node2, config) and additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) t = getNodeDataFlowType(node2)
) and ) and
node1 != node2 and node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
or or
exists(Node mid | exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and not mid instanceof FlowCheckNode and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) and t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
) )
) )
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() } private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap] bindingset[node, ap]
private predicate filter(Node node, Ap ap) { private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and not ap.isClearedAt(node) and
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() if node instanceof CastingNode
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
} }
bindingset[ap, contentType] bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() } private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCall( private predicate flowIntoCall(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx = private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParameterNode p, AccessPath ap) { TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _) Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
} }
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */ /** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
private ParameterNode p; private ParamNode p;
private AccessPath ap; private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) } SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and config.isSource(node) and
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
// ... or a step from an existing PathNode to another node. // ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid | exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() } Configuration getConfiguration() { none() }
private predicate isHidden() { private predicate isHidden() {
nodeIsHidden(this.getNode()) and hiddenNode(this.getNode()) and
not this.isSource() and not this.isSource() and
not this instanceof PathNodeSink not this instanceof PathNodeSink
} }
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and mid.getAp() instanceof AccessPathNil and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx() sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg( private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand( private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i) p.isParameterOf(callable, i)
) )
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively. * respectively.
*/ */
private predicate pathIntoCallable( private predicate pathIntoCallable(
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call DataFlowCall call
) { ) {
exists(int i, DataFlowCallable callable, AccessPath ap | exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 = private newtype TSummaryCtx1 =
TSummaryCtx1None() or TSummaryCtx1None() or
TSummaryCtx1Param(ParameterNode p) TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 = private newtype TSummaryCtx2 =
TSummaryCtx2None() or TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
exists(config.explorationLimit()) exists(config.explorationLimit())
or or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or or
exists(PartialPathNodeRev mid | exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit() distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
) )
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid | exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not clearsContent(node, ap.getHead().getContent()) and not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode if node instanceof CastingNode
then compatibleTypes(getNodeType(node), ap.getType()) then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any() else any()
) )
} }
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
( (
localFlowStep(mid.getNode(), node, config) and localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
) )
or or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
or or
partialPathStoreStep(mid, _, _, node, ap) and partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getNodeType(node)) compatibleTypes(ap.getType(), getNodeDataFlowType(node))
) )
or or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap, PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
} }
private predicate partialPathIntoCallable( private predicate partialPathIntoCallable(
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc, PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap, TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc, DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 | exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config) paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
) )
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config) apConsRev(ap, c, ap0, config)
) )
or or
exists(ParameterNode p | exists(ParamNode p |
mid.getNode() = p and mid.getNode() = p and
viableParamArg(_, p, node) and viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap, int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(PartialPathNodeRev mid, ParameterNode p | exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and mid.getNode() = p and
p.isParameterOf(_, pos) and p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic] pragma[nomagic]
private predicate revPartialPathThroughCallable( private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) { ) {
exists(DataFlowCall call, int pos | exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and revPartialPathThroughCallable0(call, mid, pos, ap, config) and

View File

@@ -35,22 +35,22 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
* calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly. * calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly.
*/ */
private module LambdaFlow { private module LambdaFlow {
private predicate viableParamNonLambda(DataFlowCall call, int i, ParameterNode p) { private predicate viableParamNonLambda(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallable(call), i) p.isParameterOf(viableCallable(call), i)
} }
private predicate viableParamLambda(DataFlowCall call, int i, ParameterNode p) { private predicate viableParamLambda(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallableLambda(call, _), i) p.isParameterOf(viableCallableLambda(call, _), i)
} }
private predicate viableParamArgNonLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) { private predicate viableParamArgNonLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i | exists(int i |
viableParamNonLambda(call, i, p) and viableParamNonLambda(call, i, p) and
arg.argumentOf(call, i) arg.argumentOf(call, i)
) )
} }
private predicate viableParamArgLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) { private predicate viableParamArgLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i | exists(int i |
viableParamLambda(call, i, p) and viableParamLambda(call, i, p) and
arg.argumentOf(call, i) arg.argumentOf(call, i)
@@ -118,8 +118,8 @@ private module LambdaFlow {
boolean toJump, DataFlowCallOption lastCall boolean toJump, DataFlowCallOption lastCall
) { ) {
revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and
if node instanceof CastNode or node instanceof ArgumentNode or node instanceof ReturnNode if castNode(node) or node instanceof ArgNode or node instanceof ReturnNode
then compatibleTypes(t, getNodeType(node)) then compatibleTypes(t, getNodeDataFlowType(node))
else any() else any()
} }
@@ -129,7 +129,7 @@ private module LambdaFlow {
boolean toJump, DataFlowCallOption lastCall boolean toJump, DataFlowCallOption lastCall
) { ) {
lambdaCall(lambdaCall, kind, node) and lambdaCall(lambdaCall, kind, node) and
t = getNodeType(node) and t = getNodeDataFlowType(node) and
toReturn = false and toReturn = false and
toJump = false and toJump = false and
lastCall = TDataFlowCallNone() lastCall = TDataFlowCallNone()
@@ -146,7 +146,7 @@ private module LambdaFlow {
getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid) getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid)
| |
preservesValue = false and preservesValue = false and
t = getNodeType(node) t = getNodeDataFlowType(node)
or or
preservesValue = true and preservesValue = true and
t = t0 t = t0
@@ -160,7 +160,7 @@ private module LambdaFlow {
toJump = true and toJump = true and
lastCall = TDataFlowCallNone() lastCall = TDataFlowCallNone()
| |
jumpStep(node, mid) and jumpStepCached(node, mid) and
t = t0 t = t0
or or
exists(boolean preservesValue | exists(boolean preservesValue |
@@ -168,7 +168,7 @@ private module LambdaFlow {
getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid) getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid)
| |
preservesValue = false and preservesValue = false and
t = getNodeType(node) t = getNodeDataFlowType(node)
or or
preservesValue = true and preservesValue = true and
t = t0 t = t0
@@ -176,7 +176,7 @@ private module LambdaFlow {
) )
or or
// flow into a callable // flow into a callable
exists(ParameterNode p, DataFlowCallOption lastCall0, DataFlowCall call | exists(ParamNode p, DataFlowCallOption lastCall0, DataFlowCall call |
revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and
( (
if lastCall0 = TDataFlowCallNone() and toJump = false if lastCall0 = TDataFlowCallNone() and toJump = false
@@ -227,7 +227,7 @@ private module LambdaFlow {
pragma[nomagic] pragma[nomagic]
predicate revLambdaFlowIn( predicate revLambdaFlowIn(
DataFlowCall lambdaCall, LambdaCallKind kind, ParameterNode p, DataFlowType t, boolean toJump, DataFlowCall lambdaCall, LambdaCallKind kind, ParamNode p, DataFlowType t, boolean toJump,
DataFlowCallOption lastCall DataFlowCallOption lastCall
) { ) {
revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall) revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall)
@@ -242,6 +242,89 @@ private DataFlowCallable viableCallableExt(DataFlowCall call) {
cached cached
private module Cached { private module Cached {
/**
* If needed, call this predicate from `DataFlowImplSpecific.qll` in order to
* force a stage-dependency on the `DataFlowImplCommon.qll` stage and therby
* collapsing the two stages.
*/
cached
predicate forceCachingInSameStage() { any() }
cached
predicate nodeEnclosingCallable(Node n, DataFlowCallable c) { c = n.getEnclosingCallable() }
cached
predicate callEnclosingCallable(DataFlowCall call, DataFlowCallable c) {
c = call.getEnclosingCallable()
}
cached
predicate nodeDataFlowType(Node n, DataFlowType t) { t = getNodeType(n) }
cached
predicate jumpStepCached(Node node1, Node node2) { jumpStep(node1, node2) }
cached
predicate clearsContentCached(Node n, Content c) { clearsContent(n, c) }
cached
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
cached
predicate outNodeExt(Node n) {
n instanceof OutNode
or
n.(PostUpdateNode).getPreUpdateNode() instanceof ArgNode
}
cached
predicate hiddenNode(Node n) { nodeIsHidden(n) }
cached
OutNodeExt getAnOutNodeExt(DataFlowCall call, ReturnKindExt k) {
result = getAnOutNode(call, k.(ValueReturnKind).getKind())
or
exists(ArgNode arg |
result.(PostUpdateNode).getPreUpdateNode() = arg and
arg.argumentOf(call, k.(ParamUpdateReturnKind).getPosition())
)
}
cached
predicate returnNodeExt(Node n, ReturnKindExt k) {
k = TValueReturn(n.(ReturnNode).getKind())
or
exists(ParamNode p, int pos |
parameterValueFlowsToPreUpdate(p, n) and
p.isParameterOf(_, pos) and
k = TParamUpdate(pos)
)
}
cached
predicate castNode(Node n) { n instanceof CastNode }
cached
predicate castingNode(Node n) {
castNode(n) or
n instanceof ParamNode or
n instanceof OutNodeExt or
// For reads, `x.f`, we want to check that the tracked type after the read (which
// is obtained by popping the head of the access path stack) is compatible with
// the type of `x.f`.
read(_, _, n)
}
cached
predicate parameterNode(Node n, DataFlowCallable c, int i) {
n.(ParameterNode).isParameterOf(c, i)
}
cached
predicate argumentNode(Node n, DataFlowCall call, int pos) {
n.(ArgumentNode).argumentOf(call, pos)
}
/** /**
* Gets a viable target for the lambda call `call`. * Gets a viable target for the lambda call `call`.
* *
@@ -261,7 +344,7 @@ private module Cached {
* The instance parameter is considered to have index `-1`. * The instance parameter is considered to have index `-1`.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate viableParam(DataFlowCall call, int i, ParameterNode p) { private predicate viableParam(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallableExt(call), i) p.isParameterOf(viableCallableExt(call), i)
} }
@@ -270,11 +353,11 @@ private module Cached {
* dispatch into account. * dispatch into account.
*/ */
cached cached
predicate viableParamArg(DataFlowCall call, ParameterNode p, ArgumentNode arg) { predicate viableParamArg(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i | exists(int i |
viableParam(call, i, p) and viableParam(call, i, p) and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
compatibleTypes(getNodeType(arg), getNodeType(p)) compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
) )
} }
@@ -312,7 +395,7 @@ private module Cached {
* `read` indicates whether it is contents of `p` that can flow to `node`. * `read` indicates whether it is contents of `p` that can flow to `node`.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate parameterValueFlowCand(ParameterNode p, Node node, boolean read) { private predicate parameterValueFlowCand(ParamNode p, Node node, boolean read) {
p = node and p = node and
read = false read = false
or or
@@ -325,30 +408,30 @@ private module Cached {
// read // read
exists(Node mid | exists(Node mid |
parameterValueFlowCand(p, mid, false) and parameterValueFlowCand(p, mid, false) and
readStep(mid, _, node) and read(mid, _, node) and
read = true read = true
) )
or or
// flow through: no prior read // flow through: no prior read
exists(ArgumentNode arg | exists(ArgNode arg |
parameterValueFlowArgCand(p, arg, false) and parameterValueFlowArgCand(p, arg, false) and
argumentValueFlowsThroughCand(arg, node, read) argumentValueFlowsThroughCand(arg, node, read)
) )
or or
// flow through: no read inside method // flow through: no read inside method
exists(ArgumentNode arg | exists(ArgNode arg |
parameterValueFlowArgCand(p, arg, read) and parameterValueFlowArgCand(p, arg, read) and
argumentValueFlowsThroughCand(arg, node, false) argumentValueFlowsThroughCand(arg, node, false)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate parameterValueFlowArgCand(ParameterNode p, ArgumentNode arg, boolean read) { private predicate parameterValueFlowArgCand(ParamNode p, ArgNode arg, boolean read) {
parameterValueFlowCand(p, arg, read) parameterValueFlowCand(p, arg, read)
} }
pragma[nomagic] pragma[nomagic]
predicate parameterValueFlowsToPreUpdateCand(ParameterNode p, PostUpdateNode n) { predicate parameterValueFlowsToPreUpdateCand(ParamNode p, PostUpdateNode n) {
parameterValueFlowCand(p, n.getPreUpdateNode(), false) parameterValueFlowCand(p, n.getPreUpdateNode(), false)
} }
@@ -360,7 +443,7 @@ private module Cached {
* `read` indicates whether it is contents of `p` that can flow to the return * `read` indicates whether it is contents of `p` that can flow to the return
* node. * node.
*/ */
predicate parameterValueFlowReturnCand(ParameterNode p, ReturnKind kind, boolean read) { predicate parameterValueFlowReturnCand(ParamNode p, ReturnKind kind, boolean read) {
exists(ReturnNode ret | exists(ReturnNode ret |
parameterValueFlowCand(p, ret, read) and parameterValueFlowCand(p, ret, read) and
kind = ret.getKind() kind = ret.getKind()
@@ -369,9 +452,9 @@ private module Cached {
pragma[nomagic] pragma[nomagic]
private predicate argumentValueFlowsThroughCand0( private predicate argumentValueFlowsThroughCand0(
DataFlowCall call, ArgumentNode arg, ReturnKind kind, boolean read DataFlowCall call, ArgNode arg, ReturnKind kind, boolean read
) { ) {
exists(ParameterNode param | viableParamArg(call, param, arg) | exists(ParamNode param | viableParamArg(call, param, arg) |
parameterValueFlowReturnCand(param, kind, read) parameterValueFlowReturnCand(param, kind, read)
) )
} }
@@ -382,14 +465,14 @@ private module Cached {
* *
* `read` indicates whether it is contents of `arg` that can flow to `out`. * `read` indicates whether it is contents of `arg` that can flow to `out`.
*/ */
predicate argumentValueFlowsThroughCand(ArgumentNode arg, Node out, boolean read) { predicate argumentValueFlowsThroughCand(ArgNode arg, Node out, boolean read) {
exists(DataFlowCall call, ReturnKind kind | exists(DataFlowCall call, ReturnKind kind |
argumentValueFlowsThroughCand0(call, arg, kind, read) and argumentValueFlowsThroughCand0(call, arg, kind, read) and
out = getAnOutNode(call, kind) out = getAnOutNode(call, kind)
) )
} }
predicate cand(ParameterNode p, Node n) { predicate cand(ParamNode p, Node n) {
parameterValueFlowCand(p, n, _) and parameterValueFlowCand(p, n, _) and
( (
parameterValueFlowReturnCand(p, _, _) parameterValueFlowReturnCand(p, _, _)
@@ -416,21 +499,21 @@ private module Cached {
* If a read step was taken, then `read` captures the `Content`, the * If a read step was taken, then `read` captures the `Content`, the
* container type, and the content type. * container type, and the content type.
*/ */
predicate parameterValueFlow(ParameterNode p, Node node, ReadStepTypesOption read) { predicate parameterValueFlow(ParamNode p, Node node, ReadStepTypesOption read) {
parameterValueFlow0(p, node, read) and parameterValueFlow0(p, node, read) and
if node instanceof CastingNode if node instanceof CastingNode
then then
// normal flow through // normal flow through
read = TReadStepTypesNone() and read = TReadStepTypesNone() and
compatibleTypes(getNodeType(p), getNodeType(node)) compatibleTypes(getNodeDataFlowType(p), getNodeDataFlowType(node))
or or
// getter // getter
compatibleTypes(read.getContentType(), getNodeType(node)) compatibleTypes(read.getContentType(), getNodeDataFlowType(node))
else any() else any()
} }
pragma[nomagic] pragma[nomagic]
private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) { private predicate parameterValueFlow0(ParamNode p, Node node, ReadStepTypesOption read) {
p = node and p = node and
Cand::cand(p, _) and Cand::cand(p, _) and
read = TReadStepTypesNone() read = TReadStepTypesNone()
@@ -447,7 +530,7 @@ private module Cached {
readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, readStepWithTypes(mid, read.getContainerType(), read.getContent(), node,
read.getContentType()) and read.getContentType()) and
Cand::parameterValueFlowReturnCand(p, _, true) and Cand::parameterValueFlowReturnCand(p, _, true) and
compatibleTypes(getNodeType(p), read.getContainerType()) compatibleTypes(getNodeDataFlowType(p), read.getContainerType())
) )
or or
parameterValueFlow0_0(TReadStepTypesNone(), p, node, read) parameterValueFlow0_0(TReadStepTypesNone(), p, node, read)
@@ -455,34 +538,32 @@ private module Cached {
pragma[nomagic] pragma[nomagic]
private predicate parameterValueFlow0_0( private predicate parameterValueFlow0_0(
ReadStepTypesOption mustBeNone, ParameterNode p, Node node, ReadStepTypesOption read ReadStepTypesOption mustBeNone, ParamNode p, Node node, ReadStepTypesOption read
) { ) {
// flow through: no prior read // flow through: no prior read
exists(ArgumentNode arg | exists(ArgNode arg |
parameterValueFlowArg(p, arg, mustBeNone) and parameterValueFlowArg(p, arg, mustBeNone) and
argumentValueFlowsThrough(arg, read, node) argumentValueFlowsThrough(arg, read, node)
) )
or or
// flow through: no read inside method // flow through: no read inside method
exists(ArgumentNode arg | exists(ArgNode arg |
parameterValueFlowArg(p, arg, read) and parameterValueFlowArg(p, arg, read) and
argumentValueFlowsThrough(arg, mustBeNone, node) argumentValueFlowsThrough(arg, mustBeNone, node)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate parameterValueFlowArg( private predicate parameterValueFlowArg(ParamNode p, ArgNode arg, ReadStepTypesOption read) {
ParameterNode p, ArgumentNode arg, ReadStepTypesOption read
) {
parameterValueFlow(p, arg, read) and parameterValueFlow(p, arg, read) and
Cand::argumentValueFlowsThroughCand(arg, _, _) Cand::argumentValueFlowsThroughCand(arg, _, _)
} }
pragma[nomagic] pragma[nomagic]
private predicate argumentValueFlowsThrough0( private predicate argumentValueFlowsThrough0(
DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read DataFlowCall call, ArgNode arg, ReturnKind kind, ReadStepTypesOption read
) { ) {
exists(ParameterNode param | viableParamArg(call, param, arg) | exists(ParamNode param | viableParamArg(call, param, arg) |
parameterValueFlowReturn(param, kind, read) parameterValueFlowReturn(param, kind, read)
) )
} }
@@ -496,18 +577,18 @@ private module Cached {
* container type, and the content type. * container type, and the content type.
*/ */
pragma[nomagic] pragma[nomagic]
predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) { predicate argumentValueFlowsThrough(ArgNode arg, ReadStepTypesOption read, Node out) {
exists(DataFlowCall call, ReturnKind kind | exists(DataFlowCall call, ReturnKind kind |
argumentValueFlowsThrough0(call, arg, kind, read) and argumentValueFlowsThrough0(call, arg, kind, read) and
out = getAnOutNode(call, kind) out = getAnOutNode(call, kind)
| |
// normal flow through // normal flow through
read = TReadStepTypesNone() and read = TReadStepTypesNone() and
compatibleTypes(getNodeType(arg), getNodeType(out)) compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(out))
or or
// getter // getter
compatibleTypes(getNodeType(arg), read.getContainerType()) and compatibleTypes(getNodeDataFlowType(arg), read.getContainerType()) and
compatibleTypes(read.getContentType(), getNodeType(out)) compatibleTypes(read.getContentType(), getNodeDataFlowType(out))
) )
} }
@@ -516,7 +597,7 @@ private module Cached {
* value-preserving steps and a single read step, not taking call * value-preserving steps and a single read step, not taking call
* contexts into account, thus representing a getter-step. * contexts into account, thus representing a getter-step.
*/ */
predicate getterStep(ArgumentNode arg, Content c, Node out) { predicate getterStep(ArgNode arg, Content c, Node out) {
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out) argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
} }
@@ -529,7 +610,7 @@ private module Cached {
* container type, and the content type. * container type, and the content type.
*/ */
private predicate parameterValueFlowReturn( private predicate parameterValueFlowReturn(
ParameterNode p, ReturnKind kind, ReadStepTypesOption read ParamNode p, ReturnKind kind, ReadStepTypesOption read
) { ) {
exists(ReturnNode ret | exists(ReturnNode ret |
parameterValueFlow(p, ret, read) and parameterValueFlow(p, ret, read) and
@@ -553,7 +634,7 @@ private module Cached {
private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) { private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) {
mayBenefitFromCallContext(call, callable) mayBenefitFromCallContext(call, callable)
or or
callable = call.getEnclosingCallable() and callEnclosingCallable(call, callable) and
exists(viableCallableLambda(call, TDataFlowCallSome(_))) exists(viableCallableLambda(call, TDataFlowCallSome(_)))
} }
@@ -611,7 +692,7 @@ private module Cached {
mayBenefitFromCallContextExt(call, _) and mayBenefitFromCallContextExt(call, _) and
c = viableCallableExt(call) and c = viableCallableExt(call) and
ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContextExt(call, ctx)) and ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContextExt(call, ctx)) and
tgts = strictcount(DataFlowCall ctx | viableCallableExt(ctx) = call.getEnclosingCallable()) and tgts = strictcount(DataFlowCall ctx | callEnclosingCallable(call, viableCallableExt(ctx))) and
ctxtgts < tgts ctxtgts < tgts
) )
} }
@@ -635,8 +716,7 @@ private module Cached {
* Holds if `p` can flow to the pre-update node associated with post-update * Holds if `p` can flow to the pre-update node associated with post-update
* node `n`, in the same callable, using only value-preserving steps. * node `n`, in the same callable, using only value-preserving steps.
*/ */
cached private predicate parameterValueFlowsToPreUpdate(ParamNode p, PostUpdateNode n) {
predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) {
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone()) parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
} }
@@ -644,9 +724,9 @@ private module Cached {
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
) { ) {
storeStep(node1, c, node2) and storeStep(node1, c, node2) and
readStep(_, c, _) and read(_, c, _) and
contentType = getNodeType(node1) and contentType = getNodeDataFlowType(node1) and
containerType = getNodeType(node2) containerType = getNodeDataFlowType(node2)
or or
exists(Node n1, Node n2 | exists(Node n1, Node n2 |
n1 = node1.(PostUpdateNode).getPreUpdateNode() and n1 = node1.(PostUpdateNode).getPreUpdateNode() and
@@ -654,12 +734,15 @@ private module Cached {
| |
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1) argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
or or
readStep(n2, c, n1) and read(n2, c, n1) and
contentType = getNodeType(n1) and contentType = getNodeDataFlowType(n1) and
containerType = getNodeType(n2) containerType = getNodeDataFlowType(n2)
) )
} }
cached
predicate read(Node node1, Content c, Node node2) { readStep(node1, c, node2) }
/** /**
* Holds if data can flow from `node1` to `node2` via a direct assignment to * Holds if data can flow from `node1` to `node2` via a direct assignment to
* `f`. * `f`.
@@ -678,8 +761,9 @@ private module Cached {
* are aliases. A typical example is a function returning `this`, implementing a fluent * are aliases. A typical example is a function returning `this`, implementing a fluent
* interface. * interface.
*/ */
cached private predicate reverseStepThroughInputOutputAlias(
predicate reverseStepThroughInputOutputAlias(PostUpdateNode fromNode, PostUpdateNode toNode) { PostUpdateNode fromNode, PostUpdateNode toNode
) {
exists(Node fromPre, Node toPre | exists(Node fromPre, Node toPre |
fromPre = fromNode.getPreUpdateNode() and fromPre = fromNode.getPreUpdateNode() and
toPre = toNode.getPreUpdateNode() toPre = toNode.getPreUpdateNode()
@@ -688,14 +772,20 @@ private module Cached {
// Does the language-specific simpleLocalFlowStep already model flow // Does the language-specific simpleLocalFlowStep already model flow
// from function input to output? // from function input to output?
fromPre = getAnOutNode(c, _) and fromPre = getAnOutNode(c, _) and
toPre.(ArgumentNode).argumentOf(c, _) and toPre.(ArgNode).argumentOf(c, _) and
simpleLocalFlowStep(toPre.(ArgumentNode), fromPre) simpleLocalFlowStep(toPre.(ArgNode), fromPre)
) )
or or
argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre) argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre)
) )
} }
cached
predicate simpleLocalFlowStepExt(Node node1, Node node2) {
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
}
/** /**
* Holds if the call context `call` either improves virtual dispatch in * Holds if the call context `call` either improves virtual dispatch in
* `callable` or if it allows us to prune unreachable nodes in `callable`. * `callable` or if it allows us to prune unreachable nodes in `callable`.
@@ -704,7 +794,7 @@ private module Cached {
predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) { predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
reducedViableImplInCallContext(_, callable, call) reducedViableImplInCallContext(_, callable, call)
or or
exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCall(n, call)) exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call))
} }
cached cached
@@ -726,12 +816,12 @@ private module Cached {
cached cached
newtype TLocalFlowCallContext = newtype TLocalFlowCallContext =
TAnyLocalCall() or TAnyLocalCall() or
TSpecificLocalCall(DataFlowCall call) { isUnreachableInCall(_, call) } TSpecificLocalCall(DataFlowCall call) { isUnreachableInCallCached(_, call) }
cached cached
newtype TReturnKindExt = newtype TReturnKindExt =
TValueReturn(ReturnKind kind) or TValueReturn(ReturnKind kind) or
TParamUpdate(int pos) { exists(ParameterNode p | p.isParameterOf(_, pos)) } TParamUpdate(int pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
cached cached
newtype TBooleanOption = newtype TBooleanOption =
@@ -761,23 +851,15 @@ private module Cached {
* A `Node` at which a cast can occur such that the type should be checked. * A `Node` at which a cast can occur such that the type should be checked.
*/ */
class CastingNode extends Node { class CastingNode extends Node {
CastingNode() { CastingNode() { castingNode(this) }
this instanceof ParameterNode or
this instanceof CastNode or
this instanceof OutNodeExt or
// For reads, `x.f`, we want to check that the tracked type after the read (which
// is obtained by popping the head of the access path stack) is compatible with
// the type of `x.f`.
readStep(_, _, this)
}
} }
private predicate readStepWithTypes( private predicate readStepWithTypes(
Node n1, DataFlowType container, Content c, Node n2, DataFlowType content Node n1, DataFlowType container, Content c, Node n2, DataFlowType content
) { ) {
readStep(n1, c, n2) and read(n1, c, n2) and
container = getNodeType(n1) and container = getNodeDataFlowType(n1) and
content = getNodeType(n2) content = getNodeDataFlowType(n2)
} }
private newtype TReadStepTypesOption = private newtype TReadStepTypesOption =
@@ -854,7 +936,7 @@ class CallContextSomeCall extends CallContextCall, TSomeCall {
override string toString() { result = "CcSomeCall" } override string toString() { result = "CcSomeCall" }
override predicate relevantFor(DataFlowCallable callable) { override predicate relevantFor(DataFlowCallable callable) {
exists(ParameterNode p | getNodeEnclosingCallable(p) = callable) exists(ParamNode p | getNodeEnclosingCallable(p) = callable)
} }
override predicate matchesCall(DataFlowCall call) { any() } override predicate matchesCall(DataFlowCall call) { any() }
@@ -866,7 +948,7 @@ class CallContextReturn extends CallContextNoCall, TReturn {
} }
override predicate relevantFor(DataFlowCallable callable) { override predicate relevantFor(DataFlowCallable callable) {
exists(DataFlowCall call | this = TReturn(_, call) and call.getEnclosingCallable() = callable) exists(DataFlowCall call | this = TReturn(_, call) and callEnclosingCallable(call, callable))
} }
} }
@@ -899,7 +981,7 @@ class LocalCallContextSpecificCall extends LocalCallContext, TSpecificLocalCall
} }
private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) { private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) {
exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCall(n, call)) exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCallCached(n, call))
} }
/** /**
@@ -913,26 +995,37 @@ LocalCallContext getLocalCallContext(CallContext ctx, DataFlowCallable callable)
else result instanceof LocalCallContextAny else result instanceof LocalCallContextAny
} }
/**
* The value of a parameter at function entry, viewed as a node in a data
* flow graph.
*/
class ParamNode extends Node {
ParamNode() { parameterNode(this, _, _) }
/**
* Holds if this node is the parameter of callable `c` at the specified
* (zero-based) position.
*/
predicate isParameterOf(DataFlowCallable c, int i) { parameterNode(this, c, i) }
}
/** A data-flow node that represents a call argument. */
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) }
}
/** /**
* A node from which flow can return to the caller. This is either a regular * A node from which flow can return to the caller. This is either a regular
* `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter. * `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter.
*/ */
class ReturnNodeExt extends Node { class ReturnNodeExt extends Node {
ReturnNodeExt() { ReturnNodeExt() { returnNodeExt(this, _) }
this instanceof ReturnNode or
parameterValueFlowsToPreUpdate(_, this)
}
/** Gets the kind of this returned value. */ /** Gets the kind of this returned value. */
ReturnKindExt getKind() { ReturnKindExt getKind() { returnNodeExt(this, result) }
result = TValueReturn(this.(ReturnNode).getKind())
or
exists(ParameterNode p, int pos |
parameterValueFlowsToPreUpdate(p, this) and
p.isParameterOf(_, pos) and
result = TParamUpdate(pos)
)
}
} }
/** /**
@@ -940,11 +1033,7 @@ class ReturnNodeExt extends Node {
* or a post-update node associated with a call argument. * or a post-update node associated with a call argument.
*/ */
class OutNodeExt extends Node { class OutNodeExt extends Node {
OutNodeExt() { OutNodeExt() { outNodeExt(this) }
this instanceof OutNode
or
this.(PostUpdateNode).getPreUpdateNode() instanceof ArgumentNode
}
} }
/** /**
@@ -957,7 +1046,7 @@ abstract class ReturnKindExt extends TReturnKindExt {
abstract string toString(); abstract string toString();
/** Gets a node corresponding to data flow out of `call`. */ /** Gets a node corresponding to data flow out of `call`. */
abstract OutNodeExt getAnOutNode(DataFlowCall call); final OutNodeExt getAnOutNode(DataFlowCall call) { result = getAnOutNodeExt(call, this) }
} }
class ValueReturnKind extends ReturnKindExt, TValueReturn { class ValueReturnKind extends ReturnKindExt, TValueReturn {
@@ -968,10 +1057,6 @@ class ValueReturnKind extends ReturnKindExt, TValueReturn {
ReturnKind getKind() { result = kind } ReturnKind getKind() { result = kind }
override string toString() { result = kind.toString() } override string toString() { result = kind.toString() }
override OutNodeExt getAnOutNode(DataFlowCall call) {
result = getAnOutNode(call, this.getKind())
}
} }
class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate { class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
@@ -982,13 +1067,6 @@ class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
int getPosition() { result = pos } int getPosition() { result = pos }
override string toString() { result = "param update " + pos } override string toString() { result = "param update " + pos }
override OutNodeExt getAnOutNode(DataFlowCall call) {
exists(ArgumentNode arg |
result.(PostUpdateNode).getPreUpdateNode() = arg and
arg.argumentOf(call, this.getPosition())
)
}
} }
/** A callable tagged with a relevant return kind. */ /** A callable tagged with a relevant return kind. */
@@ -1015,10 +1093,13 @@ class ReturnPosition extends TReturnPosition0 {
*/ */
pragma[inline] pragma[inline]
DataFlowCallable getNodeEnclosingCallable(Node n) { DataFlowCallable getNodeEnclosingCallable(Node n) {
exists(Node n0 | nodeEnclosingCallable(pragma[only_bind_out](n), pragma[only_bind_into](result))
pragma[only_bind_into](n0) = n and }
pragma[only_bind_into](result) = n0.getEnclosingCallable()
) /** Gets the type of `n` used for type pruning. */
pragma[inline]
DataFlowType getNodeDataFlowType(Node n) {
nodeDataFlowType(pragma[only_bind_out](n), pragma[only_bind_into](result))
} }
pragma[noinline] pragma[noinline]
@@ -1042,7 +1123,7 @@ predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall
cc instanceof CallContextAny and callable = viableCallableExt(call) cc instanceof CallContextAny and callable = viableCallableExt(call)
or or
exists(DataFlowCallable c0, DataFlowCall call0 | exists(DataFlowCallable c0, DataFlowCall call0 |
call0.getEnclosingCallable() = callable and callEnclosingCallable(call0, callable) and
cc = TReturn(c0, call0) and cc = TReturn(c0, call0) and
c0 = prunedViableImplInCallContextReverse(call0, call) c0 = prunedViableImplInCallContextReverse(call0, call)
) )
@@ -1063,8 +1144,6 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
result = viableCallableExt(call) and cc instanceof CallContextReturn result = viableCallableExt(call) and cc instanceof CallContextReturn
} }
predicate read = readStep/3;
/** An optional Boolean value. */ /** An optional Boolean value. */
class BooleanOption extends TBooleanOption { class BooleanOption extends TBooleanOption {
string toString() { string toString() {
@@ -1116,7 +1195,7 @@ abstract class AccessPathFront extends TAccessPathFront {
TypedContent getHead() { this = TFrontHead(result) } TypedContent getHead() { this = TFrontHead(result) }
predicate isClearedAt(Node n) { clearsContent(n, getHead().getContent()) } predicate isClearedAt(Node n) { clearsContentCached(n, getHead().getContent()) }
} }
class AccessPathFrontNil extends AccessPathFront, TFrontNil { class AccessPathFrontNil extends AccessPathFront, TFrontNil {

View File

@@ -7,7 +7,6 @@ private import DataFlowImplCommon
private import ControlFlowReachability private import ControlFlowReachability
private import FlowSummaryImpl as FlowSummaryImpl private import FlowSummaryImpl as FlowSummaryImpl
private import semmle.code.csharp.dataflow.FlowSummary private import semmle.code.csharp.dataflow.FlowSummary
private import semmle.code.csharp.Caching
private import semmle.code.csharp.Conversion private import semmle.code.csharp.Conversion
private import semmle.code.csharp.dataflow.internal.SsaImpl as SsaImpl private import semmle.code.csharp.dataflow.internal.SsaImpl as SsaImpl
private import semmle.code.csharp.ExprOrStmtParent private import semmle.code.csharp.ExprOrStmtParent
@@ -21,7 +20,6 @@ private import semmle.code.csharp.frameworks.system.threading.Tasks
abstract class NodeImpl extends Node { abstract class NodeImpl extends Node {
/** Do not call: use `getEnclosingCallable()` instead. */ /** Do not call: use `getEnclosingCallable()` instead. */
cached
abstract DataFlowCallable getEnclosingCallableImpl(); abstract DataFlowCallable getEnclosingCallableImpl();
/** Do not call: use `getType()` instead. */ /** Do not call: use `getType()` instead. */
@@ -29,9 +27,8 @@ abstract class NodeImpl extends Node {
abstract DotNet::Type getTypeImpl(); abstract DotNet::Type getTypeImpl();
/** Gets the type of this node used for type pruning. */ /** Gets the type of this node used for type pruning. */
cached
Gvn::GvnType getDataFlowType() { Gvn::GvnType getDataFlowType() {
Stages::DataFlowStage::forceCachingInSameStage() and forceCachingInSameStage() and
exists(Type t0 | result = Gvn::getGlobalValueNumber(t0) | exists(Type t0 | result = Gvn::getGlobalValueNumber(t0) |
t0 = getCSharpType(this.getType()) t0 = getCSharpType(this.getType())
or or
@@ -55,26 +52,25 @@ abstract class NodeImpl extends Node {
private class ExprNodeImpl extends ExprNode, NodeImpl { private class ExprNodeImpl extends ExprNode, NodeImpl {
override DataFlowCallable getEnclosingCallableImpl() { override DataFlowCallable getEnclosingCallableImpl() {
Stages::DataFlowStage::forceCachingInSameStage() and
result = this.getExpr().getEnclosingCallable() result = this.getExpr().getEnclosingCallable()
} }
override DotNet::Type getTypeImpl() { override DotNet::Type getTypeImpl() {
Stages::DataFlowStage::forceCachingInSameStage() and forceCachingInSameStage() and
result = this.getExpr().getType() result = this.getExpr().getType()
} }
override ControlFlow::Nodes::ElementNode getControlFlowNodeImpl() { override ControlFlow::Nodes::ElementNode getControlFlowNodeImpl() {
Stages::DataFlowStage::forceCachingInSameStage() and this = TExprNode(result) forceCachingInSameStage() and this = TExprNode(result)
} }
override Location getLocationImpl() { override Location getLocationImpl() {
Stages::DataFlowStage::forceCachingInSameStage() and result = this.getExpr().getLocation() forceCachingInSameStage() and result = this.getExpr().getLocation()
} }
override string toStringImpl() { override string toStringImpl() {
Stages::DataFlowStage::forceCachingInSameStage() and forceCachingInSameStage() and
result = this.getControlFlowNode().toString() result = this.getControlFlowNodeImpl().toString()
or or
exists(CIL::Expr e | exists(CIL::Expr e |
this = TCilExprNode(e) and this = TCilExprNode(e) and
@@ -394,6 +390,22 @@ module LocalFlow {
} }
} }
/**
* This is the local flow predicate that is used as a building block in global
* data flow. It excludes SSA flow through instance fields, as flow through fields
* is handled by the global data-flow library, but includes various other steps
* that are only relevant for global flow.
*/
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
or
LocalFlow::localFlowCapturedVarStep(nodeFrom, nodeTo)
or
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom, nodeTo, true)
or
nodeTo.(ObjectCreationNode).getPreUpdateNode() = nodeFrom.(ObjectInitializerNode)
}
pragma[noinline] pragma[noinline]
private Expr getImplicitArgument(Call c, int pos) { private Expr getImplicitArgument(Call c, int pos) {
result = c.getArgument(pos) and result = c.getArgument(pos) and
@@ -582,12 +594,16 @@ private Type getCSharpType(DotNet::Type t) {
result.matchesHandle(t) result.matchesHandle(t)
} }
private class RelevantDataFlowType extends DataFlowType {
RelevantDataFlowType() { this = any(NodeImpl n).getDataFlowType() }
}
/** A GVN type that is either a `DataFlowType` or unifiable with a `DataFlowType`. */ /** A GVN type that is either a `DataFlowType` or unifiable with a `DataFlowType`. */
private class DataFlowTypeOrUnifiable extends Gvn::GvnType { private class DataFlowTypeOrUnifiable extends Gvn::GvnType {
pragma[nomagic] pragma[nomagic]
DataFlowTypeOrUnifiable() { DataFlowTypeOrUnifiable() {
this instanceof DataFlowType or this instanceof RelevantDataFlowType or
Gvn::unifiable(any(DataFlowType t), this) Gvn::unifiable(any(RelevantDataFlowType t), this)
} }
} }
@@ -598,7 +614,7 @@ private TypeParameter getATypeParameterSubType(DataFlowTypeOrUnifiable t) {
} }
pragma[noinline] pragma[noinline]
private TypeParameter getATypeParameterSubTypeRestricted(DataFlowType t) { private TypeParameter getATypeParameterSubTypeRestricted(RelevantDataFlowType t) {
result = getATypeParameterSubType(t) result = getATypeParameterSubType(t)
} }
@@ -614,17 +630,30 @@ private Gvn::GvnType getANonTypeParameterSubType(DataFlowTypeOrUnifiable t) {
} }
pragma[noinline] pragma[noinline]
private Gvn::GvnType getANonTypeParameterSubTypeRestricted(DataFlowType t) { private Gvn::GvnType getANonTypeParameterSubTypeRestricted(RelevantDataFlowType t) {
result = getANonTypeParameterSubType(t) result = getANonTypeParameterSubType(t)
} }
/** A collection of cached types and predicates to be evaluated in the same stage. */ /** A collection of cached types and predicates to be evaluated in the same stage. */
cached cached
private module Cached { private module Cached {
private import TaintTrackingPrivate as TaintTrackingPrivate
// Add artificial dependencies to enforce all cached predicates are evaluated
// in the "DataFlowImplCommon stage"
private predicate forceCaching() {
TaintTrackingPrivate::forceCachingInSameStage() or
exists(any(NodeImpl n).getTypeImpl()) or
exists(any(NodeImpl n).getControlFlowNodeImpl()) or
exists(any(NodeImpl n).getLocationImpl()) or
exists(any(NodeImpl n).toStringImpl())
}
cached cached
newtype TNode = newtype TNode =
TExprNode(ControlFlow::Nodes::ElementNode cfn) { TExprNode(ControlFlow::Nodes::ElementNode cfn) {
Stages::DataFlowStage::forceCachingInSameStage() and cfn.getElement() instanceof Expr forceCaching() and
cfn.getElement() instanceof Expr
} or } or
TCilExprNode(CIL::Expr e) { e.getImplementation() instanceof CIL::BestImplementation } or TCilExprNode(CIL::Expr e) { e.getImplementation() instanceof CIL::BestImplementation } or
TSsaDefinitionNode(Ssa::Definition def) { TSsaDefinitionNode(Ssa::Definition def) {
@@ -679,23 +708,6 @@ private module Cached {
callCfn = any(Call c | isParamsArg(c, _, _)).getAControlFlowNode() callCfn = any(Call c | isParamsArg(c, _, _)).getAControlFlowNode()
} }
/**
* This is the local flow predicate that is used as a building block in global
* data flow. It excludes SSA flow through instance fields, as flow through fields
* is handled by the global data-flow library, but includes various other steps
* that are only relevant for global flow.
*/
cached
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
or
LocalFlow::localFlowCapturedVarStep(nodeFrom, nodeTo)
or
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom, nodeTo, true)
or
nodeTo.(ObjectCreationNode).getPreUpdateNode() = nodeFrom.(ObjectInitializerNode)
}
/** /**
* Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local * Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local
* (intra-procedural) step. * (intra-procedural) step.
@@ -714,178 +726,14 @@ private module Cached {
FlowSummaryImpl::Private::Steps::summaryThroughStep(nodeFrom, nodeTo, true) FlowSummaryImpl::Private::Steps::summaryThroughStep(nodeFrom, nodeTo, true)
} }
/**
* Holds if `pred` can flow to `succ`, by jumping from one callable to
* another. Additional steps specified by the configuration are *not*
* taken into account.
*/
cached
predicate jumpStepImpl(Node pred, Node succ) {
pred.(NonLocalJumpNode).getAJumpSuccessor(true) = succ
or
exists(FieldOrProperty fl, FieldOrPropertyRead flr |
fl.isStatic() and
fl.isFieldLike() and
fl.getAnAssignedValue() = pred.asExpr() and
fl.getAnAccess() = flr and
flr = succ.asExpr() and
flr.hasNonlocalValue()
)
or
exists(JumpReturnKind jrk, DataFlowCall call |
FlowSummaryImpl::Private::summaryReturnNode(pred, jrk) and
viableCallable(call) = jrk.getTarget() and
succ = getAnOutNode(call, jrk.getTargetReturnKind())
)
}
cached cached
newtype TContent = newtype TContent =
TFieldContent(Field f) { f.isUnboundDeclaration() } or TFieldContent(Field f) { f.isUnboundDeclaration() } or
TPropertyContent(Property p) { p.isUnboundDeclaration() } or TPropertyContent(Property p) { p.isUnboundDeclaration() } or
TElementContent() TElementContent()
/**
* Holds if data can flow from `node1` to `node2` via an assignment to
* content `c`.
*/
cached
predicate storeStepImpl(Node node1, Content c, Node node2) {
exists(StoreStepConfiguration x, ExprNode node, boolean postUpdate |
hasNodePath(x, node1, node) and
if postUpdate = true then node = node2.(PostUpdateNode).getPreUpdateNode() else node = node2
|
fieldOrPropertyStore(_, c, node1.asExpr(), node.getExpr(), postUpdate)
or
arrayStore(_, node1.asExpr(), node.getExpr(), postUpdate) and c instanceof ElementContent
)
or
exists(StoreStepConfiguration x, Expr arg, ControlFlow::Node callCfn |
x.hasExprPath(arg, node1.(ExprNode).getControlFlowNode(), _, callCfn) and
node2 = TParamsArgumentNode(callCfn) and
isParamsArg(_, arg, _) and
c instanceof ElementContent
)
or
exists(Expr e |
e = node1.asExpr() and
node2.(YieldReturnNode).getYieldReturnStmt().getExpr() = e and
c instanceof ElementContent
)
or
exists(Expr e |
e = node1.asExpr() and
node2.(AsyncReturnNode).getExpr() = e and
c = getResultContent()
)
or
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1, c, node2)
}
pragma[nomagic] pragma[nomagic]
private PropertyContent getResultContent() { private predicate commonSubTypeGeneral(DataFlowTypeOrUnifiable t1, RelevantDataFlowType t2) {
result.getProperty() = any(SystemThreadingTasksTaskTClass c_).getResultProperty()
}
/**
* Holds if data can flow from `node1` to `node2` via a read of content `c`.
*/
cached
predicate readStepImpl(Node node1, Content c, Node node2) {
exists(ReadStepConfiguration x |
hasNodePath(x, node1, node2) and
fieldOrPropertyRead(node1.asExpr(), c, node2.asExpr())
or
hasNodePath(x, node1, node2) and
arrayRead(node1.asExpr(), node2.asExpr()) and
c instanceof ElementContent
or
exists(ForeachStmt fs, Ssa::ExplicitDefinition def |
x.hasDefPath(fs.getIterableExpr(), node1.getControlFlowNode(), def.getADefinition(),
def.getControlFlowNode()) and
node2.(SsaDefinitionNode).getDefinition() = def and
c instanceof ElementContent
)
or
hasNodePath(x, node1, node2) and
node2.asExpr().(AwaitExpr).getExpr() = node1.asExpr() and
c = getResultContent()
or
// node1 = (..., node2, ...)
// node1.ItemX flows to node2
exists(TupleExpr te, int i, Expr item |
te = node1.asExpr() and
not te.isConstruction() and
c.(FieldContent).getField() = te.getType().(TupleType).getElement(i).getUnboundDeclaration() and
// node1 = (..., item, ...)
te.getArgument(i) = item
|
// item = (..., ..., ...) in node1 = (..., (..., ..., ...), ...)
node2.asExpr().(TupleExpr) = item and
hasNodePath(x, node1, node2)
or
// item = variable in node1 = (..., variable, ...)
exists(AssignableDefinitions::TupleAssignmentDefinition tad, Ssa::ExplicitDefinition def |
node2.(SsaDefinitionNode).getDefinition() = def and
def.getADefinition() = tad and
tad.getLeaf() = item and
hasNodePath(x, node1, node2)
)
or
// item = variable in node1 = (..., variable, ...) in a case/is var (..., ...)
te = any(PatternExpr pe).getAChildExpr*() and
exists(AssignableDefinitions::LocalVariableDefinition lvd, Ssa::ExplicitDefinition def |
node2.(SsaDefinitionNode).getDefinition() = def and
def.getADefinition() = lvd and
lvd.getDeclaration() = item and
hasNodePath(x, node1, node2)
)
)
)
or
FlowSummaryImpl::Private::Steps::summaryReadStep(node1, c, node2)
}
/**
* Holds if values stored inside content `c` are cleared at node `n`. For example,
* any value stored inside `f` is cleared at the pre-update node associated with `x`
* in `x.f = newValue`.
*/
cached
predicate clearsContent(Node n, Content c) {
fieldOrPropertyStore(_, c, _, n.asExpr(), true)
or
fieldOrPropertyStore(_, c, _, n.(ObjectInitializerNode).getInitializer(), false)
or
FlowSummaryImpl::Private::Steps::summaryStoresIntoArg(c, n) and
not c instanceof ElementContent
or
FlowSummaryImpl::Private::Steps::summaryClearsContent(n, c)
or
exists(WithExpr we, ObjectInitializer oi, FieldOrProperty f |
oi = we.getInitializer() and
n.asExpr() = oi and
f = oi.getAMemberInitializer().getInitializedMember() and
c = f.getContent()
)
}
/**
* Holds if the node `n` is unreachable when the call context is `call`.
*/
cached
predicate isUnreachableInCall(Node n, DataFlowCall call) {
exists(
ExplicitParameterNode paramNode, Guard guard, ControlFlow::SuccessorTypes::BooleanSuccessor bs
|
viableConstantBooleanParamArg(paramNode, bs.getValue().booleanNot(), call) and
paramNode.getSsaDefinition().getARead() = guard and
guard.controlsBlock(n.getControlFlowNode().getBasicBlock(), bs, _)
)
}
pragma[nomagic]
private predicate commonSubTypeGeneral(DataFlowTypeOrUnifiable t1, DataFlowType t2) {
not t1 instanceof Gvn::TypeParameterGvnType and not t1 instanceof Gvn::TypeParameterGvnType and
t1 = t2 t1 = t2
or or
@@ -899,102 +747,53 @@ private module Cached {
* `t2` are allowed to be type parameters. * `t2` are allowed to be type parameters.
*/ */
cached cached
predicate commonSubType(DataFlowType t1, DataFlowType t2) { commonSubTypeGeneral(t1, t2) } predicate commonSubType(RelevantDataFlowType t1, RelevantDataFlowType t2) {
commonSubTypeGeneral(t1, t2)
}
cached cached
predicate commonSubTypeUnifiableLeft(DataFlowType t1, DataFlowType t2) { predicate commonSubTypeUnifiableLeft(RelevantDataFlowType t1, RelevantDataFlowType t2) {
exists(Gvn::GvnType t | exists(Gvn::GvnType t |
Gvn::unifiable(t1, t) and Gvn::unifiable(t1, t) and
commonSubTypeGeneral(t, t2) commonSubTypeGeneral(t, t2)
) )
} }
cached
predicate outRefReturnNode(Ssa::ExplicitDefinition def, OutRefReturnKind kind) {
exists(Parameter p |
def.isLiveOutRefParameterDefinition(p) and
kind.getPosition() = p.getPosition()
|
p.isOut() and kind instanceof OutReturnKind
or
p.isRef() and kind instanceof RefReturnKind
)
}
cached
predicate summaryOutNodeCached(DataFlowCall c, Node out, ReturnKind rk) {
FlowSummaryImpl::Private::summaryOutNode(c, out, rk)
}
cached
predicate summaryArgumentNodeCached(DataFlowCall c, Node arg, int i) {
FlowSummaryImpl::Private::summaryArgumentNode(c, arg, i)
}
cached
predicate summaryPostUpdateNodeCached(Node post, ParameterNode pre) {
FlowSummaryImpl::Private::summaryPostUpdateNode(post, pre)
}
cached
predicate summaryReturnNodeCached(Node ret, ReturnKind rk) {
FlowSummaryImpl::Private::summaryReturnNode(ret, rk) and
not rk instanceof JumpReturnKind
}
cached
predicate castNode(Node n) {
n.asExpr() instanceof Cast
or
n.(AssignableDefinitionNode).getDefinition() instanceof AssignableDefinitions::PatternDefinition
}
/** Holds if `n` should be hidden from path explanations. */
cached
predicate nodeIsHidden(Node n) {
exists(Ssa::Definition def | def = n.(SsaDefinitionNode).getDefinition() |
def instanceof Ssa::PhiNode
or
def instanceof Ssa::ImplicitEntryDefinition
or
def instanceof Ssa::ImplicitCallDefinition
)
or
exists(Parameter p |
p = n.(ParameterNode).getParameter() and
not p.fromSource()
)
or
n = TInstanceParameterNode(any(Callable c | not c.fromSource()))
or
n instanceof YieldReturnNode
or
n instanceof AsyncReturnNode
or
n instanceof ImplicitCapturedArgumentNode
or
n instanceof MallocNode
or
n instanceof SummaryNode
or
n instanceof ParamsArgumentNode
or
n.asExpr() = any(WithExpr we).getInitializer()
}
cached
predicate parameterNode(Node n, DataFlowCallable c, int i) {
n.(ParameterNodeImpl).isParameterOf(c, i)
}
cached
predicate argumentNode(Node n, DataFlowCall call, int pos) {
n.(ArgumentNodeImpl).argumentOf(call, pos)
}
} }
import Cached import Cached
/** Holds if `n` should be hidden from path explanations. */
predicate nodeIsHidden(Node n) {
exists(Ssa::Definition def | def = n.(SsaDefinitionNode).getDefinition() |
def instanceof Ssa::PhiNode
or
def instanceof Ssa::ImplicitEntryDefinition
or
def instanceof Ssa::ImplicitCallDefinition
)
or
exists(Parameter p |
p = n.(ParameterNode).getParameter() and
not p.fromSource()
)
or
n = TInstanceParameterNode(any(Callable c | not c.fromSource()))
or
n instanceof YieldReturnNode
or
n instanceof AsyncReturnNode
or
n instanceof ImplicitCapturedArgumentNode
or
n instanceof MallocNode
or
n instanceof SummaryNode
or
n instanceof ParamsArgumentNode
or
n.asExpr() = any(WithExpr we).getInitializer()
}
/** An SSA definition, viewed as a node in a data flow graph. */ /** An SSA definition, viewed as a node in a data flow graph. */
class SsaDefinitionNode extends NodeImpl, TSsaDefinitionNode { class SsaDefinitionNode extends NodeImpl, TSsaDefinitionNode {
Ssa::Definition def; Ssa::Definition def;
@@ -1142,10 +941,12 @@ import ParameterNodes
/** A data-flow node that represents a call argument. */ /** A data-flow node that represents a call argument. */
class ArgumentNode extends Node { class ArgumentNode extends Node {
ArgumentNode() { argumentNode(this, _, _) } ArgumentNode() { this instanceof ArgumentNodeImpl }
/** Holds if this argument occurs at the given position in the given call. */ /** 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, int pos) {
this.(ArgumentNodeImpl).argumentOf(call, pos)
}
} }
abstract private class ArgumentNodeImpl extends Node { abstract private class ArgumentNodeImpl extends Node {
@@ -1310,14 +1111,10 @@ private module ArgumentNodes {
} }
private class SummaryArgumentNode extends SummaryNode, ArgumentNodeImpl { private class SummaryArgumentNode extends SummaryNode, ArgumentNodeImpl {
private DataFlowCall c; SummaryArgumentNode() { FlowSummaryImpl::Private::summaryArgumentNode(_, this, _) }
private int i;
SummaryArgumentNode() { summaryArgumentNodeCached(c, this, i) }
override predicate argumentOf(DataFlowCall call, int pos) { override predicate argumentOf(DataFlowCall call, int pos) {
call = c and FlowSummaryImpl::Private::summaryArgumentNode(call, this, pos)
i = pos
} }
} }
} }
@@ -1352,7 +1149,16 @@ private module ReturnNodes {
class OutRefReturnNode extends ReturnNode, SsaDefinitionNode { class OutRefReturnNode extends ReturnNode, SsaDefinitionNode {
OutRefReturnKind kind; OutRefReturnKind kind;
OutRefReturnNode() { outRefReturnNode(this.getDefinition(), kind) } OutRefReturnNode() {
exists(Parameter p |
this.getDefinition().isLiveOutRefParameterDefinition(p) and
kind.getPosition() = p.getPosition()
|
p.isOut() and kind instanceof OutReturnKind
or
p.isRef() and kind instanceof RefReturnKind
)
}
override ReturnKind getKind() { result = kind } override ReturnKind getKind() { result = kind }
} }
@@ -1449,7 +1255,10 @@ private module ReturnNodes {
private class SummaryReturnNode extends SummaryNode, ReturnNode { private class SummaryReturnNode extends SummaryNode, ReturnNode {
private ReturnKind rk; private ReturnKind rk;
SummaryReturnNode() { summaryReturnNodeCached(this, rk) } SummaryReturnNode() {
FlowSummaryImpl::Private::summaryReturnNode(this, rk) and
not rk instanceof JumpReturnKind
}
override ReturnKind getKind() { result = rk } override ReturnKind getKind() { result = rk }
} }
@@ -1460,7 +1269,6 @@ import ReturnNodes
/** A data-flow node that represents the output of a call. */ /** A data-flow node that represents the output of a call. */
abstract class OutNode extends Node { abstract class OutNode extends Node {
/** Gets the underlying call, where this node is a corresponding output of kind `kind`. */ /** Gets the underlying call, where this node is a corresponding output of kind `kind`. */
cached
abstract DataFlowCall getCall(ReturnKind kind); abstract DataFlowCall getCall(ReturnKind kind);
} }
@@ -1488,7 +1296,6 @@ private module OutNodes {
} }
override DataFlowCall getCall(ReturnKind kind) { override DataFlowCall getCall(ReturnKind kind) {
Stages::DataFlowStage::forceCachingInSameStage() and
result = call and result = call and
( (
kind instanceof NormalReturnKind and kind instanceof NormalReturnKind and
@@ -1564,14 +1371,10 @@ private module OutNodes {
} }
private class SummaryOutNode extends SummaryNode, OutNode { private class SummaryOutNode extends SummaryNode, OutNode {
private DataFlowCall c; SummaryOutNode() { FlowSummaryImpl::Private::summaryOutNode(_, this, _) }
private ReturnKind rk;
SummaryOutNode() { summaryOutNodeCached(c, this, rk) }
override DataFlowCall getCall(ReturnKind kind) { override DataFlowCall getCall(ReturnKind kind) {
result = c and FlowSummaryImpl::Private::summaryOutNode(result, this, kind)
kind = rk
} }
} }
} }
@@ -1654,7 +1457,29 @@ private class FieldOrPropertyRead extends FieldOrPropertyAccess, AssignableRead
} }
} }
predicate jumpStep = jumpStepImpl/2; /**
* Holds if `pred` can flow to `succ`, by jumping from one callable to
* another. Additional steps specified by the configuration are *not*
* taken into account.
*/
predicate jumpStep(Node pred, Node succ) {
pred.(NonLocalJumpNode).getAJumpSuccessor(true) = succ
or
exists(FieldOrProperty fl, FieldOrPropertyRead flr |
fl.isStatic() and
fl.isFieldLike() and
fl.getAnAssignedValue() = pred.asExpr() and
fl.getAnAccess() = flr and
flr = succ.asExpr() and
flr.hasNonlocalValue()
)
or
exists(JumpReturnKind jrk, DataFlowCall call |
FlowSummaryImpl::Private::summaryReturnNode(pred, jrk) and
viableCallable(call) = jrk.getTarget() and
succ = getAnOutNode(call, jrk.getTargetReturnKind())
)
}
private class StoreStepConfiguration extends ControlFlowReachabilityConfiguration { private class StoreStepConfiguration extends ControlFlowReachabilityConfiguration {
StoreStepConfiguration() { this = "StoreStepConfiguration" } StoreStepConfiguration() { this = "StoreStepConfiguration" }
@@ -1675,7 +1500,46 @@ private class StoreStepConfiguration extends ControlFlowReachabilityConfiguratio
} }
} }
predicate storeStep = storeStepImpl/3; pragma[nomagic]
private PropertyContent getResultContent() {
result.getProperty() = any(SystemThreadingTasksTaskTClass c_).getResultProperty()
}
/**
* Holds if data can flow from `node1` to `node2` via an assignment to
* content `c`.
*/
predicate storeStep(Node node1, Content c, Node node2) {
exists(StoreStepConfiguration x, ExprNode node, boolean postUpdate |
hasNodePath(x, node1, node) and
if postUpdate = true then node = node2.(PostUpdateNode).getPreUpdateNode() else node = node2
|
fieldOrPropertyStore(_, c, node1.asExpr(), node.getExpr(), postUpdate)
or
arrayStore(_, node1.asExpr(), node.getExpr(), postUpdate) and c instanceof ElementContent
)
or
exists(StoreStepConfiguration x, Expr arg, ControlFlow::Node callCfn |
x.hasExprPath(arg, node1.(ExprNode).getControlFlowNode(), _, callCfn) and
node2 = TParamsArgumentNode(callCfn) and
isParamsArg(_, arg, _) and
c instanceof ElementContent
)
or
exists(Expr e |
e = node1.asExpr() and
node2.(YieldReturnNode).getYieldReturnStmt().getExpr() = e and
c instanceof ElementContent
)
or
exists(Expr e |
e = node1.asExpr() and
node2.(AsyncReturnNode).getExpr() = e and
c = getResultContent()
)
or
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1, c, node2)
}
private class ReadStepConfiguration extends ControlFlowReachabilityConfiguration { private class ReadStepConfiguration extends ControlFlowReachabilityConfiguration {
ReadStepConfiguration() { this = "ReadStepConfiguration" } ReadStepConfiguration() { this = "ReadStepConfiguration" }
@@ -1742,7 +1606,99 @@ private class ReadStepConfiguration extends ControlFlowReachabilityConfiguration
} }
} }
predicate readStep = readStepImpl/3; /**
* Holds if data can flow from `node1` to `node2` via a read of content `c`.
*/
predicate readStep(Node node1, Content c, Node node2) {
exists(ReadStepConfiguration x |
hasNodePath(x, node1, node2) and
fieldOrPropertyRead(node1.asExpr(), c, node2.asExpr())
or
hasNodePath(x, node1, node2) and
arrayRead(node1.asExpr(), node2.asExpr()) and
c instanceof ElementContent
or
exists(ForeachStmt fs, Ssa::ExplicitDefinition def |
x.hasDefPath(fs.getIterableExpr(), node1.getControlFlowNode(), def.getADefinition(),
def.getControlFlowNode()) and
node2.(SsaDefinitionNode).getDefinition() = def and
c instanceof ElementContent
)
or
hasNodePath(x, node1, node2) and
node2.asExpr().(AwaitExpr).getExpr() = node1.asExpr() and
c = getResultContent()
or
// node1 = (..., node2, ...)
// node1.ItemX flows to node2
exists(TupleExpr te, int i, Expr item |
te = node1.asExpr() and
not te.isConstruction() and
c.(FieldContent).getField() = te.getType().(TupleType).getElement(i).getUnboundDeclaration() and
// node1 = (..., item, ...)
te.getArgument(i) = item
|
// item = (..., ..., ...) in node1 = (..., (..., ..., ...), ...)
node2.asExpr().(TupleExpr) = item and
hasNodePath(x, node1, node2)
or
// item = variable in node1 = (..., variable, ...)
exists(AssignableDefinitions::TupleAssignmentDefinition tad, Ssa::ExplicitDefinition def |
node2.(SsaDefinitionNode).getDefinition() = def and
def.getADefinition() = tad and
tad.getLeaf() = item and
hasNodePath(x, node1, node2)
)
or
// item = variable in node1 = (..., variable, ...) in a case/is var (..., ...)
te = any(PatternExpr pe).getAChildExpr*() and
exists(AssignableDefinitions::LocalVariableDefinition lvd, Ssa::ExplicitDefinition def |
node2.(SsaDefinitionNode).getDefinition() = def and
def.getADefinition() = lvd and
lvd.getDeclaration() = item and
hasNodePath(x, node1, node2)
)
)
)
or
FlowSummaryImpl::Private::Steps::summaryReadStep(node1, c, node2)
}
/**
* Holds if values stored inside content `c` are cleared at node `n`. For example,
* any value stored inside `f` is cleared at the pre-update node associated with `x`
* in `x.f = newValue`.
*/
predicate clearsContent(Node n, Content c) {
fieldOrPropertyStore(_, c, _, n.asExpr(), true)
or
fieldOrPropertyStore(_, c, _, n.(ObjectInitializerNode).getInitializer(), false)
or
FlowSummaryImpl::Private::Steps::summaryStoresIntoArg(c, n) and
not c instanceof ElementContent
or
FlowSummaryImpl::Private::Steps::summaryClearsContent(n, c)
or
exists(WithExpr we, ObjectInitializer oi, FieldOrProperty f |
oi = we.getInitializer() and
n.asExpr() = oi and
f = oi.getAMemberInitializer().getInitializedMember() and
c = f.getContent()
)
}
/**
* Holds if the node `n` is unreachable when the call context is `call`.
*/
predicate isUnreachableInCall(Node n, DataFlowCall call) {
exists(
ExplicitParameterNode paramNode, Guard guard, ControlFlow::SuccessorTypes::BooleanSuccessor bs
|
viableConstantBooleanParamArg(paramNode, bs.getValue().booleanNot(), call) and
paramNode.getSsaDefinition().getARead() = guard and
guard.controlsBlock(n.getControlFlowNode().getBasicBlock(), bs, _)
)
}
/** /**
* An entity used to represent the type of data-flow node. Two nodes will have * An entity used to represent the type of data-flow node. Two nodes will have
@@ -1753,10 +1709,7 @@ predicate readStep = readStepImpl/3;
* `DataFlowType`, while `Func<T, int>` and `Func<string, int>` are not, because * `DataFlowType`, while `Func<T, int>` and `Func<string, int>` are not, because
* `string` is not a type parameter. * `string` is not a type parameter.
*/ */
class DataFlowType extends Gvn::GvnType { class DataFlowType = Gvn::GvnType;
pragma[nomagic]
DataFlowType() { this = any(NodeImpl n).getDataFlowType() }
}
/** Gets the type of `n` used for type pruning. */ /** Gets the type of `n` used for type pruning. */
pragma[inline] pragma[inline]
@@ -1888,11 +1841,11 @@ private module PostUpdateNodes {
} }
private class SummaryPostUpdateNode extends SummaryNode, PostUpdateNode { private class SummaryPostUpdateNode extends SummaryNode, PostUpdateNode {
private Node pre; SummaryPostUpdateNode() { FlowSummaryImpl::Private::summaryPostUpdateNode(this, _) }
SummaryPostUpdateNode() { summaryPostUpdateNodeCached(this, pre) } override Node getPreUpdateNode() {
FlowSummaryImpl::Private::summaryPostUpdateNode(this, result)
override Node getPreUpdateNode() { result = pre } }
} }
} }
@@ -1900,7 +1853,12 @@ private import PostUpdateNodes
/** A node that performs a type cast. */ /** A node that performs a type cast. */
class CastNode extends Node { class CastNode extends Node {
CastNode() { castNode(this) } CastNode() {
this.asExpr() instanceof Cast
or
this.(AssignableDefinitionNode).getDefinition() instanceof
AssignableDefinitions::PatternDefinition
}
} }
class DataFlowExpr = DotNet::Expr; class DataFlowExpr = DotNet::Expr;

View File

@@ -67,6 +67,8 @@ class Node extends TNode {
} }
} }
private class TExprNode_ = TExprNode or TCilExprNode;
/** /**
* An expression, viewed as a node in a data flow graph. * An expression, viewed as a node in a data flow graph.
* *
@@ -74,9 +76,7 @@ class Node extends TNode {
* to multiple `ExprNode`s, just like it may correspond to multiple * to multiple `ExprNode`s, just like it may correspond to multiple
* `ControlFlow::Node`s. * `ControlFlow::Node`s.
*/ */
class ExprNode extends Node { class ExprNode extends Node, TExprNode_ {
ExprNode() { this = TExprNode(_) or this = TCilExprNode(_) }
/** Gets the expression corresponding to this node. */ /** Gets the expression corresponding to this node. */
DotNet::Expr getExpr() { DotNet::Expr getExpr() {
result = this.getExprAtNode(_) result = this.getExprAtNode(_)
@@ -99,7 +99,7 @@ class ExprNode extends Node {
* flow graph. * flow graph.
*/ */
class ParameterNode extends Node { class ParameterNode extends Node {
ParameterNode() { parameterNode(this, _, _) } ParameterNode() { this instanceof ParameterNodeImpl }
/** Gets the parameter corresponding to this node, if any. */ /** Gets the parameter corresponding to this node, if any. */
DotNet::Parameter getParameter() { DotNet::Parameter getParameter() {
@@ -110,7 +110,9 @@ class ParameterNode extends Node {
* Holds if this node is the parameter of callable `c` at the specified * Holds if this node is the parameter of callable `c` at the specified
* (zero-based) position. * (zero-based) position.
*/ */
predicate isParameterOf(DataFlowCallable c, int i) { parameterNode(this, c, i) } predicate isParameterOf(DataFlowCallable c, int i) {
this.(ParameterNodeImpl).isParameterOf(c, i)
}
} }
/** A definition, viewed as a node in a data flow graph. */ /** A definition, viewed as a node in a data flow graph. */

View File

@@ -1,6 +1,5 @@
private import csharp private import csharp
private import TaintTrackingPublic private import TaintTrackingPublic
private import DataFlowImplCommon
private import FlowSummaryImpl as FlowSummaryImpl private import FlowSummaryImpl as FlowSummaryImpl
private import semmle.code.csharp.Caching private import semmle.code.csharp.Caching
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
@@ -79,7 +78,6 @@ private class LocalTaintExprStepConfiguration extends ControlFlowReachabilityCon
} }
private predicate localTaintStepCommon(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { private predicate localTaintStepCommon(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
Stages::DataFlowStage::forceCachingInSameStage() and
hasNodePath(any(LocalTaintExprStepConfiguration x), nodeFrom, nodeTo) hasNodePath(any(LocalTaintExprStepConfiguration x), nodeFrom, nodeTo)
or or
localTaintStepCil(nodeFrom, nodeTo) localTaintStepCil(nodeFrom, nodeTo)
@@ -87,6 +85,11 @@ private predicate localTaintStepCommon(DataFlow::Node nodeFrom, DataFlow::Node n
cached cached
private module Cached { private module Cached {
private import DataFlowImplCommon as DataFlowImplCommon
cached
predicate forceCachingInSameStage() { DataFlowImplCommon::forceCachingInSameStage() }
/** /**
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local * Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
* (intra-procedural) step. * (intra-procedural) step.

View File

@@ -529,7 +529,7 @@ function_pointer_return_type(
int return_type_id: @type_or_ref ref); int return_type_id: @type_or_ref ref);
extend( extend(
unique int sub: @type ref, int sub: @type ref,
int super: @type_or_ref ref); int super: @type_or_ref ref);
anonymous_types( anonymous_types(

View File

@@ -613,13 +613,13 @@ foreach.cs:
# 5| r5_28(glval<Int32>) = PointerAdd[4] : r5_1, r5_27 # 5| r5_28(glval<Int32>) = PointerAdd[4] : r5_1, r5_27
# 5| r5_29(Int32) = Constant[7] : # 5| r5_29(Int32) = Constant[7] :
# 5| mu5_30(Int32) = Store[?] : &:r5_28, r5_29 # 5| mu5_30(Int32) = Store[?] : &:r5_28, r5_29
# 7| r7_1(glval<IEnumerator>) = VariableAddress[#temp7:9] : # 7| r7_1(glval<Boolean>) = VariableAddress[#temp7:9] :
# 7| r7_2(glval<Int32[]>) = VariableAddress[a_array] : # 7| r7_2(glval<Int32[]>) = VariableAddress[a_array] :
# 7| r7_3(Int32[]) = Load[a_array] : &:r7_2, ~m? # 7| r7_3(Int32[]) = Load[a_array] : &:r7_2, ~m?
# 7| r7_4(<funcaddr>) = FunctionAddress[GetEnumerator] : # 7| r7_4(<funcaddr>) = FunctionAddress[GetEnumerator] :
# 7| r7_5(IEnumerator) = Call[GetEnumerator] : func:r7_4, this:r7_3 # 7| r7_5(IEnumerator) = Call[GetEnumerator] : func:r7_4, this:r7_3
# 7| mu7_6(<unknown>) = ^CallSideEffect : ~m? # 7| mu7_6(<unknown>) = ^CallSideEffect : ~m?
# 7| mu7_7(IEnumerator) = Store[#temp7:9] : &:r7_1, r7_5 # 7| mu7_7(Boolean) = Store[#temp7:9] : &:r7_1, r7_5
#-----| Goto -> Block 1 #-----| Goto -> Block 1
# 7| Block 1 # 7| Block 1

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Removed unique base class constraint
compatibility: backwards

View File

@@ -0,0 +1,3 @@
lgtm,codescanning
* Add support for version 5 of the Kryo serialization/deserialization framework.
* Add support for detecting safe uses of Kryo utilizing `KryoPool.Builder`. [#4992](https://github.com/github/codeql/issues/4992)

View File

@@ -0,0 +1,2 @@
lgtm,codescanning
* The query "Resolving XML external entity in user-controlled data" (`java/xxe`) has been improved to report fewer false positives when a Builder / Factory (e.g. an `XMLInputFactory`) is configured safely by using a boxed boolean as second argument to one or more of its configuration methods.

View File

@@ -292,6 +292,7 @@ private predicate summaryModelCsv(string row) {
"java.util;StringTokenizer;false;StringTokenizer;;;Argument[0];Argument[-1];taint", "java.util;StringTokenizer;false;StringTokenizer;;;Argument[0];Argument[-1];taint",
"java.beans;XMLDecoder;false;XMLDecoder;;;Argument[0];Argument[-1];taint", "java.beans;XMLDecoder;false;XMLDecoder;;;Argument[0];Argument[-1];taint",
"com.esotericsoftware.kryo.io;Input;false;Input;;;Argument[0];Argument[-1];taint", "com.esotericsoftware.kryo.io;Input;false;Input;;;Argument[0];Argument[-1];taint",
"com.esotericsoftware.kryo5.io;Input;false;Input;;;Argument[0];Argument[-1];taint",
"java.io;BufferedInputStream;false;BufferedInputStream;;;Argument[0];Argument[-1];taint", "java.io;BufferedInputStream;false;BufferedInputStream;;;Argument[0];Argument[-1];taint",
"java.io;DataInputStream;false;DataInputStream;;;Argument[0];Argument[-1];taint", "java.io;DataInputStream;false;DataInputStream;;;Argument[0];Argument[-1];taint",
"java.io;ByteArrayInputStream;false;ByteArrayInputStream;;;Argument[0];Argument[-1];taint", "java.io;ByteArrayInputStream;false;ByteArrayInputStream;;;Argument[0];Argument[-1];taint",

View File

@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`. * Holds if data can flow in one local step from `node1` to `node2`.
*/ */
private predicate localFlowStep(Node node1, Node node2, Configuration config) { private predicate localFlowStep(Node node1, Node node2, Configuration config) {
( simpleLocalFlowStepExt(node1, node2) and
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts. * Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/ */
private predicate jumpStep(Node node1, Node node2, Configuration config) { private predicate jumpStep(Node node1, Node node2, Configuration config) {
jumpStep(node1, node2) and jumpStepCached(node1, node2) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) { private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
exists(ArgumentNode arg | exists(ArgNode arg |
fwdFlow(arg, cc, config) and fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg) viableParamArg(call, _, arg)
) )
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic] pragma[nomagic]
predicate viableParamArgNodeCandFwd1( predicate viableParamArgNodeCandFwd1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
viableParamArg(call, p, arg) and viableParamArg(call, p, arg) and
fwdFlow(arg, config) fwdFlow(arg, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config exists(ParamNode p |
) {
exists(ParameterNode p |
revFlow(p, toReturn, config) and revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config) viableParamArgNodeCandFwd1(call, p, arg, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config) revFlowIn(call, arg, true, config)
} }
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a * Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic] pragma[nomagic]
private predicate viableParamArgNodeCand1( private predicate viableParamArgNodeCand1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config) Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) { ) {
viableParamArgNodeCand1(call, p, arg, config) and viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, arg, p, config) and flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j | exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config) PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
) )
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand2( private predicate flowIntoCallNodeCand2(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/ */
private class FlowCheckNode extends Node { private class FlowCheckNode extends Node {
FlowCheckNode() { FlowCheckNode() {
this instanceof CastNode or castNode(this) or
clearsContent(this, _) clearsContentCached(this, _)
} }
} }
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or config.isSource(node) or
jumpStep(_, node, config) or jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or additionalJumpStep(_, node, config) or
node instanceof ParameterNode or node instanceof ParamNode or
node instanceof OutNodeExt or node instanceof OutNodeExt or
store(_, _, node, _) or store(_, _, node, _) or
read(_, _, node) or read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc LocalCallContext cc
) { ) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
( (
localFlowEntry(node1, pragma[only_bind_into](config)) and localFlowEntry(node1, pragma[only_bind_into](config)) and
( (
localFlowStepNodeCand1(node1, node2, config) and localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and preservesValue = true and
t = getNodeType(node1) t = getNodeDataFlowType(node1)
or or
additionalLocalFlowStepNodeCand2(node1, node2, config) and additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) t = getNodeDataFlowType(node2)
) and ) and
node1 != node2 and node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
or or
exists(Node mid | exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and not mid instanceof FlowCheckNode and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) and t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
) )
) )
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() } private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap] bindingset[node, ap]
private predicate filter(Node node, Ap ap) { private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and not ap.isClearedAt(node) and
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() if node instanceof CastingNode
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
} }
bindingset[ap, contentType] bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() } private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCall( private predicate flowIntoCall(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx = private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParameterNode p, AccessPath ap) { TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _) Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
} }
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */ /** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
private ParameterNode p; private ParamNode p;
private AccessPath ap; private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) } SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and config.isSource(node) and
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
// ... or a step from an existing PathNode to another node. // ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid | exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() } Configuration getConfiguration() { none() }
private predicate isHidden() { private predicate isHidden() {
nodeIsHidden(this.getNode()) and hiddenNode(this.getNode()) and
not this.isSource() and not this.isSource() and
not this instanceof PathNodeSink not this instanceof PathNodeSink
} }
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and mid.getAp() instanceof AccessPathNil and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx() sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg( private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand( private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i) p.isParameterOf(callable, i)
) )
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively. * respectively.
*/ */
private predicate pathIntoCallable( private predicate pathIntoCallable(
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call DataFlowCall call
) { ) {
exists(int i, DataFlowCallable callable, AccessPath ap | exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 = private newtype TSummaryCtx1 =
TSummaryCtx1None() or TSummaryCtx1None() or
TSummaryCtx1Param(ParameterNode p) TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 = private newtype TSummaryCtx2 =
TSummaryCtx2None() or TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
exists(config.explorationLimit()) exists(config.explorationLimit())
or or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or or
exists(PartialPathNodeRev mid | exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit() distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
) )
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid | exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not clearsContent(node, ap.getHead().getContent()) and not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode if node instanceof CastingNode
then compatibleTypes(getNodeType(node), ap.getType()) then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any() else any()
) )
} }
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
( (
localFlowStep(mid.getNode(), node, config) and localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
) )
or or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
or or
partialPathStoreStep(mid, _, _, node, ap) and partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getNodeType(node)) compatibleTypes(ap.getType(), getNodeDataFlowType(node))
) )
or or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap, PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
} }
private predicate partialPathIntoCallable( private predicate partialPathIntoCallable(
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc, PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap, TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc, DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 | exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config) paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
) )
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config) apConsRev(ap, c, ap0, config)
) )
or or
exists(ParameterNode p | exists(ParamNode p |
mid.getNode() = p and mid.getNode() = p and
viableParamArg(_, p, node) and viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap, int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(PartialPathNodeRev mid, ParameterNode p | exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and mid.getNode() = p and
p.isParameterOf(_, pos) and p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic] pragma[nomagic]
private predicate revPartialPathThroughCallable( private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) { ) {
exists(DataFlowCall call, int pos | exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and revPartialPathThroughCallable0(call, mid, pos, ap, config) and

View File

@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`. * Holds if data can flow in one local step from `node1` to `node2`.
*/ */
private predicate localFlowStep(Node node1, Node node2, Configuration config) { private predicate localFlowStep(Node node1, Node node2, Configuration config) {
( simpleLocalFlowStepExt(node1, node2) and
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts. * Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/ */
private predicate jumpStep(Node node1, Node node2, Configuration config) { private predicate jumpStep(Node node1, Node node2, Configuration config) {
jumpStep(node1, node2) and jumpStepCached(node1, node2) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) { private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
exists(ArgumentNode arg | exists(ArgNode arg |
fwdFlow(arg, cc, config) and fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg) viableParamArg(call, _, arg)
) )
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic] pragma[nomagic]
predicate viableParamArgNodeCandFwd1( predicate viableParamArgNodeCandFwd1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
viableParamArg(call, p, arg) and viableParamArg(call, p, arg) and
fwdFlow(arg, config) fwdFlow(arg, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config exists(ParamNode p |
) {
exists(ParameterNode p |
revFlow(p, toReturn, config) and revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config) viableParamArgNodeCandFwd1(call, p, arg, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config) revFlowIn(call, arg, true, config)
} }
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a * Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic] pragma[nomagic]
private predicate viableParamArgNodeCand1( private predicate viableParamArgNodeCand1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config) Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) { ) {
viableParamArgNodeCand1(call, p, arg, config) and viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, arg, p, config) and flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j | exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config) PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
) )
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand2( private predicate flowIntoCallNodeCand2(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/ */
private class FlowCheckNode extends Node { private class FlowCheckNode extends Node {
FlowCheckNode() { FlowCheckNode() {
this instanceof CastNode or castNode(this) or
clearsContent(this, _) clearsContentCached(this, _)
} }
} }
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or config.isSource(node) or
jumpStep(_, node, config) or jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or additionalJumpStep(_, node, config) or
node instanceof ParameterNode or node instanceof ParamNode or
node instanceof OutNodeExt or node instanceof OutNodeExt or
store(_, _, node, _) or store(_, _, node, _) or
read(_, _, node) or read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc LocalCallContext cc
) { ) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
( (
localFlowEntry(node1, pragma[only_bind_into](config)) and localFlowEntry(node1, pragma[only_bind_into](config)) and
( (
localFlowStepNodeCand1(node1, node2, config) and localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and preservesValue = true and
t = getNodeType(node1) t = getNodeDataFlowType(node1)
or or
additionalLocalFlowStepNodeCand2(node1, node2, config) and additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) t = getNodeDataFlowType(node2)
) and ) and
node1 != node2 and node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
or or
exists(Node mid | exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and not mid instanceof FlowCheckNode and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) and t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
) )
) )
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() } private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap] bindingset[node, ap]
private predicate filter(Node node, Ap ap) { private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and not ap.isClearedAt(node) and
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() if node instanceof CastingNode
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
} }
bindingset[ap, contentType] bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() } private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCall( private predicate flowIntoCall(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx = private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParameterNode p, AccessPath ap) { TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _) Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
} }
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */ /** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
private ParameterNode p; private ParamNode p;
private AccessPath ap; private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) } SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and config.isSource(node) and
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
// ... or a step from an existing PathNode to another node. // ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid | exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() } Configuration getConfiguration() { none() }
private predicate isHidden() { private predicate isHidden() {
nodeIsHidden(this.getNode()) and hiddenNode(this.getNode()) and
not this.isSource() and not this.isSource() and
not this instanceof PathNodeSink not this instanceof PathNodeSink
} }
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and mid.getAp() instanceof AccessPathNil and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx() sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg( private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand( private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i) p.isParameterOf(callable, i)
) )
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively. * respectively.
*/ */
private predicate pathIntoCallable( private predicate pathIntoCallable(
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call DataFlowCall call
) { ) {
exists(int i, DataFlowCallable callable, AccessPath ap | exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 = private newtype TSummaryCtx1 =
TSummaryCtx1None() or TSummaryCtx1None() or
TSummaryCtx1Param(ParameterNode p) TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 = private newtype TSummaryCtx2 =
TSummaryCtx2None() or TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
exists(config.explorationLimit()) exists(config.explorationLimit())
or or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or or
exists(PartialPathNodeRev mid | exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit() distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
) )
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid | exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not clearsContent(node, ap.getHead().getContent()) and not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode if node instanceof CastingNode
then compatibleTypes(getNodeType(node), ap.getType()) then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any() else any()
) )
} }
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
( (
localFlowStep(mid.getNode(), node, config) and localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
) )
or or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
or or
partialPathStoreStep(mid, _, _, node, ap) and partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getNodeType(node)) compatibleTypes(ap.getType(), getNodeDataFlowType(node))
) )
or or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap, PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
} }
private predicate partialPathIntoCallable( private predicate partialPathIntoCallable(
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc, PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap, TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc, DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 | exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config) paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
) )
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config) apConsRev(ap, c, ap0, config)
) )
or or
exists(ParameterNode p | exists(ParamNode p |
mid.getNode() = p and mid.getNode() = p and
viableParamArg(_, p, node) and viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap, int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(PartialPathNodeRev mid, ParameterNode p | exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and mid.getNode() = p and
p.isParameterOf(_, pos) and p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic] pragma[nomagic]
private predicate revPartialPathThroughCallable( private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) { ) {
exists(DataFlowCall call, int pos | exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and revPartialPathThroughCallable0(call, mid, pos, ap, config) and

View File

@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`. * Holds if data can flow in one local step from `node1` to `node2`.
*/ */
private predicate localFlowStep(Node node1, Node node2, Configuration config) { private predicate localFlowStep(Node node1, Node node2, Configuration config) {
( simpleLocalFlowStepExt(node1, node2) and
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts. * Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/ */
private predicate jumpStep(Node node1, Node node2, Configuration config) { private predicate jumpStep(Node node1, Node node2, Configuration config) {
jumpStep(node1, node2) and jumpStepCached(node1, node2) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) { private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
exists(ArgumentNode arg | exists(ArgNode arg |
fwdFlow(arg, cc, config) and fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg) viableParamArg(call, _, arg)
) )
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic] pragma[nomagic]
predicate viableParamArgNodeCandFwd1( predicate viableParamArgNodeCandFwd1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
viableParamArg(call, p, arg) and viableParamArg(call, p, arg) and
fwdFlow(arg, config) fwdFlow(arg, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config exists(ParamNode p |
) {
exists(ParameterNode p |
revFlow(p, toReturn, config) and revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config) viableParamArgNodeCandFwd1(call, p, arg, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config) revFlowIn(call, arg, true, config)
} }
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a * Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic] pragma[nomagic]
private predicate viableParamArgNodeCand1( private predicate viableParamArgNodeCand1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config) Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) { ) {
viableParamArgNodeCand1(call, p, arg, config) and viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, arg, p, config) and flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j | exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config) PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
) )
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand2( private predicate flowIntoCallNodeCand2(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/ */
private class FlowCheckNode extends Node { private class FlowCheckNode extends Node {
FlowCheckNode() { FlowCheckNode() {
this instanceof CastNode or castNode(this) or
clearsContent(this, _) clearsContentCached(this, _)
} }
} }
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or config.isSource(node) or
jumpStep(_, node, config) or jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or additionalJumpStep(_, node, config) or
node instanceof ParameterNode or node instanceof ParamNode or
node instanceof OutNodeExt or node instanceof OutNodeExt or
store(_, _, node, _) or store(_, _, node, _) or
read(_, _, node) or read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc LocalCallContext cc
) { ) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
( (
localFlowEntry(node1, pragma[only_bind_into](config)) and localFlowEntry(node1, pragma[only_bind_into](config)) and
( (
localFlowStepNodeCand1(node1, node2, config) and localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and preservesValue = true and
t = getNodeType(node1) t = getNodeDataFlowType(node1)
or or
additionalLocalFlowStepNodeCand2(node1, node2, config) and additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) t = getNodeDataFlowType(node2)
) and ) and
node1 != node2 and node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
or or
exists(Node mid | exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and not mid instanceof FlowCheckNode and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) and t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
) )
) )
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() } private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap] bindingset[node, ap]
private predicate filter(Node node, Ap ap) { private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and not ap.isClearedAt(node) and
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() if node instanceof CastingNode
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
} }
bindingset[ap, contentType] bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() } private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCall( private predicate flowIntoCall(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx = private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParameterNode p, AccessPath ap) { TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _) Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
} }
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */ /** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
private ParameterNode p; private ParamNode p;
private AccessPath ap; private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) } SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and config.isSource(node) and
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
// ... or a step from an existing PathNode to another node. // ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid | exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() } Configuration getConfiguration() { none() }
private predicate isHidden() { private predicate isHidden() {
nodeIsHidden(this.getNode()) and hiddenNode(this.getNode()) and
not this.isSource() and not this.isSource() and
not this instanceof PathNodeSink not this instanceof PathNodeSink
} }
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and mid.getAp() instanceof AccessPathNil and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx() sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg( private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand( private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i) p.isParameterOf(callable, i)
) )
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively. * respectively.
*/ */
private predicate pathIntoCallable( private predicate pathIntoCallable(
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call DataFlowCall call
) { ) {
exists(int i, DataFlowCallable callable, AccessPath ap | exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 = private newtype TSummaryCtx1 =
TSummaryCtx1None() or TSummaryCtx1None() or
TSummaryCtx1Param(ParameterNode p) TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 = private newtype TSummaryCtx2 =
TSummaryCtx2None() or TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
exists(config.explorationLimit()) exists(config.explorationLimit())
or or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or or
exists(PartialPathNodeRev mid | exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit() distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
) )
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid | exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not clearsContent(node, ap.getHead().getContent()) and not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode if node instanceof CastingNode
then compatibleTypes(getNodeType(node), ap.getType()) then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any() else any()
) )
} }
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
( (
localFlowStep(mid.getNode(), node, config) and localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
) )
or or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
or or
partialPathStoreStep(mid, _, _, node, ap) and partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getNodeType(node)) compatibleTypes(ap.getType(), getNodeDataFlowType(node))
) )
or or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap, PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
} }
private predicate partialPathIntoCallable( private predicate partialPathIntoCallable(
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc, PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap, TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc, DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 | exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config) paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
) )
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config) apConsRev(ap, c, ap0, config)
) )
or or
exists(ParameterNode p | exists(ParamNode p |
mid.getNode() = p and mid.getNode() = p and
viableParamArg(_, p, node) and viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap, int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(PartialPathNodeRev mid, ParameterNode p | exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and mid.getNode() = p and
p.isParameterOf(_, pos) and p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic] pragma[nomagic]
private predicate revPartialPathThroughCallable( private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) { ) {
exists(DataFlowCall call, int pos | exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and revPartialPathThroughCallable0(call, mid, pos, ap, config) and

View File

@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`. * Holds if data can flow in one local step from `node1` to `node2`.
*/ */
private predicate localFlowStep(Node node1, Node node2, Configuration config) { private predicate localFlowStep(Node node1, Node node2, Configuration config) {
( simpleLocalFlowStepExt(node1, node2) and
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts. * Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/ */
private predicate jumpStep(Node node1, Node node2, Configuration config) { private predicate jumpStep(Node node1, Node node2, Configuration config) {
jumpStep(node1, node2) and jumpStepCached(node1, node2) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) { private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
exists(ArgumentNode arg | exists(ArgNode arg |
fwdFlow(arg, cc, config) and fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg) viableParamArg(call, _, arg)
) )
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic] pragma[nomagic]
predicate viableParamArgNodeCandFwd1( predicate viableParamArgNodeCandFwd1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
viableParamArg(call, p, arg) and viableParamArg(call, p, arg) and
fwdFlow(arg, config) fwdFlow(arg, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config exists(ParamNode p |
) {
exists(ParameterNode p |
revFlow(p, toReturn, config) and revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config) viableParamArgNodeCandFwd1(call, p, arg, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config) revFlowIn(call, arg, true, config)
} }
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a * Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic] pragma[nomagic]
private predicate viableParamArgNodeCand1( private predicate viableParamArgNodeCand1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config) Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) { ) {
viableParamArgNodeCand1(call, p, arg, config) and viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, arg, p, config) and flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j | exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config) PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
) )
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand2( private predicate flowIntoCallNodeCand2(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/ */
private class FlowCheckNode extends Node { private class FlowCheckNode extends Node {
FlowCheckNode() { FlowCheckNode() {
this instanceof CastNode or castNode(this) or
clearsContent(this, _) clearsContentCached(this, _)
} }
} }
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or config.isSource(node) or
jumpStep(_, node, config) or jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or additionalJumpStep(_, node, config) or
node instanceof ParameterNode or node instanceof ParamNode or
node instanceof OutNodeExt or node instanceof OutNodeExt or
store(_, _, node, _) or store(_, _, node, _) or
read(_, _, node) or read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc LocalCallContext cc
) { ) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
( (
localFlowEntry(node1, pragma[only_bind_into](config)) and localFlowEntry(node1, pragma[only_bind_into](config)) and
( (
localFlowStepNodeCand1(node1, node2, config) and localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and preservesValue = true and
t = getNodeType(node1) t = getNodeDataFlowType(node1)
or or
additionalLocalFlowStepNodeCand2(node1, node2, config) and additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) t = getNodeDataFlowType(node2)
) and ) and
node1 != node2 and node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
or or
exists(Node mid | exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and not mid instanceof FlowCheckNode and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) and t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
) )
) )
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() } private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap] bindingset[node, ap]
private predicate filter(Node node, Ap ap) { private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and not ap.isClearedAt(node) and
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() if node instanceof CastingNode
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
} }
bindingset[ap, contentType] bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() } private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCall( private predicate flowIntoCall(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx = private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParameterNode p, AccessPath ap) { TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _) Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
} }
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */ /** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
private ParameterNode p; private ParamNode p;
private AccessPath ap; private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) } SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and config.isSource(node) and
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
// ... or a step from an existing PathNode to another node. // ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid | exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() } Configuration getConfiguration() { none() }
private predicate isHidden() { private predicate isHidden() {
nodeIsHidden(this.getNode()) and hiddenNode(this.getNode()) and
not this.isSource() and not this.isSource() and
not this instanceof PathNodeSink not this instanceof PathNodeSink
} }
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and mid.getAp() instanceof AccessPathNil and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx() sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg( private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand( private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i) p.isParameterOf(callable, i)
) )
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively. * respectively.
*/ */
private predicate pathIntoCallable( private predicate pathIntoCallable(
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call DataFlowCall call
) { ) {
exists(int i, DataFlowCallable callable, AccessPath ap | exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 = private newtype TSummaryCtx1 =
TSummaryCtx1None() or TSummaryCtx1None() or
TSummaryCtx1Param(ParameterNode p) TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 = private newtype TSummaryCtx2 =
TSummaryCtx2None() or TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
exists(config.explorationLimit()) exists(config.explorationLimit())
or or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or or
exists(PartialPathNodeRev mid | exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit() distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
) )
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid | exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not clearsContent(node, ap.getHead().getContent()) and not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode if node instanceof CastingNode
then compatibleTypes(getNodeType(node), ap.getType()) then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any() else any()
) )
} }
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
( (
localFlowStep(mid.getNode(), node, config) and localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
) )
or or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
or or
partialPathStoreStep(mid, _, _, node, ap) and partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getNodeType(node)) compatibleTypes(ap.getType(), getNodeDataFlowType(node))
) )
or or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap, PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
} }
private predicate partialPathIntoCallable( private predicate partialPathIntoCallable(
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc, PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap, TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc, DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 | exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config) paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
) )
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config) apConsRev(ap, c, ap0, config)
) )
or or
exists(ParameterNode p | exists(ParamNode p |
mid.getNode() = p and mid.getNode() = p and
viableParamArg(_, p, node) and viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap, int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(PartialPathNodeRev mid, ParameterNode p | exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and mid.getNode() = p and
p.isParameterOf(_, pos) and p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic] pragma[nomagic]
private predicate revPartialPathThroughCallable( private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) { ) {
exists(DataFlowCall call, int pos | exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and revPartialPathThroughCallable0(call, mid, pos, ap, config) and

View File

@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`. * Holds if data can flow in one local step from `node1` to `node2`.
*/ */
private predicate localFlowStep(Node node1, Node node2, Configuration config) { private predicate localFlowStep(Node node1, Node node2, Configuration config) {
( simpleLocalFlowStepExt(node1, node2) and
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts. * Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/ */
private predicate jumpStep(Node node1, Node node2, Configuration config) { private predicate jumpStep(Node node1, Node node2, Configuration config) {
jumpStep(node1, node2) and jumpStepCached(node1, node2) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) { private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
exists(ArgumentNode arg | exists(ArgNode arg |
fwdFlow(arg, cc, config) and fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg) viableParamArg(call, _, arg)
) )
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic] pragma[nomagic]
predicate viableParamArgNodeCandFwd1( predicate viableParamArgNodeCandFwd1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
viableParamArg(call, p, arg) and viableParamArg(call, p, arg) and
fwdFlow(arg, config) fwdFlow(arg, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config exists(ParamNode p |
) {
exists(ParameterNode p |
revFlow(p, toReturn, config) and revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config) viableParamArgNodeCandFwd1(call, p, arg, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config) revFlowIn(call, arg, true, config)
} }
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a * Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic] pragma[nomagic]
private predicate viableParamArgNodeCand1( private predicate viableParamArgNodeCand1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config) Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) { ) {
viableParamArgNodeCand1(call, p, arg, config) and viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, arg, p, config) and flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j | exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config) PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
) )
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand2( private predicate flowIntoCallNodeCand2(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/ */
private class FlowCheckNode extends Node { private class FlowCheckNode extends Node {
FlowCheckNode() { FlowCheckNode() {
this instanceof CastNode or castNode(this) or
clearsContent(this, _) clearsContentCached(this, _)
} }
} }
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or config.isSource(node) or
jumpStep(_, node, config) or jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or additionalJumpStep(_, node, config) or
node instanceof ParameterNode or node instanceof ParamNode or
node instanceof OutNodeExt or node instanceof OutNodeExt or
store(_, _, node, _) or store(_, _, node, _) or
read(_, _, node) or read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc LocalCallContext cc
) { ) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
( (
localFlowEntry(node1, pragma[only_bind_into](config)) and localFlowEntry(node1, pragma[only_bind_into](config)) and
( (
localFlowStepNodeCand1(node1, node2, config) and localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and preservesValue = true and
t = getNodeType(node1) t = getNodeDataFlowType(node1)
or or
additionalLocalFlowStepNodeCand2(node1, node2, config) and additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) t = getNodeDataFlowType(node2)
) and ) and
node1 != node2 and node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
or or
exists(Node mid | exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and not mid instanceof FlowCheckNode and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) and t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
) )
) )
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() } private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap] bindingset[node, ap]
private predicate filter(Node node, Ap ap) { private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and not ap.isClearedAt(node) and
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() if node instanceof CastingNode
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
} }
bindingset[ap, contentType] bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() } private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCall( private predicate flowIntoCall(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx = private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParameterNode p, AccessPath ap) { TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _) Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
} }
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */ /** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
private ParameterNode p; private ParamNode p;
private AccessPath ap; private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) } SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and config.isSource(node) and
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
// ... or a step from an existing PathNode to another node. // ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid | exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() } Configuration getConfiguration() { none() }
private predicate isHidden() { private predicate isHidden() {
nodeIsHidden(this.getNode()) and hiddenNode(this.getNode()) and
not this.isSource() and not this.isSource() and
not this instanceof PathNodeSink not this instanceof PathNodeSink
} }
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and mid.getAp() instanceof AccessPathNil and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx() sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg( private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand( private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i) p.isParameterOf(callable, i)
) )
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively. * respectively.
*/ */
private predicate pathIntoCallable( private predicate pathIntoCallable(
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call DataFlowCall call
) { ) {
exists(int i, DataFlowCallable callable, AccessPath ap | exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 = private newtype TSummaryCtx1 =
TSummaryCtx1None() or TSummaryCtx1None() or
TSummaryCtx1Param(ParameterNode p) TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 = private newtype TSummaryCtx2 =
TSummaryCtx2None() or TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
exists(config.explorationLimit()) exists(config.explorationLimit())
or or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or or
exists(PartialPathNodeRev mid | exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit() distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
) )
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid | exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not clearsContent(node, ap.getHead().getContent()) and not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode if node instanceof CastingNode
then compatibleTypes(getNodeType(node), ap.getType()) then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any() else any()
) )
} }
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
( (
localFlowStep(mid.getNode(), node, config) and localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
) )
or or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
or or
partialPathStoreStep(mid, _, _, node, ap) and partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getNodeType(node)) compatibleTypes(ap.getType(), getNodeDataFlowType(node))
) )
or or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap, PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
} }
private predicate partialPathIntoCallable( private predicate partialPathIntoCallable(
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc, PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap, TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc, DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 | exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config) paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
) )
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config) apConsRev(ap, c, ap0, config)
) )
or or
exists(ParameterNode p | exists(ParamNode p |
mid.getNode() = p and mid.getNode() = p and
viableParamArg(_, p, node) and viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap, int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(PartialPathNodeRev mid, ParameterNode p | exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and mid.getNode() = p and
p.isParameterOf(_, pos) and p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic] pragma[nomagic]
private predicate revPartialPathThroughCallable( private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) { ) {
exists(DataFlowCall call, int pos | exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and revPartialPathThroughCallable0(call, mid, pos, ap, config) and

View File

@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`. * Holds if data can flow in one local step from `node1` to `node2`.
*/ */
private predicate localFlowStep(Node node1, Node node2, Configuration config) { private predicate localFlowStep(Node node1, Node node2, Configuration config) {
( simpleLocalFlowStepExt(node1, node2) and
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts. * Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/ */
private predicate jumpStep(Node node1, Node node2, Configuration config) { private predicate jumpStep(Node node1, Node node2, Configuration config) {
jumpStep(node1, node2) and jumpStepCached(node1, node2) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) { private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
exists(ArgumentNode arg | exists(ArgNode arg |
fwdFlow(arg, cc, config) and fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg) viableParamArg(call, _, arg)
) )
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic] pragma[nomagic]
predicate viableParamArgNodeCandFwd1( predicate viableParamArgNodeCandFwd1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
viableParamArg(call, p, arg) and viableParamArg(call, p, arg) and
fwdFlow(arg, config) fwdFlow(arg, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config exists(ParamNode p |
) {
exists(ParameterNode p |
revFlow(p, toReturn, config) and revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config) viableParamArgNodeCandFwd1(call, p, arg, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config) revFlowIn(call, arg, true, config)
} }
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a * Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic] pragma[nomagic]
private predicate viableParamArgNodeCand1( private predicate viableParamArgNodeCand1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config) Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) { ) {
viableParamArgNodeCand1(call, p, arg, config) and viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, arg, p, config) and flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j | exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config) PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
) )
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand2( private predicate flowIntoCallNodeCand2(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/ */
private class FlowCheckNode extends Node { private class FlowCheckNode extends Node {
FlowCheckNode() { FlowCheckNode() {
this instanceof CastNode or castNode(this) or
clearsContent(this, _) clearsContentCached(this, _)
} }
} }
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or config.isSource(node) or
jumpStep(_, node, config) or jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or additionalJumpStep(_, node, config) or
node instanceof ParameterNode or node instanceof ParamNode or
node instanceof OutNodeExt or node instanceof OutNodeExt or
store(_, _, node, _) or store(_, _, node, _) or
read(_, _, node) or read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc LocalCallContext cc
) { ) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
( (
localFlowEntry(node1, pragma[only_bind_into](config)) and localFlowEntry(node1, pragma[only_bind_into](config)) and
( (
localFlowStepNodeCand1(node1, node2, config) and localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and preservesValue = true and
t = getNodeType(node1) t = getNodeDataFlowType(node1)
or or
additionalLocalFlowStepNodeCand2(node1, node2, config) and additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) t = getNodeDataFlowType(node2)
) and ) and
node1 != node2 and node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
or or
exists(Node mid | exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and not mid instanceof FlowCheckNode and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) and t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
) )
) )
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() } private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap] bindingset[node, ap]
private predicate filter(Node node, Ap ap) { private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and not ap.isClearedAt(node) and
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() if node instanceof CastingNode
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
} }
bindingset[ap, contentType] bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() } private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCall( private predicate flowIntoCall(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx = private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParameterNode p, AccessPath ap) { TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _) Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
} }
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */ /** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
private ParameterNode p; private ParamNode p;
private AccessPath ap; private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) } SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and config.isSource(node) and
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
// ... or a step from an existing PathNode to another node. // ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid | exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() } Configuration getConfiguration() { none() }
private predicate isHidden() { private predicate isHidden() {
nodeIsHidden(this.getNode()) and hiddenNode(this.getNode()) and
not this.isSource() and not this.isSource() and
not this instanceof PathNodeSink not this instanceof PathNodeSink
} }
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and mid.getAp() instanceof AccessPathNil and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx() sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg( private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand( private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i) p.isParameterOf(callable, i)
) )
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively. * respectively.
*/ */
private predicate pathIntoCallable( private predicate pathIntoCallable(
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call DataFlowCall call
) { ) {
exists(int i, DataFlowCallable callable, AccessPath ap | exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 = private newtype TSummaryCtx1 =
TSummaryCtx1None() or TSummaryCtx1None() or
TSummaryCtx1Param(ParameterNode p) TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 = private newtype TSummaryCtx2 =
TSummaryCtx2None() or TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
exists(config.explorationLimit()) exists(config.explorationLimit())
or or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or or
exists(PartialPathNodeRev mid | exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit() distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
) )
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid | exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not clearsContent(node, ap.getHead().getContent()) and not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode if node instanceof CastingNode
then compatibleTypes(getNodeType(node), ap.getType()) then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any() else any()
) )
} }
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
( (
localFlowStep(mid.getNode(), node, config) and localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
) )
or or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
or or
partialPathStoreStep(mid, _, _, node, ap) and partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getNodeType(node)) compatibleTypes(ap.getType(), getNodeDataFlowType(node))
) )
or or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap, PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
} }
private predicate partialPathIntoCallable( private predicate partialPathIntoCallable(
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc, PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap, TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc, DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 | exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config) paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
) )
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config) apConsRev(ap, c, ap0, config)
) )
or or
exists(ParameterNode p | exists(ParamNode p |
mid.getNode() = p and mid.getNode() = p and
viableParamArg(_, p, node) and viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap, int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(PartialPathNodeRev mid, ParameterNode p | exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and mid.getNode() = p and
p.isParameterOf(_, pos) and p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic] pragma[nomagic]
private predicate revPartialPathThroughCallable( private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) { ) {
exists(DataFlowCall call, int pos | exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and revPartialPathThroughCallable0(call, mid, pos, ap, config) and

View File

@@ -35,22 +35,22 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
* calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly. * calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly.
*/ */
private module LambdaFlow { private module LambdaFlow {
private predicate viableParamNonLambda(DataFlowCall call, int i, ParameterNode p) { private predicate viableParamNonLambda(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallable(call), i) p.isParameterOf(viableCallable(call), i)
} }
private predicate viableParamLambda(DataFlowCall call, int i, ParameterNode p) { private predicate viableParamLambda(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallableLambda(call, _), i) p.isParameterOf(viableCallableLambda(call, _), i)
} }
private predicate viableParamArgNonLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) { private predicate viableParamArgNonLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i | exists(int i |
viableParamNonLambda(call, i, p) and viableParamNonLambda(call, i, p) and
arg.argumentOf(call, i) arg.argumentOf(call, i)
) )
} }
private predicate viableParamArgLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) { private predicate viableParamArgLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i | exists(int i |
viableParamLambda(call, i, p) and viableParamLambda(call, i, p) and
arg.argumentOf(call, i) arg.argumentOf(call, i)
@@ -118,8 +118,8 @@ private module LambdaFlow {
boolean toJump, DataFlowCallOption lastCall boolean toJump, DataFlowCallOption lastCall
) { ) {
revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and
if node instanceof CastNode or node instanceof ArgumentNode or node instanceof ReturnNode if castNode(node) or node instanceof ArgNode or node instanceof ReturnNode
then compatibleTypes(t, getNodeType(node)) then compatibleTypes(t, getNodeDataFlowType(node))
else any() else any()
} }
@@ -129,7 +129,7 @@ private module LambdaFlow {
boolean toJump, DataFlowCallOption lastCall boolean toJump, DataFlowCallOption lastCall
) { ) {
lambdaCall(lambdaCall, kind, node) and lambdaCall(lambdaCall, kind, node) and
t = getNodeType(node) and t = getNodeDataFlowType(node) and
toReturn = false and toReturn = false and
toJump = false and toJump = false and
lastCall = TDataFlowCallNone() lastCall = TDataFlowCallNone()
@@ -146,7 +146,7 @@ private module LambdaFlow {
getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid) getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid)
| |
preservesValue = false and preservesValue = false and
t = getNodeType(node) t = getNodeDataFlowType(node)
or or
preservesValue = true and preservesValue = true and
t = t0 t = t0
@@ -160,7 +160,7 @@ private module LambdaFlow {
toJump = true and toJump = true and
lastCall = TDataFlowCallNone() lastCall = TDataFlowCallNone()
| |
jumpStep(node, mid) and jumpStepCached(node, mid) and
t = t0 t = t0
or or
exists(boolean preservesValue | exists(boolean preservesValue |
@@ -168,7 +168,7 @@ private module LambdaFlow {
getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid) getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid)
| |
preservesValue = false and preservesValue = false and
t = getNodeType(node) t = getNodeDataFlowType(node)
or or
preservesValue = true and preservesValue = true and
t = t0 t = t0
@@ -176,7 +176,7 @@ private module LambdaFlow {
) )
or or
// flow into a callable // flow into a callable
exists(ParameterNode p, DataFlowCallOption lastCall0, DataFlowCall call | exists(ParamNode p, DataFlowCallOption lastCall0, DataFlowCall call |
revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and
( (
if lastCall0 = TDataFlowCallNone() and toJump = false if lastCall0 = TDataFlowCallNone() and toJump = false
@@ -227,7 +227,7 @@ private module LambdaFlow {
pragma[nomagic] pragma[nomagic]
predicate revLambdaFlowIn( predicate revLambdaFlowIn(
DataFlowCall lambdaCall, LambdaCallKind kind, ParameterNode p, DataFlowType t, boolean toJump, DataFlowCall lambdaCall, LambdaCallKind kind, ParamNode p, DataFlowType t, boolean toJump,
DataFlowCallOption lastCall DataFlowCallOption lastCall
) { ) {
revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall) revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall)
@@ -242,6 +242,89 @@ private DataFlowCallable viableCallableExt(DataFlowCall call) {
cached cached
private module Cached { private module Cached {
/**
* If needed, call this predicate from `DataFlowImplSpecific.qll` in order to
* force a stage-dependency on the `DataFlowImplCommon.qll` stage and therby
* collapsing the two stages.
*/
cached
predicate forceCachingInSameStage() { any() }
cached
predicate nodeEnclosingCallable(Node n, DataFlowCallable c) { c = n.getEnclosingCallable() }
cached
predicate callEnclosingCallable(DataFlowCall call, DataFlowCallable c) {
c = call.getEnclosingCallable()
}
cached
predicate nodeDataFlowType(Node n, DataFlowType t) { t = getNodeType(n) }
cached
predicate jumpStepCached(Node node1, Node node2) { jumpStep(node1, node2) }
cached
predicate clearsContentCached(Node n, Content c) { clearsContent(n, c) }
cached
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
cached
predicate outNodeExt(Node n) {
n instanceof OutNode
or
n.(PostUpdateNode).getPreUpdateNode() instanceof ArgNode
}
cached
predicate hiddenNode(Node n) { nodeIsHidden(n) }
cached
OutNodeExt getAnOutNodeExt(DataFlowCall call, ReturnKindExt k) {
result = getAnOutNode(call, k.(ValueReturnKind).getKind())
or
exists(ArgNode arg |
result.(PostUpdateNode).getPreUpdateNode() = arg and
arg.argumentOf(call, k.(ParamUpdateReturnKind).getPosition())
)
}
cached
predicate returnNodeExt(Node n, ReturnKindExt k) {
k = TValueReturn(n.(ReturnNode).getKind())
or
exists(ParamNode p, int pos |
parameterValueFlowsToPreUpdate(p, n) and
p.isParameterOf(_, pos) and
k = TParamUpdate(pos)
)
}
cached
predicate castNode(Node n) { n instanceof CastNode }
cached
predicate castingNode(Node n) {
castNode(n) or
n instanceof ParamNode or
n instanceof OutNodeExt or
// For reads, `x.f`, we want to check that the tracked type after the read (which
// is obtained by popping the head of the access path stack) is compatible with
// the type of `x.f`.
read(_, _, n)
}
cached
predicate parameterNode(Node n, DataFlowCallable c, int i) {
n.(ParameterNode).isParameterOf(c, i)
}
cached
predicate argumentNode(Node n, DataFlowCall call, int pos) {
n.(ArgumentNode).argumentOf(call, pos)
}
/** /**
* Gets a viable target for the lambda call `call`. * Gets a viable target for the lambda call `call`.
* *
@@ -261,7 +344,7 @@ private module Cached {
* The instance parameter is considered to have index `-1`. * The instance parameter is considered to have index `-1`.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate viableParam(DataFlowCall call, int i, ParameterNode p) { private predicate viableParam(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallableExt(call), i) p.isParameterOf(viableCallableExt(call), i)
} }
@@ -270,11 +353,11 @@ private module Cached {
* dispatch into account. * dispatch into account.
*/ */
cached cached
predicate viableParamArg(DataFlowCall call, ParameterNode p, ArgumentNode arg) { predicate viableParamArg(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i | exists(int i |
viableParam(call, i, p) and viableParam(call, i, p) and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
compatibleTypes(getNodeType(arg), getNodeType(p)) compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
) )
} }
@@ -312,7 +395,7 @@ private module Cached {
* `read` indicates whether it is contents of `p` that can flow to `node`. * `read` indicates whether it is contents of `p` that can flow to `node`.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate parameterValueFlowCand(ParameterNode p, Node node, boolean read) { private predicate parameterValueFlowCand(ParamNode p, Node node, boolean read) {
p = node and p = node and
read = false read = false
or or
@@ -325,30 +408,30 @@ private module Cached {
// read // read
exists(Node mid | exists(Node mid |
parameterValueFlowCand(p, mid, false) and parameterValueFlowCand(p, mid, false) and
readStep(mid, _, node) and read(mid, _, node) and
read = true read = true
) )
or or
// flow through: no prior read // flow through: no prior read
exists(ArgumentNode arg | exists(ArgNode arg |
parameterValueFlowArgCand(p, arg, false) and parameterValueFlowArgCand(p, arg, false) and
argumentValueFlowsThroughCand(arg, node, read) argumentValueFlowsThroughCand(arg, node, read)
) )
or or
// flow through: no read inside method // flow through: no read inside method
exists(ArgumentNode arg | exists(ArgNode arg |
parameterValueFlowArgCand(p, arg, read) and parameterValueFlowArgCand(p, arg, read) and
argumentValueFlowsThroughCand(arg, node, false) argumentValueFlowsThroughCand(arg, node, false)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate parameterValueFlowArgCand(ParameterNode p, ArgumentNode arg, boolean read) { private predicate parameterValueFlowArgCand(ParamNode p, ArgNode arg, boolean read) {
parameterValueFlowCand(p, arg, read) parameterValueFlowCand(p, arg, read)
} }
pragma[nomagic] pragma[nomagic]
predicate parameterValueFlowsToPreUpdateCand(ParameterNode p, PostUpdateNode n) { predicate parameterValueFlowsToPreUpdateCand(ParamNode p, PostUpdateNode n) {
parameterValueFlowCand(p, n.getPreUpdateNode(), false) parameterValueFlowCand(p, n.getPreUpdateNode(), false)
} }
@@ -360,7 +443,7 @@ private module Cached {
* `read` indicates whether it is contents of `p` that can flow to the return * `read` indicates whether it is contents of `p` that can flow to the return
* node. * node.
*/ */
predicate parameterValueFlowReturnCand(ParameterNode p, ReturnKind kind, boolean read) { predicate parameterValueFlowReturnCand(ParamNode p, ReturnKind kind, boolean read) {
exists(ReturnNode ret | exists(ReturnNode ret |
parameterValueFlowCand(p, ret, read) and parameterValueFlowCand(p, ret, read) and
kind = ret.getKind() kind = ret.getKind()
@@ -369,9 +452,9 @@ private module Cached {
pragma[nomagic] pragma[nomagic]
private predicate argumentValueFlowsThroughCand0( private predicate argumentValueFlowsThroughCand0(
DataFlowCall call, ArgumentNode arg, ReturnKind kind, boolean read DataFlowCall call, ArgNode arg, ReturnKind kind, boolean read
) { ) {
exists(ParameterNode param | viableParamArg(call, param, arg) | exists(ParamNode param | viableParamArg(call, param, arg) |
parameterValueFlowReturnCand(param, kind, read) parameterValueFlowReturnCand(param, kind, read)
) )
} }
@@ -382,14 +465,14 @@ private module Cached {
* *
* `read` indicates whether it is contents of `arg` that can flow to `out`. * `read` indicates whether it is contents of `arg` that can flow to `out`.
*/ */
predicate argumentValueFlowsThroughCand(ArgumentNode arg, Node out, boolean read) { predicate argumentValueFlowsThroughCand(ArgNode arg, Node out, boolean read) {
exists(DataFlowCall call, ReturnKind kind | exists(DataFlowCall call, ReturnKind kind |
argumentValueFlowsThroughCand0(call, arg, kind, read) and argumentValueFlowsThroughCand0(call, arg, kind, read) and
out = getAnOutNode(call, kind) out = getAnOutNode(call, kind)
) )
} }
predicate cand(ParameterNode p, Node n) { predicate cand(ParamNode p, Node n) {
parameterValueFlowCand(p, n, _) and parameterValueFlowCand(p, n, _) and
( (
parameterValueFlowReturnCand(p, _, _) parameterValueFlowReturnCand(p, _, _)
@@ -416,21 +499,21 @@ private module Cached {
* If a read step was taken, then `read` captures the `Content`, the * If a read step was taken, then `read` captures the `Content`, the
* container type, and the content type. * container type, and the content type.
*/ */
predicate parameterValueFlow(ParameterNode p, Node node, ReadStepTypesOption read) { predicate parameterValueFlow(ParamNode p, Node node, ReadStepTypesOption read) {
parameterValueFlow0(p, node, read) and parameterValueFlow0(p, node, read) and
if node instanceof CastingNode if node instanceof CastingNode
then then
// normal flow through // normal flow through
read = TReadStepTypesNone() and read = TReadStepTypesNone() and
compatibleTypes(getNodeType(p), getNodeType(node)) compatibleTypes(getNodeDataFlowType(p), getNodeDataFlowType(node))
or or
// getter // getter
compatibleTypes(read.getContentType(), getNodeType(node)) compatibleTypes(read.getContentType(), getNodeDataFlowType(node))
else any() else any()
} }
pragma[nomagic] pragma[nomagic]
private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) { private predicate parameterValueFlow0(ParamNode p, Node node, ReadStepTypesOption read) {
p = node and p = node and
Cand::cand(p, _) and Cand::cand(p, _) and
read = TReadStepTypesNone() read = TReadStepTypesNone()
@@ -447,7 +530,7 @@ private module Cached {
readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, readStepWithTypes(mid, read.getContainerType(), read.getContent(), node,
read.getContentType()) and read.getContentType()) and
Cand::parameterValueFlowReturnCand(p, _, true) and Cand::parameterValueFlowReturnCand(p, _, true) and
compatibleTypes(getNodeType(p), read.getContainerType()) compatibleTypes(getNodeDataFlowType(p), read.getContainerType())
) )
or or
parameterValueFlow0_0(TReadStepTypesNone(), p, node, read) parameterValueFlow0_0(TReadStepTypesNone(), p, node, read)
@@ -455,34 +538,32 @@ private module Cached {
pragma[nomagic] pragma[nomagic]
private predicate parameterValueFlow0_0( private predicate parameterValueFlow0_0(
ReadStepTypesOption mustBeNone, ParameterNode p, Node node, ReadStepTypesOption read ReadStepTypesOption mustBeNone, ParamNode p, Node node, ReadStepTypesOption read
) { ) {
// flow through: no prior read // flow through: no prior read
exists(ArgumentNode arg | exists(ArgNode arg |
parameterValueFlowArg(p, arg, mustBeNone) and parameterValueFlowArg(p, arg, mustBeNone) and
argumentValueFlowsThrough(arg, read, node) argumentValueFlowsThrough(arg, read, node)
) )
or or
// flow through: no read inside method // flow through: no read inside method
exists(ArgumentNode arg | exists(ArgNode arg |
parameterValueFlowArg(p, arg, read) and parameterValueFlowArg(p, arg, read) and
argumentValueFlowsThrough(arg, mustBeNone, node) argumentValueFlowsThrough(arg, mustBeNone, node)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate parameterValueFlowArg( private predicate parameterValueFlowArg(ParamNode p, ArgNode arg, ReadStepTypesOption read) {
ParameterNode p, ArgumentNode arg, ReadStepTypesOption read
) {
parameterValueFlow(p, arg, read) and parameterValueFlow(p, arg, read) and
Cand::argumentValueFlowsThroughCand(arg, _, _) Cand::argumentValueFlowsThroughCand(arg, _, _)
} }
pragma[nomagic] pragma[nomagic]
private predicate argumentValueFlowsThrough0( private predicate argumentValueFlowsThrough0(
DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read DataFlowCall call, ArgNode arg, ReturnKind kind, ReadStepTypesOption read
) { ) {
exists(ParameterNode param | viableParamArg(call, param, arg) | exists(ParamNode param | viableParamArg(call, param, arg) |
parameterValueFlowReturn(param, kind, read) parameterValueFlowReturn(param, kind, read)
) )
} }
@@ -496,18 +577,18 @@ private module Cached {
* container type, and the content type. * container type, and the content type.
*/ */
pragma[nomagic] pragma[nomagic]
predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) { predicate argumentValueFlowsThrough(ArgNode arg, ReadStepTypesOption read, Node out) {
exists(DataFlowCall call, ReturnKind kind | exists(DataFlowCall call, ReturnKind kind |
argumentValueFlowsThrough0(call, arg, kind, read) and argumentValueFlowsThrough0(call, arg, kind, read) and
out = getAnOutNode(call, kind) out = getAnOutNode(call, kind)
| |
// normal flow through // normal flow through
read = TReadStepTypesNone() and read = TReadStepTypesNone() and
compatibleTypes(getNodeType(arg), getNodeType(out)) compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(out))
or or
// getter // getter
compatibleTypes(getNodeType(arg), read.getContainerType()) and compatibleTypes(getNodeDataFlowType(arg), read.getContainerType()) and
compatibleTypes(read.getContentType(), getNodeType(out)) compatibleTypes(read.getContentType(), getNodeDataFlowType(out))
) )
} }
@@ -516,7 +597,7 @@ private module Cached {
* value-preserving steps and a single read step, not taking call * value-preserving steps and a single read step, not taking call
* contexts into account, thus representing a getter-step. * contexts into account, thus representing a getter-step.
*/ */
predicate getterStep(ArgumentNode arg, Content c, Node out) { predicate getterStep(ArgNode arg, Content c, Node out) {
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out) argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
} }
@@ -529,7 +610,7 @@ private module Cached {
* container type, and the content type. * container type, and the content type.
*/ */
private predicate parameterValueFlowReturn( private predicate parameterValueFlowReturn(
ParameterNode p, ReturnKind kind, ReadStepTypesOption read ParamNode p, ReturnKind kind, ReadStepTypesOption read
) { ) {
exists(ReturnNode ret | exists(ReturnNode ret |
parameterValueFlow(p, ret, read) and parameterValueFlow(p, ret, read) and
@@ -553,7 +634,7 @@ private module Cached {
private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) { private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) {
mayBenefitFromCallContext(call, callable) mayBenefitFromCallContext(call, callable)
or or
callable = call.getEnclosingCallable() and callEnclosingCallable(call, callable) and
exists(viableCallableLambda(call, TDataFlowCallSome(_))) exists(viableCallableLambda(call, TDataFlowCallSome(_)))
} }
@@ -611,7 +692,7 @@ private module Cached {
mayBenefitFromCallContextExt(call, _) and mayBenefitFromCallContextExt(call, _) and
c = viableCallableExt(call) and c = viableCallableExt(call) and
ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContextExt(call, ctx)) and ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContextExt(call, ctx)) and
tgts = strictcount(DataFlowCall ctx | viableCallableExt(ctx) = call.getEnclosingCallable()) and tgts = strictcount(DataFlowCall ctx | callEnclosingCallable(call, viableCallableExt(ctx))) and
ctxtgts < tgts ctxtgts < tgts
) )
} }
@@ -635,8 +716,7 @@ private module Cached {
* Holds if `p` can flow to the pre-update node associated with post-update * Holds if `p` can flow to the pre-update node associated with post-update
* node `n`, in the same callable, using only value-preserving steps. * node `n`, in the same callable, using only value-preserving steps.
*/ */
cached private predicate parameterValueFlowsToPreUpdate(ParamNode p, PostUpdateNode n) {
predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) {
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone()) parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
} }
@@ -644,9 +724,9 @@ private module Cached {
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
) { ) {
storeStep(node1, c, node2) and storeStep(node1, c, node2) and
readStep(_, c, _) and read(_, c, _) and
contentType = getNodeType(node1) and contentType = getNodeDataFlowType(node1) and
containerType = getNodeType(node2) containerType = getNodeDataFlowType(node2)
or or
exists(Node n1, Node n2 | exists(Node n1, Node n2 |
n1 = node1.(PostUpdateNode).getPreUpdateNode() and n1 = node1.(PostUpdateNode).getPreUpdateNode() and
@@ -654,12 +734,15 @@ private module Cached {
| |
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1) argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
or or
readStep(n2, c, n1) and read(n2, c, n1) and
contentType = getNodeType(n1) and contentType = getNodeDataFlowType(n1) and
containerType = getNodeType(n2) containerType = getNodeDataFlowType(n2)
) )
} }
cached
predicate read(Node node1, Content c, Node node2) { readStep(node1, c, node2) }
/** /**
* Holds if data can flow from `node1` to `node2` via a direct assignment to * Holds if data can flow from `node1` to `node2` via a direct assignment to
* `f`. * `f`.
@@ -678,8 +761,9 @@ private module Cached {
* are aliases. A typical example is a function returning `this`, implementing a fluent * are aliases. A typical example is a function returning `this`, implementing a fluent
* interface. * interface.
*/ */
cached private predicate reverseStepThroughInputOutputAlias(
predicate reverseStepThroughInputOutputAlias(PostUpdateNode fromNode, PostUpdateNode toNode) { PostUpdateNode fromNode, PostUpdateNode toNode
) {
exists(Node fromPre, Node toPre | exists(Node fromPre, Node toPre |
fromPre = fromNode.getPreUpdateNode() and fromPre = fromNode.getPreUpdateNode() and
toPre = toNode.getPreUpdateNode() toPre = toNode.getPreUpdateNode()
@@ -688,14 +772,20 @@ private module Cached {
// Does the language-specific simpleLocalFlowStep already model flow // Does the language-specific simpleLocalFlowStep already model flow
// from function input to output? // from function input to output?
fromPre = getAnOutNode(c, _) and fromPre = getAnOutNode(c, _) and
toPre.(ArgumentNode).argumentOf(c, _) and toPre.(ArgNode).argumentOf(c, _) and
simpleLocalFlowStep(toPre.(ArgumentNode), fromPre) simpleLocalFlowStep(toPre.(ArgNode), fromPre)
) )
or or
argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre) argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre)
) )
} }
cached
predicate simpleLocalFlowStepExt(Node node1, Node node2) {
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
}
/** /**
* Holds if the call context `call` either improves virtual dispatch in * Holds if the call context `call` either improves virtual dispatch in
* `callable` or if it allows us to prune unreachable nodes in `callable`. * `callable` or if it allows us to prune unreachable nodes in `callable`.
@@ -704,7 +794,7 @@ private module Cached {
predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) { predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
reducedViableImplInCallContext(_, callable, call) reducedViableImplInCallContext(_, callable, call)
or or
exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCall(n, call)) exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call))
} }
cached cached
@@ -726,12 +816,12 @@ private module Cached {
cached cached
newtype TLocalFlowCallContext = newtype TLocalFlowCallContext =
TAnyLocalCall() or TAnyLocalCall() or
TSpecificLocalCall(DataFlowCall call) { isUnreachableInCall(_, call) } TSpecificLocalCall(DataFlowCall call) { isUnreachableInCallCached(_, call) }
cached cached
newtype TReturnKindExt = newtype TReturnKindExt =
TValueReturn(ReturnKind kind) or TValueReturn(ReturnKind kind) or
TParamUpdate(int pos) { exists(ParameterNode p | p.isParameterOf(_, pos)) } TParamUpdate(int pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
cached cached
newtype TBooleanOption = newtype TBooleanOption =
@@ -761,23 +851,15 @@ private module Cached {
* A `Node` at which a cast can occur such that the type should be checked. * A `Node` at which a cast can occur such that the type should be checked.
*/ */
class CastingNode extends Node { class CastingNode extends Node {
CastingNode() { CastingNode() { castingNode(this) }
this instanceof ParameterNode or
this instanceof CastNode or
this instanceof OutNodeExt or
// For reads, `x.f`, we want to check that the tracked type after the read (which
// is obtained by popping the head of the access path stack) is compatible with
// the type of `x.f`.
readStep(_, _, this)
}
} }
private predicate readStepWithTypes( private predicate readStepWithTypes(
Node n1, DataFlowType container, Content c, Node n2, DataFlowType content Node n1, DataFlowType container, Content c, Node n2, DataFlowType content
) { ) {
readStep(n1, c, n2) and read(n1, c, n2) and
container = getNodeType(n1) and container = getNodeDataFlowType(n1) and
content = getNodeType(n2) content = getNodeDataFlowType(n2)
} }
private newtype TReadStepTypesOption = private newtype TReadStepTypesOption =
@@ -854,7 +936,7 @@ class CallContextSomeCall extends CallContextCall, TSomeCall {
override string toString() { result = "CcSomeCall" } override string toString() { result = "CcSomeCall" }
override predicate relevantFor(DataFlowCallable callable) { override predicate relevantFor(DataFlowCallable callable) {
exists(ParameterNode p | getNodeEnclosingCallable(p) = callable) exists(ParamNode p | getNodeEnclosingCallable(p) = callable)
} }
override predicate matchesCall(DataFlowCall call) { any() } override predicate matchesCall(DataFlowCall call) { any() }
@@ -866,7 +948,7 @@ class CallContextReturn extends CallContextNoCall, TReturn {
} }
override predicate relevantFor(DataFlowCallable callable) { override predicate relevantFor(DataFlowCallable callable) {
exists(DataFlowCall call | this = TReturn(_, call) and call.getEnclosingCallable() = callable) exists(DataFlowCall call | this = TReturn(_, call) and callEnclosingCallable(call, callable))
} }
} }
@@ -899,7 +981,7 @@ class LocalCallContextSpecificCall extends LocalCallContext, TSpecificLocalCall
} }
private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) { private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) {
exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCall(n, call)) exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCallCached(n, call))
} }
/** /**
@@ -913,26 +995,37 @@ LocalCallContext getLocalCallContext(CallContext ctx, DataFlowCallable callable)
else result instanceof LocalCallContextAny else result instanceof LocalCallContextAny
} }
/**
* The value of a parameter at function entry, viewed as a node in a data
* flow graph.
*/
class ParamNode extends Node {
ParamNode() { parameterNode(this, _, _) }
/**
* Holds if this node is the parameter of callable `c` at the specified
* (zero-based) position.
*/
predicate isParameterOf(DataFlowCallable c, int i) { parameterNode(this, c, i) }
}
/** A data-flow node that represents a call argument. */
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) }
}
/** /**
* A node from which flow can return to the caller. This is either a regular * A node from which flow can return to the caller. This is either a regular
* `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter. * `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter.
*/ */
class ReturnNodeExt extends Node { class ReturnNodeExt extends Node {
ReturnNodeExt() { ReturnNodeExt() { returnNodeExt(this, _) }
this instanceof ReturnNode or
parameterValueFlowsToPreUpdate(_, this)
}
/** Gets the kind of this returned value. */ /** Gets the kind of this returned value. */
ReturnKindExt getKind() { ReturnKindExt getKind() { returnNodeExt(this, result) }
result = TValueReturn(this.(ReturnNode).getKind())
or
exists(ParameterNode p, int pos |
parameterValueFlowsToPreUpdate(p, this) and
p.isParameterOf(_, pos) and
result = TParamUpdate(pos)
)
}
} }
/** /**
@@ -940,11 +1033,7 @@ class ReturnNodeExt extends Node {
* or a post-update node associated with a call argument. * or a post-update node associated with a call argument.
*/ */
class OutNodeExt extends Node { class OutNodeExt extends Node {
OutNodeExt() { OutNodeExt() { outNodeExt(this) }
this instanceof OutNode
or
this.(PostUpdateNode).getPreUpdateNode() instanceof ArgumentNode
}
} }
/** /**
@@ -957,7 +1046,7 @@ abstract class ReturnKindExt extends TReturnKindExt {
abstract string toString(); abstract string toString();
/** Gets a node corresponding to data flow out of `call`. */ /** Gets a node corresponding to data flow out of `call`. */
abstract OutNodeExt getAnOutNode(DataFlowCall call); final OutNodeExt getAnOutNode(DataFlowCall call) { result = getAnOutNodeExt(call, this) }
} }
class ValueReturnKind extends ReturnKindExt, TValueReturn { class ValueReturnKind extends ReturnKindExt, TValueReturn {
@@ -968,10 +1057,6 @@ class ValueReturnKind extends ReturnKindExt, TValueReturn {
ReturnKind getKind() { result = kind } ReturnKind getKind() { result = kind }
override string toString() { result = kind.toString() } override string toString() { result = kind.toString() }
override OutNodeExt getAnOutNode(DataFlowCall call) {
result = getAnOutNode(call, this.getKind())
}
} }
class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate { class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
@@ -982,13 +1067,6 @@ class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
int getPosition() { result = pos } int getPosition() { result = pos }
override string toString() { result = "param update " + pos } override string toString() { result = "param update " + pos }
override OutNodeExt getAnOutNode(DataFlowCall call) {
exists(ArgumentNode arg |
result.(PostUpdateNode).getPreUpdateNode() = arg and
arg.argumentOf(call, this.getPosition())
)
}
} }
/** A callable tagged with a relevant return kind. */ /** A callable tagged with a relevant return kind. */
@@ -1015,10 +1093,13 @@ class ReturnPosition extends TReturnPosition0 {
*/ */
pragma[inline] pragma[inline]
DataFlowCallable getNodeEnclosingCallable(Node n) { DataFlowCallable getNodeEnclosingCallable(Node n) {
exists(Node n0 | nodeEnclosingCallable(pragma[only_bind_out](n), pragma[only_bind_into](result))
pragma[only_bind_into](n0) = n and }
pragma[only_bind_into](result) = n0.getEnclosingCallable()
) /** Gets the type of `n` used for type pruning. */
pragma[inline]
DataFlowType getNodeDataFlowType(Node n) {
nodeDataFlowType(pragma[only_bind_out](n), pragma[only_bind_into](result))
} }
pragma[noinline] pragma[noinline]
@@ -1042,7 +1123,7 @@ predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall
cc instanceof CallContextAny and callable = viableCallableExt(call) cc instanceof CallContextAny and callable = viableCallableExt(call)
or or
exists(DataFlowCallable c0, DataFlowCall call0 | exists(DataFlowCallable c0, DataFlowCall call0 |
call0.getEnclosingCallable() = callable and callEnclosingCallable(call0, callable) and
cc = TReturn(c0, call0) and cc = TReturn(c0, call0) and
c0 = prunedViableImplInCallContextReverse(call0, call) c0 = prunedViableImplInCallContextReverse(call0, call)
) )
@@ -1063,8 +1144,6 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
result = viableCallableExt(call) and cc instanceof CallContextReturn result = viableCallableExt(call) and cc instanceof CallContextReturn
} }
predicate read = readStep/3;
/** An optional Boolean value. */ /** An optional Boolean value. */
class BooleanOption extends TBooleanOption { class BooleanOption extends TBooleanOption {
string toString() { string toString() {
@@ -1116,7 +1195,7 @@ abstract class AccessPathFront extends TAccessPathFront {
TypedContent getHead() { this = TFrontHead(result) } TypedContent getHead() { this = TFrontHead(result) }
predicate isClearedAt(Node n) { clearsContent(n, getHead().getContent()) } predicate isClearedAt(Node n) { clearsContentCached(n, getHead().getContent()) }
} }
class AccessPathFrontNil extends AccessPathFront, TFrontNil { class AccessPathFrontNil extends AccessPathFront, TFrontNil {

View File

@@ -4,71 +4,48 @@ private import semmle.code.java.dataflow.FlowSummary
private import semmle.code.java.dataflow.TypeFlow private import semmle.code.java.dataflow.TypeFlow
private import DataFlowPrivate private import DataFlowPrivate
private import FlowSummaryImpl as FlowSummaryImpl private import FlowSummaryImpl as FlowSummaryImpl
private import DataFlowImplCommon as DataFlowImplCommon
cached cached
private module Cached { newtype TNode =
cached TExprNode(Expr e) {
newtype TNode = DataFlowImplCommon::forceCachingInSameStage() and
TExprNode(Expr e) { not e.getType() instanceof VoidType and
not e.getType() instanceof VoidType and not e.getParent*() instanceof Annotation
not e.getParent*() instanceof Annotation } or
} or TExplicitParameterNode(Parameter p) {
TExplicitParameterNode(Parameter p) { exists(p.getCallable().getBody()) or p.getCallable() instanceof SummarizedCallable
exists(p.getCallable().getBody()) or p.getCallable() instanceof SummarizedCallable } or
} or TImplicitVarargsArray(Call c) {
TImplicitVarargsArray(Call c) { c.getCallee().isVarargs() and
c.getCallee().isVarargs() and not exists(Argument arg | arg.getCall() = c and arg.isExplicitVarargsArray())
not exists(Argument arg | arg.getCall() = c and arg.isExplicitVarargsArray()) } or
} or TInstanceParameterNode(Callable c) {
TInstanceParameterNode(Callable c) { (exists(c.getBody()) or c instanceof SummarizedCallable) and
(exists(c.getBody()) or c instanceof SummarizedCallable) and not c.isStatic()
not c.isStatic() } or
} or TImplicitInstanceAccess(InstanceAccessExt ia) { not ia.isExplicit(_) } or
TImplicitInstanceAccess(InstanceAccessExt ia) { not ia.isExplicit(_) } or TMallocNode(ClassInstanceExpr cie) or
TMallocNode(ClassInstanceExpr cie) or TExplicitExprPostUpdate(Expr e) {
TExplicitExprPostUpdate(Expr e) { explicitInstanceArgument(_, e)
explicitInstanceArgument(_, e) or
or e instanceof Argument and not e.getType() instanceof ImmutableType
e instanceof Argument and not e.getType() instanceof ImmutableType or
or exists(FieldAccess fa | fa.getField() instanceof InstanceField and e = fa.getQualifier())
exists(FieldAccess fa | fa.getField() instanceof InstanceField and e = fa.getQualifier()) or
or exists(ArrayAccess aa | e = aa.getArray())
exists(ArrayAccess aa | e = aa.getArray()) } or
} or TImplicitExprPostUpdate(InstanceAccessExt ia) {
TImplicitExprPostUpdate(InstanceAccessExt ia) { implicitInstanceArgument(_, ia)
implicitInstanceArgument(_, ia) or
or exists(FieldAccess fa |
exists(FieldAccess fa | fa.getField() instanceof InstanceField and ia.isImplicitFieldQualifier(fa)
fa.getField() instanceof InstanceField and ia.isImplicitFieldQualifier(fa) )
) } or
} or TSummaryInternalNode(SummarizedCallable c, FlowSummaryImpl::Private::SummaryNodeState state) {
TSummaryInternalNode(SummarizedCallable c, FlowSummaryImpl::Private::SummaryNodeState state) { FlowSummaryImpl::Private::summaryNodeRange(c, state)
FlowSummaryImpl::Private::summaryNodeRange(c, state)
}
cached
predicate summaryOutNodeCached(DataFlowCall c, Node out) {
FlowSummaryImpl::Private::summaryOutNode(c, out, _)
} }
cached
predicate summaryArgumentNodeCached(DataFlowCall c, Node arg, int i) {
FlowSummaryImpl::Private::summaryArgumentNode(c, arg, i)
}
cached
predicate summaryPostUpdateNodeCached(Node post, ParameterNode pre) {
FlowSummaryImpl::Private::summaryPostUpdateNode(post, pre)
}
cached
predicate summaryReturnNodeCached(Node ret) {
FlowSummaryImpl::Private::summaryReturnNode(ret, _)
}
}
private import Cached
private predicate explicitInstanceArgument(Call call, Expr instarg) { private predicate explicitInstanceArgument(Call call, Expr instarg) {
call instanceof MethodAccess and call instanceof MethodAccess and
instarg = call.getQualifier() and instarg = call.getQualifier() and
@@ -404,13 +381,15 @@ module Private {
override string toString() { result = "[summary] " + state + " in " + c } override string toString() { result = "[summary] " + state + " in " + c }
/** Holds if this summary node is the `i`th argument of `call`. */ /** Holds if this summary node is the `i`th argument of `call`. */
predicate isArgumentOf(DataFlowCall call, int i) { summaryArgumentNodeCached(call, this, i) } predicate isArgumentOf(DataFlowCall call, int i) {
FlowSummaryImpl::Private::summaryArgumentNode(call, this, i)
}
/** Holds if this summary node is a return node. */ /** Holds if this summary node is a return node. */
predicate isReturn() { summaryReturnNodeCached(this) } predicate isReturn() { FlowSummaryImpl::Private::summaryReturnNode(this, _) }
/** Holds if this summary node is an out node for `call`. */ /** Holds if this summary node is an out node for `call`. */
predicate isOut(DataFlowCall call) { summaryOutNodeCached(call, this) } predicate isOut(DataFlowCall call) { FlowSummaryImpl::Private::summaryOutNode(call, this, _) }
} }
SummaryNode getSummaryNode(SummarizedCallable c, FlowSummaryImpl::Private::SummaryNodeState state) { SummaryNode getSummaryNode(SummarizedCallable c, FlowSummaryImpl::Private::SummaryNodeState state) {
@@ -439,7 +418,7 @@ private class MallocNode extends Node, TMallocNode {
private class SummaryPostUpdateNode extends SummaryNode, PostUpdateNode { private class SummaryPostUpdateNode extends SummaryNode, PostUpdateNode {
private Node pre; private Node pre;
SummaryPostUpdateNode() { summaryPostUpdateNodeCached(this, pre) } SummaryPostUpdateNode() { FlowSummaryImpl::Private::summaryPostUpdateNode(this, pre) }
override Node getPreUpdateNode() { result = pre } override Node getPreUpdateNode() { result = pre }
} }

View File

@@ -284,7 +284,6 @@ private class ConstantBooleanArgumentNode extends ArgumentNode, ExprNode {
/** /**
* Holds if the node `n` is unreachable when the call context is `call`. * Holds if the node `n` is unreachable when the call context is `call`.
*/ */
cached
predicate isUnreachableInCall(Node n, DataFlowCall call) { predicate isUnreachableInCall(Node n, DataFlowCall call) {
exists( exists(
ExplicitParameterNode paramNode, ConstantBooleanArgumentNode arg, SsaImplicitInit param, ExplicitParameterNode paramNode, ConstantBooleanArgumentNode arg, SsaImplicitInit param,

View File

@@ -11,6 +11,7 @@ private import semmle.code.java.dataflow.FlowSteps
private import semmle.code.java.dataflow.FlowSummary private import semmle.code.java.dataflow.FlowSummary
import semmle.code.java.dataflow.InstanceAccess import semmle.code.java.dataflow.InstanceAccess
private import FlowSummaryImpl as FlowSummaryImpl private import FlowSummaryImpl as FlowSummaryImpl
private import TaintTrackingUtil as TaintTrackingUtil
import DataFlowNodes::Public import DataFlowNodes::Public
/** Holds if `n` is an access to an unqualified `this` at `cfgnode`. */ /** Holds if `n` is an access to an unqualified `this` at `cfgnode`. */
@@ -112,6 +113,7 @@ predicate localFlowStep(Node node1, Node node2) {
*/ */
cached cached
predicate simpleLocalFlowStep(Node node1, Node node2) { predicate simpleLocalFlowStep(Node node1, Node node2) {
TaintTrackingUtil::forceCachingInSameStage() and
// Variable flow steps through adjacent def-use and use-use pairs. // Variable flow steps through adjacent def-use and use-use pairs.
exists(SsaExplicitUpdate upd | exists(SsaExplicitUpdate upd |
upd.getDefiningExpr().(VariableAssign).getSource() = node1.asExpr() or upd.getDefiningExpr().(VariableAssign).getSource() = node1.asExpr() or

View File

@@ -29,55 +29,69 @@ predicate localExprTaint(Expr src, Expr sink) {
localTaint(DataFlow::exprNode(src), DataFlow::exprNode(sink)) localTaint(DataFlow::exprNode(src), DataFlow::exprNode(sink))
} }
/** cached
* Holds if taint can flow in one local step from `src` to `sink`. private module Cached {
*/ private import DataFlowImplCommon as DataFlowImplCommon
predicate localTaintStep(DataFlow::Node src, DataFlow::Node sink) {
DataFlow::localFlowStep(src, sink) or cached
localAdditionalTaintStep(src, sink) or predicate forceCachingInSameStage() { DataFlowImplCommon::forceCachingInSameStage() }
// Simple flow through library code is included in the exposed local
// step relation, even though flow is technically inter-procedural /**
FlowSummaryImpl::Private::Steps::summaryThroughStep(src, sink, false) * Holds if taint can flow in one local step from `src` to `sink`.
*/
cached
predicate localTaintStep(DataFlow::Node src, DataFlow::Node sink) {
DataFlow::localFlowStep(src, sink) or
localAdditionalTaintStep(src, sink) or
// Simple flow through library code is included in the exposed local
// step relation, even though flow is technically inter-procedural
FlowSummaryImpl::Private::Steps::summaryThroughStep(src, sink, false)
}
/**
* Holds if taint can flow in one local step from `src` to `sink` excluding
* local data flow steps. That is, `src` and `sink` are likely to represent
* different objects.
*/
cached
predicate localAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
localAdditionalTaintExprStep(src.asExpr(), sink.asExpr())
or
localAdditionalTaintUpdateStep(src.asExpr(),
sink.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr())
or
exists(Argument arg |
src.asExpr() = arg and
arg.isVararg() and
sink.(DataFlow::ImplicitVarargsArray).getCall() = arg.getCall()
)
or
FlowSummaryImpl::Private::Steps::summaryLocalStep(src, sink, false)
}
/**
* Holds if the additional step from `src` to `sink` should be included in all
* global taint flow configurations.
*/
cached
predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
localAdditionalTaintStep(src, sink) or
any(AdditionalTaintStep a).step(src, sink)
}
/**
* Holds if `node` should be a sanitizer in all global taint flow configurations
* but not in local taint.
*/
cached
predicate defaultTaintSanitizer(DataFlow::Node node) {
// Ignore paths through test code.
node.getEnclosingCallable().getDeclaringType() instanceof NonSecurityTestClass or
node.asExpr() instanceof ValidatedVariableAccess
}
} }
/** import Cached
* Holds if taint can flow in one local step from `src` to `sink` excluding
* local data flow steps. That is, `src` and `sink` are likely to represent
* different objects.
*/
predicate localAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
localAdditionalTaintExprStep(src.asExpr(), sink.asExpr())
or
localAdditionalTaintUpdateStep(src.asExpr(),
sink.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr())
or
exists(Argument arg |
src.asExpr() = arg and
arg.isVararg() and
sink.(DataFlow::ImplicitVarargsArray).getCall() = arg.getCall()
)
or
FlowSummaryImpl::Private::Steps::summaryLocalStep(src, sink, false)
}
/**
* Holds if the additional step from `src` to `sink` should be included in all
* global taint flow configurations.
*/
predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
localAdditionalTaintStep(src, sink) or
any(AdditionalTaintStep a).step(src, sink)
}
/**
* Holds if `node` should be a sanitizer in all global taint flow configurations
* but not in local taint.
*/
predicate defaultTaintSanitizer(DataFlow::Node node) {
// Ignore paths through test code.
node.getEnclosingCallable().getDeclaringType() instanceof NonSecurityTestClass or
node.asExpr() instanceof ValidatedVariableAccess
}
/** /**
* Holds if taint can flow in one local step from `src` to `sink` excluding * Holds if taint can flow in one local step from `src` to `sink` excluding

View File

@@ -3,19 +3,60 @@
*/ */
import java import java
private import semmle.code.java.dataflow.DataFlow
private import semmle.code.java.dataflow.FlowSteps
/** /**
* The type `com.esotericsoftware.kryo.Kryo`. * The type `com.esotericsoftware.kryo.Kryo`.
*/ */
class Kryo extends RefType { class Kryo extends RefType {
Kryo() { this.hasQualifiedName("com.esotericsoftware.kryo", "Kryo") } Kryo() {
hasQualifiedName("com.esotericsoftware.kryo", "Kryo") or
hasQualifiedName("com.esotericsoftware.kryo5", "Kryo")
}
} }
/** /**
* A Kryo input stream. * A Kryo input stream.
*/ */
class KryoInput extends RefType { class KryoInput extends RefType {
KryoInput() { this.hasQualifiedName("com.esotericsoftware.kryo.io", "Input") } KryoInput() {
hasQualifiedName("com.esotericsoftware.kryo.io", "Input") or
hasQualifiedName("com.esotericsoftware.kryo5.io", "Input")
}
}
/**
* A Kryo pool.
*/
class KryoPool extends RefType {
KryoPool() {
hasQualifiedName("com.esotericsoftware.kryo.pool", "KryoPool") or
hasQualifiedName("com.esotericsoftware.kryo5.pool", "KryoPool")
}
}
/**
* A Kryo pool builder.
*/
class KryoPoolBuilder extends RefType {
KryoPoolBuilder() {
hasQualifiedName("com.esotericsoftware.kryo.pool", "KryoPool$Builder") or
hasQualifiedName("com.esotericsoftware.kryo5.pool", "KryoPool$Builder")
}
}
/**
* A Kryo pool builder method used in a fluent API call chain.
*/
class KryoPoolBuilderMethod extends Method {
KryoPoolBuilderMethod() {
getDeclaringType() instanceof KryoPoolBuilder and
(
getReturnType() instanceof KryoPoolBuilder or
getReturnType() instanceof KryoPool
)
}
} }
/** /**
@@ -45,3 +86,13 @@ class KryoEnableWhiteListing extends MethodAccess {
) )
} }
} }
/**
* A KryoPool method that uses a Kryo instance.
*/
class KryoPoolRunMethod extends Method {
KryoPoolRunMethod() {
getDeclaringType() instanceof KryoPool and
hasName("run")
}
}

View File

@@ -48,6 +48,65 @@ class SafeKryo extends DataFlow2::Configuration {
ma.getMethod() instanceof KryoReadObjectMethod ma.getMethod() instanceof KryoReadObjectMethod
) )
} }
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
stepKryoPoolBuilderFactoryArgToConstructor(node1, node2) or
stepKryoPoolRunMethodAccessQualifierToFunctionalArgument(node1, node2) or
stepKryoPoolBuilderChainMethod(node1, node2) or
stepKryoPoolBorrowMethod(node1, node2)
}
/**
* Holds when a functional expression is used to create a `KryoPool.Builder`.
* Eg. `new KryoPool.Builder(() -> new Kryo())`
*/
private predicate stepKryoPoolBuilderFactoryArgToConstructor(
DataFlow::Node node1, DataFlow::Node node2
) {
exists(ConstructorCall cc, FunctionalExpr fe |
cc.getConstructedType() instanceof KryoPoolBuilder and
fe.asMethod().getBody().getAStmt().(ReturnStmt).getResult() = node1.asExpr() and
node2.asExpr() = cc and
cc.getArgument(0) = fe
)
}
/**
* Holds when a `KryoPool.run` is called to use a `Kryo` instance.
* Eg. `pool.run(kryo -> ...)`
*/
private predicate stepKryoPoolRunMethodAccessQualifierToFunctionalArgument(
DataFlow::Node node1, DataFlow::Node node2
) {
exists(MethodAccess ma |
ma.getMethod() instanceof KryoPoolRunMethod and
node1.asExpr() = ma.getQualifier() and
ma.getArgument(0).(FunctionalExpr).asMethod().getParameter(0) = node2.asParameter()
)
}
/**
* Holds when a `KryoPool.Builder` method is called fluently.
*/
private predicate stepKryoPoolBuilderChainMethod(DataFlow::Node node1, DataFlow::Node node2) {
exists(MethodAccess ma |
ma.getMethod() instanceof KryoPoolBuilderMethod and
ma = node2.asExpr() and
ma.getQualifier() = node1.asExpr()
)
}
/**
* Holds when a `KryoPool.borrow` method is called.
*/
private predicate stepKryoPoolBorrowMethod(DataFlow::Node node1, DataFlow::Node node2) {
exists(MethodAccess ma |
ma.getMethod() =
any(Method m | m.getDeclaringType() instanceof KryoPool and m.hasName("borrow")) and
node1.asExpr() = ma.getQualifier() and
node2.asExpr() = ma
)
}
} }
predicate unsafeDeserialization(MethodAccess ma, Expr sink) { predicate unsafeDeserialization(MethodAccess ma, Expr sink) {

View File

@@ -36,7 +36,10 @@ abstract class ParserConfig extends MethodAccess {
*/ */
predicate disables(Expr e) { predicate disables(Expr e) {
this.getArgument(0) = e and this.getArgument(0) = e and
this.getArgument(1).(BooleanLiteral).getBooleanValue() = false (
this.getArgument(1).(BooleanLiteral).getBooleanValue() = false or
this.getArgument(1).(FieldAccess).getField().hasQualifiedName("java.lang", "Boolean", "FALSE")
)
} }
/** /**
@@ -44,7 +47,10 @@ abstract class ParserConfig extends MethodAccess {
*/ */
predicate enables(Expr e) { predicate enables(Expr e) {
this.getArgument(0) = e and this.getArgument(0) = e and
this.getArgument(1).(BooleanLiteral).getBooleanValue() = true (
this.getArgument(1).(BooleanLiteral).getBooleanValue() = true or
this.getArgument(1).(FieldAccess).getField().hasQualifiedName("java.lang", "Boolean", "TRUE")
)
} }
} }

View File

@@ -0,0 +1,34 @@
import java.io.*;
import java.net.Socket;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.pool.KryoPool;
import com.esotericsoftware.kryo.io.Input;
public class KryoTest {
private Kryo getSafeKryo() {
Kryo kryo = new Kryo();
kryo.setRegistrationRequired(true);
// ... kryo.register(A.class) ...
return kryo;
}
public void kryoDeserialize(Socket sock) throws java.io.IOException {
KryoPool kryoPool = new KryoPool.Builder(this::getSafeKryo).softReferences().build();
Input input = new Input(sock.getInputStream());
Object o = kryoPool.run(kryo -> kryo.readClassAndObject(input)); // OK
}
public void kryoDeserialize2(Socket sock) throws java.io.IOException {
KryoPool kryoPool = new KryoPool.Builder(this::getSafeKryo).softReferences().build();
Input input = new Input(sock.getInputStream());
Kryo k = kryoPool.borrow();
try {
Object o = k.readClassAndObject(input); // OK
} finally {
kryoPool.release(k);
}
}
}

View File

@@ -0,0 +1,7 @@
package com.esotericsoftware.kryo.pool;
import com.esotericsoftware.kryo.Kryo;
public interface KryoCallback<T> {
T execute (Kryo kryo);
}

View File

@@ -0,0 +1,7 @@
package com.esotericsoftware.kryo.pool;
import com.esotericsoftware.kryo.Kryo;
public interface KryoFactory {
Kryo create ();
}

View File

@@ -0,0 +1,30 @@
package com.esotericsoftware.kryo.pool;
import com.esotericsoftware.kryo.Kryo;
import java.util.Queue;
public interface KryoPool {
Kryo borrow ();
void release (Kryo kryo);
<T> T run (KryoCallback<T> callback);
static class Builder {
public Builder (KryoFactory factory) {
}
public Builder queue (Queue<Kryo> queue) {
return null;
}
public Builder softReferences () {
return null;
}
public KryoPool build () {
return null;
}
}
}

View File

@@ -6,16 +6,13 @@ import javascript
module Base64 { module Base64 {
/** A call to a base64 encoder. */ /** A call to a base64 encoder. */
class Encode extends DataFlow::Node { class Encode extends DataFlow::Node instanceof Encode::Range {
Encode::Range encode;
Encode() { this = encode }
/** Gets the input passed to the encoder. */ /** Gets the input passed to the encoder. */
DataFlow::Node getInput() { result = encode.getInput() } DataFlow::Node getInput() { result = super.getInput() }
/** Gets the base64-encoded output of the encoder. */ /** Gets the base64-encoded output of the encoder. */
DataFlow::Node getOutput() { result = encode.getOutput() } DataFlow::Node getOutput() { result = super.getOutput() }
} }
module Encode { module Encode {
@@ -34,16 +31,13 @@ module Base64 {
} }
/** A call to a base64 decoder. */ /** A call to a base64 decoder. */
class Decode extends DataFlow::Node { class Decode extends DataFlow::Node instanceof Decode::Range {
Decode::Range encode;
Decode() { this = encode }
/** Gets the base64-encoded input passed to the decoder. */ /** Gets the base64-encoded input passed to the decoder. */
DataFlow::Node getInput() { result = encode.getInput() } DataFlow::Node getInput() { result = super.getInput() }
/** Gets the output of the decoder. */ /** Gets the output of the decoder. */
DataFlow::Node getOutput() { result = encode.getOutput() } DataFlow::Node getOutput() { result = super.getOutput() }
} }
module Decode { module Decode {

View File

@@ -8,15 +8,14 @@ module Closure {
/** /**
* A reference to a Closure namespace. * A reference to a Closure namespace.
*/ */
class ClosureNamespaceRef extends DataFlow::Node { class ClosureNamespaceRef extends DataFlow::Node instanceof ClosureNamespaceRef::Range {
ClosureNamespaceRef::Range range;
ClosureNamespaceRef() { this = range }
/** /**
* Gets the namespace being referenced. * Gets the namespace being referenced.
*/ */
string getClosureNamespace() { result = range.getClosureNamespace() } string getClosureNamespace() {
result = super.getClosureNamespace()
}
} }
module ClosureNamespaceRef { module ClosureNamespaceRef {
@@ -36,8 +35,7 @@ module Closure {
/** /**
* A data flow node that returns the value of a closure namespace. * A data flow node that returns the value of a closure namespace.
*/ */
class ClosureNamespaceAccess extends ClosureNamespaceRef { class ClosureNamespaceAccess extends ClosureNamespaceRef instanceof ClosureNamespaceAccess::Range {
override ClosureNamespaceAccess::Range range;
} }
module ClosureNamespaceAccess { module ClosureNamespaceAccess {
@@ -80,8 +78,7 @@ module Closure {
/** /**
* A top-level call to `goog.provide`. * A top-level call to `goog.provide`.
*/ */
class ClosureProvideCall extends ClosureNamespaceRef, DataFlow::MethodCallNode { class ClosureProvideCall extends ClosureNamespaceRef, DataFlow::MethodCallNode instanceof DefaultClosureProvideCall {
override DefaultClosureProvideCall range;
} }
/** /**
@@ -94,8 +91,7 @@ module Closure {
/** /**
* A call to `goog.require`. * A call to `goog.require`.
*/ */
class ClosureRequireCall extends ClosureNamespaceAccess, DataFlow::MethodCallNode { class ClosureRequireCall extends ClosureNamespaceAccess, DataFlow::MethodCallNode instanceof DefaultClosureRequireCall {
override DefaultClosureRequireCall range;
} }
/** /**
@@ -111,8 +107,7 @@ module Closure {
/** /**
* A top-level call to `goog.module` or `goog.declareModuleId`. * A top-level call to `goog.module` or `goog.declareModuleId`.
*/ */
class ClosureModuleDeclaration extends ClosureNamespaceRef, DataFlow::MethodCallNode { class ClosureModuleDeclaration extends ClosureNamespaceRef, DataFlow::MethodCallNode instanceof DefaultClosureModuleDeclaration {
override DefaultClosureModuleDeclaration range;
} }
private GlobalVariable googVariable() { variables(result, "goog", any(GlobalScope sc)) } private GlobalVariable googVariable() { variables(result, "goog", any(GlobalScope sc)) }

View File

@@ -16,16 +16,13 @@ private import javascript
* ~A.indexOf(B) * ~A.indexOf(B)
* ``` * ```
*/ */
class InclusionTest extends DataFlow::Node { class InclusionTest extends DataFlow::Node instanceof InclusionTest::Range {
InclusionTest::Range range;
InclusionTest() { this = range }
/** Gets the `A` in `A.includes(B)`. */ /** Gets the `A` in `A.includes(B)`. */
DataFlow::Node getContainerNode() { result = range.getContainerNode() } DataFlow::Node getContainerNode() { result = super.getContainerNode() }
/** Gets the `B` in `A.includes(B)`. */ /** Gets the `B` in `A.includes(B)`. */
DataFlow::Node getContainedNode() { result = range.getContainedNode() } DataFlow::Node getContainedNode() { result = super.getContainedNode() }
/** /**
* Gets the polarity of the check. * Gets the polarity of the check.
@@ -33,7 +30,7 @@ class InclusionTest extends DataFlow::Node {
* If the polarity is `false` the check returns `true` if the container does not contain * If the polarity is `false` the check returns `true` if the container does not contain
* the given element. * the given element.
*/ */
boolean getPolarity() { result = range.getPolarity() } boolean getPolarity() { result = super.getPolarity() }
} }
module InclusionTest { module InclusionTest {

View File

@@ -9,27 +9,24 @@ import javascript
* *
* Additional candidates can be added by subclassing `MembershipCandidate::Range` * Additional candidates can be added by subclassing `MembershipCandidate::Range`
*/ */
class MembershipCandidate extends DataFlow::Node { class MembershipCandidate extends DataFlow::Node instanceof MembershipCandidate::Range {
MembershipCandidate::Range range;
MembershipCandidate() { this = range }
/** /**
* Gets the expression that performs the membership test, if any. * Gets the expression that performs the membership test, if any.
*/ */
DataFlow::Node getTest() { result = range.getTest() } DataFlow::Node getTest() { result = super.getTest() }
/** /**
* Gets a string that this candidate is tested against, if * Gets a string that this candidate is tested against, if
* it can be determined. * it can be determined.
*/ */
string getAMemberString() { result = range.getAMemberString() } string getAMemberString() { result = super.getAMemberString() }
/** /**
* Gets a node that this candidate is tested against, if * Gets a node that this candidate is tested against, if
* it can be determined. * it can be determined.
*/ */
DataFlow::Node getAMemberNode() { result = range.getAMemberNode() } DataFlow::Node getAMemberNode() { result = super.getAMemberNode() }
/** /**
* Gets the polarity of the test. * Gets the polarity of the test.
@@ -37,7 +34,7 @@ class MembershipCandidate extends DataFlow::Node {
* If the polarity is `false` the test returns `true` if the * If the polarity is `false` the test returns `true` if the
* collection does not contain this candidate. * collection does not contain this candidate.
*/ */
boolean getTestPolarity() { result = range.getTestPolarity() } boolean getTestPolarity() { result = super.getTestPolarity() }
} }
/** /**

View File

@@ -8,20 +8,17 @@ module StringOps {
/** /**
* A expression that is equivalent to `A.startsWith(B)` or `!A.startsWith(B)`. * A expression that is equivalent to `A.startsWith(B)` or `!A.startsWith(B)`.
*/ */
class StartsWith extends DataFlow::Node { class StartsWith extends DataFlow::Node instanceof StartsWith::Range {
StartsWith::Range range;
StartsWith() { range = this }
/** /**
* Gets the `A` in `A.startsWith(B)`. * Gets the `A` in `A.startsWith(B)`.
*/ */
DataFlow::Node getBaseString() { result = range.getBaseString() } DataFlow::Node getBaseString() { result = super.getBaseString() }
/** /**
* Gets the `B` in `A.startsWith(B)`. * Gets the `B` in `A.startsWith(B)`.
*/ */
DataFlow::Node getSubstring() { result = range.getSubstring() } DataFlow::Node getSubstring() { result = super.getSubstring() }
/** /**
* Gets the polarity of the check. * Gets the polarity of the check.
@@ -29,7 +26,7 @@ module StringOps {
* If the polarity is `false` the check returns `true` if the string does not start * If the polarity is `false` the check returns `true` if the string does not start
* with the given substring. * with the given substring.
*/ */
boolean getPolarity() { result = range.getPolarity() } boolean getPolarity() { result = super.getPolarity() }
} }
module StartsWith { module StartsWith {
@@ -237,20 +234,17 @@ module StringOps {
/** /**
* An expression that is equivalent to `A.endsWith(B)` or `!A.endsWith(B)`. * An expression that is equivalent to `A.endsWith(B)` or `!A.endsWith(B)`.
*/ */
class EndsWith extends DataFlow::Node { class EndsWith extends DataFlow::Node instanceof EndsWith::Range {
EndsWith::Range range;
EndsWith() { this = range }
/** /**
* Gets the `A` in `A.startsWith(B)`. * Gets the `A` in `A.startsWith(B)`.
*/ */
DataFlow::Node getBaseString() { result = range.getBaseString() } DataFlow::Node getBaseString() { result = super.getBaseString() }
/** /**
* Gets the `B` in `A.startsWith(B)`. * Gets the `B` in `A.startsWith(B)`.
*/ */
DataFlow::Node getSubstring() { result = range.getSubstring() } DataFlow::Node getSubstring() { result = super.getSubstring() }
/** /**
* Gets the polarity if the check. * Gets the polarity if the check.
@@ -258,7 +252,7 @@ module StringOps {
* If the polarity is `false` the check returns `true` if the string does not end * If the polarity is `false` the check returns `true` if the string does not end
* with the given substring. * with the given substring.
*/ */
boolean getPolarity() { result = range.getPolarity() } boolean getPolarity() { result = super.getPolarity() }
} }
module EndsWith { module EndsWith {
@@ -662,10 +656,7 @@ module StringOps {
* if (!match) { ... } // <--- 'match' is the RegExpTest * if (!match) { ... } // <--- 'match' is the RegExpTest
* ``` * ```
*/ */
class RegExpTest extends DataFlow::Node { class RegExpTest extends DataFlow::Node instanceof RegExpTest::Range {
RegExpTest::Range range;
RegExpTest() { this = range }
/** /**
* Gets the AST of the regular expression used in the test, if it can be seen locally. * Gets the AST of the regular expression used in the test, if it can be seen locally.
@@ -673,7 +664,7 @@ module StringOps {
RegExpTerm getRegExp() { RegExpTerm getRegExp() {
result = getRegExpOperand().getALocalSource().(DataFlow::RegExpCreationNode).getRoot() result = getRegExpOperand().getALocalSource().(DataFlow::RegExpCreationNode).getRoot()
or or
result = range.getRegExpOperand(true).asExpr().(StringLiteral).asRegExp() result = this.(RegExpTest::Range).getRegExpOperand(true).asExpr().(StringLiteral).asRegExp()
} }
/** /**
@@ -681,12 +672,12 @@ module StringOps {
* *
* In some cases this represents a string value being coerced to a RegExp object. * In some cases this represents a string value being coerced to a RegExp object.
*/ */
DataFlow::Node getRegExpOperand() { result = range.getRegExpOperand(_) } DataFlow::Node getRegExpOperand() { result = super.getRegExpOperand(_) }
/** /**
* Gets the data flow node corresponding to the string being tested against the regular expression. * Gets the data flow node corresponding to the string being tested against the regular expression.
*/ */
DataFlow::Node getStringOperand() { result = range.getStringOperand() } DataFlow::Node getStringOperand() { result = super.getStringOperand() }
/** /**
* Gets the return value indicating that the string matched the regular expression. * Gets the return value indicating that the string matched the regular expression.
@@ -694,7 +685,7 @@ module StringOps {
* For example, for `regexp.exec(str) == null`, the polarity is `false`, and for * For example, for `regexp.exec(str) == null`, the polarity is `false`, and for
* `regexp.exec(str) != null` the polarity is `true`. * `regexp.exec(str) != null` the polarity is `true`.
*/ */
boolean getPolarity() { result = range.getPolarity() } boolean getPolarity() { result = super.getPolarity() }
} }
/** /**

View File

@@ -701,13 +701,10 @@ class ArrayCreationNode extends DataFlow::ValueNode, DataFlow::SourceNode {
* define(["fs"], function(fs) { ... }); // AMD module * define(["fs"], function(fs) { ... }); // AMD module
* ``` * ```
*/ */
class ModuleImportNode extends DataFlow::SourceNode { class ModuleImportNode extends DataFlow::SourceNode instanceof ModuleImportNode::Range {
ModuleImportNode::Range range;
ModuleImportNode() { this = range }
/** Gets the path of the imported module. */ /** Gets the path of the imported module. */
string getPath() { result = range.getPath() } string getPath() { result = super.getPath() }
} }
module ModuleImportNode { module ModuleImportNode {
@@ -843,25 +840,22 @@ module MemberKind {
* *
* Additional patterns can be recognized as class nodes, by extending `DataFlow::ClassNode::Range`. * Additional patterns can be recognized as class nodes, by extending `DataFlow::ClassNode::Range`.
*/ */
class ClassNode extends DataFlow::SourceNode { class ClassNode extends DataFlow::SourceNode instanceof ClassNode::Range {
ClassNode::Range impl;
ClassNode() { this = impl }
/** /**
* Gets the unqualified name of the class, if it has one or one can be determined from the context. * Gets the unqualified name of the class, if it has one or one can be determined from the context.
*/ */
string getName() { result = impl.getName() } string getName() { result = super.getName() }
/** /**
* Gets a description of the class. * Gets a description of the class.
*/ */
string describe() { result = impl.describe() } string describe() { result = super.describe() }
/** /**
* Gets the constructor function of this class. * Gets the constructor function of this class.
*/ */
FunctionNode getConstructor() { result = impl.getConstructor() } FunctionNode getConstructor() { result = super.getConstructor() }
/** /**
* Gets an instance method declared in this class, with the given name, if any. * Gets an instance method declared in this class, with the given name, if any.
@@ -869,7 +863,7 @@ class ClassNode extends DataFlow::SourceNode {
* Does not include methods from superclasses. * Does not include methods from superclasses.
*/ */
FunctionNode getInstanceMethod(string name) { FunctionNode getInstanceMethod(string name) {
result = impl.getInstanceMember(name, MemberKind::method()) result = super.getInstanceMember(name, MemberKind::method())
} }
/** /**
@@ -879,7 +873,9 @@ class ClassNode extends DataFlow::SourceNode {
* *
* Does not include methods from superclasses. * Does not include methods from superclasses.
*/ */
FunctionNode getAnInstanceMethod() { result = impl.getAnInstanceMember(MemberKind::method()) } FunctionNode getAnInstanceMethod() {
result = super.getAnInstanceMember(MemberKind::method())
}
/** /**
* Gets the instance method, getter, or setter with the given name and kind. * Gets the instance method, getter, or setter with the given name and kind.
@@ -887,7 +883,7 @@ class ClassNode extends DataFlow::SourceNode {
* Does not include members from superclasses. * Does not include members from superclasses.
*/ */
FunctionNode getInstanceMember(string name, MemberKind kind) { FunctionNode getInstanceMember(string name, MemberKind kind) {
result = impl.getInstanceMember(name, kind) result = super.getInstanceMember(name, kind)
} }
/** /**
@@ -895,31 +891,35 @@ class ClassNode extends DataFlow::SourceNode {
* *
* Does not include members from superclasses. * Does not include members from superclasses.
*/ */
FunctionNode getAnInstanceMember(MemberKind kind) { result = impl.getAnInstanceMember(kind) } FunctionNode getAnInstanceMember(MemberKind kind) {
result = super.getAnInstanceMember(kind)
}
/** /**
* Gets an instance method, getter, or setter declared in this class. * Gets an instance method, getter, or setter declared in this class.
* *
* Does not include members from superclasses. * Does not include members from superclasses.
*/ */
FunctionNode getAnInstanceMember() { result = impl.getAnInstanceMember(_) } FunctionNode getAnInstanceMember() { result = super.getAnInstanceMember(_) }
/** /**
* Gets the static method declared in this class with the given name. * Gets the static method declared in this class with the given name.
*/ */
FunctionNode getStaticMethod(string name) { result = impl.getStaticMethod(name) } FunctionNode getStaticMethod(string name) {
result = super.getStaticMethod(name)
}
/** /**
* Gets a static method declared in this class. * Gets a static method declared in this class.
* *
* The constructor is not considered a static method. * The constructor is not considered a static method.
*/ */
FunctionNode getAStaticMethod() { result = impl.getAStaticMethod() } FunctionNode getAStaticMethod() { result = super.getAStaticMethod() }
/** /**
* Gets a dataflow node that refers to the superclass of this class. * Gets a dataflow node that refers to the superclass of this class.
*/ */
DataFlow::Node getASuperClassNode() { result = impl.getASuperClassNode() } DataFlow::Node getASuperClassNode() { result = super.getASuperClassNode() }
/** /**
* Gets a direct super class of this class. * Gets a direct super class of this class.
@@ -1065,13 +1065,13 @@ class ClassNode extends DataFlow::SourceNode {
* Gets the type annotation for the field `fieldName`, if any. * Gets the type annotation for the field `fieldName`, if any.
*/ */
TypeAnnotation getFieldTypeAnnotation(string fieldName) { TypeAnnotation getFieldTypeAnnotation(string fieldName) {
result = impl.getFieldTypeAnnotation(fieldName) result = super.getFieldTypeAnnotation(fieldName)
} }
/** /**
* Gets a decorator applied to this class. * Gets a decorator applied to this class.
*/ */
DataFlow::Node getADecorator() { result = impl.getADecorator() } DataFlow::Node getADecorator() { result = super.getADecorator() }
} }
module ClassNode { module ClassNode {
@@ -1357,10 +1357,7 @@ module ClassNode {
* _.partial(fn, x, y, z) * _.partial(fn, x, y, z)
* ``` * ```
*/ */
class PartialInvokeNode extends DataFlow::Node { class PartialInvokeNode extends DataFlow::Node instanceof PartialInvokeNode::Range {
PartialInvokeNode::Range range;
PartialInvokeNode() { this = range }
/** Gets a node holding a callback invoked by this partial invocation node. */ /** Gets a node holding a callback invoked by this partial invocation node. */
DataFlow::Node getACallbackNode() { DataFlow::Node getACallbackNode() {
@@ -1373,26 +1370,26 @@ class PartialInvokeNode extends DataFlow::Node {
* Holds if `argument` is passed as argument `index` to the function in `callback`. * Holds if `argument` is passed as argument `index` to the function in `callback`.
*/ */
predicate isPartialArgument(DataFlow::Node callback, DataFlow::Node argument, int index) { predicate isPartialArgument(DataFlow::Node callback, DataFlow::Node argument, int index) {
range.isPartialArgument(callback, argument, index) super.isPartialArgument(callback, argument, index)
} }
/** /**
* Gets a node referring to a bound version of `callback` with `boundArgs` arguments bound. * Gets a node referring to a bound version of `callback` with `boundArgs` arguments bound.
*/ */
DataFlow::SourceNode getBoundFunction(DataFlow::Node callback, int boundArgs) { DataFlow::SourceNode getBoundFunction(DataFlow::Node callback, int boundArgs) {
result = range.getBoundFunction(callback, boundArgs) result = super.getBoundFunction(callback, boundArgs)
} }
/** /**
* Gets the node holding the receiver to be passed to the bound function, if specified. * Gets the node holding the receiver to be passed to the bound function, if specified.
*/ */
DataFlow::Node getBoundReceiver() { result = range.getBoundReceiver(_) } DataFlow::Node getBoundReceiver() { result = super.getBoundReceiver(_) }
/** /**
* Gets the node holding the receiver to be passed to the bound function, if specified. * Gets the node holding the receiver to be passed to the bound function, if specified.
*/ */
DataFlow::Node getBoundReceiver(DataFlow::Node callback) { DataFlow::Node getBoundReceiver(DataFlow::Node callback) {
result = range.getBoundReceiver(callback) result = super.getBoundReceiver(callback)
} }
} }

View File

@@ -32,10 +32,7 @@ module Cheerio {
* Creation of `cheerio` object, a collection of virtual DOM elements * Creation of `cheerio` object, a collection of virtual DOM elements
* with an interface similar to that of a jQuery object. * with an interface similar to that of a jQuery object.
*/ */
class CheerioObjectCreation extends DataFlow::SourceNode { class CheerioObjectCreation extends DataFlow::SourceNode instanceof CheerioObjectCreation::Range {
CheerioObjectCreation::Range range;
CheerioObjectCreation() { this = range }
} }
module CheerioObjectCreation { module CheerioObjectCreation {

View File

@@ -18,25 +18,22 @@ import javascript
* To model additional APIs, extend `ClientRequest::Range` and implement its abstract member * To model additional APIs, extend `ClientRequest::Range` and implement its abstract member
* predicates. * predicates.
*/ */
class ClientRequest extends DataFlow::InvokeNode { class ClientRequest extends DataFlow::InvokeNode instanceof ClientRequest::Range {
ClientRequest::Range self;
ClientRequest() { this = self }
/** /**
* Gets the URL of the request. * Gets the URL of the request.
*/ */
DataFlow::Node getUrl() { result = self.getUrl() } DataFlow::Node getUrl() { result = super.getUrl() }
/** /**
* Gets the host of the request. * Gets the host of the request.
*/ */
DataFlow::Node getHost() { result = self.getHost() } DataFlow::Node getHost() { result = super.getHost() }
/** /**
* Gets a node that contributes to the data-part this request. * Gets a node that contributes to the data-part this request.
*/ */
DataFlow::Node getADataNode() { result = self.getADataNode() } DataFlow::Node getADataNode() { result = super.getADataNode() }
/** /**
* Gets a data flow node that refers to some representation of the response, possibly * Gets a data flow node that refers to some representation of the response, possibly
@@ -60,7 +57,7 @@ class ClientRequest extends DataFlow::InvokeNode {
* - Any value provided by custom implementations of `ClientRequest::Range`. * - Any value provided by custom implementations of `ClientRequest::Range`.
*/ */
DataFlow::Node getAResponseDataNode(string responseType, boolean promise) { DataFlow::Node getAResponseDataNode(string responseType, boolean promise) {
result = self.getAResponseDataNode(responseType, promise) result = this.(ClientRequest::Range).getAResponseDataNode(responseType, promise)
} }
/** /**
@@ -72,7 +69,7 @@ class ClientRequest extends DataFlow::InvokeNode {
/** /**
* Gets a data-flow node that determines where in the file-system the result of the request should be saved. * Gets a data-flow node that determines where in the file-system the result of the request should be saved.
*/ */
DataFlow::Node getASavePath() { result = self.getASavePath() } DataFlow::Node getASavePath() { result = super.getASavePath() }
} }
deprecated class CustomClientRequest = ClientRequest::Range; deprecated class CustomClientRequest = ClientRequest::Range;

View File

@@ -8,10 +8,7 @@ import javascript
* A call to a function that constructs a function composition `f(g(h(...)))` from a * A call to a function that constructs a function composition `f(g(h(...)))` from a
* series functions `f, g, h, ...`. * series functions `f, g, h, ...`.
*/ */
class FunctionCompositionCall extends DataFlow::CallNode { class FunctionCompositionCall extends DataFlow::CallNode instanceof FunctionCompositionCall::Range {
FunctionCompositionCall::Range range;
FunctionCompositionCall() { this = range }
/** /**
* Gets the `i`th function in the composition `f(g(h(...)))`, counting from left to right. * Gets the `i`th function in the composition `f(g(h(...)))`, counting from left to right.
@@ -19,7 +16,9 @@ class FunctionCompositionCall extends DataFlow::CallNode {
* Note that this is the opposite of the order in which the function are invoked, * Note that this is the opposite of the order in which the function are invoked,
* that is, `g` occurs later than `f` in `f(g(...))` but is invoked before `f`. * that is, `g` occurs later than `f` in `f(g(...))` but is invoked before `f`.
*/ */
DataFlow::Node getOperandNode(int i) { result = range.getOperandNode(i) } DataFlow::Node getOperandNode(int i) {
result = super.getOperandNode(i)
}
/** Gets a node holding one of the functions to be composed. */ /** Gets a node holding one of the functions to be composed. */
final DataFlow::Node getAnOperandNode() { result = getOperandNode(_) } final DataFlow::Node getAnOperandNode() { result = getOperandNode(_) }
@@ -38,7 +37,7 @@ class FunctionCompositionCall extends DataFlow::CallNode {
final DataFlow::Node getAnOperandFunction() { result = getOperandFunction(_) } final DataFlow::Node getAnOperandFunction() { result = getOperandFunction(_) }
/** Gets the number of functions being composed. */ /** Gets the number of functions being composed. */
int getNumOperand() { result = range.getNumOperand() } int getNumOperand() { result = super.getNumOperand() }
} }
/** /**

View File

@@ -181,8 +181,7 @@ module Electron {
/** /**
* A Node.js-style HTTP or HTTPS request made using an Electron module. * A Node.js-style HTTP or HTTPS request made using an Electron module.
*/ */
class ElectronClientRequest extends NodeJSLib::NodeJSClientRequest { class ElectronClientRequest extends NodeJSLib::NodeJSClientRequest instanceof ElectronClientRequest::Range {
override ElectronClientRequest::Range self;
} }
module ElectronClientRequest { module ElectronClientRequest {

View File

@@ -68,40 +68,40 @@ module EventEmitter {
* An EventEmitter instance that implements the EventEmitter API. * An EventEmitter instance that implements the EventEmitter API.
* Extend EventEmitter::Range to mark something as being an EventEmitter. * Extend EventEmitter::Range to mark something as being an EventEmitter.
*/ */
class EventEmitter extends DataFlow::Node { class EventEmitter extends DataFlow::Node instanceof EventEmitter::Range {
EventEmitter::Range range;
EventEmitter() { this = range }
} }
/** /**
* A registration of an event handler on an EventEmitter. * A registration of an event handler on an EventEmitter.
*/ */
class EventRegistration extends DataFlow::Node { class EventRegistration extends DataFlow::Node instanceof EventRegistration::Range {
EventRegistration::Range range;
EventRegistration() { this = range }
/** Gets the EventEmitter that the event handler is registered on. */ /** Gets the EventEmitter that the event handler is registered on. */
final EventEmitter getEmitter() { result = range.getEmitter() } final EventEmitter getEmitter() { result = super.getEmitter() }
/** Gets the name of the channel if possible. */ /** Gets the name of the channel if possible. */
string getChannel() { result = range.getChannel() } string getChannel() { result = super.getChannel() }
/** Gets the `i`th parameter in the event handler. */ /** Gets the `i`th parameter in the event handler. */
DataFlow::Node getReceivedItem(int i) { result = range.getReceivedItem(i) } DataFlow::Node getReceivedItem(int i) {
result = super.getReceivedItem(i)
}
/** /**
* Gets a value that is returned by the event handler. * Gets a value that is returned by the event handler.
* The default implementation is that no value can be returned. * The default implementation is that no value can be returned.
*/ */
DataFlow::Node getAReturnedValue() { result = range.getAReturnedValue() } DataFlow::Node getAReturnedValue() {
result = super.getAReturnedValue()
}
/** /**
* Get a dispatch that this event handler can return a value to. * Get a dispatch that this event handler can return a value to.
* The default implementation is that there exists no such dispatch. * The default implementation is that there exists no such dispatch.
*/ */
EventDispatch getAReturnDispatch() { result = range.getAReturnDispatch() } EventDispatch getAReturnDispatch() {
result = super.getAReturnDispatch()
}
} }
module EventRegistration { module EventRegistration {
@@ -140,26 +140,23 @@ module EventRegistration {
/** /**
* A dispatch of an event on an EventEmitter. * A dispatch of an event on an EventEmitter.
*/ */
class EventDispatch extends DataFlow::Node { class EventDispatch extends DataFlow::Node instanceof EventDispatch::Range {
EventDispatch::Range range;
EventDispatch() { this = range }
/** Gets the emitter that the event dispatch happens on. */ /** Gets the emitter that the event dispatch happens on. */
EventEmitter getEmitter() { result = range.getEmitter() } EventEmitter getEmitter() { result = super.getEmitter() }
/** Gets the name of the channel if possible. */ /** Gets the name of the channel if possible. */
string getChannel() { result = range.getChannel() } string getChannel() { result = this.(EventDispatch::Range).getChannel() }
/** Gets the `i`th argument that is send to the event handler. */ /** Gets the `i`th argument that is send to the event handler. */
DataFlow::Node getSentItem(int i) { result = range.getSentItem(i) } DataFlow::Node getSentItem(int i) { result = super.getSentItem(i) }
/** /**
* Get an EventRegistration that this event dispatch can send an event to. * Get an EventRegistration that this event dispatch can send an event to.
* The default implementation is that the emitters of the dispatch and registration have to be equal. * The default implementation is that the emitters of the dispatch and registration have to be equal.
* Channels are by default ignored. * Channels are by default ignored.
*/ */
EventRegistration getAReceiver() { result = range.getAReceiver() } EventRegistration getAReceiver() { result = super.getAReceiver() }
} }
module EventDispatch { module EventDispatch {

View File

@@ -540,16 +540,13 @@ module HTTP {
/** /**
* An object that contains one or more potential route handlers. * An object that contains one or more potential route handlers.
*/ */
class RouteHandlerCandidateContainer extends DataFlow::Node { class RouteHandlerCandidateContainer extends DataFlow::Node instanceof RouteHandlerCandidateContainer::Range {
RouteHandlerCandidateContainer::Range self;
RouteHandlerCandidateContainer() { this = self }
/** /**
* Gets the route handler in this container that is accessed at `access`. * Gets the route handler in this container that is accessed at `access`.
*/ */
DataFlow::SourceNode getRouteHandler(DataFlow::SourceNode access) { DataFlow::SourceNode getRouteHandler(DataFlow::SourceNode access) {
result = self.getRouteHandler(access) result = super.getRouteHandler(access)
} }
} }

View File

@@ -831,8 +831,7 @@ module NodeJSLib {
* A data flow node that is an HTTP or HTTPS client request made by a Node.js application, * A data flow node that is an HTTP or HTTPS client request made by a Node.js application,
* for example `http.request(url)`. * for example `http.request(url)`.
*/ */
class NodeJSClientRequest extends ClientRequest { class NodeJSClientRequest extends ClientRequest instanceof NodeJSClientRequest::Range {
override NodeJSClientRequest::Range self;
} }
module NodeJSClientRequest { module NodeJSClientRequest {

View File

@@ -14,20 +14,17 @@ import javascript
* To model additional APIs, extend `PropertyProjection::Range` and implement its abstract member * To model additional APIs, extend `PropertyProjection::Range` and implement its abstract member
* predicates. * predicates.
*/ */
class PropertyProjection extends DataFlow::CallNode { class PropertyProjection extends DataFlow::CallNode instanceof PropertyProjection::Range {
PropertyProjection::Range self;
PropertyProjection() { this = self }
/** /**
* Gets the argument for the object to project properties from, such as `o` in `_.get(o, 'a.b')`. * Gets the argument for the object to project properties from, such as `o` in `_.get(o, 'a.b')`.
*/ */
DataFlow::Node getObject() { result = self.getObject() } DataFlow::Node getObject() { result = super.getObject() }
/** /**
* Gets an argument that selects the properties to project, such as `'a.b'` in `_.get(o, 'a.b')`. * Gets an argument that selects the properties to project, such as `'a.b'` in `_.get(o, 'a.b')`.
*/ */
DataFlow::Node getASelector() { result = self.getASelector() } DataFlow::Node getASelector() { result = super.getASelector() }
/** /**
* Holds if this call returns the value of a single projected property, as opposed to an object that can contain multiple projected properties. * Holds if this call returns the value of a single projected property, as opposed to an object that can contain multiple projected properties.
@@ -36,7 +33,7 @@ class PropertyProjection extends DataFlow::CallNode {
* - This predicate holds for `_.get({a: 'b'}, 'a')`, which returns `'b'`, * - This predicate holds for `_.get({a: 'b'}, 'a')`, which returns `'b'`,
* - This predicate does not hold for `_.pick({a: 'b', c: 'd'}}, 'a')`, which returns `{a: 'b'}`, * - This predicate does not hold for `_.pick({a: 'b', c: 'd'}}, 'a')`, which returns `{a: 'b'}`,
*/ */
predicate isSingletonProjection() { self.isSingletonProjection() } predicate isSingletonProjection() { super.isSingletonProjection() }
} }
module PropertyProjection { module PropertyProjection {

View File

@@ -56,10 +56,7 @@ module Redux {
/** /**
* Creation of a redux store, usually via a call to `createStore`. * Creation of a redux store, usually via a call to `createStore`.
*/ */
class StoreCreation extends DataFlow::SourceNode { class StoreCreation extends DataFlow::SourceNode instanceof StoreCreation::Range {
StoreCreation::Range range;
StoreCreation() { this = range }
/** Gets a reference to the store. */ /** Gets a reference to the store. */
DataFlow::SourceNode ref() { result = asApiNode().getAUse() } DataFlow::SourceNode ref() { result = asApiNode().getAUse() }
@@ -68,7 +65,7 @@ module Redux {
API::Node asApiNode() { result.getAnImmediateUse() = this } API::Node asApiNode() { result.getAnImmediateUse() = this }
/** Gets the data flow node holding the root reducer for this store. */ /** Gets the data flow node holding the root reducer for this store. */
DataFlow::Node getReducerArg() { result = range.getReducerArg() } DataFlow::Node getReducerArg() { result = super.getReducerArg() }
/** Gets a data flow node referring to the root reducer. */ /** Gets a data flow node referring to the root reducer. */
DataFlow::SourceNode getAReducerSource() { result = getReducerArg().(ReducerArg).getASource() } DataFlow::SourceNode getAReducerSource() { result = getReducerArg().(ReducerArg).getASource() }
@@ -423,13 +420,10 @@ module Redux {
* Some action creators dispatch the action to a store, while for others, the value is returned and it is simply assumed to be dispatched * Some action creators dispatch the action to a store, while for others, the value is returned and it is simply assumed to be dispatched
* at some point. We model all action creators as if they dispatch the action they create. * at some point. We model all action creators as if they dispatch the action they create.
*/ */
class ActionCreator extends DataFlow::SourceNode { class ActionCreator extends DataFlow::SourceNode instanceof ActionCreator::Range {
ActionCreator::Range range;
ActionCreator() { this = range }
/** Gets the `type` property of actions created by this action creator, if it is known. */ /** Gets the `type` property of actions created by this action creator, if it is known. */
string getTypeTag() { result = range.getTypeTag() } string getTypeTag() { result = super.getTypeTag() }
/** /**
* Gets the middleware function that transforms arguments passed to this function into the * Gets the middleware function that transforms arguments passed to this function into the
@@ -442,7 +436,7 @@ module Redux {
* the action payload. Otherwise, the return value is the payload itself. * the action payload. Otherwise, the return value is the payload itself.
*/ */
DataFlow::FunctionNode getMiddlewareFunction(boolean async) { DataFlow::FunctionNode getMiddlewareFunction(boolean async) {
result = range.getMiddlewareFunction(async) result = super.getMiddlewareFunction(async)
} }
/** Gets a data flow node referring to this action creator. */ /** Gets a data flow node referring to this action creator. */

View File

@@ -14,13 +14,10 @@ module ShellJS {
} }
/** A member of the `shelljs` library. */ /** A member of the `shelljs` library. */
class Member extends DataFlow::SourceNode { class Member extends DataFlow::SourceNode instanceof Member::Range {
Member::Range range;
Member() { this = range }
/** Gets the name of `shelljs` member being referenced, such as `cat` in `shelljs.cat`. */ /** Gets the name of `shelljs` member being referenced, such as `cat` in `shelljs.cat`. */
string getName() { result = range.getName() } string getName() { result = super.getName() }
} }
module Member { module Member {

View File

@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`. * Holds if data can flow in one local step from `node1` to `node2`.
*/ */
private predicate localFlowStep(Node node1, Node node2, Configuration config) { private predicate localFlowStep(Node node1, Node node2, Configuration config) {
( simpleLocalFlowStepExt(node1, node2) and
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts. * Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/ */
private predicate jumpStep(Node node1, Node node2, Configuration config) { private predicate jumpStep(Node node1, Node node2, Configuration config) {
jumpStep(node1, node2) and jumpStepCached(node1, node2) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) { private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
exists(ArgumentNode arg | exists(ArgNode arg |
fwdFlow(arg, cc, config) and fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg) viableParamArg(call, _, arg)
) )
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic] pragma[nomagic]
predicate viableParamArgNodeCandFwd1( predicate viableParamArgNodeCandFwd1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
viableParamArg(call, p, arg) and viableParamArg(call, p, arg) and
fwdFlow(arg, config) fwdFlow(arg, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config exists(ParamNode p |
) {
exists(ParameterNode p |
revFlow(p, toReturn, config) and revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config) viableParamArgNodeCandFwd1(call, p, arg, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config) revFlowIn(call, arg, true, config)
} }
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a * Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic] pragma[nomagic]
private predicate viableParamArgNodeCand1( private predicate viableParamArgNodeCand1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config) Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) { ) {
viableParamArgNodeCand1(call, p, arg, config) and viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, arg, p, config) and flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j | exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config) PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
) )
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand2( private predicate flowIntoCallNodeCand2(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/ */
private class FlowCheckNode extends Node { private class FlowCheckNode extends Node {
FlowCheckNode() { FlowCheckNode() {
this instanceof CastNode or castNode(this) or
clearsContent(this, _) clearsContentCached(this, _)
} }
} }
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or config.isSource(node) or
jumpStep(_, node, config) or jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or additionalJumpStep(_, node, config) or
node instanceof ParameterNode or node instanceof ParamNode or
node instanceof OutNodeExt or node instanceof OutNodeExt or
store(_, _, node, _) or store(_, _, node, _) or
read(_, _, node) or read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc LocalCallContext cc
) { ) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
( (
localFlowEntry(node1, pragma[only_bind_into](config)) and localFlowEntry(node1, pragma[only_bind_into](config)) and
( (
localFlowStepNodeCand1(node1, node2, config) and localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and preservesValue = true and
t = getNodeType(node1) t = getNodeDataFlowType(node1)
or or
additionalLocalFlowStepNodeCand2(node1, node2, config) and additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) t = getNodeDataFlowType(node2)
) and ) and
node1 != node2 and node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
or or
exists(Node mid | exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and not mid instanceof FlowCheckNode and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) and t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
) )
) )
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() } private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap] bindingset[node, ap]
private predicate filter(Node node, Ap ap) { private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and not ap.isClearedAt(node) and
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() if node instanceof CastingNode
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
} }
bindingset[ap, contentType] bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() } private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCall( private predicate flowIntoCall(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx = private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParameterNode p, AccessPath ap) { TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _) Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
} }
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */ /** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
private ParameterNode p; private ParamNode p;
private AccessPath ap; private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) } SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and config.isSource(node) and
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
// ... or a step from an existing PathNode to another node. // ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid | exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() } Configuration getConfiguration() { none() }
private predicate isHidden() { private predicate isHidden() {
nodeIsHidden(this.getNode()) and hiddenNode(this.getNode()) and
not this.isSource() and not this.isSource() and
not this instanceof PathNodeSink not this instanceof PathNodeSink
} }
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and mid.getAp() instanceof AccessPathNil and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx() sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg( private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand( private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i) p.isParameterOf(callable, i)
) )
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively. * respectively.
*/ */
private predicate pathIntoCallable( private predicate pathIntoCallable(
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call DataFlowCall call
) { ) {
exists(int i, DataFlowCallable callable, AccessPath ap | exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 = private newtype TSummaryCtx1 =
TSummaryCtx1None() or TSummaryCtx1None() or
TSummaryCtx1Param(ParameterNode p) TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 = private newtype TSummaryCtx2 =
TSummaryCtx2None() or TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
exists(config.explorationLimit()) exists(config.explorationLimit())
or or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or or
exists(PartialPathNodeRev mid | exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit() distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
) )
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid | exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not clearsContent(node, ap.getHead().getContent()) and not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode if node instanceof CastingNode
then compatibleTypes(getNodeType(node), ap.getType()) then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any() else any()
) )
} }
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
( (
localFlowStep(mid.getNode(), node, config) and localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
) )
or or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
or or
partialPathStoreStep(mid, _, _, node, ap) and partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getNodeType(node)) compatibleTypes(ap.getType(), getNodeDataFlowType(node))
) )
or or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap, PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
} }
private predicate partialPathIntoCallable( private predicate partialPathIntoCallable(
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc, PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap, TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc, DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 | exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config) paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
) )
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config) apConsRev(ap, c, ap0, config)
) )
or or
exists(ParameterNode p | exists(ParamNode p |
mid.getNode() = p and mid.getNode() = p and
viableParamArg(_, p, node) and viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap, int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(PartialPathNodeRev mid, ParameterNode p | exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and mid.getNode() = p and
p.isParameterOf(_, pos) and p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic] pragma[nomagic]
private predicate revPartialPathThroughCallable( private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) { ) {
exists(DataFlowCall call, int pos | exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and revPartialPathThroughCallable0(call, mid, pos, ap, config) and

View File

@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`. * Holds if data can flow in one local step from `node1` to `node2`.
*/ */
private predicate localFlowStep(Node node1, Node node2, Configuration config) { private predicate localFlowStep(Node node1, Node node2, Configuration config) {
( simpleLocalFlowStepExt(node1, node2) and
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts. * Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/ */
private predicate jumpStep(Node node1, Node node2, Configuration config) { private predicate jumpStep(Node node1, Node node2, Configuration config) {
jumpStep(node1, node2) and jumpStepCached(node1, node2) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) { private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
exists(ArgumentNode arg | exists(ArgNode arg |
fwdFlow(arg, cc, config) and fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg) viableParamArg(call, _, arg)
) )
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic] pragma[nomagic]
predicate viableParamArgNodeCandFwd1( predicate viableParamArgNodeCandFwd1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
viableParamArg(call, p, arg) and viableParamArg(call, p, arg) and
fwdFlow(arg, config) fwdFlow(arg, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config exists(ParamNode p |
) {
exists(ParameterNode p |
revFlow(p, toReturn, config) and revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config) viableParamArgNodeCandFwd1(call, p, arg, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config) revFlowIn(call, arg, true, config)
} }
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a * Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic] pragma[nomagic]
private predicate viableParamArgNodeCand1( private predicate viableParamArgNodeCand1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config) Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) { ) {
viableParamArgNodeCand1(call, p, arg, config) and viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, arg, p, config) and flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j | exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config) PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
) )
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand2( private predicate flowIntoCallNodeCand2(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/ */
private class FlowCheckNode extends Node { private class FlowCheckNode extends Node {
FlowCheckNode() { FlowCheckNode() {
this instanceof CastNode or castNode(this) or
clearsContent(this, _) clearsContentCached(this, _)
} }
} }
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or config.isSource(node) or
jumpStep(_, node, config) or jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or additionalJumpStep(_, node, config) or
node instanceof ParameterNode or node instanceof ParamNode or
node instanceof OutNodeExt or node instanceof OutNodeExt or
store(_, _, node, _) or store(_, _, node, _) or
read(_, _, node) or read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc LocalCallContext cc
) { ) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
( (
localFlowEntry(node1, pragma[only_bind_into](config)) and localFlowEntry(node1, pragma[only_bind_into](config)) and
( (
localFlowStepNodeCand1(node1, node2, config) and localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and preservesValue = true and
t = getNodeType(node1) t = getNodeDataFlowType(node1)
or or
additionalLocalFlowStepNodeCand2(node1, node2, config) and additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) t = getNodeDataFlowType(node2)
) and ) and
node1 != node2 and node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
or or
exists(Node mid | exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and not mid instanceof FlowCheckNode and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) and t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
) )
) )
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() } private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap] bindingset[node, ap]
private predicate filter(Node node, Ap ap) { private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and not ap.isClearedAt(node) and
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() if node instanceof CastingNode
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
} }
bindingset[ap, contentType] bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() } private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCall( private predicate flowIntoCall(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx = private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParameterNode p, AccessPath ap) { TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _) Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
} }
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */ /** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
private ParameterNode p; private ParamNode p;
private AccessPath ap; private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) } SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and config.isSource(node) and
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
// ... or a step from an existing PathNode to another node. // ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid | exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() } Configuration getConfiguration() { none() }
private predicate isHidden() { private predicate isHidden() {
nodeIsHidden(this.getNode()) and hiddenNode(this.getNode()) and
not this.isSource() and not this.isSource() and
not this instanceof PathNodeSink not this instanceof PathNodeSink
} }
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and mid.getAp() instanceof AccessPathNil and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx() sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg( private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand( private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i) p.isParameterOf(callable, i)
) )
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively. * respectively.
*/ */
private predicate pathIntoCallable( private predicate pathIntoCallable(
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call DataFlowCall call
) { ) {
exists(int i, DataFlowCallable callable, AccessPath ap | exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 = private newtype TSummaryCtx1 =
TSummaryCtx1None() or TSummaryCtx1None() or
TSummaryCtx1Param(ParameterNode p) TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 = private newtype TSummaryCtx2 =
TSummaryCtx2None() or TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
exists(config.explorationLimit()) exists(config.explorationLimit())
or or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or or
exists(PartialPathNodeRev mid | exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit() distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
) )
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid | exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not clearsContent(node, ap.getHead().getContent()) and not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode if node instanceof CastingNode
then compatibleTypes(getNodeType(node), ap.getType()) then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any() else any()
) )
} }
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
( (
localFlowStep(mid.getNode(), node, config) and localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
) )
or or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
or or
partialPathStoreStep(mid, _, _, node, ap) and partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getNodeType(node)) compatibleTypes(ap.getType(), getNodeDataFlowType(node))
) )
or or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap, PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
} }
private predicate partialPathIntoCallable( private predicate partialPathIntoCallable(
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc, PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap, TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc, DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 | exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config) paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
) )
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config) apConsRev(ap, c, ap0, config)
) )
or or
exists(ParameterNode p | exists(ParamNode p |
mid.getNode() = p and mid.getNode() = p and
viableParamArg(_, p, node) and viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap, int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(PartialPathNodeRev mid, ParameterNode p | exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and mid.getNode() = p and
p.isParameterOf(_, pos) and p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic] pragma[nomagic]
private predicate revPartialPathThroughCallable( private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) { ) {
exists(DataFlowCall call, int pos | exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and revPartialPathThroughCallable0(call, mid, pos, ap, config) and

View File

@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`. * Holds if data can flow in one local step from `node1` to `node2`.
*/ */
private predicate localFlowStep(Node node1, Node node2, Configuration config) { private predicate localFlowStep(Node node1, Node node2, Configuration config) {
( simpleLocalFlowStepExt(node1, node2) and
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts. * Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/ */
private predicate jumpStep(Node node1, Node node2, Configuration config) { private predicate jumpStep(Node node1, Node node2, Configuration config) {
jumpStep(node1, node2) and jumpStepCached(node1, node2) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) { private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
exists(ArgumentNode arg | exists(ArgNode arg |
fwdFlow(arg, cc, config) and fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg) viableParamArg(call, _, arg)
) )
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic] pragma[nomagic]
predicate viableParamArgNodeCandFwd1( predicate viableParamArgNodeCandFwd1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
viableParamArg(call, p, arg) and viableParamArg(call, p, arg) and
fwdFlow(arg, config) fwdFlow(arg, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config exists(ParamNode p |
) {
exists(ParameterNode p |
revFlow(p, toReturn, config) and revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config) viableParamArgNodeCandFwd1(call, p, arg, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config) revFlowIn(call, arg, true, config)
} }
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a * Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic] pragma[nomagic]
private predicate viableParamArgNodeCand1( private predicate viableParamArgNodeCand1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config) Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) { ) {
viableParamArgNodeCand1(call, p, arg, config) and viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, arg, p, config) and flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j | exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config) PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
) )
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand2( private predicate flowIntoCallNodeCand2(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/ */
private class FlowCheckNode extends Node { private class FlowCheckNode extends Node {
FlowCheckNode() { FlowCheckNode() {
this instanceof CastNode or castNode(this) or
clearsContent(this, _) clearsContentCached(this, _)
} }
} }
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or config.isSource(node) or
jumpStep(_, node, config) or jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or additionalJumpStep(_, node, config) or
node instanceof ParameterNode or node instanceof ParamNode or
node instanceof OutNodeExt or node instanceof OutNodeExt or
store(_, _, node, _) or store(_, _, node, _) or
read(_, _, node) or read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc LocalCallContext cc
) { ) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
( (
localFlowEntry(node1, pragma[only_bind_into](config)) and localFlowEntry(node1, pragma[only_bind_into](config)) and
( (
localFlowStepNodeCand1(node1, node2, config) and localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and preservesValue = true and
t = getNodeType(node1) t = getNodeDataFlowType(node1)
or or
additionalLocalFlowStepNodeCand2(node1, node2, config) and additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) t = getNodeDataFlowType(node2)
) and ) and
node1 != node2 and node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
or or
exists(Node mid | exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and not mid instanceof FlowCheckNode and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) and t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
) )
) )
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() } private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap] bindingset[node, ap]
private predicate filter(Node node, Ap ap) { private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and not ap.isClearedAt(node) and
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() if node instanceof CastingNode
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
} }
bindingset[ap, contentType] bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() } private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCall( private predicate flowIntoCall(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx = private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParameterNode p, AccessPath ap) { TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _) Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
} }
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */ /** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
private ParameterNode p; private ParamNode p;
private AccessPath ap; private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) } SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and config.isSource(node) and
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
// ... or a step from an existing PathNode to another node. // ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid | exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() } Configuration getConfiguration() { none() }
private predicate isHidden() { private predicate isHidden() {
nodeIsHidden(this.getNode()) and hiddenNode(this.getNode()) and
not this.isSource() and not this.isSource() and
not this instanceof PathNodeSink not this instanceof PathNodeSink
} }
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and mid.getAp() instanceof AccessPathNil and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx() sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg( private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand( private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i) p.isParameterOf(callable, i)
) )
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively. * respectively.
*/ */
private predicate pathIntoCallable( private predicate pathIntoCallable(
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call DataFlowCall call
) { ) {
exists(int i, DataFlowCallable callable, AccessPath ap | exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 = private newtype TSummaryCtx1 =
TSummaryCtx1None() or TSummaryCtx1None() or
TSummaryCtx1Param(ParameterNode p) TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 = private newtype TSummaryCtx2 =
TSummaryCtx2None() or TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
exists(config.explorationLimit()) exists(config.explorationLimit())
or or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or or
exists(PartialPathNodeRev mid | exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit() distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
) )
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid | exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not clearsContent(node, ap.getHead().getContent()) and not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode if node instanceof CastingNode
then compatibleTypes(getNodeType(node), ap.getType()) then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any() else any()
) )
} }
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
( (
localFlowStep(mid.getNode(), node, config) and localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
) )
or or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
or or
partialPathStoreStep(mid, _, _, node, ap) and partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getNodeType(node)) compatibleTypes(ap.getType(), getNodeDataFlowType(node))
) )
or or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap, PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
} }
private predicate partialPathIntoCallable( private predicate partialPathIntoCallable(
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc, PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap, TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc, DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 | exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config) paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
) )
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config) apConsRev(ap, c, ap0, config)
) )
or or
exists(ParameterNode p | exists(ParamNode p |
mid.getNode() = p and mid.getNode() = p and
viableParamArg(_, p, node) and viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap, int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(PartialPathNodeRev mid, ParameterNode p | exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and mid.getNode() = p and
p.isParameterOf(_, pos) and p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic] pragma[nomagic]
private predicate revPartialPathThroughCallable( private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) { ) {
exists(DataFlowCall call, int pos | exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and revPartialPathThroughCallable0(call, mid, pos, ap, config) and

View File

@@ -211,10 +211,7 @@ private predicate fullBarrier(Node node, Configuration config) {
* Holds if data can flow in one local step from `node1` to `node2`. * Holds if data can flow in one local step from `node1` to `node2`.
*/ */
private predicate localFlowStep(Node node1, Node node2, Configuration config) { private predicate localFlowStep(Node node1, Node node2, Configuration config) {
( simpleLocalFlowStepExt(node1, node2) and
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -237,7 +234,7 @@ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts. * Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/ */
private predicate jumpStep(Node node1, Node node2, Configuration config) { private predicate jumpStep(Node node1, Node node2, Configuration config) {
jumpStep(node1, node2) and jumpStepCached(node1, node2) and
not outBarrier(node1, config) and not outBarrier(node1, config) and
not inBarrier(node2, config) and not inBarrier(node2, config) and
not fullBarrier(node1, config) and not fullBarrier(node1, config) and
@@ -388,7 +385,7 @@ private module Stage1 {
*/ */
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) { private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
exists(ArgumentNode arg | exists(ArgNode arg |
fwdFlow(arg, cc, config) and fwdFlow(arg, cc, config) and
viableParamArg(call, _, arg) viableParamArg(call, _, arg)
) )
@@ -515,24 +512,22 @@ private module Stage1 {
pragma[nomagic] pragma[nomagic]
predicate viableParamArgNodeCandFwd1( predicate viableParamArgNodeCandFwd1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
viableParamArg(call, p, arg) and viableParamArg(call, p, arg) and
fwdFlow(arg, config) fwdFlow(arg, config)
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(DataFlowCall call, ArgNode arg, boolean toReturn, Configuration config) {
DataFlowCall call, ArgumentNode arg, boolean toReturn, Configuration config exists(ParamNode p |
) {
exists(ParameterNode p |
revFlow(p, toReturn, config) and revFlow(p, toReturn, config) and
viableParamArgNodeCandFwd1(call, p, arg, config) viableParamArgNodeCandFwd1(call, p, arg, config)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn(DataFlowCall call, ArgumentNode arg, Configuration config) { private predicate revFlowInToReturn(DataFlowCall call, ArgNode arg, Configuration config) {
revFlowIn(call, arg, true, config) revFlowIn(call, arg, true, config)
} }
@@ -597,7 +592,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a * Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary. * candidate for the origin of a summary.
*/ */
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind | exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and throughFlowNodeCand(p, config) and
returnFlowCallableNodeCand(c, kind, config) and returnFlowCallableNodeCand(c, kind, config) and
@@ -663,7 +658,7 @@ private predicate flowOutOfCallNodeCand1(
pragma[nomagic] pragma[nomagic]
private predicate viableParamArgNodeCand1( private predicate viableParamArgNodeCand1(
DataFlowCall call, ParameterNode p, ArgumentNode arg, Configuration config DataFlowCall call, ParamNode p, ArgNode arg, Configuration config
) { ) {
Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and Stage1::viableParamArgNodeCandFwd1(call, p, arg, config) and
Stage1::revFlow(arg, config) Stage1::revFlow(arg, config)
@@ -675,7 +670,7 @@ private predicate viableParamArgNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, Configuration config DataFlowCall call, ArgNode arg, ParamNode p, Configuration config
) { ) {
viableParamArgNodeCand1(call, p, arg, config) and viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and Stage1::revFlow(p, config) and
@@ -735,8 +730,7 @@ private predicate flowOutOfCallNodeCand1(
*/ */
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand1( private predicate flowIntoCallNodeCand1(
DataFlowCall call, ArgumentNode arg, ParameterNode p, boolean allowsFieldFlow, DataFlowCall call, ArgNode arg, ParamNode p, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, arg, p, config) and flowIntoCallNodeCand1(call, arg, p, config) and
exists(int b, int j | exists(int b, int j |
@@ -944,10 +938,10 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -992,7 +986,7 @@ private module Stage2 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config) PrevStage::parameterMayFlowThrough(p, _, getApprox(ap), config)
) )
@@ -1133,10 +1127,9 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1146,7 +1139,7 @@ private module Stage2 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1199,13 +1192,13 @@ private module Stage2 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -1245,8 +1238,7 @@ private predicate flowOutOfCallNodeCand2(
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCallNodeCand2( private predicate flowIntoCallNodeCand2(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand1(call, node1, node2, allowsFieldFlow, config) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) and Stage2::revFlow(node2, pragma[only_bind_into](config)) and
@@ -1260,8 +1252,8 @@ private module LocalFlowBigStep {
*/ */
private class FlowCheckNode extends Node { private class FlowCheckNode extends Node {
FlowCheckNode() { FlowCheckNode() {
this instanceof CastNode or castNode(this) or
clearsContent(this, _) clearsContentCached(this, _)
} }
} }
@@ -1275,7 +1267,7 @@ private module LocalFlowBigStep {
config.isSource(node) or config.isSource(node) or
jumpStep(_, node, config) or jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or additionalJumpStep(_, node, config) or
node instanceof ParameterNode or node instanceof ParamNode or
node instanceof OutNodeExt or node instanceof OutNodeExt or
store(_, _, node, _) or store(_, _, node, _) or
read(_, _, node) or read(_, _, node) or
@@ -1321,21 +1313,21 @@ private module LocalFlowBigStep {
Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config, Node node1, Node node2, boolean preservesValue, DataFlowType t, Configuration config,
LocalCallContext cc LocalCallContext cc
) { ) {
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node2, cc.(LocalCallContextSpecificCall).getCall()) and
( (
localFlowEntry(node1, pragma[only_bind_into](config)) and localFlowEntry(node1, pragma[only_bind_into](config)) and
( (
localFlowStepNodeCand1(node1, node2, config) and localFlowStepNodeCand1(node1, node2, config) and
preservesValue = true and preservesValue = true and
t = getNodeType(node1) t = getNodeDataFlowType(node1)
or or
additionalLocalFlowStepNodeCand2(node1, node2, config) and additionalLocalFlowStepNodeCand2(node1, node2, config) and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) t = getNodeDataFlowType(node2)
) and ) and
node1 != node2 and node1 != node2 and
cc.relevantFor(getNodeEnclosingCallable(node1)) and cc.relevantFor(getNodeEnclosingCallable(node1)) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node1, cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
or or
exists(Node mid | exists(Node mid |
@@ -1350,7 +1342,7 @@ private module LocalFlowBigStep {
additionalLocalFlowStepNodeCand2(mid, node2, config) and additionalLocalFlowStepNodeCand2(mid, node2, config) and
not mid instanceof FlowCheckNode and not mid instanceof FlowCheckNode and
preservesValue = false and preservesValue = false and
t = getNodeType(node2) and t = getNodeDataFlowType(node2) and
Stage2::revFlow(node2, pragma[only_bind_into](config)) Stage2::revFlow(node2, pragma[only_bind_into](config))
) )
) )
@@ -1384,7 +1376,7 @@ private module Stage3 {
private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() } private ApApprox getApprox(Ap ap) { result = ap.toBoolNonEmpty() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TFrontNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TFrontNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -1443,7 +1435,9 @@ private module Stage3 {
bindingset[node, ap] bindingset[node, ap]
private predicate filter(Node node, Ap ap) { private predicate filter(Node node, Ap ap) {
not ap.isClearedAt(node) and not ap.isClearedAt(node) and
if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() if node instanceof CastingNode
then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any()
} }
bindingset[ap, contentType] bindingset[ap, contentType]
@@ -1583,10 +1577,10 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -1631,7 +1625,7 @@ private module Stage3 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -1772,10 +1766,9 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -1785,7 +1778,7 @@ private module Stage3 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -1838,13 +1831,13 @@ private module Stage3 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2088,7 +2081,7 @@ private module Stage4 {
private ApApprox getApprox(Ap ap) { result = ap.getFront() } private ApApprox getApprox(Ap ap) { result = ap.getFront() }
private ApNil getApNil(Node node) { private ApNil getApNil(Node node) {
PrevStage::revFlow(node, _) and result = TNil(getNodeType(node)) PrevStage::revFlow(node, _) and result = TNil(getNodeDataFlowType(node))
} }
bindingset[tc, tail] bindingset[tc, tail]
@@ -2155,8 +2148,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate flowIntoCall( private predicate flowIntoCall(
DataFlowCall call, ArgumentNode node1, ParameterNode node2, boolean allowsFieldFlow, DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
Configuration config
) { ) {
flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and flowIntoCallNodeCand2(call, node1, node2, allowsFieldFlow, config) and
PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and PrevStage::revFlow(node2, _, _, _, pragma[only_bind_into](config)) and
@@ -2300,10 +2292,10 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate fwdFlowIn( private predicate fwdFlowIn(
DataFlowCall call, ParameterNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap, DataFlowCall call, ParamNode p, Cc outercc, Cc innercc, ApOption argAp, Ap ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg, boolean allowsFieldFlow | exists(ArgNode arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc) innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
@@ -2348,7 +2340,7 @@ private module Stage4 {
private predicate fwdFlowIsEntered( private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config DataFlowCall call, Cc cc, ApOption argAp, Ap ap, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
fwdFlowIn(call, p, cc, _, argAp, ap, config) and fwdFlowIn(call, p, cc, _, argAp, ap, config) and
PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config) PrevStage::parameterMayFlowThrough(p, _, unbindApa(getApprox(ap)), config)
) )
@@ -2489,10 +2481,9 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowIn( private predicate revFlowIn(
DataFlowCall call, ArgumentNode arg, boolean toReturn, ApOption returnAp, Ap ap, DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
Configuration config
) { ) {
exists(ParameterNode p, boolean allowsFieldFlow | exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) flowIntoCall(call, arg, p, allowsFieldFlow, config)
| |
@@ -2502,7 +2493,7 @@ private module Stage4 {
pragma[nomagic] pragma[nomagic]
private predicate revFlowInToReturn( private predicate revFlowInToReturn(
DataFlowCall call, ArgumentNode arg, Ap returnAp, Ap ap, Configuration config DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) { ) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config) revFlowIn(call, arg, true, apSome(returnAp), ap, config)
} }
@@ -2555,13 +2546,13 @@ private module Stage4 {
pragma[noinline] pragma[noinline]
private predicate parameterFlow( private predicate parameterFlow(
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config ParamNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
) { ) {
revFlow(p, true, apSome(ap0), ap, config) and revFlow(p, true, apSome(ap0), ap, config) and
c = getNodeEnclosingCallable(p) c = getNodeEnclosingCallable(p)
} }
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) { predicate parameterMayFlowThrough(ParamNode p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos | exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
parameterFlow(p, ap, ap0, c, config) and parameterFlow(p, ap, ap0, c, config) and
c = getNodeEnclosingCallable(ret) and c = getNodeEnclosingCallable(ret) and
@@ -2606,7 +2597,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
private newtype TSummaryCtx = private newtype TSummaryCtx =
TSummaryCtxNone() or TSummaryCtxNone() or
TSummaryCtxSome(ParameterNode p, AccessPath ap) { TSummaryCtxSome(ParamNode p, AccessPath ap) {
Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _) Stage4::parameterMayFlowThrough(p, _, ap.getApprox(), _)
} }
@@ -2627,7 +2618,7 @@ private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
/** A summary context from which a flow summary can be generated. */ /** A summary context from which a flow summary can be generated. */
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome { private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
private ParameterNode p; private ParamNode p;
private AccessPath ap; private AccessPath ap;
SummaryCtxSome() { this = TSummaryCtxSome(p, ap) } SummaryCtxSome() { this = TSummaryCtxSome(p, ap) }
@@ -2758,7 +2749,7 @@ private newtype TPathNode =
config.isSource(node) and config.isSource(node) and
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
// ... or a step from an existing PathNode to another node. // ... or a step from an existing PathNode to another node.
exists(PathNodeMid mid | exists(PathNodeMid mid |
@@ -2979,7 +2970,7 @@ class PathNode extends TPathNode {
Configuration getConfiguration() { none() } Configuration getConfiguration() { none() }
private predicate isHidden() { private predicate isHidden() {
nodeIsHidden(this.getNode()) and hiddenNode(this.getNode()) and
not this.isSource() and not this.isSource() and
not this instanceof PathNodeSink not this instanceof PathNodeSink
} }
@@ -3148,7 +3139,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc instanceof SummaryCtxNone and sc instanceof SummaryCtxNone and
mid.getAp() instanceof AccessPathNil and mid.getAp() instanceof AccessPathNil and
ap = TAccessPathNil(getNodeType(node)) ap = TAccessPathNil(getNodeDataFlowType(node))
or or
exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and exists(TypedContent tc | pathStoreStep(mid, node, ap.pop(tc), tc, cc)) and
sc = mid.getSummaryCtx() sc = mid.getSummaryCtx()
@@ -3235,7 +3226,7 @@ pragma[noinline]
private predicate pathIntoArg( private predicate pathIntoArg(
PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa PathNodeMid mid, int i, CallContext cc, DataFlowCall call, AccessPath ap, AccessPathApprox apa
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3248,7 +3239,7 @@ pragma[noinline]
private predicate parameterCand( private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) { ) {
exists(ParameterNode p | exists(ParamNode p |
Stage4::revFlow(p, _, _, apa, config) and Stage4::revFlow(p, _, _, apa, config) and
p.isParameterOf(callable, i) p.isParameterOf(callable, i)
) )
@@ -3272,7 +3263,7 @@ private predicate pathIntoCallable0(
* respectively. * respectively.
*/ */
private predicate pathIntoCallable( private predicate pathIntoCallable(
PathNodeMid mid, ParameterNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc, PathNodeMid mid, ParamNode p, CallContext outercc, CallContextCall innercc, SummaryCtx sc,
DataFlowCall call DataFlowCall call
) { ) {
exists(int i, DataFlowCallable callable, AccessPath ap | exists(int i, DataFlowCallable callable, AccessPath ap |
@@ -3568,7 +3559,7 @@ private module FlowExploration {
private newtype TSummaryCtx1 = private newtype TSummaryCtx1 =
TSummaryCtx1None() or TSummaryCtx1None() or
TSummaryCtx1Param(ParameterNode p) TSummaryCtx1Param(ParamNode p)
private newtype TSummaryCtx2 = private newtype TSummaryCtx2 =
TSummaryCtx2None() or TSummaryCtx2None() or
@@ -3591,7 +3582,7 @@ private module FlowExploration {
cc instanceof CallContextAny and cc instanceof CallContextAny and
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
exists(config.explorationLimit()) exists(config.explorationLimit())
or or
@@ -3611,7 +3602,7 @@ private module FlowExploration {
or or
exists(PartialPathNodeRev mid | exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, sc1, sc2, ap, config) and revPartialPathStep(mid, node, sc1, sc2, ap, config) and
not clearsContent(node, ap.getHead()) and not clearsContentCached(node, ap.getHead()) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit() distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
) )
@@ -3625,9 +3616,9 @@ private module FlowExploration {
exists(PartialPathNodeFwd mid | exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, cc, sc1, sc2, ap, config) and partialPathStep(mid, node, cc, sc1, sc2, ap, config) and
not fullBarrier(node, config) and not fullBarrier(node, config) and
not clearsContent(node, ap.getHead().getContent()) and not clearsContentCached(node, ap.getHead().getContent()) and
if node instanceof CastingNode if node instanceof CastingNode
then compatibleTypes(getNodeType(node), ap.getType()) then compatibleTypes(getNodeDataFlowType(node), ap.getType())
else any() else any()
) )
} }
@@ -3783,7 +3774,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2, PartialPathNodeFwd mid, Node node, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and not isUnreachableInCallCached(node, cc.(CallContextSpecificCall).getCall()) and
( (
localFlowStep(mid.getNode(), node, config) and localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and cc = mid.getCallContext() and
@@ -3797,7 +3788,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
) )
or or
@@ -3813,7 +3804,7 @@ private module FlowExploration {
sc1 = TSummaryCtx1None() and sc1 = TSummaryCtx1None() and
sc2 = TSummaryCtx2None() and sc2 = TSummaryCtx2None() and
mid.getAp() instanceof PartialAccessPathNil and mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getNodeType(node)) and ap = TPartialNil(getNodeDataFlowType(node)) and
config = mid.getConfiguration() config = mid.getConfiguration()
or or
partialPathStoreStep(mid, _, _, node, ap) and partialPathStoreStep(mid, _, _, node, ap) and
@@ -3827,7 +3818,7 @@ private module FlowExploration {
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
sc2 = mid.getSummaryCtx2() and sc2 = mid.getSummaryCtx2() and
apConsFwd(ap, tc, ap0, config) and apConsFwd(ap, tc, ap0, config) and
compatibleTypes(ap.getType(), getNodeType(node)) compatibleTypes(ap.getType(), getNodeDataFlowType(node))
) )
or or
partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config) partialPathIntoCallable(mid, node, _, cc, sc1, sc2, _, ap, config)
@@ -3924,7 +3915,7 @@ private module FlowExploration {
PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap, PartialPathNodeFwd mid, int i, CallContext cc, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(ArgumentNode arg | exists(ArgNode arg |
arg = mid.getNode() and arg = mid.getNode() and
cc = mid.getCallContext() and cc = mid.getCallContext() and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
@@ -3943,7 +3934,7 @@ private module FlowExploration {
} }
private predicate partialPathIntoCallable( private predicate partialPathIntoCallable(
PartialPathNodeFwd mid, ParameterNode p, CallContext outercc, CallContextCall innercc, PartialPathNodeFwd mid, ParamNode p, CallContext outercc, CallContextCall innercc,
TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap, TSummaryCtx1 sc1, TSummaryCtx2 sc2, DataFlowCall call, PartialAccessPath ap,
Configuration config Configuration config
) { ) {
@@ -3980,7 +3971,7 @@ private module FlowExploration {
DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc, DataFlowCall call, PartialPathNodeFwd mid, ReturnKindExt kind, CallContext cc,
PartialAccessPath ap, Configuration config PartialAccessPath ap, Configuration config
) { ) {
exists(ParameterNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 | exists(ParamNode p, CallContext innercc, TSummaryCtx1 sc1, TSummaryCtx2 sc2 |
partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and partialPathIntoCallable(mid, p, cc, innercc, sc1, sc2, call, _, config) and
paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config) paramFlowsThroughInPartialPath(kind, innercc, sc1, sc2, ap, config)
) )
@@ -4037,7 +4028,7 @@ private module FlowExploration {
apConsRev(ap, c, ap0, config) apConsRev(ap, c, ap0, config)
) )
or or
exists(ParameterNode p | exists(ParamNode p |
mid.getNode() = p and mid.getNode() = p and
viableParamArg(_, p, node) and viableParamArg(_, p, node) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4115,7 +4106,7 @@ private module FlowExploration {
int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap, int pos, TRevSummaryCtx1Some sc1, TRevSummaryCtx2Some sc2, RevPartialAccessPath ap,
Configuration config Configuration config
) { ) {
exists(PartialPathNodeRev mid, ParameterNode p | exists(PartialPathNodeRev mid, ParamNode p |
mid.getNode() = p and mid.getNode() = p and
p.isParameterOf(_, pos) and p.isParameterOf(_, pos) and
sc1 = mid.getSummaryCtx1() and sc1 = mid.getSummaryCtx1() and
@@ -4138,7 +4129,7 @@ private module FlowExploration {
pragma[nomagic] pragma[nomagic]
private predicate revPartialPathThroughCallable( private predicate revPartialPathThroughCallable(
PartialPathNodeRev mid, ArgumentNode node, RevPartialAccessPath ap, Configuration config PartialPathNodeRev mid, ArgNode node, RevPartialAccessPath ap, Configuration config
) { ) {
exists(DataFlowCall call, int pos | exists(DataFlowCall call, int pos |
revPartialPathThroughCallable0(call, mid, pos, ap, config) and revPartialPathThroughCallable0(call, mid, pos, ap, config) and

View File

@@ -35,22 +35,22 @@ predicate accessPathCostLimits(int apLimit, int tupleLimit) {
* calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly. * calls. For this reason, we cannot reuse the code from `DataFlowImpl.qll` directly.
*/ */
private module LambdaFlow { private module LambdaFlow {
private predicate viableParamNonLambda(DataFlowCall call, int i, ParameterNode p) { private predicate viableParamNonLambda(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallable(call), i) p.isParameterOf(viableCallable(call), i)
} }
private predicate viableParamLambda(DataFlowCall call, int i, ParameterNode p) { private predicate viableParamLambda(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallableLambda(call, _), i) p.isParameterOf(viableCallableLambda(call, _), i)
} }
private predicate viableParamArgNonLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) { private predicate viableParamArgNonLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i | exists(int i |
viableParamNonLambda(call, i, p) and viableParamNonLambda(call, i, p) and
arg.argumentOf(call, i) arg.argumentOf(call, i)
) )
} }
private predicate viableParamArgLambda(DataFlowCall call, ParameterNode p, ArgumentNode arg) { private predicate viableParamArgLambda(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i | exists(int i |
viableParamLambda(call, i, p) and viableParamLambda(call, i, p) and
arg.argumentOf(call, i) arg.argumentOf(call, i)
@@ -118,8 +118,8 @@ private module LambdaFlow {
boolean toJump, DataFlowCallOption lastCall boolean toJump, DataFlowCallOption lastCall
) { ) {
revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and revLambdaFlow0(lambdaCall, kind, node, t, toReturn, toJump, lastCall) and
if node instanceof CastNode or node instanceof ArgumentNode or node instanceof ReturnNode if castNode(node) or node instanceof ArgNode or node instanceof ReturnNode
then compatibleTypes(t, getNodeType(node)) then compatibleTypes(t, getNodeDataFlowType(node))
else any() else any()
} }
@@ -129,7 +129,7 @@ private module LambdaFlow {
boolean toJump, DataFlowCallOption lastCall boolean toJump, DataFlowCallOption lastCall
) { ) {
lambdaCall(lambdaCall, kind, node) and lambdaCall(lambdaCall, kind, node) and
t = getNodeType(node) and t = getNodeDataFlowType(node) and
toReturn = false and toReturn = false and
toJump = false and toJump = false and
lastCall = TDataFlowCallNone() lastCall = TDataFlowCallNone()
@@ -146,7 +146,7 @@ private module LambdaFlow {
getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid) getNodeEnclosingCallable(node) = getNodeEnclosingCallable(mid)
| |
preservesValue = false and preservesValue = false and
t = getNodeType(node) t = getNodeDataFlowType(node)
or or
preservesValue = true and preservesValue = true and
t = t0 t = t0
@@ -160,7 +160,7 @@ private module LambdaFlow {
toJump = true and toJump = true and
lastCall = TDataFlowCallNone() lastCall = TDataFlowCallNone()
| |
jumpStep(node, mid) and jumpStepCached(node, mid) and
t = t0 t = t0
or or
exists(boolean preservesValue | exists(boolean preservesValue |
@@ -168,7 +168,7 @@ private module LambdaFlow {
getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid) getNodeEnclosingCallable(node) != getNodeEnclosingCallable(mid)
| |
preservesValue = false and preservesValue = false and
t = getNodeType(node) t = getNodeDataFlowType(node)
or or
preservesValue = true and preservesValue = true and
t = t0 t = t0
@@ -176,7 +176,7 @@ private module LambdaFlow {
) )
or or
// flow into a callable // flow into a callable
exists(ParameterNode p, DataFlowCallOption lastCall0, DataFlowCall call | exists(ParamNode p, DataFlowCallOption lastCall0, DataFlowCall call |
revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and revLambdaFlowIn(lambdaCall, kind, p, t, toJump, lastCall0) and
( (
if lastCall0 = TDataFlowCallNone() and toJump = false if lastCall0 = TDataFlowCallNone() and toJump = false
@@ -227,7 +227,7 @@ private module LambdaFlow {
pragma[nomagic] pragma[nomagic]
predicate revLambdaFlowIn( predicate revLambdaFlowIn(
DataFlowCall lambdaCall, LambdaCallKind kind, ParameterNode p, DataFlowType t, boolean toJump, DataFlowCall lambdaCall, LambdaCallKind kind, ParamNode p, DataFlowType t, boolean toJump,
DataFlowCallOption lastCall DataFlowCallOption lastCall
) { ) {
revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall) revLambdaFlow(lambdaCall, kind, p, t, false, toJump, lastCall)
@@ -242,6 +242,89 @@ private DataFlowCallable viableCallableExt(DataFlowCall call) {
cached cached
private module Cached { private module Cached {
/**
* If needed, call this predicate from `DataFlowImplSpecific.qll` in order to
* force a stage-dependency on the `DataFlowImplCommon.qll` stage and therby
* collapsing the two stages.
*/
cached
predicate forceCachingInSameStage() { any() }
cached
predicate nodeEnclosingCallable(Node n, DataFlowCallable c) { c = n.getEnclosingCallable() }
cached
predicate callEnclosingCallable(DataFlowCall call, DataFlowCallable c) {
c = call.getEnclosingCallable()
}
cached
predicate nodeDataFlowType(Node n, DataFlowType t) { t = getNodeType(n) }
cached
predicate jumpStepCached(Node node1, Node node2) { jumpStep(node1, node2) }
cached
predicate clearsContentCached(Node n, Content c) { clearsContent(n, c) }
cached
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
cached
predicate outNodeExt(Node n) {
n instanceof OutNode
or
n.(PostUpdateNode).getPreUpdateNode() instanceof ArgNode
}
cached
predicate hiddenNode(Node n) { nodeIsHidden(n) }
cached
OutNodeExt getAnOutNodeExt(DataFlowCall call, ReturnKindExt k) {
result = getAnOutNode(call, k.(ValueReturnKind).getKind())
or
exists(ArgNode arg |
result.(PostUpdateNode).getPreUpdateNode() = arg and
arg.argumentOf(call, k.(ParamUpdateReturnKind).getPosition())
)
}
cached
predicate returnNodeExt(Node n, ReturnKindExt k) {
k = TValueReturn(n.(ReturnNode).getKind())
or
exists(ParamNode p, int pos |
parameterValueFlowsToPreUpdate(p, n) and
p.isParameterOf(_, pos) and
k = TParamUpdate(pos)
)
}
cached
predicate castNode(Node n) { n instanceof CastNode }
cached
predicate castingNode(Node n) {
castNode(n) or
n instanceof ParamNode or
n instanceof OutNodeExt or
// For reads, `x.f`, we want to check that the tracked type after the read (which
// is obtained by popping the head of the access path stack) is compatible with
// the type of `x.f`.
read(_, _, n)
}
cached
predicate parameterNode(Node n, DataFlowCallable c, int i) {
n.(ParameterNode).isParameterOf(c, i)
}
cached
predicate argumentNode(Node n, DataFlowCall call, int pos) {
n.(ArgumentNode).argumentOf(call, pos)
}
/** /**
* Gets a viable target for the lambda call `call`. * Gets a viable target for the lambda call `call`.
* *
@@ -261,7 +344,7 @@ private module Cached {
* The instance parameter is considered to have index `-1`. * The instance parameter is considered to have index `-1`.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate viableParam(DataFlowCall call, int i, ParameterNode p) { private predicate viableParam(DataFlowCall call, int i, ParamNode p) {
p.isParameterOf(viableCallableExt(call), i) p.isParameterOf(viableCallableExt(call), i)
} }
@@ -270,11 +353,11 @@ private module Cached {
* dispatch into account. * dispatch into account.
*/ */
cached cached
predicate viableParamArg(DataFlowCall call, ParameterNode p, ArgumentNode arg) { predicate viableParamArg(DataFlowCall call, ParamNode p, ArgNode arg) {
exists(int i | exists(int i |
viableParam(call, i, p) and viableParam(call, i, p) and
arg.argumentOf(call, i) and arg.argumentOf(call, i) and
compatibleTypes(getNodeType(arg), getNodeType(p)) compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(p))
) )
} }
@@ -312,7 +395,7 @@ private module Cached {
* `read` indicates whether it is contents of `p` that can flow to `node`. * `read` indicates whether it is contents of `p` that can flow to `node`.
*/ */
pragma[nomagic] pragma[nomagic]
private predicate parameterValueFlowCand(ParameterNode p, Node node, boolean read) { private predicate parameterValueFlowCand(ParamNode p, Node node, boolean read) {
p = node and p = node and
read = false read = false
or or
@@ -325,30 +408,30 @@ private module Cached {
// read // read
exists(Node mid | exists(Node mid |
parameterValueFlowCand(p, mid, false) and parameterValueFlowCand(p, mid, false) and
readStep(mid, _, node) and read(mid, _, node) and
read = true read = true
) )
or or
// flow through: no prior read // flow through: no prior read
exists(ArgumentNode arg | exists(ArgNode arg |
parameterValueFlowArgCand(p, arg, false) and parameterValueFlowArgCand(p, arg, false) and
argumentValueFlowsThroughCand(arg, node, read) argumentValueFlowsThroughCand(arg, node, read)
) )
or or
// flow through: no read inside method // flow through: no read inside method
exists(ArgumentNode arg | exists(ArgNode arg |
parameterValueFlowArgCand(p, arg, read) and parameterValueFlowArgCand(p, arg, read) and
argumentValueFlowsThroughCand(arg, node, false) argumentValueFlowsThroughCand(arg, node, false)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate parameterValueFlowArgCand(ParameterNode p, ArgumentNode arg, boolean read) { private predicate parameterValueFlowArgCand(ParamNode p, ArgNode arg, boolean read) {
parameterValueFlowCand(p, arg, read) parameterValueFlowCand(p, arg, read)
} }
pragma[nomagic] pragma[nomagic]
predicate parameterValueFlowsToPreUpdateCand(ParameterNode p, PostUpdateNode n) { predicate parameterValueFlowsToPreUpdateCand(ParamNode p, PostUpdateNode n) {
parameterValueFlowCand(p, n.getPreUpdateNode(), false) parameterValueFlowCand(p, n.getPreUpdateNode(), false)
} }
@@ -360,7 +443,7 @@ private module Cached {
* `read` indicates whether it is contents of `p` that can flow to the return * `read` indicates whether it is contents of `p` that can flow to the return
* node. * node.
*/ */
predicate parameterValueFlowReturnCand(ParameterNode p, ReturnKind kind, boolean read) { predicate parameterValueFlowReturnCand(ParamNode p, ReturnKind kind, boolean read) {
exists(ReturnNode ret | exists(ReturnNode ret |
parameterValueFlowCand(p, ret, read) and parameterValueFlowCand(p, ret, read) and
kind = ret.getKind() kind = ret.getKind()
@@ -369,9 +452,9 @@ private module Cached {
pragma[nomagic] pragma[nomagic]
private predicate argumentValueFlowsThroughCand0( private predicate argumentValueFlowsThroughCand0(
DataFlowCall call, ArgumentNode arg, ReturnKind kind, boolean read DataFlowCall call, ArgNode arg, ReturnKind kind, boolean read
) { ) {
exists(ParameterNode param | viableParamArg(call, param, arg) | exists(ParamNode param | viableParamArg(call, param, arg) |
parameterValueFlowReturnCand(param, kind, read) parameterValueFlowReturnCand(param, kind, read)
) )
} }
@@ -382,14 +465,14 @@ private module Cached {
* *
* `read` indicates whether it is contents of `arg` that can flow to `out`. * `read` indicates whether it is contents of `arg` that can flow to `out`.
*/ */
predicate argumentValueFlowsThroughCand(ArgumentNode arg, Node out, boolean read) { predicate argumentValueFlowsThroughCand(ArgNode arg, Node out, boolean read) {
exists(DataFlowCall call, ReturnKind kind | exists(DataFlowCall call, ReturnKind kind |
argumentValueFlowsThroughCand0(call, arg, kind, read) and argumentValueFlowsThroughCand0(call, arg, kind, read) and
out = getAnOutNode(call, kind) out = getAnOutNode(call, kind)
) )
} }
predicate cand(ParameterNode p, Node n) { predicate cand(ParamNode p, Node n) {
parameterValueFlowCand(p, n, _) and parameterValueFlowCand(p, n, _) and
( (
parameterValueFlowReturnCand(p, _, _) parameterValueFlowReturnCand(p, _, _)
@@ -416,21 +499,21 @@ private module Cached {
* If a read step was taken, then `read` captures the `Content`, the * If a read step was taken, then `read` captures the `Content`, the
* container type, and the content type. * container type, and the content type.
*/ */
predicate parameterValueFlow(ParameterNode p, Node node, ReadStepTypesOption read) { predicate parameterValueFlow(ParamNode p, Node node, ReadStepTypesOption read) {
parameterValueFlow0(p, node, read) and parameterValueFlow0(p, node, read) and
if node instanceof CastingNode if node instanceof CastingNode
then then
// normal flow through // normal flow through
read = TReadStepTypesNone() and read = TReadStepTypesNone() and
compatibleTypes(getNodeType(p), getNodeType(node)) compatibleTypes(getNodeDataFlowType(p), getNodeDataFlowType(node))
or or
// getter // getter
compatibleTypes(read.getContentType(), getNodeType(node)) compatibleTypes(read.getContentType(), getNodeDataFlowType(node))
else any() else any()
} }
pragma[nomagic] pragma[nomagic]
private predicate parameterValueFlow0(ParameterNode p, Node node, ReadStepTypesOption read) { private predicate parameterValueFlow0(ParamNode p, Node node, ReadStepTypesOption read) {
p = node and p = node and
Cand::cand(p, _) and Cand::cand(p, _) and
read = TReadStepTypesNone() read = TReadStepTypesNone()
@@ -447,7 +530,7 @@ private module Cached {
readStepWithTypes(mid, read.getContainerType(), read.getContent(), node, readStepWithTypes(mid, read.getContainerType(), read.getContent(), node,
read.getContentType()) and read.getContentType()) and
Cand::parameterValueFlowReturnCand(p, _, true) and Cand::parameterValueFlowReturnCand(p, _, true) and
compatibleTypes(getNodeType(p), read.getContainerType()) compatibleTypes(getNodeDataFlowType(p), read.getContainerType())
) )
or or
parameterValueFlow0_0(TReadStepTypesNone(), p, node, read) parameterValueFlow0_0(TReadStepTypesNone(), p, node, read)
@@ -455,34 +538,32 @@ private module Cached {
pragma[nomagic] pragma[nomagic]
private predicate parameterValueFlow0_0( private predicate parameterValueFlow0_0(
ReadStepTypesOption mustBeNone, ParameterNode p, Node node, ReadStepTypesOption read ReadStepTypesOption mustBeNone, ParamNode p, Node node, ReadStepTypesOption read
) { ) {
// flow through: no prior read // flow through: no prior read
exists(ArgumentNode arg | exists(ArgNode arg |
parameterValueFlowArg(p, arg, mustBeNone) and parameterValueFlowArg(p, arg, mustBeNone) and
argumentValueFlowsThrough(arg, read, node) argumentValueFlowsThrough(arg, read, node)
) )
or or
// flow through: no read inside method // flow through: no read inside method
exists(ArgumentNode arg | exists(ArgNode arg |
parameterValueFlowArg(p, arg, read) and parameterValueFlowArg(p, arg, read) and
argumentValueFlowsThrough(arg, mustBeNone, node) argumentValueFlowsThrough(arg, mustBeNone, node)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate parameterValueFlowArg( private predicate parameterValueFlowArg(ParamNode p, ArgNode arg, ReadStepTypesOption read) {
ParameterNode p, ArgumentNode arg, ReadStepTypesOption read
) {
parameterValueFlow(p, arg, read) and parameterValueFlow(p, arg, read) and
Cand::argumentValueFlowsThroughCand(arg, _, _) Cand::argumentValueFlowsThroughCand(arg, _, _)
} }
pragma[nomagic] pragma[nomagic]
private predicate argumentValueFlowsThrough0( private predicate argumentValueFlowsThrough0(
DataFlowCall call, ArgumentNode arg, ReturnKind kind, ReadStepTypesOption read DataFlowCall call, ArgNode arg, ReturnKind kind, ReadStepTypesOption read
) { ) {
exists(ParameterNode param | viableParamArg(call, param, arg) | exists(ParamNode param | viableParamArg(call, param, arg) |
parameterValueFlowReturn(param, kind, read) parameterValueFlowReturn(param, kind, read)
) )
} }
@@ -496,18 +577,18 @@ private module Cached {
* container type, and the content type. * container type, and the content type.
*/ */
pragma[nomagic] pragma[nomagic]
predicate argumentValueFlowsThrough(ArgumentNode arg, ReadStepTypesOption read, Node out) { predicate argumentValueFlowsThrough(ArgNode arg, ReadStepTypesOption read, Node out) {
exists(DataFlowCall call, ReturnKind kind | exists(DataFlowCall call, ReturnKind kind |
argumentValueFlowsThrough0(call, arg, kind, read) and argumentValueFlowsThrough0(call, arg, kind, read) and
out = getAnOutNode(call, kind) out = getAnOutNode(call, kind)
| |
// normal flow through // normal flow through
read = TReadStepTypesNone() and read = TReadStepTypesNone() and
compatibleTypes(getNodeType(arg), getNodeType(out)) compatibleTypes(getNodeDataFlowType(arg), getNodeDataFlowType(out))
or or
// getter // getter
compatibleTypes(getNodeType(arg), read.getContainerType()) and compatibleTypes(getNodeDataFlowType(arg), read.getContainerType()) and
compatibleTypes(read.getContentType(), getNodeType(out)) compatibleTypes(read.getContentType(), getNodeDataFlowType(out))
) )
} }
@@ -516,7 +597,7 @@ private module Cached {
* value-preserving steps and a single read step, not taking call * value-preserving steps and a single read step, not taking call
* contexts into account, thus representing a getter-step. * contexts into account, thus representing a getter-step.
*/ */
predicate getterStep(ArgumentNode arg, Content c, Node out) { predicate getterStep(ArgNode arg, Content c, Node out) {
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out) argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
} }
@@ -529,7 +610,7 @@ private module Cached {
* container type, and the content type. * container type, and the content type.
*/ */
private predicate parameterValueFlowReturn( private predicate parameterValueFlowReturn(
ParameterNode p, ReturnKind kind, ReadStepTypesOption read ParamNode p, ReturnKind kind, ReadStepTypesOption read
) { ) {
exists(ReturnNode ret | exists(ReturnNode ret |
parameterValueFlow(p, ret, read) and parameterValueFlow(p, ret, read) and
@@ -553,7 +634,7 @@ private module Cached {
private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) { private predicate mayBenefitFromCallContextExt(DataFlowCall call, DataFlowCallable callable) {
mayBenefitFromCallContext(call, callable) mayBenefitFromCallContext(call, callable)
or or
callable = call.getEnclosingCallable() and callEnclosingCallable(call, callable) and
exists(viableCallableLambda(call, TDataFlowCallSome(_))) exists(viableCallableLambda(call, TDataFlowCallSome(_)))
} }
@@ -611,7 +692,7 @@ private module Cached {
mayBenefitFromCallContextExt(call, _) and mayBenefitFromCallContextExt(call, _) and
c = viableCallableExt(call) and c = viableCallableExt(call) and
ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContextExt(call, ctx)) and ctxtgts = count(DataFlowCall ctx | c = viableImplInCallContextExt(call, ctx)) and
tgts = strictcount(DataFlowCall ctx | viableCallableExt(ctx) = call.getEnclosingCallable()) and tgts = strictcount(DataFlowCall ctx | callEnclosingCallable(call, viableCallableExt(ctx))) and
ctxtgts < tgts ctxtgts < tgts
) )
} }
@@ -635,8 +716,7 @@ private module Cached {
* Holds if `p` can flow to the pre-update node associated with post-update * Holds if `p` can flow to the pre-update node associated with post-update
* node `n`, in the same callable, using only value-preserving steps. * node `n`, in the same callable, using only value-preserving steps.
*/ */
cached private predicate parameterValueFlowsToPreUpdate(ParamNode p, PostUpdateNode n) {
predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) {
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone()) parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
} }
@@ -644,9 +724,9 @@ private module Cached {
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
) { ) {
storeStep(node1, c, node2) and storeStep(node1, c, node2) and
readStep(_, c, _) and read(_, c, _) and
contentType = getNodeType(node1) and contentType = getNodeDataFlowType(node1) and
containerType = getNodeType(node2) containerType = getNodeDataFlowType(node2)
or or
exists(Node n1, Node n2 | exists(Node n1, Node n2 |
n1 = node1.(PostUpdateNode).getPreUpdateNode() and n1 = node1.(PostUpdateNode).getPreUpdateNode() and
@@ -654,12 +734,15 @@ private module Cached {
| |
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1) argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
or or
readStep(n2, c, n1) and read(n2, c, n1) and
contentType = getNodeType(n1) and contentType = getNodeDataFlowType(n1) and
containerType = getNodeType(n2) containerType = getNodeDataFlowType(n2)
) )
} }
cached
predicate read(Node node1, Content c, Node node2) { readStep(node1, c, node2) }
/** /**
* Holds if data can flow from `node1` to `node2` via a direct assignment to * Holds if data can flow from `node1` to `node2` via a direct assignment to
* `f`. * `f`.
@@ -678,8 +761,9 @@ private module Cached {
* are aliases. A typical example is a function returning `this`, implementing a fluent * are aliases. A typical example is a function returning `this`, implementing a fluent
* interface. * interface.
*/ */
cached private predicate reverseStepThroughInputOutputAlias(
predicate reverseStepThroughInputOutputAlias(PostUpdateNode fromNode, PostUpdateNode toNode) { PostUpdateNode fromNode, PostUpdateNode toNode
) {
exists(Node fromPre, Node toPre | exists(Node fromPre, Node toPre |
fromPre = fromNode.getPreUpdateNode() and fromPre = fromNode.getPreUpdateNode() and
toPre = toNode.getPreUpdateNode() toPre = toNode.getPreUpdateNode()
@@ -688,14 +772,20 @@ private module Cached {
// Does the language-specific simpleLocalFlowStep already model flow // Does the language-specific simpleLocalFlowStep already model flow
// from function input to output? // from function input to output?
fromPre = getAnOutNode(c, _) and fromPre = getAnOutNode(c, _) and
toPre.(ArgumentNode).argumentOf(c, _) and toPre.(ArgNode).argumentOf(c, _) and
simpleLocalFlowStep(toPre.(ArgumentNode), fromPre) simpleLocalFlowStep(toPre.(ArgNode), fromPre)
) )
or or
argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre) argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre)
) )
} }
cached
predicate simpleLocalFlowStepExt(Node node1, Node node2) {
simpleLocalFlowStep(node1, node2) or
reverseStepThroughInputOutputAlias(node1, node2)
}
/** /**
* Holds if the call context `call` either improves virtual dispatch in * Holds if the call context `call` either improves virtual dispatch in
* `callable` or if it allows us to prune unreachable nodes in `callable`. * `callable` or if it allows us to prune unreachable nodes in `callable`.
@@ -704,7 +794,7 @@ private module Cached {
predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) { predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
reducedViableImplInCallContext(_, callable, call) reducedViableImplInCallContext(_, callable, call)
or or
exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCall(n, call)) exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call))
} }
cached cached
@@ -726,12 +816,12 @@ private module Cached {
cached cached
newtype TLocalFlowCallContext = newtype TLocalFlowCallContext =
TAnyLocalCall() or TAnyLocalCall() or
TSpecificLocalCall(DataFlowCall call) { isUnreachableInCall(_, call) } TSpecificLocalCall(DataFlowCall call) { isUnreachableInCallCached(_, call) }
cached cached
newtype TReturnKindExt = newtype TReturnKindExt =
TValueReturn(ReturnKind kind) or TValueReturn(ReturnKind kind) or
TParamUpdate(int pos) { exists(ParameterNode p | p.isParameterOf(_, pos)) } TParamUpdate(int pos) { exists(ParamNode p | p.isParameterOf(_, pos)) }
cached cached
newtype TBooleanOption = newtype TBooleanOption =
@@ -761,23 +851,15 @@ private module Cached {
* A `Node` at which a cast can occur such that the type should be checked. * A `Node` at which a cast can occur such that the type should be checked.
*/ */
class CastingNode extends Node { class CastingNode extends Node {
CastingNode() { CastingNode() { castingNode(this) }
this instanceof ParameterNode or
this instanceof CastNode or
this instanceof OutNodeExt or
// For reads, `x.f`, we want to check that the tracked type after the read (which
// is obtained by popping the head of the access path stack) is compatible with
// the type of `x.f`.
readStep(_, _, this)
}
} }
private predicate readStepWithTypes( private predicate readStepWithTypes(
Node n1, DataFlowType container, Content c, Node n2, DataFlowType content Node n1, DataFlowType container, Content c, Node n2, DataFlowType content
) { ) {
readStep(n1, c, n2) and read(n1, c, n2) and
container = getNodeType(n1) and container = getNodeDataFlowType(n1) and
content = getNodeType(n2) content = getNodeDataFlowType(n2)
} }
private newtype TReadStepTypesOption = private newtype TReadStepTypesOption =
@@ -854,7 +936,7 @@ class CallContextSomeCall extends CallContextCall, TSomeCall {
override string toString() { result = "CcSomeCall" } override string toString() { result = "CcSomeCall" }
override predicate relevantFor(DataFlowCallable callable) { override predicate relevantFor(DataFlowCallable callable) {
exists(ParameterNode p | getNodeEnclosingCallable(p) = callable) exists(ParamNode p | getNodeEnclosingCallable(p) = callable)
} }
override predicate matchesCall(DataFlowCall call) { any() } override predicate matchesCall(DataFlowCall call) { any() }
@@ -866,7 +948,7 @@ class CallContextReturn extends CallContextNoCall, TReturn {
} }
override predicate relevantFor(DataFlowCallable callable) { override predicate relevantFor(DataFlowCallable callable) {
exists(DataFlowCall call | this = TReturn(_, call) and call.getEnclosingCallable() = callable) exists(DataFlowCall call | this = TReturn(_, call) and callEnclosingCallable(call, callable))
} }
} }
@@ -899,7 +981,7 @@ class LocalCallContextSpecificCall extends LocalCallContext, TSpecificLocalCall
} }
private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) { private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) {
exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCall(n, call)) exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCallCached(n, call))
} }
/** /**
@@ -913,26 +995,37 @@ LocalCallContext getLocalCallContext(CallContext ctx, DataFlowCallable callable)
else result instanceof LocalCallContextAny else result instanceof LocalCallContextAny
} }
/**
* The value of a parameter at function entry, viewed as a node in a data
* flow graph.
*/
class ParamNode extends Node {
ParamNode() { parameterNode(this, _, _) }
/**
* Holds if this node is the parameter of callable `c` at the specified
* (zero-based) position.
*/
predicate isParameterOf(DataFlowCallable c, int i) { parameterNode(this, c, i) }
}
/** A data-flow node that represents a call argument. */
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) }
}
/** /**
* A node from which flow can return to the caller. This is either a regular * A node from which flow can return to the caller. This is either a regular
* `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter. * `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter.
*/ */
class ReturnNodeExt extends Node { class ReturnNodeExt extends Node {
ReturnNodeExt() { ReturnNodeExt() { returnNodeExt(this, _) }
this instanceof ReturnNode or
parameterValueFlowsToPreUpdate(_, this)
}
/** Gets the kind of this returned value. */ /** Gets the kind of this returned value. */
ReturnKindExt getKind() { ReturnKindExt getKind() { returnNodeExt(this, result) }
result = TValueReturn(this.(ReturnNode).getKind())
or
exists(ParameterNode p, int pos |
parameterValueFlowsToPreUpdate(p, this) and
p.isParameterOf(_, pos) and
result = TParamUpdate(pos)
)
}
} }
/** /**
@@ -940,11 +1033,7 @@ class ReturnNodeExt extends Node {
* or a post-update node associated with a call argument. * or a post-update node associated with a call argument.
*/ */
class OutNodeExt extends Node { class OutNodeExt extends Node {
OutNodeExt() { OutNodeExt() { outNodeExt(this) }
this instanceof OutNode
or
this.(PostUpdateNode).getPreUpdateNode() instanceof ArgumentNode
}
} }
/** /**
@@ -957,7 +1046,7 @@ abstract class ReturnKindExt extends TReturnKindExt {
abstract string toString(); abstract string toString();
/** Gets a node corresponding to data flow out of `call`. */ /** Gets a node corresponding to data flow out of `call`. */
abstract OutNodeExt getAnOutNode(DataFlowCall call); final OutNodeExt getAnOutNode(DataFlowCall call) { result = getAnOutNodeExt(call, this) }
} }
class ValueReturnKind extends ReturnKindExt, TValueReturn { class ValueReturnKind extends ReturnKindExt, TValueReturn {
@@ -968,10 +1057,6 @@ class ValueReturnKind extends ReturnKindExt, TValueReturn {
ReturnKind getKind() { result = kind } ReturnKind getKind() { result = kind }
override string toString() { result = kind.toString() } override string toString() { result = kind.toString() }
override OutNodeExt getAnOutNode(DataFlowCall call) {
result = getAnOutNode(call, this.getKind())
}
} }
class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate { class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
@@ -982,13 +1067,6 @@ class ParamUpdateReturnKind extends ReturnKindExt, TParamUpdate {
int getPosition() { result = pos } int getPosition() { result = pos }
override string toString() { result = "param update " + pos } override string toString() { result = "param update " + pos }
override OutNodeExt getAnOutNode(DataFlowCall call) {
exists(ArgumentNode arg |
result.(PostUpdateNode).getPreUpdateNode() = arg and
arg.argumentOf(call, this.getPosition())
)
}
} }
/** A callable tagged with a relevant return kind. */ /** A callable tagged with a relevant return kind. */
@@ -1015,10 +1093,13 @@ class ReturnPosition extends TReturnPosition0 {
*/ */
pragma[inline] pragma[inline]
DataFlowCallable getNodeEnclosingCallable(Node n) { DataFlowCallable getNodeEnclosingCallable(Node n) {
exists(Node n0 | nodeEnclosingCallable(pragma[only_bind_out](n), pragma[only_bind_into](result))
pragma[only_bind_into](n0) = n and }
pragma[only_bind_into](result) = n0.getEnclosingCallable()
) /** Gets the type of `n` used for type pruning. */
pragma[inline]
DataFlowType getNodeDataFlowType(Node n) {
nodeDataFlowType(pragma[only_bind_out](n), pragma[only_bind_into](result))
} }
pragma[noinline] pragma[noinline]
@@ -1042,7 +1123,7 @@ predicate resolveReturn(CallContext cc, DataFlowCallable callable, DataFlowCall
cc instanceof CallContextAny and callable = viableCallableExt(call) cc instanceof CallContextAny and callable = viableCallableExt(call)
or or
exists(DataFlowCallable c0, DataFlowCall call0 | exists(DataFlowCallable c0, DataFlowCall call0 |
call0.getEnclosingCallable() = callable and callEnclosingCallable(call0, callable) and
cc = TReturn(c0, call0) and cc = TReturn(c0, call0) and
c0 = prunedViableImplInCallContextReverse(call0, call) c0 = prunedViableImplInCallContextReverse(call0, call)
) )
@@ -1063,8 +1144,6 @@ DataFlowCallable resolveCall(DataFlowCall call, CallContext cc) {
result = viableCallableExt(call) and cc instanceof CallContextReturn result = viableCallableExt(call) and cc instanceof CallContextReturn
} }
predicate read = readStep/3;
/** An optional Boolean value. */ /** An optional Boolean value. */
class BooleanOption extends TBooleanOption { class BooleanOption extends TBooleanOption {
string toString() { string toString() {
@@ -1116,7 +1195,7 @@ abstract class AccessPathFront extends TAccessPathFront {
TypedContent getHead() { this = TFrontHead(result) } TypedContent getHead() { this = TFrontHead(result) }
predicate isClearedAt(Node n) { clearsContent(n, getHead().getContent()) } predicate isClearedAt(Node n) { clearsContentCached(n, getHead().getContent()) }
} }
class AccessPathFrontNil extends AccessPathFront, TFrontNil { class AccessPathFrontNil extends AccessPathFront, TFrontNil {

View File

@@ -228,7 +228,6 @@ module EssaFlow {
* data flow. It is a strict subset of the `localFlowStep` predicate, as it * data flow. It is a strict subset of the `localFlowStep` predicate, as it
* excludes SSA flow through instance fields. * excludes SSA flow through instance fields.
*/ */
cached
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
// If there is ESSA-flow out of a node `node`, we want flow // If there is ESSA-flow out of a node `node`, we want flow
// both out of `node` and any post-update node of `node`. // both out of `node` and any post-update node of `node`.
@@ -1559,7 +1558,6 @@ predicate kwUnpackReadStep(CfgNode nodeFrom, DictionaryElementContent c, Node no
* any value stored inside `f` is cleared at the pre-update node associated with `x` * any value stored inside `f` is cleared at the pre-update node associated with `x`
* in `x.f = newValue`. * in `x.f = newValue`.
*/ */
cached
predicate clearsContent(Node n, Content c) { predicate clearsContent(Node n, Content c) {
exists(CallNode call, CallableValue callable, string name | exists(CallNode call, CallableValue callable, string name |
call_unpacks(call, _, callable, name, _) and call_unpacks(call, _, callable, name, _) and

View File

@@ -9,36 +9,42 @@ private import semmle.python.dataflow.new.internal.TaintTrackingPublic
*/ */
predicate defaultTaintSanitizer(DataFlow::Node node) { none() } predicate defaultTaintSanitizer(DataFlow::Node node) { none() }
/** private module Cached {
* Holds if the additional step from `nodeFrom` to `nodeTo` should be included in all /**
* global taint flow configurations. * Holds if the additional step from `nodeFrom` to `nodeTo` should be included in all
*/ * global taint flow configurations.
predicate defaultAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { */
localAdditionalTaintStep(nodeFrom, nodeTo) cached
or predicate defaultAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
any(AdditionalTaintStep a).step(nodeFrom, nodeTo) localAdditionalTaintStep(nodeFrom, nodeTo)
or
any(AdditionalTaintStep a).step(nodeFrom, nodeTo)
}
/**
* Holds if taint can flow in one local step from `nodeFrom` to `nodeTo` excluding
* local data flow steps. That is, `nodeFrom` and `nodeTo` are likely to represent
* different objects.
*/
cached
predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
concatStep(nodeFrom, nodeTo)
or
subscriptStep(nodeFrom, nodeTo)
or
stringManipulation(nodeFrom, nodeTo)
or
containerStep(nodeFrom, nodeTo)
or
copyStep(nodeFrom, nodeTo)
or
forStep(nodeFrom, nodeTo)
or
unpackingAssignmentStep(nodeFrom, nodeTo)
}
} }
/** import Cached
* Holds if taint can flow in one local step from `nodeFrom` to `nodeTo` excluding
* local data flow steps. That is, `nodeFrom` and `nodeTo` are likely to represent
* different objects.
*/
predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
concatStep(nodeFrom, nodeTo)
or
subscriptStep(nodeFrom, nodeTo)
or
stringManipulation(nodeFrom, nodeTo)
or
containerStep(nodeFrom, nodeTo)
or
copyStep(nodeFrom, nodeTo)
or
forStep(nodeFrom, nodeTo)
or
unpackingAssignmentStep(nodeFrom, nodeTo)
}
/** /**
* Holds if taint can flow from `nodeFrom` to `nodeTo` with a step related to concatenation. * Holds if taint can flow from `nodeFrom` to `nodeTo` with a step related to concatenation.