Skip to content

Commit aa22aad

Browse files
committed
Data flow: Depth 1 call contexts in store/load matching
1 parent 434fad7 commit aa22aad

File tree

2 files changed

+188
-76
lines changed

2 files changed

+188
-76
lines changed

shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll

+108-23
Original file line numberDiff line numberDiff line change
@@ -2572,23 +2572,25 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
25722572

25732573
pragma[nomagic]
25742574
private predicate revFlowThroughArg(
2575-
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
2576-
Ap ap
2575+
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, FlowState state, ReturnCtx returnCtx,
2576+
ApOption returnAp, Ap ap
25772577
) {
2578-
exists(ParamNodeEx p, Ap innerReturnAp |
2578+
exists(Ap innerReturnAp |
25792579
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp) and
25802580
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp)
25812581
)
25822582
}
25832583

25842584
pragma[nomagic]
2585-
predicate callMayFlowThroughRev(DataFlowCall call) {
2585+
additional predicate callMayFlowThroughRev(DataFlowCall call, ParamNodeEx p) {
25862586
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
25872587
revFlow(arg, state, returnCtx, returnAp, ap) and
2588-
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap)
2588+
revFlowThroughArg(call, arg, p, state, returnCtx, returnAp, ap)
25892589
)
25902590
}
25912591

