Skip to content

Commit

Permalink
Data flow: Performance improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
hvitved committed Sep 19, 2023
1 parent cdf5872 commit 3499f59
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 57 deletions.
190 changes: 134 additions & 56 deletions shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll
Original file line number Diff line number Diff line change
Expand Up @@ -1335,7 +1335,7 @@ module MakeImpl<InputSig Lang> {
)
or
// flow into a callable
fwdFlowIn(_, node, state, _, cc, _, _, _, t, ap, apa) and
fwdFlowIn(node, apa, state, cc, t, ap) and
if PrevStage::parameterMayFlowThrough(node, apa)
then (
summaryCtx = TParamNodeSome(node.asNode()) and
Expand Down Expand Up @@ -1413,72 +1413,128 @@ module MakeImpl<InputSig Lang> {
)
}

bindingset[call, ctx]
pragma[inline_late]
private DataFlowCallable viableImplCallContextReducedInlineLate(
DataFlowCall call, CcCall ctx
) {
result = viableImplCallContextReduced(call, ctx)
}
private signature module FwdFlowInInputSig {
default predicate callRestriction(DataFlowCall call) { any() }

bindingset[arg, ctx]
pragma[inline_late]
private DataFlowCallable viableImplCallContextReducedInlineLate(
DataFlowCall call, ArgNodeEx arg, CcCall ctx
) {
call = arg.getCall() and
result = viableImplCallContextReducedInlineLate(call, ctx)
bindingset[p, apa]
default predicate parameterRestriction(ParamNodeEx p, ApApprox apa) { any() }
}

bindingset[call]
pragma[inline_late]
private predicate flowIntoCallApaInlineLate(
DataFlowCall call, DataFlowCallable c, ArgNodeEx arg, ParamNodeEx p,
boolean allowsFieldFlow, ApApprox apa
) {
flowIntoCallApa(call, c, arg, p, allowsFieldFlow, apa)
/**
* Exposes the inlined predicate `fwdFlowIn`, which is used to calculate both
* flow in and flow through.
*
* For flow in, only a subset of the columns are needed, specifically we don't
* need to record the argument that flows into the parameter.
*
* For flow through, we do need to record the argument, however, we can restrict
* this to arguments that may actually flow through, using `callRestriction` and
* `parameterRestriction`, which reduces the argument-to-parameter fan-in
* significantly.
*/
private module FwdFlowIn<FwdFlowInInputSig I> {
pragma[nomagic]
private predicate flowIntoCallApaRestricted(
DataFlowCall call, DataFlowCallable c, ArgNodeEx arg, ParamNodeEx p,
boolean allowsFieldFlow, ApApprox apa
) {
flowIntoCallApa(call, c, arg, p, allowsFieldFlow, apa) and
I::callRestriction(call) and
I::parameterRestriction(p, apa)
}

pragma[nomagic]
private DataFlowCallable viableImplCallContextReducedRestricted(
DataFlowCall call, CcCall ctx
) {
result = viableImplCallContextReduced(call, ctx) and
flowIntoCallApaRestricted(call, result, _, _, _, _)
}

bindingset[call, ctx]
pragma[inline_late]
private DataFlowCallable viableImplCallContextReducedInlineLate(
DataFlowCall call, CcCall ctx
) {
result = viableImplCallContextReducedRestricted(call, ctx)
}

bindingset[arg, ctx]
pragma[inline_late]
private DataFlowCallable viableImplCallContextReducedInlineLate(
DataFlowCall call, ArgNodeEx arg, CcCall ctx
) {
flowIntoCallApaRestricted(call, _, arg, _, _, _) and
result = viableImplCallContextReducedInlineLate(call, ctx)
}

bindingset[call]
pragma[inline_late]
private predicate flowIntoCallApaInlineLate(
DataFlowCall call, DataFlowCallable c, ArgNodeEx arg, ParamNodeEx p,
boolean allowsFieldFlow, ApApprox apa
) {
flowIntoCallApaRestricted(call, c, arg, p, allowsFieldFlow, apa)
}

bindingset[call, ctx]
pragma[inline_late]
private predicate viableImplNotCallContextReducedInlineLate(DataFlowCall call, Cc ctx) {
viableImplNotCallContextReduced(call, ctx)
}

bindingset[arg, outercc]
pragma[inline_late]
private predicate viableImplArgNotCallContextReduced(
DataFlowCall call, ArgNodeEx arg, Cc outercc
) {
flowIntoCallApaRestricted(call, _, arg, _, _, _) and
viableImplNotCallContextReducedInlineLate(call, outercc)
}

pragma[inline]
predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParamNodeOption summaryCtx, TypOption argT, ApOption argAp, Typ t, Ap ap, ApApprox apa
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow, DataFlowCallable inner |
fwdFlow(arg, state, outercc, summaryCtx, argT, argAp, t, ap, apa) and
(
inner = viableImplCallContextReducedInlineLate(call, arg, outercc)
or
viableImplArgNotCallContextReduced(call, arg, outercc)
) and
flowIntoCallApaInlineLate(call, inner, arg, p, allowsFieldFlow, apa)
|
innercc = getCallContextCall(call, inner) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
}

bindingset[call, ctx]
pragma[inline_late]
private predicate viableImplNotCallContextReducedInlineLate(DataFlowCall call, Cc ctx) {
viableImplNotCallContextReduced(call, ctx)
}
private module FwdFlowInNoRestriction implements FwdFlowInInputSig { }

bindingset[arg, outercc]
pragma[inline_late]
private predicate viableImplArgNotCallContextReduced(
DataFlowCall call, ArgNodeEx arg, Cc outercc
pragma[nomagic]
private predicate fwdFlowIn(
ParamNodeEx p, ApApprox apa, FlowState state, CcCall innercc, Typ t, Ap ap
) {
call = arg.getCall() and
viableImplNotCallContextReducedInlineLate(call, outercc)
FwdFlowIn<FwdFlowInNoRestriction>::fwdFlowIn(_, p, state, _, innercc, _, _, _, t, ap, apa)
}

pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParamNodeOption summaryCtx, TypOption argT, ApOption argAp, Typ t, Ap ap, ApApprox apa
private DataFlowCallable viableImplCallContextReducedReverseRestricted(
DataFlowCall call, CcNoCall ctx
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow, DataFlowCallable inner |
fwdFlow(arg, state, outercc, summaryCtx, argT, argAp, t, ap, apa) and
(
inner = viableImplCallContextReducedInlineLate(call, arg, outercc)
or
viableImplArgNotCallContextReduced(call, arg, outercc)
) and
flowIntoCallApaInlineLate(call, inner, arg, p, allowsFieldFlow, apa)
|
innercc = getCallContextCall(call, inner) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
result = viableImplCallContextReducedReverse(call, ctx) and
flowOutOfCallApa(call, result, _, _, _, _, _)
}

bindingset[ctx, result]
pragma[inline_late]
private DataFlowCallable viableImplCallContextReducedReverseInlineLate(
DataFlowCall call, CcNoCall ctx
) {
result = viableImplCallContextReducedReverse(call, ctx)
result = viableImplCallContextReducedReverseRestricted(call, ctx)
}

bindingset[call]
Expand Down Expand Up @@ -1564,6 +1620,12 @@ module MakeImpl<InputSig Lang> {
innerArgApa)
}

private module FwdFlowThroughRestriction implements FwdFlowInInputSig {
predicate callRestriction = PrevStage::callMayFlowThroughRev/1;

predicate parameterRestriction = PrevStage::parameterMayFlowThrough/2;
}

/**
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`
* and data might flow through the target callable and back out at `call`.
Expand All @@ -1573,12 +1635,8 @@ module MakeImpl<InputSig Lang> {
DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, TypOption argT,
ApOption argAp, ParamNodeEx p, Typ t, Ap ap
) {
exists(ApApprox apa |
fwdFlowIn(call, pragma[only_bind_into](p), _, cc, innerCc, summaryCtx, argT, argAp, t,
ap, pragma[only_bind_into](apa)) and
PrevStage::parameterMayFlowThrough(p, apa) and
PrevStage::callMayFlowThroughRev(call)
)
FwdFlowIn<FwdFlowThroughRestriction>::fwdFlowIn(call, p, _, cc, innerCc, summaryCtx, argT,
argAp, t, ap, _)
}

pragma[nomagic]
Expand Down Expand Up @@ -3720,6 +3778,26 @@ module MakeImpl<InputSig Lang> {
)
}

pragma[nomagic]
private DataFlowCallable prunedViableImplInCallContextCand(DataFlowCall call, CallContext cc) {
result = prunedViableImplInCallContext(call, cc) and
parameterCand(result, _, _)
}

pragma[nomagic]
private DataFlowCallable viableCallableExtCand(DataFlowCall call) {
result = viableCallableExt(call) and
parameterCand(result, _, _)
}

bindingset[call, cc]
private DataFlowCallable resolveCallCand(DataFlowCall call, CallContext cc) {
result = prunedViableImplInCallContextCand(call, cc)
or
noPrunedViableImplInCallContext(call, cc) and
result = viableCallableExtCand(call)
}

pragma[nomagic]
private predicate pathIntoCallable0(
PathNodeMid mid, DataFlowCallable callable, ParameterPosition pos, FlowState state,
Expand All @@ -3728,7 +3806,7 @@ module MakeImpl<InputSig Lang> {
exists(AccessPathApprox apa |
pathIntoArg(mid, pragma[only_bind_into](pos), state, outercc, call, t, ap,
pragma[only_bind_into](apa)) and
callable = resolveCall(call, outercc) and
callable = resolveCallCand(call, outercc) and
parameterCand(callable, pragma[only_bind_into](pos), pragma[only_bind_into](apa))
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ module MakeImplCommon<InputSig Lang> {
}
}

private DataFlowCallable viableCallableExt(DataFlowCall call) {
DataFlowCallable viableCallableExt(DataFlowCall call) {
result = viableCallable(call)
or
result = viableCallableLambda(call, _)
Expand Down

0 comments on commit 3499f59

Please sign in to comment.