Skip to content

Commit 43cd2c0

Browse files
committed
Data flow: Depth 1 call contexts in store/load matching
1 parent 93f7e92 commit 43cd2c0

File tree

2 files changed

+193
-82
lines changed

2 files changed

+193
-82
lines changed

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

+113-29
Original file line numberDiff line numberDiff line change
@@ -1617,9 +1617,9 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
16171617
)
16181618
}
16191619

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

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

16351635
abstract Location getLocation();
16361636
}
16371637

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

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

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

26582658
pragma[nomagic]
26592659
private predicate revFlowThroughArg(
2660-
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
2661-
Ap ap
2660+
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, FlowState state, ReturnCtx returnCtx,
2661+
ApOption returnAp, Ap ap
26622662
) {
2663-
exists(ParamNodeEx p, Ap innerReturnAp |
2663+
exists(Ap innerReturnAp |
26642664
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp) and
26652665
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp)
26662666
)
26672667
}
26682668

26692669
pragma[nomagic]
2670-
predicate callMayFlowThroughRev(DataFlowCall call) {
2670+
additional predicate callMayFlowThroughRev(DataFlowCall call, ParamNodeEx p) {
26712671
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
26722672
revFlow(arg, state, returnCtx, returnAp, ap) and
2673-
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap)
2673+
revFlowThroughArg(call, arg, p, state, returnCtx, returnAp, ap)
26742674
)
26752675
}
26762676

2677+
predicate callMayFlowThroughRev(DataFlowCall call) { callMayFlowThroughRev(call, _) }
2678+
26772679
predicate callEdgeArgParam(
26782680
DataFlowCall call, DataFlowCallable c, ArgNodeEx arg, ParamNodeEx p,
26792681
boolean allowsFieldFlow, Ap ap
@@ -3933,24 +3935,67 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
39333935
private module StoreReadMatchingInput implements StoreReadMatchingInputSig {
39343936
class NodeEx = NodeExAlias;
39353937

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

@@ -3976,12 +4021,51 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
39764021
)
39774022
}
39784023

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

3983-
predicate callEdgeReturn(NodeEx ret, NodeEx out, boolean mayFlowThrough) {
3984-
PrevStage::callEdgeReturn(_, _, ret, _, out, true, true) and
4067+
predicate callEdgeReturn(DataFlowCall call, NodeEx ret, NodeEx out, boolean mayFlowThrough) {
4068+
PrevStage::callEdgeReturn(call, _, ret, _, out, true, true) and
39854069
if flowThroughOutOfCall(ret, out) then mayFlowThrough = true else mayFlowThrough = false
39864070
}
39874071

0 commit comments

Comments
 (0)