Skip to content

Commit 13806f5

Browse files
committed
Data flow: Depth 1 call contexts in store/load matching
1 parent ddd4af0 commit 13806f5

File tree

2 files changed

+193
-82
lines changed

2 files changed

+193
-82
lines changed

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

Lines changed: 113 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1616,9 +1616,9 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
16161616
)
16171617
}
16181618

1619-
private newtype TSummaryCtx =
1620-
TSummaryCtxNone() or
1621-
TSummaryCtxSome(ParamNodeEx p, FlowState state, Typ t, Ap ap) {
1619+
additional newtype TSummaryCtx =
1620+
additional TSummaryCtxNone() or
1621+
additional TSummaryCtxSome(ParamNodeEx p, FlowState state, Typ t, Ap ap) {
16221622
fwdFlowIn(p, _, state, _, t, ap, true)
16231623
}
16241624

@@ -1628,21 +1628,21 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
16281628
*
16291629
* Summaries are only created for parameters that may flow through.
16301630
*/
1631-
private class SummaryCtx extends TSummaryCtx {
1631+
additional class SummaryCtx extends TSummaryCtx {
16321632
abstract string toString();
16331633

16341634
abstract Location getLocation();
16351635
}
16361636

16371637
/** A summary context from which no flow summary can be generated. */
1638-
private class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
1638+
additional class SummaryCtxNone extends SummaryCtx, TSummaryCtxNone {
16391639
override string toString() { result = "<none>" }
16401640

16411641
override Location getLocation() { result.hasLocationInfo("", 0, 0, 0, 0) }
16421642
}
16431643

16441644
/** A summary context from which a flow summary can be generated. */
1645-
private class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
1645+
additional class SummaryCtxSome extends SummaryCtx, TSummaryCtxSome {
16461646
private ParamNodeEx p;
16471647
private FlowState state;
16481648
private Typ t;
@@ -2650,23 +2650,25 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
26502650

26512651
pragma[nomagic]
26522652
private predicate revFlowThroughArg(
2653-
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
2654-
Ap ap
2653+
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, FlowState state, ReturnCtx returnCtx,
2654+
ApOption returnAp, Ap ap
26552655
) {
2656-
exists(ParamNodeEx p, Ap innerReturnAp |
2656+
exists(Ap innerReturnAp |
26572657
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp) and
26582658
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp)
26592659
)
26602660
}
26612661

26622662
pragma[nomagic]
2663-
predicate callMayFlowThroughRev(DataFlowCall call) {
2663+
additional predicate callMayFlowThroughRev(DataFlowCall call, ParamNodeEx p) {
26642664
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
26652665
revFlow(arg, state, returnCtx, returnAp, ap) and
2666-
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap)
2666+
revFlowThroughArg(call, arg, p, state, returnCtx, returnAp, ap)
26672667
)
26682668
}
26692669

2670+
predicate callMayFlowThroughRev(DataFlowCall call) { callMayFlowThroughRev(call, _) }
2671+
26702672
predicate callEdgeArgParam(
26712673
DataFlowCall call, DataFlowCallable c, ArgNodeEx arg, ParamNodeEx p,
26722674
boolean allowsFieldFlow, Ap ap
@@ -3931,24 +3933,67 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
39313933
private module StoreReadMatchingInput implements StoreReadMatchingInputSig {
39323934
class NodeEx = NodeExAlias;
39333935

3934-
predicate nodeRange(NodeEx node, boolean fromArg) {
3935-
exists(PrevStage::Ap ap |
3936-
PrevStage::revFlowAp(node, ap) and
3936+
/**
3937+
* Gets a call context for `node` that is relevant for either improved virtual
3938+
* dispatch or for flow-through.
3939+
*/
3940+
pragma[nomagic]
3941+
private DataFlowCallOption getACallCtx(NodeEx node, PrevStage::Ap ap, boolean fromArg) {
3942+
exists(PrevStage::Cc cc, PrevStage::SummaryCtx summaryCtx |
3943+
PrevStage::fwdFlow(node, _, cc, summaryCtx, _, ap, _)
3944+
|
3945+
PrevStage::instanceofCcCall(cc) and
3946+
fromArg = true and
39373947
(
3938-
ap = true
3939-
or
3940-
PrevStage::storeStepCand(node, ap, _, _, _, _)
3948+
// virtual dispatch may be improved
3949+
exists(DataFlowCall call, DataFlowCallable c |
3950+
PrevStage::callEdgeArgParam(call, c, _, _, _, _) and
3951+
cc = Stage2Param::getSpecificCallContextCall(call, c) and
3952+
c = node.getEnclosingCallable() and
3953+
result = TDataFlowCallSome(call)
3954+
)
39413955
or
3942-
PrevStage::readStepCand(_, _, node)
3956+
not cc = Stage2Param::getSpecificCallContextCall(_, _) and
3957+
(
3958+
// flow-through not possible
3959+
summaryCtx instanceof PrevStage::SummaryCtxNone and
3960+
result = TDataFlowCallNone()
3961+
or
3962+
exists(DataFlowCall call, ParamNodeEx p, PrevStage::Ap argAp |
3963+
summaryCtx = PrevStage::TSummaryCtxSome(p, _, _, argAp)
3964+
|
3965+
if
3966+
PrevStage::parameterMayFlowThrough(p, argAp) and
3967+
PrevStage::callMayFlowThroughRev(call, p)
3968+
then
3969+
// flow-through possible
3970+
result = TDataFlowCallSome(call)
3971+
else (
3972+
// flow-through not possible, but `node` can reach a sink without
3973+
// flowing back out
3974+
PrevStage::callEdgeArgParam(call, _, _, p, _, _) and
3975+
result = TDataFlowCallNone()
3976+
)
3977+
)
3978+
)
39433979
)
3980+
or
3981+
PrevStage::instanceofCcNoCall(cc) and
3982+
fromArg = false and
3983+
result = TDataFlowCallNone()
3984+
)
3985+
}
3986+
3987+
predicate nodeRange(NodeEx node, boolean fromArg, DataFlowCallOption summaryCtx) {
3988+
exists(PrevStage::Ap ap |
3989+
PrevStage::revFlowAp(node, ap) and
3990+
summaryCtx = getACallCtx(node, ap, fromArg)
39443991
|
3945-
exists(PrevStage::Cc cc | PrevStage::fwdFlow(node, _, cc, _, _, ap, _) |
3946-
PrevStage::instanceofCcCall(cc) and
3947-
fromArg = true
3948-
or
3949-
PrevStage::instanceofCcNoCall(cc) and
3950-
fromArg = false
3951-
)
3992+
ap = true
3993+
or
3994+
PrevStage::storeStepCand(node, ap, _, _, _, _)
3995+
or
3996+
PrevStage::readStepCand(_, _, node)
39523997
)
39533998
}
39543999

@@ -3974,12 +4019,51 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
39744019
)
39754020
}
39764021

3977-
predicate callEdgeArgParam(NodeEx arg, NodeEx param) {
3978-
PrevStage::callEdgeArgParam(_, _, arg, param, true, true)
4022+
pragma[nomagic]
4023+
private predicate callEdgeArgParam(
4024+
DataFlowCall call, DataFlowCallable c, NodeEx arg, NodeEx param,
4025+
DataFlowCallOption innerCallCtx
4026+
) {
4027+
PrevStage::callEdgeArgParam(call, c, arg, param, true, true) and
4028+
innerCallCtx = getACallCtx(param, true, true) and
4029+
(
4030+
innerCallCtx = TDataFlowCallNone()
4031+
or
4032+
innerCallCtx = TDataFlowCallSome(call)
4033+
)
4034+
}
4035+
4036+
pragma[nomagic]
4037+
private predicate callEdgeArgParamCallContextReduced(
4038+
DataFlowCall call, NodeEx arg, NodeEx param, Stage2Param::CcCall outerCcCall,
4039+
DataFlowCallOption innerCallCtx
4040+
) {
4041+
exists(DataFlowCallable c |
4042+
callEdgeArgParam(call, c, arg, param, innerCallCtx) and
4043+
Stage2Param::viableImplCallContextReduced(call, outerCcCall) = c
4044+
)
4045+
}
4046+
4047+
bindingset[outerCallCtx]
4048+
predicate callEdgeArgParam(
4049+
NodeEx arg, NodeEx param, DataFlowCallOption outerCallCtx, DataFlowCallOption innerCallCtx
4050+
) {
4051+
exists(DataFlowCall call | callEdgeArgParam(call, _, arg, param, innerCallCtx) |
4052+
outerCallCtx = TDataFlowCallNone()
4053+
or
4054+
exists(DataFlowCall outerCall, Stage2Param::CcCall outerCcCall |
4055+
outerCallCtx = TDataFlowCallSome(outerCall) and
4056+
outerCcCall = Stage2Param::getCallContextCall(outerCall, call.getEnclosingCallable())
4057+
|
4058+
callEdgeArgParamCallContextReduced(call, arg, param, outerCcCall, innerCallCtx)
4059+
or
4060+
Stage2Param::viableImplNotCallContextReduced(call, outerCcCall)
4061+
)
4062+
)
39794063
}
39804064

3981-
predicate callEdgeReturn(NodeEx ret, NodeEx out, boolean mayFlowThrough) {
3982-
PrevStage::callEdgeReturn(_, _, ret, _, out, true, true) and
4065+
predicate callEdgeReturn(DataFlowCall call, NodeEx ret, NodeEx out, boolean mayFlowThrough) {
4066+
PrevStage::callEdgeReturn(call, _, ret, _, out, true, true) and
39834067
if flowThroughOutOfCall(ret, out) then mayFlowThrough = true else mayFlowThrough = false
39844068
}
39854069

0 commit comments

Comments
 (0)