Skip to content

Commit 492add1

Browse files
committed
Data flow: Force join-order for Node::getEnclosingCallable()
1 parent 32f1da7 commit 492add1

File tree

2 files changed

+53
-53
lines changed

2 files changed

+53
-53
lines changed

csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll

Lines changed: 36 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -207,18 +207,6 @@ private predicate fullBarrier(Node node, Configuration config) {
207207
)
208208
}
209209

210-
private class AdditionalFlowStepSource extends Node {
211-
AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) }
212-
}
213-
214-
pragma[noinline]
215-
private predicate isAdditionalFlowStep(
216-
AdditionalFlowStepSource node1, Node node2, DataFlowCallable callable1, Configuration config
217-
) {
218-
config.isAdditionalFlowStep(node1, node2) and
219-
callable1 = node1.getEnclosingCallable()
220-
}
221-
222210
/**
223211
* Holds if data can flow in one local step from `node1` to `node2`.
224212
*/
@@ -237,7 +225,8 @@ private predicate localFlowStep(Node node1, Node node2, Configuration config) {
237225
* Holds if the additional step from `node1` to `node2` does not jump between callables.
238226
*/
239227
private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
240-
isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and
228+
config.isAdditionalFlowStep(node1, node2) and
229+
getNodeEnclosingCallable(node1) = getNodeEnclosingCallable(node2) and
241230
not outBarrier(node1, config) and
242231
not inBarrier(node2, config) and
243232
not fullBarrier(node1, config) and
@@ -259,14 +248,12 @@ private predicate jumpStep(Node node1, Node node2, Configuration config) {
259248
* Holds if the additional step from `node1` to `node2` jumps between callables.
260249
*/
261250
private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
262-
exists(DataFlowCallable callable1 |
263-
isAdditionalFlowStep(node1, node2, callable1, config) and
264-
node2.getEnclosingCallable() != callable1 and
265-
not outBarrier(node1, config) and
266-
not inBarrier(node2, config) and
267-
not fullBarrier(node1, config) and
268-
not fullBarrier(node2, config)
269-
)
251+
config.isAdditionalFlowStep(node1, node2) and
252+
getNodeEnclosingCallable(node1) != getNodeEnclosingCallable(node2) and
253+
not outBarrier(node1, config) and
254+
not inBarrier(node2, config) and
255+
not fullBarrier(node1, config) and
256+
not fullBarrier(node2, config)
270257
}
271258

272259
/**
@@ -601,7 +588,7 @@ private module Stage1 {
601588
) {
602589
exists(ReturnNodeExt ret |
603590
throughFlowNodeCand(ret, config) and
604-
callable = ret.getEnclosingCallable() and
591+
callable = getNodeEnclosingCallable(ret) and
605592
kind = ret.getKind()
606593
)
607594
}
@@ -614,7 +601,7 @@ private module Stage1 {
614601
exists(ReturnKindExt kind |
615602
throughFlowNodeCand(p, config) and
616603
returnFlowCallableNodeCand(c, kind, config) and
617-
p.getEnclosingCallable() = c and
604+
getNodeEnclosingCallable(p) = c and
618605
exists(ap) and
619606
// we don't expect a parameter to return stored in itself
620607
not exists(int pos |
@@ -966,7 +953,7 @@ private module Stage2 {
966953
exists(ArgumentNode arg, boolean allowsFieldFlow |
967954
fwdFlow(arg, outercc, argAp, ap, config) and
968955
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
969-
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
956+
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
970957
|
971958
ap instanceof ApNil or allowsFieldFlow = true
972959
)
@@ -985,7 +972,7 @@ private module Stage2 {
985972
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
986973
fwdFlow(ret, innercc, argAp, ap, config) and
987974
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
988-
inner = ret.getEnclosingCallable() and
975+
inner = getNodeEnclosingCallable(ret) and
989976
checkCallContextReturn(innercc, inner, call) and
990977
ccOut = getCallContextReturn(inner, call)
991978
|
@@ -1216,13 +1203,13 @@ private module Stage2 {
12161203
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
12171204
) {
12181205
revFlow(p, true, apSome(ap0), ap, config) and
1219-
c = p.getEnclosingCallable()
1206+
c = getNodeEnclosingCallable(p)
12201207
}
12211208

12221209
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
12231210
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
12241211
parameterFlow(p, ap, ap0, c, config) and
1225-
c = ret.getEnclosingCallable() and
1212+
c = getNodeEnclosingCallable(ret) and
12261213
revFlow(ret, true, apSome(_), ap0, config) and
12271214
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
12281215
kind = ret.getKind() and
@@ -1348,7 +1335,7 @@ private module LocalFlowBigStep {
13481335
t = getNodeType(node2)
13491336
) and
13501337
node1 != node2 and
1351-
cc.relevantFor(node1.getEnclosingCallable()) and
1338+
cc.relevantFor(getNodeEnclosingCallable(node1)) and
13521339
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
13531340
Stage2::revFlow(node2, unbind(config))
13541341
or
@@ -1594,7 +1581,7 @@ private module Stage3 {
15941581
exists(ArgumentNode arg, boolean allowsFieldFlow |
15951582
fwdFlow(arg, outercc, argAp, ap, config) and
15961583
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
1597-
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
1584+
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
15981585
|
15991586
ap instanceof ApNil or allowsFieldFlow = true
16001587
)
@@ -1613,7 +1600,7 @@ private module Stage3 {
16131600
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
16141601
fwdFlow(ret, innercc, argAp, ap, config) and
16151602
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
1616-
inner = ret.getEnclosingCallable() and
1603+
inner = getNodeEnclosingCallable(ret) and
16171604
checkCallContextReturn(innercc, inner, call) and
16181605
ccOut = getCallContextReturn(inner, call)
16191606
|
@@ -1844,13 +1831,13 @@ private module Stage3 {
18441831
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
18451832
) {
18461833
revFlow(p, true, apSome(ap0), ap, config) and
1847-
c = p.getEnclosingCallable()
1834+
c = getNodeEnclosingCallable(p)
18481835
}
18491836

18501837
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
18511838
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
18521839
parameterFlow(p, ap, ap0, c, config) and
1853-
c = ret.getEnclosingCallable() and
1840+
c = getNodeEnclosingCallable(ret) and
18541841
revFlow(ret, true, apSome(_), ap0, config) and
18551842
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
18561843
kind = ret.getKind() and
@@ -2135,7 +2122,7 @@ private module Stage4 {
21352122
bindingset[node, cc, config]
21362123
private LocalCc getLocalCc(Node node, Cc cc, Configuration config) {
21372124
localFlowEntry(node, config) and
2138-
result = getLocalCallContext(cc, node.getEnclosingCallable())
2125+
result = getLocalCallContext(cc, getNodeEnclosingCallable(node))
21392126
}
21402127

21412128
private predicate localStep(
@@ -2300,7 +2287,7 @@ private module Stage4 {
23002287
exists(ArgumentNode arg, boolean allowsFieldFlow |
23012288
fwdFlow(arg, outercc, argAp, ap, config) and
23022289
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
2303-
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
2290+
innercc = getCallContextCall(call, getNodeEnclosingCallable(p), outercc)
23042291
|
23052292
ap instanceof ApNil or allowsFieldFlow = true
23062293
)
@@ -2319,7 +2306,7 @@ private module Stage4 {
23192306
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
23202307
fwdFlow(ret, innercc, argAp, ap, config) and
23212308
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
2322-
inner = ret.getEnclosingCallable() and
2309+
inner = getNodeEnclosingCallable(ret) and
23232310
checkCallContextReturn(innercc, inner, call) and
23242311
ccOut = getCallContextReturn(inner, call)
23252312
|
@@ -2550,13 +2537,13 @@ private module Stage4 {
25502537
ParameterNode p, Ap ap, Ap ap0, DataFlowCallable c, Configuration config
25512538
) {
25522539
revFlow(p, true, apSome(ap0), ap, config) and
2553-
c = p.getEnclosingCallable()
2540+
c = getNodeEnclosingCallable(p)
25542541
}
25552542

25562543
predicate parameterMayFlowThrough(ParameterNode p, DataFlowCallable c, Ap ap, Configuration config) {
25572544
exists(ReturnNodeExt ret, Ap ap0, ReturnKindExt kind, int pos |
25582545
parameterFlow(p, ap, ap0, c, config) and
2559-
c = ret.getEnclosingCallable() and
2546+
c = getNodeEnclosingCallable(ret) and
25602547
revFlow(ret, true, apSome(_), ap0, config) and
25612548
fwdFlow(ret, any(CcCall ccc), apSome(ap), ap0, config) and
25622549
kind = ret.getKind() and
@@ -2590,7 +2577,7 @@ private predicate nodeMayUseSummary(Node n, AccessPathApprox apa, Configuration
25902577
Stage4::parameterMayFlowThrough(_, c, apa, _) and
25912578
Stage4::revFlow(n, true, _, apa0, config) and
25922579
Stage4::fwdFlow(n, any(CallContextCall ccc), TAccessPathApproxSome(apa), apa0, config) and
2593-
n.getEnclosingCallable() = c
2580+
getNodeEnclosingCallable(n) = c
25942581
)
25952582
}
25962583

@@ -3119,7 +3106,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, SummaryCt
31193106
conf = mid.getConfiguration() and
31203107
cc = mid.getCallContext() and
31213108
sc = mid.getSummaryCtx() and
3122-
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
3109+
localCC = getLocalCallContext(cc, getNodeEnclosingCallable(midnode)) and
31233110
ap0 = mid.getAp()
31243111
|
31253112
localFlowBigStep(midnode, node, true, _, conf, localCC) and
@@ -3405,22 +3392,22 @@ private module FlowExploration {
34053392
// flow out of a callable
34063393
viableReturnPosOut(_, getReturnPosition(node1), node2)
34073394
|
3408-
c1 = node1.getEnclosingCallable() and
3409-
c2 = node2.getEnclosingCallable() and
3395+
c1 = getNodeEnclosingCallable(node1) and
3396+
c2 = getNodeEnclosingCallable(node2) and
34103397
c1 != c2
34113398
)
34123399
}
34133400

34143401
private predicate interestingCallableSrc(DataFlowCallable c, Configuration config) {
3415-
exists(Node n | config.isSource(n) and c = n.getEnclosingCallable())
3402+
exists(Node n | config.isSource(n) and c = getNodeEnclosingCallable(n))
34163403
or
34173404
exists(DataFlowCallable mid |
34183405
interestingCallableSrc(mid, config) and callableStep(mid, c, config)
34193406
)
34203407
}
34213408

34223409
private predicate interestingCallableSink(DataFlowCallable c, Configuration config) {
3423-
exists(Node n | config.isSink(n) and c = n.getEnclosingCallable())
3410+
exists(Node n | config.isSink(n) and c = getNodeEnclosingCallable(n))
34243411
or
34253412
exists(DataFlowCallable mid |
34263413
interestingCallableSink(mid, config) and callableStep(c, mid, config)
@@ -3449,13 +3436,13 @@ private module FlowExploration {
34493436
exists(Node n, Configuration config |
34503437
ce1 = TCallableSrc() and
34513438
config.isSource(n) and
3452-
ce2 = TCallable(n.getEnclosingCallable(), config)
3439+
ce2 = TCallable(getNodeEnclosingCallable(n), config)
34533440
)
34543441
or
34553442
exists(Node n, Configuration config |
34563443
ce2 = TCallableSink() and
34573444
config.isSink(n) and
3458-
ce1 = TCallable(n.getEnclosingCallable(), config)
3445+
ce1 = TCallable(getNodeEnclosingCallable(n), config)
34593446
)
34603447
}
34613448

@@ -3586,7 +3573,7 @@ private module FlowExploration {
35863573
exists(config.explorationLimit())
35873574
or
35883575
partialPathNodeMk0(node, cc, sc1, sc2, ap, config) and
3589-
distSrc(node.getEnclosingCallable(), config) <= config.explorationLimit()
3576+
distSrc(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
35903577
} or
35913578
TPartialPathNodeRev(
35923579
Node node, TRevSummaryCtx1 sc1, TRevSummaryCtx2 sc2, RevPartialAccessPath ap,
@@ -3603,7 +3590,7 @@ private module FlowExploration {
36033590
revPartialPathStep(mid, node, sc1, sc2, ap, config) and
36043591
not clearsContent(node, ap.getHead()) and
36053592
not fullBarrier(node, config) and
3606-
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
3593+
distSink(getNodeEnclosingCallable(node), config) <= config.explorationLimit()
36073594
)
36083595
}
36093596

@@ -3662,15 +3649,15 @@ private module FlowExploration {
36623649
* of interprocedural steps.
36633650
*/
36643651
int getSourceDistance() {
3665-
result = distSrc(this.getNode().getEnclosingCallable(), this.getConfiguration())
3652+
result = distSrc(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
36663653
}
36673654

36683655
/**
36693656
* Gets the approximate distance to the nearest sink measured in number
36703657
* of interprocedural steps.
36713658
*/
36723659
int getSinkDistance() {
3673-
result = distSink(this.getNode().getEnclosingCallable(), this.getConfiguration())
3660+
result = distSink(getNodeEnclosingCallable(this.getNode()), this.getConfiguration())
36743661
}
36753662

36763663
private string ppAp() {

csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ private module Cached {
447447
predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
448448
reducedViableImplInCallContext(_, callable, call)
449449
or
450-
exists(Node n | n.getEnclosingCallable() = callable | isUnreachableInCall(n, call))
450+
exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCall(n, call))
451451
}
452452

453453
cached
@@ -592,7 +592,7 @@ class CallContextSomeCall extends CallContextCall, TSomeCall {
592592
override string toString() { result = "CcSomeCall" }
593593

594594
override predicate relevantFor(DataFlowCallable callable) {
595-
exists(ParameterNode p | p.getEnclosingCallable() = callable)
595+
exists(ParameterNode p | getNodeEnclosingCallable(p) = callable)
596596
}
597597

598598
override predicate matchesCall(DataFlowCall call) { any() }
@@ -637,7 +637,7 @@ class LocalCallContextSpecificCall extends LocalCallContext, TSpecificLocalCall
637637
}
638638

639639
private predicate relevantLocalCCtx(DataFlowCall call, DataFlowCallable callable) {
640-
exists(Node n | n.getEnclosingCallable() = callable and isUnreachableInCall(n, call))
640+
exists(Node n | getNodeEnclosingCallable(n) = callable and isUnreachableInCall(n, call))
641641
}
642642

643643
/**
@@ -746,9 +746,22 @@ class ReturnPosition extends TReturnPosition0 {
746746
string toString() { result = "[" + kind + "] " + c }
747747
}
748748

749+
/**
750+
* Gets the enclosing callable of `n`. Unlike `n.getEnclosingCallable()`, this
751+
* predicate ensures that joins go from `n` to the result instead of the other
752+
* way around.
753+
*/
754+
pragma[inline]
755+
DataFlowCallable getNodeEnclosingCallable(Node n) {
756+
exists(Node n0 |
757+
pragma[only_bind_into](n0) = n and
758+
result = n0.getEnclosingCallable()
759+
)
760+
}
761+
749762
pragma[noinline]
750763
private DataFlowCallable returnNodeGetEnclosingCallable(ReturnNodeExt ret) {
751-
result = ret.getEnclosingCallable()
764+
result = getNodeEnclosingCallable(ret)
752765
}
753766

754767
pragma[noinline]

0 commit comments

Comments
 (0)