2592+
predicate callMayFlowThroughRev(DataFlowCall call) { callMayFlowThroughRev(call, _) }
2593+
25922594
predicate callEdgeArgParam(
25932595
DataFlowCall call, DataFlowCallable c, ArgNodeEx arg, ParamNodeEx p,
25942596
boolean allowsFieldFlow, Ap ap
@@ -3856,24 +3858,68 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
38563858
private module StoreReadMatchingInput implements StoreReadMatchingInputSig {
38573859
class NodeEx = NodeExAlias;
38583860

3859-
predicate nodeRange(NodeEx node, boolean fromArg) {
3860-
exists(PrevStage::Ap ap |
3861-
PrevStage::revFlowAp(node, ap) and
3861+
/**
3862+
* Gets a call context for `node` that is relevant for either improved virtual
3863+
* dispatch or for flow-through.
3864+
*/
3865+
pragma[nomagic]
3866+
private DataFlowCallOption getACallCtx(NodeEx node, PrevStage::Ap ap, boolean fromArg) {
3867+
exists(PrevStage::Cc cc, ParamNodeOption summaryCtx, PrevStage::ApOption argAp |
3868+
PrevStage::fwdFlow(node, _, cc, summaryCtx, _, argAp, _, ap, _)
3869+
|
3870+
PrevStage::instanceofCcCall(cc) and
3871+
fromArg = true and
38623872
(
3863-
ap = true
3864-
or
3865-
PrevStage::storeStepCand(node, ap, _, _, _, _)
3873+
// virtual dispatch may be improved
3874+
exists(DataFlowCall call, DataFlowCallable c |
3875+
PrevStage::callEdgeArgParam(call, c, _, _, _, _) and
3876+
cc = Stage2Param::getSpecificCallContextCall(call, c) and
3877+
c = node.getEnclosingCallable() and
3878+
result = TDataFlowCallSome(call)
3879+
)
38663880
or
3867-
PrevStage::readStepCand(_, _, node)
3881+
not cc = Stage2Param::getSpecificCallContextCall(_, _) and
3882+
(
3883+
// flow-through not possible
3884+
summaryCtx instanceof TParamNodeNone and
3885+
result = TDataFlowCallNone()
3886+
or
3887+
exists(DataFlowCall call, ParamNodeEx p, PrevStage::Ap argApSome |
3888+
summaryCtx = TParamNodeSome(p.asNode()) and
3889+
argAp = PrevStage::apSome(argApSome)
3890+
|
3891+
if
3892+
PrevStage::parameterMayFlowThrough(p, argApSome) and
3893+
PrevStage::callMayFlowThroughRev(call, p)
3894+
then
3895+
// flow-through possible
3896+
result = TDataFlowCallSome(call)
3897+
else (
3898+
// flow-through not possible, but `node` can reach a sink without
3899+
// flowing back out
3900+
PrevStage::callEdgeArgParam(call, _, _, p, _, _) and
3901+
result = TDataFlowCallNone()
3902+
)
3903+
)
3904+
)
38683905
)
3906+
or
3907+
PrevStage::instanceofCcNoCall(cc) and
3908+
fromArg = false and
3909+
result = TDataFlowCallNone()
3910+
)
3911+
}
3912+
3913+
predicate nodeRange(NodeEx node, boolean fromArg, DataFlowCallOption summaryCtx) {
3914+
exists(PrevStage::Ap ap |
3915+
PrevStage::revFlowAp(node, ap) and
3916+
summaryCtx = getACallCtx(node, ap, fromArg)
38693917
|
3870-
exists(PrevStage::Cc cc | PrevStage::fwdFlow(node, _, cc, _, _, _, _, ap, _) |
3871-
PrevStage::instanceofCcCall(cc) and
3872-
fromArg = true
3873-
or
3874-
PrevStage::instanceofCcNoCall(cc) and
3875-
fromArg = false
3876-
)
3918+
ap = true
3919+
or
3920+
PrevStage::storeStepCand(node, ap, _, _, _, _)
3921+
or
3922+
PrevStage::readStepCand(_, _, node)
38773923
)
38783924
}
38793925

@@ -3899,12 +3945,51 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
38993945
)
39003946
}
39013947

3902-
predicate callEdgeArgParam(NodeEx arg, NodeEx param) {
3903-
PrevStage::callEdgeArgParam(_, _, arg, param, true, true)
3948+
pragma[nomagic]
3949+
private predicate callEdgeArgParam(
3950+
DataFlowCall call, DataFlowCallable c, NodeEx arg, NodeEx param,
3951+
DataFlowCallOption innerCallCtx
3952+
) {
3953+
PrevStage::callEdgeArgParam(call, c, arg, param, true, true) and
3954+
innerCallCtx = getACallCtx(param, true, true) and
3955+
(
3956+
innerCallCtx = TDataFlowCallNone()
3957+
or
3958+
innerCallCtx = TDataFlowCallSome(call)
3959+
)
3960+
}
3961+
3962+
pragma[nomagic]
3963+
private predicate callEdgeArgParamCallContextReduced(
3964+
DataFlowCall call, NodeEx arg, NodeEx param, Stage2Param::CcCall outerCcCall,
3965+
DataFlowCallOption innerCallCtx
3966+
) {
3967+
exists(DataFlowCallable c |
3968+
callEdgeArgParam(call, c, arg, param, innerCallCtx) and
3969+
Stage2Param::viableImplCallContextReduced(call, outerCcCall) = c
3970+
)
3971+
}
3972+
3973+
bindingset[outerCallCtx]
3974+
predicate callEdgeArgParam(
3975+
NodeEx arg, NodeEx param, DataFlowCallOption outerCallCtx, DataFlowCallOption innerCallCtx
3976+
) {
3977+
exists(DataFlowCall call | callEdgeArgParam(call, _, arg, param, innerCallCtx) |
3978+
outerCallCtx = TDataFlowCallNone()
3979+
or
3980+
exists(DataFlowCall outerCall, Stage2Param::CcCall outerCcCall |
3981+
outerCallCtx = TDataFlowCallSome(outerCall) and
3982+
outerCcCall = Stage2Param::getCallContextCall(outerCall, call.getEnclosingCallable())
3983+
|
3984+
callEdgeArgParamCallContextReduced(call, arg, param, outerCcCall, innerCallCtx)
3985+
or
3986+
Stage2Param::viableImplNotCallContextReduced(call, outerCcCall)
3987+
)
3988+
)
39043989
}
39053990

3906-
predicate callEdgeReturn(NodeEx ret, NodeEx out, boolean mayFlowThrough) {
3907-
PrevStage::callEdgeReturn(_, _, ret, _, out, true, true) and
3991+
predicate callEdgeReturn(DataFlowCall call, NodeEx ret, NodeEx out, boolean mayFlowThrough) {
3992+
PrevStage::callEdgeReturn(call, _, ret, _, out, true, true) and
39083993
if flowThroughOutOfCall(ret, out) then mayFlowThrough = true else mayFlowThrough = false
39093994
}
39103995

0 commit comments

Comments
 (0)