diff --git a/shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll b/shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll index e0812062fd229..262bc5f1d2729 100644 --- a/shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll +++ b/shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll @@ -647,7 +647,7 @@ module MakeImpl Lang> { // inline to reduce the number of iterations pragma[inline] private predicate fwdFlowIn(DataFlowCallEx call, NodeEx arg, Cc cc, ParamNodeEx p) { - exists(DataFlowCall underlyingCall | underlyingCall = call.asDataFlowCall(_) | + exists(DataFlowCall underlyingCall | underlyingCall = call.projectToCall() | // call context cannot help reduce virtual dispatch fwdFlow(arg, cc) and viableParamArgEx(call, p, arg) and @@ -680,7 +680,7 @@ module MakeImpl Lang> { ) { fwdFlow(arg, true) and viableParamArgEx(call, p, arg) and - CachedCallContextSensitivity::reducedViableImplInCallContext(call.asDataFlowCall(_), _, _) and + CachedCallContextSensitivity::reducedViableImplInCallContext(call.projectToCall(), _, _) and target = p.getEnclosingCallable() and not fullBarrier(p) } @@ -694,7 +694,7 @@ module MakeImpl Lang> { private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(DataFlowCall call) { exists(DataFlowCallEx ctx | fwdFlowIsEntered(ctx, _) and - result = viableImplInCallContextExt(call, ctx.asDataFlowCall(_)) + result = viableImplInCallContextExt(call, ctx.projectToCall()) ) } @@ -1246,7 +1246,7 @@ module MakeImpl Lang> { DataFlowCall ctx ) { returnCallEdge1(c, scope, call, out) and - c = viableImplInCallContextExt(call.asDataFlowCall(_), ctx) + c = viableImplInCallContextExt(call.projectToCall(), ctx) } private int ctxDispatchFanoutOnReturn(NodeEx out, DataFlowCallEx ctx) { @@ -1255,10 +1255,10 @@ module MakeImpl Lang> { not Stage1::revFlow(out, false) and call.getEnclosingCallable() = c and returnCallEdge1(c, _, ctx, _) and - mayBenefitFromCallContextExt(call.asDataFlowCall(_), _) and + mayBenefitFromCallContextExt(call.projectToCall(), _) and result = count(DataFlowCallable tgt, SndLevelScopeOption scope | - returnCallEdgeInCtx1(tgt, scope, call, out, ctx.asDataFlowCall(_)) + returnCallEdgeInCtx1(tgt, scope, call, out, ctx.projectToCall()) ) ) } @@ -1531,7 +1531,7 @@ module MakeImpl Lang> { PrevStage::callEdgeReturn(call, _, ret, kind, out, allowsFieldFlow, apa) and PrevStage::callMayFlowThroughRev(call) and PrevStage::returnMayFlowThrough(ret, argApa, apa, kind) and - matchesCall(ccc, call.asDataFlowCall(_)) + matchesCall(ccc, call.projectToCall()) ) } @@ -1860,7 +1860,7 @@ module MakeImpl Lang> { private DataFlowCallable viableImplCallContextReducedRestricted( DataFlowCallEx call, CcCall ctx ) { - result = viableImplCallContextReduced(call.asDataFlowCall(_), ctx) and + result = viableImplCallContextReduced(call.projectToCall(), ctx) and callEdgeArgParamRestricted(call, result, _, _, _, _) } @@ -1905,7 +1905,7 @@ module MakeImpl Lang> { ) { callEdgeArgParamRestricted(call, _, arg, _, _, _) and instanceofCc(outercc) and - viableImplNotCallContextReducedInlineLate(call.asDataFlowCall(_), outercc) + viableImplNotCallContextReducedInlineLate(call.projectToCall(), outercc) } pragma[inline] @@ -1949,7 +1949,7 @@ module MakeImpl Lang> { DataFlowCallEx call, DataFlowCallable inner, CcCall innercc, boolean cc ) { not enableTypeFlow() and - FwdTypeFlow::typeFlowValidEdgeIn(call.asDataFlowCall(_), inner, cc) and + FwdTypeFlow::typeFlowValidEdgeIn(call.projectToCall(), inner, cc) and innercc = getCallContextCall(call, inner) } @@ -1959,7 +1959,7 @@ module MakeImpl Lang> { CcCall innercc, boolean emptyAp, ApApprox apa, boolean cc ) { fwdFlowInCandTypeFlowEnabled(call, arg, outercc, inner, p, emptyAp, apa, cc) and - FwdTypeFlow::typeFlowValidEdgeIn(call.asDataFlowCall(_), inner, cc) and + FwdTypeFlow::typeFlowValidEdgeIn(call.projectToCall(), inner, cc) and innercc = getCallContextCall(call, inner) } @@ -2011,7 +2011,7 @@ module MakeImpl Lang> { private DataFlowCallEx viableImplCallContextReducedReverseRestricted( DataFlowCallable c, CcNoCall ctx ) { - result.asDataFlowCall(_) = viableImplCallContextReducedReverse(c, ctx) and + result.projectToCall() = viableImplCallContextReducedReverse(c, ctx) and PrevStage::callEdgeReturn(result, c, _, _, _, _, _) } @@ -2075,7 +2075,7 @@ module MakeImpl Lang> { CcNoCall outercc, ApApprox apa, boolean allowsFieldFlow ) { fwdFlowOutCand(call, ret, innercc, inner, out, apa, allowsFieldFlow) and - FwdTypeFlow::typeFlowValidEdgeOut(call.asDataFlowCall(_), inner) and + FwdTypeFlow::typeFlowValidEdgeOut(call.projectToCall(), inner) and outercc = getCallContextReturn(inner, call) } @@ -2096,11 +2096,11 @@ module MakeImpl Lang> { predicate enableTypeFlow = Param::enableTypeFlow/0; predicate relevantCallEdgeIn(DataFlowCall call, DataFlowCallable c) { - PrevStage::relevantCallEdgeIn(MkDataFlowCallEx(call, _), c) + PrevStage::relevantCallEdgeIn(injectCall(call), c) } predicate relevantCallEdgeOut(DataFlowCall call, DataFlowCallable c) { - PrevStage::relevantCallEdgeOut(MkDataFlowCallEx(call, _), c) + PrevStage::relevantCallEdgeOut(injectCall(call), c) } pragma[nomagic] @@ -2108,11 +2108,11 @@ module MakeImpl Lang> { DataFlowCall call, DataFlowCallable c, ParamNodeEx p, FlowState state, CcCall innercc, Typ t, Ap ap, TypOption stored, boolean cc ) { - FwdFlowInNoThrough::fwdFlowIn(MkDataFlowCallEx(call, _), _, c, p, state, _, innercc, _, - t, ap, _, stored, cc) + FwdFlowInNoThrough::fwdFlowIn(injectCall(call), _, c, p, state, _, innercc, _, t, ap, _, + stored, cc) or - FwdFlowInThrough::fwdFlowIn(MkDataFlowCallEx(call, _), _, c, p, state, _, innercc, _, t, - ap, _, stored, cc) + FwdFlowInThrough::fwdFlowIn(injectCall(call), _, c, p, state, _, innercc, _, t, ap, _, + stored, cc) } pragma[nomagic] @@ -2136,7 +2136,7 @@ module MakeImpl Lang> { DataFlowCall call, DataFlowCallable c, NodeEx node, FlowState state, Cc cc, Typ t, Ap ap, TypOption stored ) { - fwdFlowOut(MkDataFlowCallEx(call, _), c, node, state, cc, _, t, ap, _, stored) + fwdFlowOut(injectCall(call), c, node, state, cc, _, t, ap, _, stored) } pragma[nomagic] @@ -2180,7 +2180,7 @@ module MakeImpl Lang> { boolean allowsFieldFlow, ApApprox apa ) { PrevStage::callEdgeArgParam(call, c, arg, p, allowsFieldFlow, apa) and - FwdTypeFlowInput::dataFlowTakenCallEdgeIn(call.asDataFlowCall(_), c, _) + FwdTypeFlowInput::dataFlowTakenCallEdgeIn(call.projectToCall(), c, _) } pragma[nomagic] @@ -2319,8 +2319,8 @@ module MakeImpl Lang> { if allowsFieldFlow = false then ap instanceof ApNil else any() | // both directions are needed for flow-through - FwdTypeFlowInput::dataFlowTakenCallEdgeIn(call.asDataFlowCall(_), c, _) or - FwdTypeFlowInput::dataFlowTakenCallEdgeOut(call.asDataFlowCall(_), c) + FwdTypeFlowInput::dataFlowTakenCallEdgeIn(call.projectToCall(), c, _) or + FwdTypeFlowInput::dataFlowTakenCallEdgeOut(call.projectToCall(), c) ) } @@ -2450,24 +2450,24 @@ module MakeImpl Lang> { predicate enableTypeFlow = Param::enableTypeFlow/0; predicate relevantCallEdgeIn(DataFlowCall call, DataFlowCallable c) { - flowOutOfCallAp(MkDataFlowCallEx(call, _), c, _, _, _, _) + flowOutOfCallAp(injectCall(call), c, _, _, _, _) } predicate relevantCallEdgeOut(DataFlowCall call, DataFlowCallable c) { - flowIntoCallAp(MkDataFlowCallEx(call, _), c, _, _, _) + flowIntoCallAp(injectCall(call), c, _, _, _) } pragma[nomagic] predicate dataFlowTakenCallEdgeIn(DataFlowCall call, DataFlowCallable c, boolean cc) { exists(RetNodeEx ret | - revFlowOut(MkDataFlowCallEx(call, _), ret, _, _, _, cc, _, _) and + revFlowOut(injectCall(call), ret, _, _, _, cc, _, _) and c = ret.getEnclosingCallable() ) } pragma[nomagic] predicate dataFlowTakenCallEdgeOut(DataFlowCall call, DataFlowCallable c) { - revFlowIn(MkDataFlowCallEx(call, _), c, _, _, _) + revFlowIn(injectCall(call), c, _, _, _) } predicate dataFlowNonCallEntry(DataFlowCallable c, boolean cc) { @@ -2493,7 +2493,7 @@ module MakeImpl Lang> { DataFlowCallEx call, DataFlowCallable c, ArgNodeEx arg, ParamNodeEx p, Ap ap ) { flowIntoCallAp(call, c, arg, p, ap) and - RevTypeFlow::typeFlowValidEdgeOut(call.asDataFlowCall(_), c) + RevTypeFlow::typeFlowValidEdgeOut(call.projectToCall(), c) } pragma[nomagic] @@ -2502,7 +2502,7 @@ module MakeImpl Lang> { ) { exists(DataFlowCallable c | flowOutOfCallAp(call, c, ret, pos, out, ap) and - RevTypeFlow::typeFlowValidEdgeIn(call.asDataFlowCall(_), c, cc) + RevTypeFlow::typeFlowValidEdgeIn(call.projectToCall(), c, cc) ) } @@ -2558,7 +2558,7 @@ module MakeImpl Lang> { exists(RetNodeEx ret, FlowState state, CcCall ccc | revFlowOut(call, ret, pos, state, returnCtx, _, returnAp, ap) and returnFlowsThrough(ret, pos, state, ccc, _, _, _, _, _, ap) and - matchesCall(ccc, call.asDataFlowCall(_)) + matchesCall(ccc, call.projectToCall()) ) } @@ -2694,8 +2694,8 @@ module MakeImpl Lang> { allowsFieldFlow = true | // both directions are needed for flow-through - RevTypeFlowInput::dataFlowTakenCallEdgeIn(call.asDataFlowCall(_), c, _) or - RevTypeFlowInput::dataFlowTakenCallEdgeOut(call.asDataFlowCall(_), c) + RevTypeFlowInput::dataFlowTakenCallEdgeIn(call.projectToCall(), c, _) or + RevTypeFlowInput::dataFlowTakenCallEdgeOut(call.projectToCall(), c) ) } @@ -2709,7 +2709,7 @@ module MakeImpl Lang> { revFlow(out, pragma[only_bind_into](state), pragma[only_bind_into](ap)) and kind = pos.getKind() and allowsFieldFlow = true and - RevTypeFlowInput::dataFlowTakenCallEdgeIn(call.asDataFlowCall(_), c, _) + RevTypeFlowInput::dataFlowTakenCallEdgeIn(call.projectToCall(), c, _) ) } @@ -3932,11 +3932,11 @@ module MakeImpl Lang> { private module CallContextSensitivityInput implements CallContextSensitivityInputSig { predicate relevantCallEdgeIn(DataFlowCall call, DataFlowCallable c) { - PrevStage::relevantCallEdgeIn(MkDataFlowCallEx(call, _), c) + PrevStage::relevantCallEdgeIn(injectCall(call), c) } predicate relevantCallEdgeOut(DataFlowCall call, DataFlowCallable c) { - PrevStage::relevantCallEdgeOut(MkDataFlowCallEx(call, _), c) + PrevStage::relevantCallEdgeOut(injectCall(call), c) } predicate reducedViableImplInCallContextCand = @@ -4336,11 +4336,11 @@ module MakeImpl Lang> { private module CallContextSensitivityInput implements CallContextSensitivityInputSig { predicate relevantCallEdgeIn(DataFlowCall call, DataFlowCallable c) { - PrevStage::relevantCallEdgeIn(MkDataFlowCallEx(call, _), c) + PrevStage::relevantCallEdgeIn(injectCall(call), c) } predicate relevantCallEdgeOut(DataFlowCall call, DataFlowCallable c) { - PrevStage::relevantCallEdgeOut(MkDataFlowCallEx(call, _), c) + PrevStage::relevantCallEdgeOut(injectCall(call), c) } predicate reducedViableImplInCallContextCand = @@ -4536,11 +4536,11 @@ module MakeImpl Lang> { private module CallContextSensitivityInput implements CallContextSensitivityInputSig { predicate relevantCallEdgeIn(DataFlowCall call, DataFlowCallable c) { - PrevStage::relevantCallEdgeIn(MkDataFlowCallEx(call, _), c) + PrevStage::relevantCallEdgeIn(injectCall(call), c) } predicate relevantCallEdgeOut(DataFlowCall call, DataFlowCallable c) { - PrevStage::relevantCallEdgeOut(MkDataFlowCallEx(call, _), c) + PrevStage::relevantCallEdgeOut(injectCall(call), c) } predicate reducedViableImplInCallContextCand = @@ -5553,7 +5553,7 @@ module MakeImpl Lang> { partialPathOutOfCallable0(mid, pos, state, innercc, t, ap) and c = pos.getCallable() and kind = pos.getKind() and - CachedCallContextSensitivity::resolveReturn(innercc, c, call.asDataFlowCall(_)) and + CachedCallContextSensitivity::resolveReturn(innercc, c, call.projectToCall()) and cc = CachedCallContextSensitivity::getCallContextReturn(c, call) ) } @@ -5590,7 +5590,7 @@ module MakeImpl Lang> { CallContext outercc, DataFlowCallEx call, DataFlowType t, PartialAccessPath ap ) { partialPathIntoArg(mid, pos, state, outercc, call, t, ap) and - callable = CachedCallContextSensitivity::resolveCall(call.asDataFlowCall(_), outercc) + callable = CachedCallContextSensitivity::resolveCall(call.projectToCall(), outercc) } private predicate partialPathIntoCallable( diff --git a/shared/dataflow/codeql/dataflow/internal/DataFlowImplCommon.qll b/shared/dataflow/codeql/dataflow/internal/DataFlowImplCommon.qll index c2e68f694d4ab..28a22a0ddc817 100644 --- a/shared/dataflow/codeql/dataflow/internal/DataFlowImplCommon.qll +++ b/shared/dataflow/codeql/dataflow/internal/DataFlowImplCommon.qll @@ -779,9 +779,9 @@ module MakeImplCommon Lang> { /** Gets the call context when returning from `c` to `call`. */ bindingset[call, c] CallContextNoCall getCallContextReturn(DataFlowCallable c, DataFlowCallEx call) { - result = Input2::getSpecificCallContextReturn(c, call.asDataFlowCall(_)) + result = Input2::getSpecificCallContextReturn(c, call.projectToCall()) or - not exists(Input2::getSpecificCallContextReturn(c, call.asDataFlowCall(_))) and + not exists(Input2::getSpecificCallContextReturn(c, call.projectToCall())) and result = TAnyCallContext() } @@ -810,8 +810,8 @@ module MakeImplCommon Lang> { bindingset[call, c] CallContextCall getCallContextCall(DataFlowCallEx call, DataFlowCallable c) { - if recordDataFlowCallSiteDispatch(call.asDataFlowCall(_), c) - then result = Input2::getSpecificCallContextCall(call.asDataFlowCall(_), c) + if recordDataFlowCallSiteDispatch(call.projectToCall(), c) + then result = Input2::getSpecificCallContextCall(call.projectToCall(), c) else result = TSomeCall() } } @@ -838,8 +838,8 @@ module MakeImplCommon Lang> { bindingset[call, c] CallContextCall getCallContextCall(DataFlowCallEx call, DataFlowCallable c) { - if recordDataFlowCallSite(call.asDataFlowCall(_), c) - then result = Input2::getSpecificCallContextCall(call.asDataFlowCall(_), c) + if recordDataFlowCallSite(call.projectToCall(), c) + then result = Input2::getSpecificCallContextCall(call.projectToCall(), c) else result = TSomeCall() } } @@ -932,23 +932,26 @@ module MakeImplCommon Lang> { CastingNodeEx() { castingNodeEx(this) } } - final class DataFlowCallEx extends MkDataFlowCallEx { - DataFlowCall asDataFlowCall(boolean allowFwdFlowOut) { - this = MkDataFlowCallEx(result, allowFwdFlowOut) - } + DataFlowCallEx injectCall(DataFlowCall c) { result.projectToCall() = c } - DataFlowCallable getEnclosingCallable() { - result = this.asDataFlowCall(_).getEnclosingCallable() - } + abstract class DataFlowCallEx extends TDataFlowCallEx { + abstract DataFlowCall projectToCall(); - string toString() { - exists(boolean allowFwdFlowOut, string s | - s = this.asDataFlowCall(allowFwdFlowOut).toString() and - if allowFwdFlowOut = true then result = s else result = s + " (no fwd flow out)" - ) - } + DataFlowCallable getEnclosingCallable() { result = this.projectToCall().getEnclosingCallable() } + + abstract string toString(); + + Location getLocation() { result = this.projectToCall().getLocation() } + } + + final class NormalDataFlowCall extends DataFlowCallEx, TNormalDataFlowCall { + private DataFlowCall call; + + NormalDataFlowCall() { this = TNormalDataFlowCall(call) } - Location getLocation() { result = this.asDataFlowCall(_).getLocation() } + override DataFlowCall projectToCall() { result = call } + + override string toString() { result = call.toString() } } final class ArgumentPositionEx extends TArgumentPositionEx { @@ -982,11 +985,11 @@ module MakeImplCommon Lang> { } final class NormalArgNodeEx extends ArgNodeEx { - private DataFlowCallEx call_; + private NormalDataFlowCall call_; private ArgumentPositionEx pos_; NormalArgNodeEx() { - this.asNode().(ArgNode).argumentOf(call_.asDataFlowCall(true), pos_.asArgumentPosition()) + this.asNode().(ArgNode).argumentOf(call_.projectToCall(), pos_.asArgumentPosition()) } override predicate argumentOf(DataFlowCallEx call, ArgumentPositionEx pos) { @@ -1104,15 +1107,33 @@ module MakeImplCommon Lang> { ) } + final class ReverseDataFlowCall extends DataFlowCallEx, TReverseDataFlowCall { + private DataFlowCall call; + private boolean allowFwdFlowOut; + + ReverseDataFlowCall() { this = TReverseDataFlowCall(call, allowFwdFlowOut) } + + override DataFlowCall projectToCall() { result = call } + + override string toString() { + exists(string s | + s = call.toString() and + if allowFwdFlowOut = true + then result = s + " [Reverse]" + else result = s + " [Reverse, no out flow]" + ) + } + } + final class ReverseArgNodeEx extends ArgNodeEx { - private DataFlowCallEx call_; + private ReverseFlow::ReverseDataFlowCall call_; private ArgumentPositionEx pos_; ReverseArgNodeEx() { - exists(boolean allowFwdFlowOut | + exists(DataFlowCall c, boolean allowFwdFlowOut | + call_ = TReverseDataFlowCall(c, allowFwdFlowOut) and pragma[only_bind_into](this.asNodeReverse(allowFwdFlowOut)) = - getAnOutNode(call_.asDataFlowCall(allowFwdFlowOut), - pos_.asReturnKind().(ValueReturnKind).getKind()) + getAnOutNode(c, pos_.asReturnKind().(ValueReturnKind).getKind()) ) } @@ -1151,7 +1172,9 @@ module MakeImplCommon Lang> { predicate forceCachingInSameStage() { any() } cached - newtype TDataFlowCallEx = MkDataFlowCallEx(DataFlowCall call, Boolean allowFwdFlowOut) + newtype TDataFlowCallEx = + TNormalDataFlowCall(DataFlowCall call) or + TReverseDataFlowCall(DataFlowCall call, Boolean allowFwdFlowOut) cached newtype TArgumentPositionEx = @@ -1243,16 +1266,20 @@ module MakeImplCommon Lang> { cached OutNodeEx getAnOutNodeEx(DataFlowCallEx call, ReturnKindExt k) { - exists(DataFlowCall c, boolean allowFwdFlowOut | c = call.asDataFlowCall(allowFwdFlowOut) | + exists(DataFlowCall c | + c = call.(NormalDataFlowCall).projectToCall() and result.asNode() = getAnOutNode(c, k.(ValueReturnKind).getKind()) or exists(ArgNode arg | arg.argumentOf(c, k.(ParamUpdateReturnKind).getAMatchingArgumentPosition()) | - allowFwdFlowOut = false and + call = TReverseDataFlowCall(c, false) and result.asNodeReverse(_) = arg or - allowFwdFlowOut = true and + ( + call = TReverseDataFlowCall(c, true) or + c = call.(NormalDataFlowCall).projectToCall() + ) and result.asNode().(PostUpdateNode).getPreUpdateNode() = arg ) ) @@ -1494,7 +1521,7 @@ module MakeImplCommon Lang> { // viableParamArg(call, p.asNode(), arg.asNode()) // or exists(ParameterPositionEx ppos, DataFlowCall underlyingCall | - underlyingCall = call.asDataFlowCall(_) and + underlyingCall = call.projectToCall() and viableParamEx(underlyingCall, ppos, p) and argumentPositionMatchEx(call, arg, ppos) and compatibleTypesFilter(arg.getDataFlowType(), p.getDataFlowType()) and @@ -1527,7 +1554,7 @@ module MakeImplCommon Lang> { cached predicate viableReturnPosOutEx(DataFlowCallEx call, ReturnPosition pos, OutNodeEx out) { exists(ReturnKindExt kind | - pos = viableReturnPos(call.asDataFlowCall(_), kind) and + pos = viableReturnPos(call.projectToCall(), kind) and out = kind.getAnOutNodeEx(call) //and // call.toString().matches("%GetBox1%") ) @@ -1778,8 +1805,7 @@ module MakeImplCommon Lang> { parameterValueFlowReturn(param, kind, read, model, innerCtx) and callable = nodeGetEnclosingCallable(param) and outerCtx = - CachedCallContextSensitivity::getCallContextReturn(callable, - MkDataFlowCallEx(call, true)) + CachedCallContextSensitivity::getCallContextReturn(callable, TNormalDataFlowCall(call)) | CachedCallContextSensitivity::viableImplNotCallContextReducedReverse(innerCtx) or