From 2d29fa1d157456b9f41c1025d43c06c4c0e3d0ad Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 4 Jun 2020 11:13:23 +0200 Subject: [PATCH 1/4] Data flow: Use precise call contexts in `flowFwd()` --- .../csharp/dataflow/internal/DataFlowImpl.qll | 113 +++++++++++------- .../dataflow/internal/DataFlowImplCommon.qll | 16 ++- 2 files changed, 80 insertions(+), 49 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index 5042dce683f..4e6eb9d86c0 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption { * Holds if `node` is reachable with access path `ap` from a source in * the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an + * The call context `cc` records whether the node is reached through an * argument in a call, and if so, `argAp` records the access path of that * argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argAp, apf, ap, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and + exists(Node mid, AccessPathNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and apf = ap.(AccessPathNil).getFront() ) or exists(Node mid | flowFwd(mid, _, _, apf, ap, config) and jumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() ) or exists(Node mid, AccessPathNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() @@ -1704,40 +1704,51 @@ private predicate flowFwd0( ) or // store - exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config)) or // read exists(TypedContent tc | - flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, cc, _, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(CallContextNoCall innercc, DataFlowCallable c | + flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or exists(AccessPath argAp0 | flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + flowFwdIsEntered(call, cc, argAp, argAp0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argAp, apf, ap, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwd(mid, cc, argAp, apf0, ap0, config) and flowFwdStore0(mid, tc, node, apf0, apf, config) ) } @@ -1764,20 +1775,20 @@ private predicate flowFwdStore0( pragma[nomagic] private predicate flowFwdRead0( - Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, - boolean fromArg, AccessPathOption argAp, Configuration config + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc, + AccessPathOption argAp, Configuration config ) { - flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + flowFwd(node1, cc, argAp, apf0, ap0, config) and readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, TypedContent tc | - flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and flowCand(node, _, _, apf, unbind(config)) and flowCandConsCand(tc, apf, unbind(config)) ) @@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argAp, apf, ap, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1809,13 +1823,19 @@ private predicate flowFwdIn( pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argAp, apf, ap, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg( DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config) } /** @@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } @@ -1920,7 +1940,7 @@ private predicate flow0( // flow out of a callable flowOut(_, node, _, _, ap, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config) then returnAp = TAccessPathSome(ap) else returnAp = TAccessPathNone() } @@ -2006,9 +2026,10 @@ private predicate flowIsReturned( DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { - exists(ReturnNodeExt ret | + exists(ReturnNodeExt ret, CallContextCall ccc | flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and + ccc.matchesCall(call) ) } @@ -2031,7 +2052,7 @@ private newtype TSummaryCtx = exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | parameterFlow(p, ap, ret.getEnclosingCallable(), config) and flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) + flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config) ) } @@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0( ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } @@ -2867,7 +2888,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll index 27ab1d01feb..892250f44bb 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll @@ -512,13 +512,19 @@ abstract class CallContext extends TCallContext { abstract predicate relevantFor(DataFlowCallable callable); } -class CallContextAny extends CallContext, TAnyCallContext { +abstract class CallContextNoCall extends CallContext { } + +class CallContextAny extends CallContextNoCall, TAnyCallContext { override string toString() { result = "CcAny" } override predicate relevantFor(DataFlowCallable callable) { any() } } -abstract class CallContextCall extends CallContext { } +abstract class CallContextCall extends CallContext { + /** Holds if this call context may be `call`. */ + bindingset[call] + abstract predicate matchesCall(DataFlowCall call); +} class CallContextSpecificCall extends CallContextCall, TSpecificCall { override string toString() { @@ -529,6 +535,8 @@ class CallContextSpecificCall extends CallContextCall, TSpecificCall { recordDataFlowCallSite(getCall(), callable) } + override predicate matchesCall(DataFlowCall call) { call = this.getCall() } + DataFlowCall getCall() { this = TSpecificCall(result) } } @@ -538,9 +546,11 @@ class CallContextSomeCall extends CallContextCall, TSomeCall { override predicate relevantFor(DataFlowCallable callable) { exists(ParameterNode p | p.getEnclosingCallable() = callable) } + + override predicate matchesCall(DataFlowCall call) { any() } } -class CallContextReturn extends CallContext, TReturn { +class CallContextReturn extends CallContextNoCall, TReturn { override string toString() { exists(DataFlowCall call | this = TReturn(_, call) | result = "CcReturn(" + call + ")") } From 9ebf8d1d580f8f5b68a62a256ae1d8b74aa9b79c Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 29 Jun 2020 20:02:37 +0200 Subject: [PATCH 2/4] Data flow: Sync files --- .../cpp/dataflow/internal/DataFlowImpl.qll | 113 +++++++++++------- .../cpp/dataflow/internal/DataFlowImpl2.qll | 113 +++++++++++------- .../cpp/dataflow/internal/DataFlowImpl3.qll | 113 +++++++++++------- .../cpp/dataflow/internal/DataFlowImpl4.qll | 113 +++++++++++------- .../dataflow/internal/DataFlowImplCommon.qll | 16 ++- .../dataflow/internal/DataFlowImplLocal.qll | 113 +++++++++++------- .../cpp/ir/dataflow/internal/DataFlowImpl.qll | 113 +++++++++++------- .../ir/dataflow/internal/DataFlowImpl2.qll | 113 +++++++++++------- .../ir/dataflow/internal/DataFlowImpl3.qll | 113 +++++++++++------- .../ir/dataflow/internal/DataFlowImpl4.qll | 113 +++++++++++------- .../dataflow/internal/DataFlowImplCommon.qll | 16 ++- .../dataflow/internal/DataFlowImpl2.qll | 113 +++++++++++------- .../dataflow/internal/DataFlowImpl3.qll | 113 +++++++++++------- .../dataflow/internal/DataFlowImpl4.qll | 113 +++++++++++------- .../dataflow/internal/DataFlowImpl5.qll | 113 +++++++++++------- .../java/dataflow/internal/DataFlowImpl.qll | 113 +++++++++++------- .../java/dataflow/internal/DataFlowImpl2.qll | 113 +++++++++++------- .../java/dataflow/internal/DataFlowImpl3.qll | 113 +++++++++++------- .../java/dataflow/internal/DataFlowImpl4.qll | 113 +++++++++++------- .../java/dataflow/internal/DataFlowImpl5.qll | 113 +++++++++++------- .../dataflow/internal/DataFlowImplCommon.qll | 16 ++- 21 files changed, 1245 insertions(+), 837 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index 5042dce683f..4e6eb9d86c0 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption { * Holds if `node` is reachable with access path `ap` from a source in * the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an + * The call context `cc` records whether the node is reached through an * argument in a call, and if so, `argAp` records the access path of that * argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argAp, apf, ap, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and + exists(Node mid, AccessPathNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and apf = ap.(AccessPathNil).getFront() ) or exists(Node mid | flowFwd(mid, _, _, apf, ap, config) and jumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() ) or exists(Node mid, AccessPathNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() @@ -1704,40 +1704,51 @@ private predicate flowFwd0( ) or // store - exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config)) or // read exists(TypedContent tc | - flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, cc, _, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(CallContextNoCall innercc, DataFlowCallable c | + flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or exists(AccessPath argAp0 | flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + flowFwdIsEntered(call, cc, argAp, argAp0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argAp, apf, ap, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwd(mid, cc, argAp, apf0, ap0, config) and flowFwdStore0(mid, tc, node, apf0, apf, config) ) } @@ -1764,20 +1775,20 @@ private predicate flowFwdStore0( pragma[nomagic] private predicate flowFwdRead0( - Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, - boolean fromArg, AccessPathOption argAp, Configuration config + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc, + AccessPathOption argAp, Configuration config ) { - flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + flowFwd(node1, cc, argAp, apf0, ap0, config) and readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, TypedContent tc | - flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and flowCand(node, _, _, apf, unbind(config)) and flowCandConsCand(tc, apf, unbind(config)) ) @@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argAp, apf, ap, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1809,13 +1823,19 @@ private predicate flowFwdIn( pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argAp, apf, ap, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg( DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config) } /** @@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } @@ -1920,7 +1940,7 @@ private predicate flow0( // flow out of a callable flowOut(_, node, _, _, ap, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config) then returnAp = TAccessPathSome(ap) else returnAp = TAccessPathNone() } @@ -2006,9 +2026,10 @@ private predicate flowIsReturned( DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { - exists(ReturnNodeExt ret | + exists(ReturnNodeExt ret, CallContextCall ccc | flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and + ccc.matchesCall(call) ) } @@ -2031,7 +2052,7 @@ private newtype TSummaryCtx = exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | parameterFlow(p, ap, ret.getEnclosingCallable(), config) and flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) + flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config) ) } @@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0( ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } @@ -2867,7 +2888,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index 5042dce683f..4e6eb9d86c0 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption { * Holds if `node` is reachable with access path `ap` from a source in * the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an + * The call context `cc` records whether the node is reached through an * argument in a call, and if so, `argAp` records the access path of that * argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argAp, apf, ap, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and + exists(Node mid, AccessPathNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and apf = ap.(AccessPathNil).getFront() ) or exists(Node mid | flowFwd(mid, _, _, apf, ap, config) and jumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() ) or exists(Node mid, AccessPathNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() @@ -1704,40 +1704,51 @@ private predicate flowFwd0( ) or // store - exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config)) or // read exists(TypedContent tc | - flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, cc, _, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(CallContextNoCall innercc, DataFlowCallable c | + flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or exists(AccessPath argAp0 | flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + flowFwdIsEntered(call, cc, argAp, argAp0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argAp, apf, ap, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwd(mid, cc, argAp, apf0, ap0, config) and flowFwdStore0(mid, tc, node, apf0, apf, config) ) } @@ -1764,20 +1775,20 @@ private predicate flowFwdStore0( pragma[nomagic] private predicate flowFwdRead0( - Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, - boolean fromArg, AccessPathOption argAp, Configuration config + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc, + AccessPathOption argAp, Configuration config ) { - flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + flowFwd(node1, cc, argAp, apf0, ap0, config) and readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, TypedContent tc | - flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and flowCand(node, _, _, apf, unbind(config)) and flowCandConsCand(tc, apf, unbind(config)) ) @@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argAp, apf, ap, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1809,13 +1823,19 @@ private predicate flowFwdIn( pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argAp, apf, ap, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg( DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config) } /** @@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } @@ -1920,7 +1940,7 @@ private predicate flow0( // flow out of a callable flowOut(_, node, _, _, ap, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config) then returnAp = TAccessPathSome(ap) else returnAp = TAccessPathNone() } @@ -2006,9 +2026,10 @@ private predicate flowIsReturned( DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { - exists(ReturnNodeExt ret | + exists(ReturnNodeExt ret, CallContextCall ccc | flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and + ccc.matchesCall(call) ) } @@ -2031,7 +2052,7 @@ private newtype TSummaryCtx = exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | parameterFlow(p, ap, ret.getEnclosingCallable(), config) and flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) + flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config) ) } @@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0( ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } @@ -2867,7 +2888,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index 5042dce683f..4e6eb9d86c0 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption { * Holds if `node` is reachable with access path `ap` from a source in * the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an + * The call context `cc` records whether the node is reached through an * argument in a call, and if so, `argAp` records the access path of that * argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argAp, apf, ap, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and + exists(Node mid, AccessPathNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and apf = ap.(AccessPathNil).getFront() ) or exists(Node mid | flowFwd(mid, _, _, apf, ap, config) and jumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() ) or exists(Node mid, AccessPathNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() @@ -1704,40 +1704,51 @@ private predicate flowFwd0( ) or // store - exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config)) or // read exists(TypedContent tc | - flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, cc, _, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(CallContextNoCall innercc, DataFlowCallable c | + flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or exists(AccessPath argAp0 | flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + flowFwdIsEntered(call, cc, argAp, argAp0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argAp, apf, ap, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwd(mid, cc, argAp, apf0, ap0, config) and flowFwdStore0(mid, tc, node, apf0, apf, config) ) } @@ -1764,20 +1775,20 @@ private predicate flowFwdStore0( pragma[nomagic] private predicate flowFwdRead0( - Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, - boolean fromArg, AccessPathOption argAp, Configuration config + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc, + AccessPathOption argAp, Configuration config ) { - flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + flowFwd(node1, cc, argAp, apf0, ap0, config) and readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, TypedContent tc | - flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and flowCand(node, _, _, apf, unbind(config)) and flowCandConsCand(tc, apf, unbind(config)) ) @@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argAp, apf, ap, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1809,13 +1823,19 @@ private predicate flowFwdIn( pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argAp, apf, ap, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg( DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config) } /** @@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } @@ -1920,7 +1940,7 @@ private predicate flow0( // flow out of a callable flowOut(_, node, _, _, ap, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config) then returnAp = TAccessPathSome(ap) else returnAp = TAccessPathNone() } @@ -2006,9 +2026,10 @@ private predicate flowIsReturned( DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { - exists(ReturnNodeExt ret | + exists(ReturnNodeExt ret, CallContextCall ccc | flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and + ccc.matchesCall(call) ) } @@ -2031,7 +2052,7 @@ private newtype TSummaryCtx = exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | parameterFlow(p, ap, ret.getEnclosingCallable(), config) and flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) + flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config) ) } @@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0( ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } @@ -2867,7 +2888,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index 5042dce683f..4e6eb9d86c0 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption { * Holds if `node` is reachable with access path `ap` from a source in * the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an + * The call context `cc` records whether the node is reached through an * argument in a call, and if so, `argAp` records the access path of that * argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argAp, apf, ap, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and + exists(Node mid, AccessPathNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and apf = ap.(AccessPathNil).getFront() ) or exists(Node mid | flowFwd(mid, _, _, apf, ap, config) and jumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() ) or exists(Node mid, AccessPathNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() @@ -1704,40 +1704,51 @@ private predicate flowFwd0( ) or // store - exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config)) or // read exists(TypedContent tc | - flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, cc, _, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(CallContextNoCall innercc, DataFlowCallable c | + flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or exists(AccessPath argAp0 | flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + flowFwdIsEntered(call, cc, argAp, argAp0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argAp, apf, ap, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwd(mid, cc, argAp, apf0, ap0, config) and flowFwdStore0(mid, tc, node, apf0, apf, config) ) } @@ -1764,20 +1775,20 @@ private predicate flowFwdStore0( pragma[nomagic] private predicate flowFwdRead0( - Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, - boolean fromArg, AccessPathOption argAp, Configuration config + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc, + AccessPathOption argAp, Configuration config ) { - flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + flowFwd(node1, cc, argAp, apf0, ap0, config) and readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, TypedContent tc | - flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and flowCand(node, _, _, apf, unbind(config)) and flowCandConsCand(tc, apf, unbind(config)) ) @@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argAp, apf, ap, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1809,13 +1823,19 @@ private predicate flowFwdIn( pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argAp, apf, ap, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg( DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config) } /** @@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } @@ -1920,7 +1940,7 @@ private predicate flow0( // flow out of a callable flowOut(_, node, _, _, ap, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config) then returnAp = TAccessPathSome(ap) else returnAp = TAccessPathNone() } @@ -2006,9 +2026,10 @@ private predicate flowIsReturned( DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { - exists(ReturnNodeExt ret | + exists(ReturnNodeExt ret, CallContextCall ccc | flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and + ccc.matchesCall(call) ) } @@ -2031,7 +2052,7 @@ private newtype TSummaryCtx = exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | parameterFlow(p, ap, ret.getEnclosingCallable(), config) and flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) + flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config) ) } @@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0( ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } @@ -2867,7 +2888,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll index 27ab1d01feb..892250f44bb 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll @@ -512,13 +512,19 @@ abstract class CallContext extends TCallContext { abstract predicate relevantFor(DataFlowCallable callable); } -class CallContextAny extends CallContext, TAnyCallContext { +abstract class CallContextNoCall extends CallContext { } + +class CallContextAny extends CallContextNoCall, TAnyCallContext { override string toString() { result = "CcAny" } override predicate relevantFor(DataFlowCallable callable) { any() } } -abstract class CallContextCall extends CallContext { } +abstract class CallContextCall extends CallContext { + /** Holds if this call context may be `call`. */ + bindingset[call] + abstract predicate matchesCall(DataFlowCall call); +} class CallContextSpecificCall extends CallContextCall, TSpecificCall { override string toString() { @@ -529,6 +535,8 @@ class CallContextSpecificCall extends CallContextCall, TSpecificCall { recordDataFlowCallSite(getCall(), callable) } + override predicate matchesCall(DataFlowCall call) { call = this.getCall() } + DataFlowCall getCall() { this = TSpecificCall(result) } } @@ -538,9 +546,11 @@ class CallContextSomeCall extends CallContextCall, TSomeCall { override predicate relevantFor(DataFlowCallable callable) { exists(ParameterNode p | p.getEnclosingCallable() = callable) } + + override predicate matchesCall(DataFlowCall call) { any() } } -class CallContextReturn extends CallContext, TReturn { +class CallContextReturn extends CallContextNoCall, TReturn { override string toString() { exists(DataFlowCall call | this = TReturn(_, call) | result = "CcReturn(" + call + ")") } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index 5042dce683f..4e6eb9d86c0 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption { * Holds if `node` is reachable with access path `ap` from a source in * the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an + * The call context `cc` records whether the node is reached through an * argument in a call, and if so, `argAp` records the access path of that * argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argAp, apf, ap, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and + exists(Node mid, AccessPathNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and apf = ap.(AccessPathNil).getFront() ) or exists(Node mid | flowFwd(mid, _, _, apf, ap, config) and jumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() ) or exists(Node mid, AccessPathNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() @@ -1704,40 +1704,51 @@ private predicate flowFwd0( ) or // store - exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config)) or // read exists(TypedContent tc | - flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, cc, _, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(CallContextNoCall innercc, DataFlowCallable c | + flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or exists(AccessPath argAp0 | flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + flowFwdIsEntered(call, cc, argAp, argAp0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argAp, apf, ap, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwd(mid, cc, argAp, apf0, ap0, config) and flowFwdStore0(mid, tc, node, apf0, apf, config) ) } @@ -1764,20 +1775,20 @@ private predicate flowFwdStore0( pragma[nomagic] private predicate flowFwdRead0( - Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, - boolean fromArg, AccessPathOption argAp, Configuration config + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc, + AccessPathOption argAp, Configuration config ) { - flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + flowFwd(node1, cc, argAp, apf0, ap0, config) and readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, TypedContent tc | - flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and flowCand(node, _, _, apf, unbind(config)) and flowCandConsCand(tc, apf, unbind(config)) ) @@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argAp, apf, ap, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1809,13 +1823,19 @@ private predicate flowFwdIn( pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argAp, apf, ap, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg( DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config) } /** @@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } @@ -1920,7 +1940,7 @@ private predicate flow0( // flow out of a callable flowOut(_, node, _, _, ap, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config) then returnAp = TAccessPathSome(ap) else returnAp = TAccessPathNone() } @@ -2006,9 +2026,10 @@ private predicate flowIsReturned( DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { - exists(ReturnNodeExt ret | + exists(ReturnNodeExt ret, CallContextCall ccc | flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and + ccc.matchesCall(call) ) } @@ -2031,7 +2052,7 @@ private newtype TSummaryCtx = exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | parameterFlow(p, ap, ret.getEnclosingCallable(), config) and flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) + flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config) ) } @@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0( ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } @@ -2867,7 +2888,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index 5042dce683f..4e6eb9d86c0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption { * Holds if `node` is reachable with access path `ap` from a source in * the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an + * The call context `cc` records whether the node is reached through an * argument in a call, and if so, `argAp` records the access path of that * argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argAp, apf, ap, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and + exists(Node mid, AccessPathNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and apf = ap.(AccessPathNil).getFront() ) or exists(Node mid | flowFwd(mid, _, _, apf, ap, config) and jumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() ) or exists(Node mid, AccessPathNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() @@ -1704,40 +1704,51 @@ private predicate flowFwd0( ) or // store - exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config)) or // read exists(TypedContent tc | - flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, cc, _, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(CallContextNoCall innercc, DataFlowCallable c | + flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or exists(AccessPath argAp0 | flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + flowFwdIsEntered(call, cc, argAp, argAp0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argAp, apf, ap, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwd(mid, cc, argAp, apf0, ap0, config) and flowFwdStore0(mid, tc, node, apf0, apf, config) ) } @@ -1764,20 +1775,20 @@ private predicate flowFwdStore0( pragma[nomagic] private predicate flowFwdRead0( - Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, - boolean fromArg, AccessPathOption argAp, Configuration config + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc, + AccessPathOption argAp, Configuration config ) { - flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + flowFwd(node1, cc, argAp, apf0, ap0, config) and readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, TypedContent tc | - flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and flowCand(node, _, _, apf, unbind(config)) and flowCandConsCand(tc, apf, unbind(config)) ) @@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argAp, apf, ap, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1809,13 +1823,19 @@ private predicate flowFwdIn( pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argAp, apf, ap, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg( DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config) } /** @@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } @@ -1920,7 +1940,7 @@ private predicate flow0( // flow out of a callable flowOut(_, node, _, _, ap, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config) then returnAp = TAccessPathSome(ap) else returnAp = TAccessPathNone() } @@ -2006,9 +2026,10 @@ private predicate flowIsReturned( DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { - exists(ReturnNodeExt ret | + exists(ReturnNodeExt ret, CallContextCall ccc | flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and + ccc.matchesCall(call) ) } @@ -2031,7 +2052,7 @@ private newtype TSummaryCtx = exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | parameterFlow(p, ap, ret.getEnclosingCallable(), config) and flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) + flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config) ) } @@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0( ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } @@ -2867,7 +2888,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index 5042dce683f..4e6eb9d86c0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption { * Holds if `node` is reachable with access path `ap` from a source in * the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an + * The call context `cc` records whether the node is reached through an * argument in a call, and if so, `argAp` records the access path of that * argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argAp, apf, ap, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and + exists(Node mid, AccessPathNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and apf = ap.(AccessPathNil).getFront() ) or exists(Node mid | flowFwd(mid, _, _, apf, ap, config) and jumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() ) or exists(Node mid, AccessPathNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() @@ -1704,40 +1704,51 @@ private predicate flowFwd0( ) or // store - exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config)) or // read exists(TypedContent tc | - flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, cc, _, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(CallContextNoCall innercc, DataFlowCallable c | + flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or exists(AccessPath argAp0 | flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + flowFwdIsEntered(call, cc, argAp, argAp0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argAp, apf, ap, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwd(mid, cc, argAp, apf0, ap0, config) and flowFwdStore0(mid, tc, node, apf0, apf, config) ) } @@ -1764,20 +1775,20 @@ private predicate flowFwdStore0( pragma[nomagic] private predicate flowFwdRead0( - Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, - boolean fromArg, AccessPathOption argAp, Configuration config + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc, + AccessPathOption argAp, Configuration config ) { - flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + flowFwd(node1, cc, argAp, apf0, ap0, config) and readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, TypedContent tc | - flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and flowCand(node, _, _, apf, unbind(config)) and flowCandConsCand(tc, apf, unbind(config)) ) @@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argAp, apf, ap, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1809,13 +1823,19 @@ private predicate flowFwdIn( pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argAp, apf, ap, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg( DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config) } /** @@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } @@ -1920,7 +1940,7 @@ private predicate flow0( // flow out of a callable flowOut(_, node, _, _, ap, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config) then returnAp = TAccessPathSome(ap) else returnAp = TAccessPathNone() } @@ -2006,9 +2026,10 @@ private predicate flowIsReturned( DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { - exists(ReturnNodeExt ret | + exists(ReturnNodeExt ret, CallContextCall ccc | flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and + ccc.matchesCall(call) ) } @@ -2031,7 +2052,7 @@ private newtype TSummaryCtx = exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | parameterFlow(p, ap, ret.getEnclosingCallable(), config) and flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) + flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config) ) } @@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0( ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } @@ -2867,7 +2888,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index 5042dce683f..4e6eb9d86c0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption { * Holds if `node` is reachable with access path `ap` from a source in * the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an + * The call context `cc` records whether the node is reached through an * argument in a call, and if so, `argAp` records the access path of that * argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argAp, apf, ap, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and + exists(Node mid, AccessPathNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and apf = ap.(AccessPathNil).getFront() ) or exists(Node mid | flowFwd(mid, _, _, apf, ap, config) and jumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() ) or exists(Node mid, AccessPathNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() @@ -1704,40 +1704,51 @@ private predicate flowFwd0( ) or // store - exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config)) or // read exists(TypedContent tc | - flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, cc, _, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(CallContextNoCall innercc, DataFlowCallable c | + flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or exists(AccessPath argAp0 | flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + flowFwdIsEntered(call, cc, argAp, argAp0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argAp, apf, ap, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwd(mid, cc, argAp, apf0, ap0, config) and flowFwdStore0(mid, tc, node, apf0, apf, config) ) } @@ -1764,20 +1775,20 @@ private predicate flowFwdStore0( pragma[nomagic] private predicate flowFwdRead0( - Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, - boolean fromArg, AccessPathOption argAp, Configuration config + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc, + AccessPathOption argAp, Configuration config ) { - flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + flowFwd(node1, cc, argAp, apf0, ap0, config) and readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, TypedContent tc | - flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and flowCand(node, _, _, apf, unbind(config)) and flowCandConsCand(tc, apf, unbind(config)) ) @@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argAp, apf, ap, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1809,13 +1823,19 @@ private predicate flowFwdIn( pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argAp, apf, ap, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg( DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config) } /** @@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } @@ -1920,7 +1940,7 @@ private predicate flow0( // flow out of a callable flowOut(_, node, _, _, ap, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config) then returnAp = TAccessPathSome(ap) else returnAp = TAccessPathNone() } @@ -2006,9 +2026,10 @@ private predicate flowIsReturned( DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { - exists(ReturnNodeExt ret | + exists(ReturnNodeExt ret, CallContextCall ccc | flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and + ccc.matchesCall(call) ) } @@ -2031,7 +2052,7 @@ private newtype TSummaryCtx = exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | parameterFlow(p, ap, ret.getEnclosingCallable(), config) and flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) + flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config) ) } @@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0( ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } @@ -2867,7 +2888,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index 5042dce683f..4e6eb9d86c0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption { * Holds if `node` is reachable with access path `ap` from a source in * the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an + * The call context `cc` records whether the node is reached through an * argument in a call, and if so, `argAp` records the access path of that * argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argAp, apf, ap, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and + exists(Node mid, AccessPathNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and apf = ap.(AccessPathNil).getFront() ) or exists(Node mid | flowFwd(mid, _, _, apf, ap, config) and jumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() ) or exists(Node mid, AccessPathNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() @@ -1704,40 +1704,51 @@ private predicate flowFwd0( ) or // store - exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config)) or // read exists(TypedContent tc | - flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, cc, _, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(CallContextNoCall innercc, DataFlowCallable c | + flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or exists(AccessPath argAp0 | flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + flowFwdIsEntered(call, cc, argAp, argAp0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argAp, apf, ap, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwd(mid, cc, argAp, apf0, ap0, config) and flowFwdStore0(mid, tc, node, apf0, apf, config) ) } @@ -1764,20 +1775,20 @@ private predicate flowFwdStore0( pragma[nomagic] private predicate flowFwdRead0( - Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, - boolean fromArg, AccessPathOption argAp, Configuration config + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc, + AccessPathOption argAp, Configuration config ) { - flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + flowFwd(node1, cc, argAp, apf0, ap0, config) and readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, TypedContent tc | - flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and flowCand(node, _, _, apf, unbind(config)) and flowCandConsCand(tc, apf, unbind(config)) ) @@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argAp, apf, ap, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1809,13 +1823,19 @@ private predicate flowFwdIn( pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argAp, apf, ap, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg( DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config) } /** @@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } @@ -1920,7 +1940,7 @@ private predicate flow0( // flow out of a callable flowOut(_, node, _, _, ap, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config) then returnAp = TAccessPathSome(ap) else returnAp = TAccessPathNone() } @@ -2006,9 +2026,10 @@ private predicate flowIsReturned( DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { - exists(ReturnNodeExt ret | + exists(ReturnNodeExt ret, CallContextCall ccc | flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and + ccc.matchesCall(call) ) } @@ -2031,7 +2052,7 @@ private newtype TSummaryCtx = exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | parameterFlow(p, ap, ret.getEnclosingCallable(), config) and flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) + flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config) ) } @@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0( ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } @@ -2867,7 +2888,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll index 27ab1d01feb..892250f44bb 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll @@ -512,13 +512,19 @@ abstract class CallContext extends TCallContext { abstract predicate relevantFor(DataFlowCallable callable); } -class CallContextAny extends CallContext, TAnyCallContext { +abstract class CallContextNoCall extends CallContext { } + +class CallContextAny extends CallContextNoCall, TAnyCallContext { override string toString() { result = "CcAny" } override predicate relevantFor(DataFlowCallable callable) { any() } } -abstract class CallContextCall extends CallContext { } +abstract class CallContextCall extends CallContext { + /** Holds if this call context may be `call`. */ + bindingset[call] + abstract predicate matchesCall(DataFlowCall call); +} class CallContextSpecificCall extends CallContextCall, TSpecificCall { override string toString() { @@ -529,6 +535,8 @@ class CallContextSpecificCall extends CallContextCall, TSpecificCall { recordDataFlowCallSite(getCall(), callable) } + override predicate matchesCall(DataFlowCall call) { call = this.getCall() } + DataFlowCall getCall() { this = TSpecificCall(result) } } @@ -538,9 +546,11 @@ class CallContextSomeCall extends CallContextCall, TSomeCall { override predicate relevantFor(DataFlowCallable callable) { exists(ParameterNode p | p.getEnclosingCallable() = callable) } + + override predicate matchesCall(DataFlowCall call) { any() } } -class CallContextReturn extends CallContext, TReturn { +class CallContextReturn extends CallContextNoCall, TReturn { override string toString() { exists(DataFlowCall call | this = TReturn(_, call) | result = "CcReturn(" + call + ")") } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index 5042dce683f..4e6eb9d86c0 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption { * Holds if `node` is reachable with access path `ap` from a source in * the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an + * The call context `cc` records whether the node is reached through an * argument in a call, and if so, `argAp` records the access path of that * argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argAp, apf, ap, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and + exists(Node mid, AccessPathNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and apf = ap.(AccessPathNil).getFront() ) or exists(Node mid | flowFwd(mid, _, _, apf, ap, config) and jumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() ) or exists(Node mid, AccessPathNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() @@ -1704,40 +1704,51 @@ private predicate flowFwd0( ) or // store - exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config)) or // read exists(TypedContent tc | - flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, cc, _, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(CallContextNoCall innercc, DataFlowCallable c | + flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or exists(AccessPath argAp0 | flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + flowFwdIsEntered(call, cc, argAp, argAp0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argAp, apf, ap, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwd(mid, cc, argAp, apf0, ap0, config) and flowFwdStore0(mid, tc, node, apf0, apf, config) ) } @@ -1764,20 +1775,20 @@ private predicate flowFwdStore0( pragma[nomagic] private predicate flowFwdRead0( - Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, - boolean fromArg, AccessPathOption argAp, Configuration config + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc, + AccessPathOption argAp, Configuration config ) { - flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + flowFwd(node1, cc, argAp, apf0, ap0, config) and readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, TypedContent tc | - flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and flowCand(node, _, _, apf, unbind(config)) and flowCandConsCand(tc, apf, unbind(config)) ) @@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argAp, apf, ap, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1809,13 +1823,19 @@ private predicate flowFwdIn( pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argAp, apf, ap, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg( DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config) } /** @@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } @@ -1920,7 +1940,7 @@ private predicate flow0( // flow out of a callable flowOut(_, node, _, _, ap, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config) then returnAp = TAccessPathSome(ap) else returnAp = TAccessPathNone() } @@ -2006,9 +2026,10 @@ private predicate flowIsReturned( DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { - exists(ReturnNodeExt ret | + exists(ReturnNodeExt ret, CallContextCall ccc | flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and + ccc.matchesCall(call) ) } @@ -2031,7 +2052,7 @@ private newtype TSummaryCtx = exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | parameterFlow(p, ap, ret.getEnclosingCallable(), config) and flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) + flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config) ) } @@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0( ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } @@ -2867,7 +2888,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index 5042dce683f..4e6eb9d86c0 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption { * Holds if `node` is reachable with access path `ap` from a source in * the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an + * The call context `cc` records whether the node is reached through an * argument in a call, and if so, `argAp` records the access path of that * argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argAp, apf, ap, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and + exists(Node mid, AccessPathNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and apf = ap.(AccessPathNil).getFront() ) or exists(Node mid | flowFwd(mid, _, _, apf, ap, config) and jumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() ) or exists(Node mid, AccessPathNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() @@ -1704,40 +1704,51 @@ private predicate flowFwd0( ) or // store - exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config)) or // read exists(TypedContent tc | - flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, cc, _, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(CallContextNoCall innercc, DataFlowCallable c | + flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or exists(AccessPath argAp0 | flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + flowFwdIsEntered(call, cc, argAp, argAp0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argAp, apf, ap, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwd(mid, cc, argAp, apf0, ap0, config) and flowFwdStore0(mid, tc, node, apf0, apf, config) ) } @@ -1764,20 +1775,20 @@ private predicate flowFwdStore0( pragma[nomagic] private predicate flowFwdRead0( - Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, - boolean fromArg, AccessPathOption argAp, Configuration config + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc, + AccessPathOption argAp, Configuration config ) { - flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + flowFwd(node1, cc, argAp, apf0, ap0, config) and readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, TypedContent tc | - flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and flowCand(node, _, _, apf, unbind(config)) and flowCandConsCand(tc, apf, unbind(config)) ) @@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argAp, apf, ap, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1809,13 +1823,19 @@ private predicate flowFwdIn( pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argAp, apf, ap, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg( DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config) } /** @@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } @@ -1920,7 +1940,7 @@ private predicate flow0( // flow out of a callable flowOut(_, node, _, _, ap, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config) then returnAp = TAccessPathSome(ap) else returnAp = TAccessPathNone() } @@ -2006,9 +2026,10 @@ private predicate flowIsReturned( DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { - exists(ReturnNodeExt ret | + exists(ReturnNodeExt ret, CallContextCall ccc | flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and + ccc.matchesCall(call) ) } @@ -2031,7 +2052,7 @@ private newtype TSummaryCtx = exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | parameterFlow(p, ap, ret.getEnclosingCallable(), config) and flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) + flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config) ) } @@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0( ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } @@ -2867,7 +2888,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index 5042dce683f..4e6eb9d86c0 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption { * Holds if `node` is reachable with access path `ap` from a source in * the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an + * The call context `cc` records whether the node is reached through an * argument in a call, and if so, `argAp` records the access path of that * argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argAp, apf, ap, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and + exists(Node mid, AccessPathNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and apf = ap.(AccessPathNil).getFront() ) or exists(Node mid | flowFwd(mid, _, _, apf, ap, config) and jumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() ) or exists(Node mid, AccessPathNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() @@ -1704,40 +1704,51 @@ private predicate flowFwd0( ) or // store - exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config)) or // read exists(TypedContent tc | - flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, cc, _, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(CallContextNoCall innercc, DataFlowCallable c | + flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or exists(AccessPath argAp0 | flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + flowFwdIsEntered(call, cc, argAp, argAp0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argAp, apf, ap, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwd(mid, cc, argAp, apf0, ap0, config) and flowFwdStore0(mid, tc, node, apf0, apf, config) ) } @@ -1764,20 +1775,20 @@ private predicate flowFwdStore0( pragma[nomagic] private predicate flowFwdRead0( - Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, - boolean fromArg, AccessPathOption argAp, Configuration config + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc, + AccessPathOption argAp, Configuration config ) { - flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + flowFwd(node1, cc, argAp, apf0, ap0, config) and readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, TypedContent tc | - flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and flowCand(node, _, _, apf, unbind(config)) and flowCandConsCand(tc, apf, unbind(config)) ) @@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argAp, apf, ap, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1809,13 +1823,19 @@ private predicate flowFwdIn( pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argAp, apf, ap, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg( DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config) } /** @@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } @@ -1920,7 +1940,7 @@ private predicate flow0( // flow out of a callable flowOut(_, node, _, _, ap, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config) then returnAp = TAccessPathSome(ap) else returnAp = TAccessPathNone() } @@ -2006,9 +2026,10 @@ private predicate flowIsReturned( DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { - exists(ReturnNodeExt ret | + exists(ReturnNodeExt ret, CallContextCall ccc | flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and + ccc.matchesCall(call) ) } @@ -2031,7 +2052,7 @@ private newtype TSummaryCtx = exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | parameterFlow(p, ap, ret.getEnclosingCallable(), config) and flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) + flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config) ) } @@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0( ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } @@ -2867,7 +2888,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index 5042dce683f..4e6eb9d86c0 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption { * Holds if `node` is reachable with access path `ap` from a source in * the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an + * The call context `cc` records whether the node is reached through an * argument in a call, and if so, `argAp` records the access path of that * argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argAp, apf, ap, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and + exists(Node mid, AccessPathNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and apf = ap.(AccessPathNil).getFront() ) or exists(Node mid | flowFwd(mid, _, _, apf, ap, config) and jumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() ) or exists(Node mid, AccessPathNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() @@ -1704,40 +1704,51 @@ private predicate flowFwd0( ) or // store - exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config)) or // read exists(TypedContent tc | - flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, cc, _, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(CallContextNoCall innercc, DataFlowCallable c | + flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or exists(AccessPath argAp0 | flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + flowFwdIsEntered(call, cc, argAp, argAp0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argAp, apf, ap, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwd(mid, cc, argAp, apf0, ap0, config) and flowFwdStore0(mid, tc, node, apf0, apf, config) ) } @@ -1764,20 +1775,20 @@ private predicate flowFwdStore0( pragma[nomagic] private predicate flowFwdRead0( - Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, - boolean fromArg, AccessPathOption argAp, Configuration config + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc, + AccessPathOption argAp, Configuration config ) { - flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + flowFwd(node1, cc, argAp, apf0, ap0, config) and readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, TypedContent tc | - flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and flowCand(node, _, _, apf, unbind(config)) and flowCandConsCand(tc, apf, unbind(config)) ) @@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argAp, apf, ap, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1809,13 +1823,19 @@ private predicate flowFwdIn( pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argAp, apf, ap, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg( DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config) } /** @@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } @@ -1920,7 +1940,7 @@ private predicate flow0( // flow out of a callable flowOut(_, node, _, _, ap, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config) then returnAp = TAccessPathSome(ap) else returnAp = TAccessPathNone() } @@ -2006,9 +2026,10 @@ private predicate flowIsReturned( DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { - exists(ReturnNodeExt ret | + exists(ReturnNodeExt ret, CallContextCall ccc | flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and + ccc.matchesCall(call) ) } @@ -2031,7 +2052,7 @@ private newtype TSummaryCtx = exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | parameterFlow(p, ap, ret.getEnclosingCallable(), config) and flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) + flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config) ) } @@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0( ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } @@ -2867,7 +2888,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index 5042dce683f..4e6eb9d86c0 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption { * Holds if `node` is reachable with access path `ap` from a source in * the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an + * The call context `cc` records whether the node is reached through an * argument in a call, and if so, `argAp` records the access path of that * argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argAp, apf, ap, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and + exists(Node mid, AccessPathNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and apf = ap.(AccessPathNil).getFront() ) or exists(Node mid | flowFwd(mid, _, _, apf, ap, config) and jumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() ) or exists(Node mid, AccessPathNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() @@ -1704,40 +1704,51 @@ private predicate flowFwd0( ) or // store - exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config)) or // read exists(TypedContent tc | - flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, cc, _, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(CallContextNoCall innercc, DataFlowCallable c | + flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or exists(AccessPath argAp0 | flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + flowFwdIsEntered(call, cc, argAp, argAp0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argAp, apf, ap, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwd(mid, cc, argAp, apf0, ap0, config) and flowFwdStore0(mid, tc, node, apf0, apf, config) ) } @@ -1764,20 +1775,20 @@ private predicate flowFwdStore0( pragma[nomagic] private predicate flowFwdRead0( - Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, - boolean fromArg, AccessPathOption argAp, Configuration config + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc, + AccessPathOption argAp, Configuration config ) { - flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + flowFwd(node1, cc, argAp, apf0, ap0, config) and readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, TypedContent tc | - flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and flowCand(node, _, _, apf, unbind(config)) and flowCandConsCand(tc, apf, unbind(config)) ) @@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argAp, apf, ap, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1809,13 +1823,19 @@ private predicate flowFwdIn( pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argAp, apf, ap, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg( DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config) } /** @@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } @@ -1920,7 +1940,7 @@ private predicate flow0( // flow out of a callable flowOut(_, node, _, _, ap, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config) then returnAp = TAccessPathSome(ap) else returnAp = TAccessPathNone() } @@ -2006,9 +2026,10 @@ private predicate flowIsReturned( DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { - exists(ReturnNodeExt ret | + exists(ReturnNodeExt ret, CallContextCall ccc | flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and + ccc.matchesCall(call) ) } @@ -2031,7 +2052,7 @@ private newtype TSummaryCtx = exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | parameterFlow(p, ap, ret.getEnclosingCallable(), config) and flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) + flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config) ) } @@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0( ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } @@ -2867,7 +2888,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index 5042dce683f..4e6eb9d86c0 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption { * Holds if `node` is reachable with access path `ap` from a source in * the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an + * The call context `cc` records whether the node is reached through an * argument in a call, and if so, `argAp` records the access path of that * argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argAp, apf, ap, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and + exists(Node mid, AccessPathNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and apf = ap.(AccessPathNil).getFront() ) or exists(Node mid | flowFwd(mid, _, _, apf, ap, config) and jumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() ) or exists(Node mid, AccessPathNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() @@ -1704,40 +1704,51 @@ private predicate flowFwd0( ) or // store - exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config)) or // read exists(TypedContent tc | - flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, cc, _, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(CallContextNoCall innercc, DataFlowCallable c | + flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or exists(AccessPath argAp0 | flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + flowFwdIsEntered(call, cc, argAp, argAp0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argAp, apf, ap, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwd(mid, cc, argAp, apf0, ap0, config) and flowFwdStore0(mid, tc, node, apf0, apf, config) ) } @@ -1764,20 +1775,20 @@ private predicate flowFwdStore0( pragma[nomagic] private predicate flowFwdRead0( - Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, - boolean fromArg, AccessPathOption argAp, Configuration config + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc, + AccessPathOption argAp, Configuration config ) { - flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + flowFwd(node1, cc, argAp, apf0, ap0, config) and readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, TypedContent tc | - flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and flowCand(node, _, _, apf, unbind(config)) and flowCandConsCand(tc, apf, unbind(config)) ) @@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argAp, apf, ap, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1809,13 +1823,19 @@ private predicate flowFwdIn( pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argAp, apf, ap, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg( DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config) } /** @@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } @@ -1920,7 +1940,7 @@ private predicate flow0( // flow out of a callable flowOut(_, node, _, _, ap, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config) then returnAp = TAccessPathSome(ap) else returnAp = TAccessPathNone() } @@ -2006,9 +2026,10 @@ private predicate flowIsReturned( DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { - exists(ReturnNodeExt ret | + exists(ReturnNodeExt ret, CallContextCall ccc | flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and + ccc.matchesCall(call) ) } @@ -2031,7 +2052,7 @@ private newtype TSummaryCtx = exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | parameterFlow(p, ap, ret.getEnclosingCallable(), config) and flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) + flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config) ) } @@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0( ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } @@ -2867,7 +2888,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index 5042dce683f..4e6eb9d86c0 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption { * Holds if `node` is reachable with access path `ap` from a source in * the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an + * The call context `cc` records whether the node is reached through an * argument in a call, and if so, `argAp` records the access path of that * argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argAp, apf, ap, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and + exists(Node mid, AccessPathNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and apf = ap.(AccessPathNil).getFront() ) or exists(Node mid | flowFwd(mid, _, _, apf, ap, config) and jumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() ) or exists(Node mid, AccessPathNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() @@ -1704,40 +1704,51 @@ private predicate flowFwd0( ) or // store - exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config)) or // read exists(TypedContent tc | - flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, cc, _, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(CallContextNoCall innercc, DataFlowCallable c | + flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or exists(AccessPath argAp0 | flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + flowFwdIsEntered(call, cc, argAp, argAp0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argAp, apf, ap, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwd(mid, cc, argAp, apf0, ap0, config) and flowFwdStore0(mid, tc, node, apf0, apf, config) ) } @@ -1764,20 +1775,20 @@ private predicate flowFwdStore0( pragma[nomagic] private predicate flowFwdRead0( - Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, - boolean fromArg, AccessPathOption argAp, Configuration config + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc, + AccessPathOption argAp, Configuration config ) { - flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + flowFwd(node1, cc, argAp, apf0, ap0, config) and readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, TypedContent tc | - flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and flowCand(node, _, _, apf, unbind(config)) and flowCandConsCand(tc, apf, unbind(config)) ) @@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argAp, apf, ap, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1809,13 +1823,19 @@ private predicate flowFwdIn( pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argAp, apf, ap, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg( DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config) } /** @@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } @@ -1920,7 +1940,7 @@ private predicate flow0( // flow out of a callable flowOut(_, node, _, _, ap, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config) then returnAp = TAccessPathSome(ap) else returnAp = TAccessPathNone() } @@ -2006,9 +2026,10 @@ private predicate flowIsReturned( DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { - exists(ReturnNodeExt ret | + exists(ReturnNodeExt ret, CallContextCall ccc | flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and + ccc.matchesCall(call) ) } @@ -2031,7 +2052,7 @@ private newtype TSummaryCtx = exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | parameterFlow(p, ap, ret.getEnclosingCallable(), config) and flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) + flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config) ) } @@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0( ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } @@ -2867,7 +2888,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index 5042dce683f..4e6eb9d86c0 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption { * Holds if `node` is reachable with access path `ap` from a source in * the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an + * The call context `cc` records whether the node is reached through an * argument in a call, and if so, `argAp` records the access path of that * argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argAp, apf, ap, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and + exists(Node mid, AccessPathNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and apf = ap.(AccessPathNil).getFront() ) or exists(Node mid | flowFwd(mid, _, _, apf, ap, config) and jumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() ) or exists(Node mid, AccessPathNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() @@ -1704,40 +1704,51 @@ private predicate flowFwd0( ) or // store - exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config)) or // read exists(TypedContent tc | - flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, cc, _, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(CallContextNoCall innercc, DataFlowCallable c | + flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or exists(AccessPath argAp0 | flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + flowFwdIsEntered(call, cc, argAp, argAp0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argAp, apf, ap, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwd(mid, cc, argAp, apf0, ap0, config) and flowFwdStore0(mid, tc, node, apf0, apf, config) ) } @@ -1764,20 +1775,20 @@ private predicate flowFwdStore0( pragma[nomagic] private predicate flowFwdRead0( - Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, - boolean fromArg, AccessPathOption argAp, Configuration config + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc, + AccessPathOption argAp, Configuration config ) { - flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + flowFwd(node1, cc, argAp, apf0, ap0, config) and readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, TypedContent tc | - flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and flowCand(node, _, _, apf, unbind(config)) and flowCandConsCand(tc, apf, unbind(config)) ) @@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argAp, apf, ap, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1809,13 +1823,19 @@ private predicate flowFwdIn( pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argAp, apf, ap, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg( DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config) } /** @@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } @@ -1920,7 +1940,7 @@ private predicate flow0( // flow out of a callable flowOut(_, node, _, _, ap, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config) then returnAp = TAccessPathSome(ap) else returnAp = TAccessPathNone() } @@ -2006,9 +2026,10 @@ private predicate flowIsReturned( DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { - exists(ReturnNodeExt ret | + exists(ReturnNodeExt ret, CallContextCall ccc | flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and + ccc.matchesCall(call) ) } @@ -2031,7 +2052,7 @@ private newtype TSummaryCtx = exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | parameterFlow(p, ap, ret.getEnclosingCallable(), config) and flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) + flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config) ) } @@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0( ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } @@ -2867,7 +2888,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index 5042dce683f..4e6eb9d86c0 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption { * Holds if `node` is reachable with access path `ap` from a source in * the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an + * The call context `cc` records whether the node is reached through an * argument in a call, and if so, `argAp` records the access path of that * argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argAp, apf, ap, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and + exists(Node mid, AccessPathNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and apf = ap.(AccessPathNil).getFront() ) or exists(Node mid | flowFwd(mid, _, _, apf, ap, config) and jumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() ) or exists(Node mid, AccessPathNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() @@ -1704,40 +1704,51 @@ private predicate flowFwd0( ) or // store - exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config)) or // read exists(TypedContent tc | - flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, cc, _, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(CallContextNoCall innercc, DataFlowCallable c | + flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or exists(AccessPath argAp0 | flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + flowFwdIsEntered(call, cc, argAp, argAp0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argAp, apf, ap, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwd(mid, cc, argAp, apf0, ap0, config) and flowFwdStore0(mid, tc, node, apf0, apf, config) ) } @@ -1764,20 +1775,20 @@ private predicate flowFwdStore0( pragma[nomagic] private predicate flowFwdRead0( - Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, - boolean fromArg, AccessPathOption argAp, Configuration config + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc, + AccessPathOption argAp, Configuration config ) { - flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + flowFwd(node1, cc, argAp, apf0, ap0, config) and readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, TypedContent tc | - flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and flowCand(node, _, _, apf, unbind(config)) and flowCandConsCand(tc, apf, unbind(config)) ) @@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argAp, apf, ap, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1809,13 +1823,19 @@ private predicate flowFwdIn( pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argAp, apf, ap, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg( DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config) } /** @@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } @@ -1920,7 +1940,7 @@ private predicate flow0( // flow out of a callable flowOut(_, node, _, _, ap, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config) then returnAp = TAccessPathSome(ap) else returnAp = TAccessPathNone() } @@ -2006,9 +2026,10 @@ private predicate flowIsReturned( DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { - exists(ReturnNodeExt ret | + exists(ReturnNodeExt ret, CallContextCall ccc | flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and + ccc.matchesCall(call) ) } @@ -2031,7 +2052,7 @@ private newtype TSummaryCtx = exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | parameterFlow(p, ap, ret.getEnclosingCallable(), config) and flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) + flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config) ) } @@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0( ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } @@ -2867,7 +2888,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll index 27ab1d01feb..892250f44bb 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @@ -512,13 +512,19 @@ abstract class CallContext extends TCallContext { abstract predicate relevantFor(DataFlowCallable callable); } -class CallContextAny extends CallContext, TAnyCallContext { +abstract class CallContextNoCall extends CallContext { } + +class CallContextAny extends CallContextNoCall, TAnyCallContext { override string toString() { result = "CcAny" } override predicate relevantFor(DataFlowCallable callable) { any() } } -abstract class CallContextCall extends CallContext { } +abstract class CallContextCall extends CallContext { + /** Holds if this call context may be `call`. */ + bindingset[call] + abstract predicate matchesCall(DataFlowCall call); +} class CallContextSpecificCall extends CallContextCall, TSpecificCall { override string toString() { @@ -529,6 +535,8 @@ class CallContextSpecificCall extends CallContextCall, TSpecificCall { recordDataFlowCallSite(getCall(), callable) } + override predicate matchesCall(DataFlowCall call) { call = this.getCall() } + DataFlowCall getCall() { this = TSpecificCall(result) } } @@ -538,9 +546,11 @@ class CallContextSomeCall extends CallContextCall, TSomeCall { override predicate relevantFor(DataFlowCallable callable) { exists(ParameterNode p | p.getEnclosingCallable() = callable) } + + override predicate matchesCall(DataFlowCall call) { any() } } -class CallContextReturn extends CallContext, TReturn { +class CallContextReturn extends CallContextNoCall, TReturn { override string toString() { exists(DataFlowCall call | this = TReturn(_, call) | result = "CcReturn(" + call + ")") } From e518cbabd678557352bcc83b8238ac6afcedf588 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 29 Jul 2020 09:44:33 +0200 Subject: [PATCH 3/4] Python: Sync data flow files --- .../dataflow/internal/DataFlowImpl.qll | 113 +++++++++++------- .../dataflow/internal/DataFlowImpl2.qll | 113 +++++++++++------- .../dataflow/internal/DataFlowImplCommon.qll | 16 ++- 3 files changed, 147 insertions(+), 95 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll b/python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll index 5042dce683f..4e6eb9d86c0 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption { * Holds if `node` is reachable with access path `ap` from a source in * the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an + * The call context `cc` records whether the node is reached through an * argument in a call, and if so, `argAp` records the access path of that * argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argAp, apf, ap, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and + exists(Node mid, AccessPathNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and apf = ap.(AccessPathNil).getFront() ) or exists(Node mid | flowFwd(mid, _, _, apf, ap, config) and jumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() ) or exists(Node mid, AccessPathNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() @@ -1704,40 +1704,51 @@ private predicate flowFwd0( ) or // store - exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config)) or // read exists(TypedContent tc | - flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, cc, _, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(CallContextNoCall innercc, DataFlowCallable c | + flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or exists(AccessPath argAp0 | flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + flowFwdIsEntered(call, cc, argAp, argAp0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argAp, apf, ap, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwd(mid, cc, argAp, apf0, ap0, config) and flowFwdStore0(mid, tc, node, apf0, apf, config) ) } @@ -1764,20 +1775,20 @@ private predicate flowFwdStore0( pragma[nomagic] private predicate flowFwdRead0( - Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, - boolean fromArg, AccessPathOption argAp, Configuration config + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc, + AccessPathOption argAp, Configuration config ) { - flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + flowFwd(node1, cc, argAp, apf0, ap0, config) and readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, TypedContent tc | - flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and flowCand(node, _, _, apf, unbind(config)) and flowCandConsCand(tc, apf, unbind(config)) ) @@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argAp, apf, ap, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1809,13 +1823,19 @@ private predicate flowFwdIn( pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argAp, apf, ap, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg( DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config) } /** @@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } @@ -1920,7 +1940,7 @@ private predicate flow0( // flow out of a callable flowOut(_, node, _, _, ap, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config) then returnAp = TAccessPathSome(ap) else returnAp = TAccessPathNone() } @@ -2006,9 +2026,10 @@ private predicate flowIsReturned( DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { - exists(ReturnNodeExt ret | + exists(ReturnNodeExt ret, CallContextCall ccc | flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and + ccc.matchesCall(call) ) } @@ -2031,7 +2052,7 @@ private newtype TSummaryCtx = exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | parameterFlow(p, ap, ret.getEnclosingCallable(), config) and flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) + flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config) ) } @@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0( ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } @@ -2867,7 +2888,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll b/python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll index 5042dce683f..4e6eb9d86c0 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll @@ -1066,7 +1066,7 @@ private module LocalFlowBigStep { * Holds if `node` can be the first node in a maximal subsequence of local * flow steps in a dataflow path. */ - private predicate localFlowEntry(Node node, Configuration config) { + predicate localFlowEntry(Node node, Configuration config) { nodeCand2(node, config) and ( config.isSource(node) or @@ -1650,53 +1650,53 @@ private class AccessPathOption extends TAccessPathOption { * Holds if `node` is reachable with access path `ap` from a source in * the configuration `config`. * - * The Boolean `fromArg` records whether the node is reached through an + * The call context `cc` records whether the node is reached through an * argument in a call, and if so, `argAp` records the access path of that * argument. */ private predicate flowFwd( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwd0(node, fromArg, argAp, apf, ap, config) and + flowFwd0(node, cc, argAp, apf, ap, config) and flowCand(node, _, _, apf, config) } private predicate flowFwd0( - Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { flowCand(node, _, _, _, config) and config.isSource(node) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() or flowCand(node, _, _, _, unbind(config)) and ( - exists(Node mid | - flowFwd(mid, fromArg, argAp, apf, ap, config) and - localFlowBigStep(mid, node, true, _, config, _) + exists(Node mid, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, apf, ap, localCC, config) and + localFlowBigStep(mid, node, true, _, config, localCC) ) or - exists(Node mid, AccessPathNil nil | - flowFwd(mid, fromArg, argAp, _, nil, config) and - localFlowBigStep(mid, node, false, apf, config, _) and + exists(Node mid, AccessPathNil nil, LocalCallContext localCC | + flowFwdLocalEntry(mid, cc, argAp, _, nil, localCC, config) and + localFlowBigStep(mid, node, false, apf, config, localCC) and apf = ap.(AccessPathNil).getFront() ) or exists(Node mid | flowFwd(mid, _, _, apf, ap, config) and jumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() ) or exists(Node mid, AccessPathNil nil | flowFwd(mid, _, _, _, nil, config) and additionalJumpStep(mid, node, config) and - fromArg = false and + cc instanceof CallContextAny and argAp = TAccessPathNone() and ap = TNil(getNodeType(node)) and apf = ap.(AccessPathNil).getFront() @@ -1704,40 +1704,51 @@ private predicate flowFwd0( ) or // store - exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, fromArg, argAp, config)) + exists(TypedContent tc | flowFwdStore(node, tc, pop(tc, ap), apf, cc, argAp, config)) or // read exists(TypedContent tc | - flowFwdRead(node, _, push(tc, ap), apf, fromArg, argAp, config) and + flowFwdRead(node, _, push(tc, ap), apf, cc, argAp, config) and flowFwdConsCand(tc, apf, ap, config) ) or // flow into a callable - flowFwdIn(_, node, _, _, apf, ap, config) and - fromArg = true and + flowFwdIn(_, node, cc, _, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - flowFwdOut(call, node, fromArg, argAp, apf, ap, config) and - fromArg = false + exists(CallContextNoCall innercc, DataFlowCallable c | + flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() + ) or exists(AccessPath argAp0 | flowFwdOutFromArg(call, node, argAp0, apf, ap, config) and - flowFwdIsEntered(call, fromArg, argAp, argAp0, config) + flowFwdIsEntered(call, cc, argAp, argAp0, config) ) ) } +pragma[nomagic] +private predicate flowFwdLocalEntry( + Node node, CallContext cc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, + LocalCallContext localCC, Configuration config +) { + flowFwd(node, cc, argAp, apf, ap, config) and + localFlowEntry(node, config) and + localCC = getLocalCallContext(cc, node.getEnclosingCallable()) +} + pragma[nomagic] private predicate flowFwdStore( - Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, TypedContent tc, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, AccessPathFront apf0 | - flowFwd(mid, fromArg, argAp, apf0, ap0, config) and + flowFwd(mid, cc, argAp, apf0, ap0, config) and flowFwdStore0(mid, tc, node, apf0, apf, config) ) } @@ -1764,20 +1775,20 @@ private predicate flowFwdStore0( pragma[nomagic] private predicate flowFwdRead0( - Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, - boolean fromArg, AccessPathOption argAp, Configuration config + Node node1, TypedContent tc, AccessPathFrontHead apf0, AccessPath ap0, Node node2, CallContext cc, + AccessPathOption argAp, Configuration config ) { - flowFwd(node1, fromArg, argAp, apf0, ap0, config) and + flowFwd(node1, cc, argAp, apf0, ap0, config) and readCandFwd(node1, tc, apf0, node2, config) } pragma[nomagic] private predicate flowFwdRead( - Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, boolean fromArg, + Node node, AccessPathFrontHead apf0, AccessPath ap0, AccessPathFront apf, CallContext cc, AccessPathOption argAp, Configuration config ) { exists(Node mid, TypedContent tc | - flowFwdRead0(mid, tc, apf0, ap0, node, fromArg, argAp, config) and + flowFwdRead0(mid, tc, apf0, ap0, node, cc, argAp, config) and flowCand(node, _, _, apf, unbind(config)) and flowCandConsCand(tc, apf, unbind(config)) ) @@ -1795,13 +1806,16 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - exists(ArgumentNode arg, boolean allowsFieldFlow | - flowFwd(arg, fromArg, argAp, apf, ap, config) and + exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | + flowFwd(arg, outercc, argAp, apf, ap, config) and flowIntoCallNodeCand2(call, arg, p, allowsFieldFlow, config) and - flowCand(p, _, _, _, unbind(config)) + c = p.getEnclosingCallable() and + c = resolveCall(call, outercc) and + flowCand(p, _, _, _, unbind(config)) and + if recordDataFlowCallSite(call, c) then innercc = TSpecificCall(call) else innercc = TSomeCall() | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1809,13 +1823,19 @@ private predicate flowFwdIn( pragma[nomagic] private predicate flowFwdOut( - DataFlowCall call, Node node, boolean fromArg, AccessPathOption argAp, AccessPathFront apf, - AccessPath ap, Configuration config + DataFlowCall call, Node node, CallContext innercc, DataFlowCallable innerc, + AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ReturnNodeExt ret, boolean allowsFieldFlow | - flowFwd(ret, fromArg, argAp, apf, ap, config) and + flowFwd(ret, innercc, argAp, apf, ap, config) and flowOutOfCallNodeCand2(call, ret, node, allowsFieldFlow, config) and - flowCand(node, _, _, _, unbind(config)) + innerc = ret.getEnclosingCallable() and + flowCand(node, _, _, _, unbind(config)) and + ( + resolveReturn(innercc, innerc, call) + or + innercc.(CallContextCall).matchesCall(call) + ) | ap instanceof AccessPathNil or allowsFieldFlow = true ) @@ -1826,7 +1846,7 @@ private predicate flowFwdOutFromArg( DataFlowCall call, Node node, AccessPath argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { - flowFwdOut(call, node, true, TAccessPathSome(argAp), apf, ap, config) + flowFwdOut(call, node, any(CallContextCall ccc), _, TAccessPathSome(argAp), apf, ap, config) } /** @@ -1834,10 +1854,10 @@ private predicate flowFwdOutFromArg( */ pragma[nomagic] private predicate flowFwdIsEntered( - DataFlowCall call, boolean fromArg, AccessPathOption argAp, AccessPath ap, Configuration config + DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, fromArg, argAp, apf, ap, config) and + flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } @@ -1920,7 +1940,7 @@ private predicate flow0( // flow out of a callable flowOut(_, node, _, _, ap, config) and toReturn = true and - if flowFwd(node, true, TAccessPathSome(_), _, ap, config) + if flowFwd(node, any(CallContextCall ccc), TAccessPathSome(_), _, ap, config) then returnAp = TAccessPathSome(ap) else returnAp = TAccessPathNone() } @@ -2006,9 +2026,10 @@ private predicate flowIsReturned( DataFlowCall call, boolean toReturn, AccessPathOption returnAp, AccessPath ap, Configuration config ) { - exists(ReturnNodeExt ret | + exists(ReturnNodeExt ret, CallContextCall ccc | flowOut(call, ret, toReturn, returnAp, ap, config) and - flowFwd(ret, true, TAccessPathSome(_), _, ap, config) + flowFwd(ret, ccc, TAccessPathSome(_), _, ap, config) and + ccc.matchesCall(call) ) } @@ -2031,7 +2052,7 @@ private newtype TSummaryCtx = exists(ReturnNodeExt ret, Configuration config, AccessPath ap0 | parameterFlow(p, ap, ret.getEnclosingCallable(), config) and flow(ret, true, TAccessPathSome(_), ap0, config) and - flowFwd(ret, true, TAccessPathSome(ap), _, ap0, config) + flowFwd(ret, any(CallContextCall ccc), TAccessPathSome(ap), _, ap0, config) ) } @@ -2352,7 +2373,7 @@ private predicate pathOutOfCallable0( ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } @@ -2867,7 +2888,7 @@ private module FlowExploration { ) { pos = getReturnPosition(mid.getNode()) and innercc = mid.getCallContext() and - not innercc instanceof CallContextCall and + innercc instanceof CallContextNoCall and ap = mid.getAp() and config = mid.getConfiguration() } diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll b/python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll index 27ab1d01feb..892250f44bb 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll @@ -512,13 +512,19 @@ abstract class CallContext extends TCallContext { abstract predicate relevantFor(DataFlowCallable callable); } -class CallContextAny extends CallContext, TAnyCallContext { +abstract class CallContextNoCall extends CallContext { } + +class CallContextAny extends CallContextNoCall, TAnyCallContext { override string toString() { result = "CcAny" } override predicate relevantFor(DataFlowCallable callable) { any() } } -abstract class CallContextCall extends CallContext { } +abstract class CallContextCall extends CallContext { + /** Holds if this call context may be `call`. */ + bindingset[call] + abstract predicate matchesCall(DataFlowCall call); +} class CallContextSpecificCall extends CallContextCall, TSpecificCall { override string toString() { @@ -529,6 +535,8 @@ class CallContextSpecificCall extends CallContextCall, TSpecificCall { recordDataFlowCallSite(getCall(), callable) } + override predicate matchesCall(DataFlowCall call) { call = this.getCall() } + DataFlowCall getCall() { this = TSpecificCall(result) } } @@ -538,9 +546,11 @@ class CallContextSomeCall extends CallContextCall, TSomeCall { override predicate relevantFor(DataFlowCallable callable) { exists(ParameterNode p | p.getEnclosingCallable() = callable) } + + override predicate matchesCall(DataFlowCall call) { any() } } -class CallContextReturn extends CallContext, TReturn { +class CallContextReturn extends CallContextNoCall, TReturn { override string toString() { exists(DataFlowCall call | this = TReturn(_, call) | result = "CcReturn(" + call + ")") } From a2fc92b9dbafa432032464b7ffd084ba43599c08 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 17 Aug 2020 15:46:43 +0200 Subject: [PATCH 4/4] Data flow: Address review comments --- .../semmle/code/cpp/dataflow/internal/DataFlowImpl.qll | 10 +++++----- .../code/cpp/dataflow/internal/DataFlowImpl2.qll | 10 +++++----- .../code/cpp/dataflow/internal/DataFlowImpl3.qll | 10 +++++----- .../code/cpp/dataflow/internal/DataFlowImpl4.qll | 10 +++++----- .../code/cpp/dataflow/internal/DataFlowImplLocal.qll | 10 +++++----- .../code/cpp/ir/dataflow/internal/DataFlowImpl.qll | 10 +++++----- .../code/cpp/ir/dataflow/internal/DataFlowImpl2.qll | 10 +++++----- .../code/cpp/ir/dataflow/internal/DataFlowImpl3.qll | 10 +++++----- .../code/cpp/ir/dataflow/internal/DataFlowImpl4.qll | 10 +++++----- .../code/csharp/dataflow/internal/DataFlowImpl.qll | 10 +++++----- .../code/csharp/dataflow/internal/DataFlowImpl2.qll | 10 +++++----- .../code/csharp/dataflow/internal/DataFlowImpl3.qll | 10 +++++----- .../code/csharp/dataflow/internal/DataFlowImpl4.qll | 10 +++++----- .../code/csharp/dataflow/internal/DataFlowImpl5.qll | 10 +++++----- .../code/java/dataflow/internal/DataFlowImpl.qll | 10 +++++----- .../code/java/dataflow/internal/DataFlowImpl2.qll | 10 +++++----- .../code/java/dataflow/internal/DataFlowImpl3.qll | 10 +++++----- .../code/java/dataflow/internal/DataFlowImpl4.qll | 10 +++++----- .../code/java/dataflow/internal/DataFlowImpl5.qll | 10 +++++----- .../experimental/dataflow/internal/DataFlowImpl.qll | 10 +++++----- .../experimental/dataflow/internal/DataFlowImpl2.qll | 10 +++++----- 21 files changed, 105 insertions(+), 105 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index 4e6eb9d86c0..8c210edbe5f 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -1713,15 +1713,15 @@ private predicate flowFwd0( ) or // flow into a callable - flowFwdIn(_, node, cc, _, _, apf, ap, config) and + flowFwdIn(_, node, _, cc, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - exists(CallContextNoCall innercc, DataFlowCallable c | - flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() ) or @@ -1806,7 +1806,7 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | @@ -1857,7 +1857,7 @@ private predicate flowFwdIsEntered( DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index 4e6eb9d86c0..8c210edbe5f 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -1713,15 +1713,15 @@ private predicate flowFwd0( ) or // flow into a callable - flowFwdIn(_, node, cc, _, _, apf, ap, config) and + flowFwdIn(_, node, _, cc, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - exists(CallContextNoCall innercc, DataFlowCallable c | - flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() ) or @@ -1806,7 +1806,7 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | @@ -1857,7 +1857,7 @@ private predicate flowFwdIsEntered( DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index 4e6eb9d86c0..8c210edbe5f 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -1713,15 +1713,15 @@ private predicate flowFwd0( ) or // flow into a callable - flowFwdIn(_, node, cc, _, _, apf, ap, config) and + flowFwdIn(_, node, _, cc, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - exists(CallContextNoCall innercc, DataFlowCallable c | - flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() ) or @@ -1806,7 +1806,7 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | @@ -1857,7 +1857,7 @@ private predicate flowFwdIsEntered( DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index 4e6eb9d86c0..8c210edbe5f 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -1713,15 +1713,15 @@ private predicate flowFwd0( ) or // flow into a callable - flowFwdIn(_, node, cc, _, _, apf, ap, config) and + flowFwdIn(_, node, _, cc, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - exists(CallContextNoCall innercc, DataFlowCallable c | - flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() ) or @@ -1806,7 +1806,7 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | @@ -1857,7 +1857,7 @@ private predicate flowFwdIsEntered( DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index 4e6eb9d86c0..8c210edbe5f 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -1713,15 +1713,15 @@ private predicate flowFwd0( ) or // flow into a callable - flowFwdIn(_, node, cc, _, _, apf, ap, config) and + flowFwdIn(_, node, _, cc, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - exists(CallContextNoCall innercc, DataFlowCallable c | - flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() ) or @@ -1806,7 +1806,7 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | @@ -1857,7 +1857,7 @@ private predicate flowFwdIsEntered( DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index 4e6eb9d86c0..8c210edbe5f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -1713,15 +1713,15 @@ private predicate flowFwd0( ) or // flow into a callable - flowFwdIn(_, node, cc, _, _, apf, ap, config) and + flowFwdIn(_, node, _, cc, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - exists(CallContextNoCall innercc, DataFlowCallable c | - flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() ) or @@ -1806,7 +1806,7 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | @@ -1857,7 +1857,7 @@ private predicate flowFwdIsEntered( DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index 4e6eb9d86c0..8c210edbe5f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -1713,15 +1713,15 @@ private predicate flowFwd0( ) or // flow into a callable - flowFwdIn(_, node, cc, _, _, apf, ap, config) and + flowFwdIn(_, node, _, cc, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - exists(CallContextNoCall innercc, DataFlowCallable c | - flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() ) or @@ -1806,7 +1806,7 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | @@ -1857,7 +1857,7 @@ private predicate flowFwdIsEntered( DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index 4e6eb9d86c0..8c210edbe5f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -1713,15 +1713,15 @@ private predicate flowFwd0( ) or // flow into a callable - flowFwdIn(_, node, cc, _, _, apf, ap, config) and + flowFwdIn(_, node, _, cc, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - exists(CallContextNoCall innercc, DataFlowCallable c | - flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() ) or @@ -1806,7 +1806,7 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | @@ -1857,7 +1857,7 @@ private predicate flowFwdIsEntered( DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index 4e6eb9d86c0..8c210edbe5f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -1713,15 +1713,15 @@ private predicate flowFwd0( ) or // flow into a callable - flowFwdIn(_, node, cc, _, _, apf, ap, config) and + flowFwdIn(_, node, _, cc, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - exists(CallContextNoCall innercc, DataFlowCallable c | - flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() ) or @@ -1806,7 +1806,7 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | @@ -1857,7 +1857,7 @@ private predicate flowFwdIsEntered( DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index 4e6eb9d86c0..8c210edbe5f 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -1713,15 +1713,15 @@ private predicate flowFwd0( ) or // flow into a callable - flowFwdIn(_, node, cc, _, _, apf, ap, config) and + flowFwdIn(_, node, _, cc, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - exists(CallContextNoCall innercc, DataFlowCallable c | - flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() ) or @@ -1806,7 +1806,7 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | @@ -1857,7 +1857,7 @@ private predicate flowFwdIsEntered( DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index 4e6eb9d86c0..8c210edbe5f 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -1713,15 +1713,15 @@ private predicate flowFwd0( ) or // flow into a callable - flowFwdIn(_, node, cc, _, _, apf, ap, config) and + flowFwdIn(_, node, _, cc, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - exists(CallContextNoCall innercc, DataFlowCallable c | - flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() ) or @@ -1806,7 +1806,7 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | @@ -1857,7 +1857,7 @@ private predicate flowFwdIsEntered( DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index 4e6eb9d86c0..8c210edbe5f 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -1713,15 +1713,15 @@ private predicate flowFwd0( ) or // flow into a callable - flowFwdIn(_, node, cc, _, _, apf, ap, config) and + flowFwdIn(_, node, _, cc, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - exists(CallContextNoCall innercc, DataFlowCallable c | - flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() ) or @@ -1806,7 +1806,7 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | @@ -1857,7 +1857,7 @@ private predicate flowFwdIsEntered( DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index 4e6eb9d86c0..8c210edbe5f 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -1713,15 +1713,15 @@ private predicate flowFwd0( ) or // flow into a callable - flowFwdIn(_, node, cc, _, _, apf, ap, config) and + flowFwdIn(_, node, _, cc, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - exists(CallContextNoCall innercc, DataFlowCallable c | - flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() ) or @@ -1806,7 +1806,7 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | @@ -1857,7 +1857,7 @@ private predicate flowFwdIsEntered( DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index 4e6eb9d86c0..8c210edbe5f 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -1713,15 +1713,15 @@ private predicate flowFwd0( ) or // flow into a callable - flowFwdIn(_, node, cc, _, _, apf, ap, config) and + flowFwdIn(_, node, _, cc, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - exists(CallContextNoCall innercc, DataFlowCallable c | - flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() ) or @@ -1806,7 +1806,7 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | @@ -1857,7 +1857,7 @@ private predicate flowFwdIsEntered( DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index 4e6eb9d86c0..8c210edbe5f 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -1713,15 +1713,15 @@ private predicate flowFwd0( ) or // flow into a callable - flowFwdIn(_, node, cc, _, _, apf, ap, config) and + flowFwdIn(_, node, _, cc, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - exists(CallContextNoCall innercc, DataFlowCallable c | - flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() ) or @@ -1806,7 +1806,7 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | @@ -1857,7 +1857,7 @@ private predicate flowFwdIsEntered( DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index 4e6eb9d86c0..8c210edbe5f 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -1713,15 +1713,15 @@ private predicate flowFwd0( ) or // flow into a callable - flowFwdIn(_, node, cc, _, _, apf, ap, config) and + flowFwdIn(_, node, _, cc, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - exists(CallContextNoCall innercc, DataFlowCallable c | - flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() ) or @@ -1806,7 +1806,7 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | @@ -1857,7 +1857,7 @@ private predicate flowFwdIsEntered( DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index 4e6eb9d86c0..8c210edbe5f 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -1713,15 +1713,15 @@ private predicate flowFwd0( ) or // flow into a callable - flowFwdIn(_, node, cc, _, _, apf, ap, config) and + flowFwdIn(_, node, _, cc, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - exists(CallContextNoCall innercc, DataFlowCallable c | - flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() ) or @@ -1806,7 +1806,7 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | @@ -1857,7 +1857,7 @@ private predicate flowFwdIsEntered( DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index 4e6eb9d86c0..8c210edbe5f 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -1713,15 +1713,15 @@ private predicate flowFwd0( ) or // flow into a callable - flowFwdIn(_, node, cc, _, _, apf, ap, config) and + flowFwdIn(_, node, _, cc, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - exists(CallContextNoCall innercc, DataFlowCallable c | - flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() ) or @@ -1806,7 +1806,7 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | @@ -1857,7 +1857,7 @@ private predicate flowFwdIsEntered( DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index 4e6eb9d86c0..8c210edbe5f 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -1713,15 +1713,15 @@ private predicate flowFwd0( ) or // flow into a callable - flowFwdIn(_, node, cc, _, _, apf, ap, config) and + flowFwdIn(_, node, _, cc, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - exists(CallContextNoCall innercc, DataFlowCallable c | - flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() ) or @@ -1806,7 +1806,7 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | @@ -1857,7 +1857,7 @@ private predicate flowFwdIsEntered( DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll b/python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll index 4e6eb9d86c0..8c210edbe5f 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll @@ -1713,15 +1713,15 @@ private predicate flowFwd0( ) or // flow into a callable - flowFwdIn(_, node, cc, _, _, apf, ap, config) and + flowFwdIn(_, node, _, cc, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - exists(CallContextNoCall innercc, DataFlowCallable c | - flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() ) or @@ -1806,7 +1806,7 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | @@ -1857,7 +1857,7 @@ private predicate flowFwdIsEntered( DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) } diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll b/python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll index 4e6eb9d86c0..8c210edbe5f 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll @@ -1713,15 +1713,15 @@ private predicate flowFwd0( ) or // flow into a callable - flowFwdIn(_, node, cc, _, _, apf, ap, config) and + flowFwdIn(_, node, _, cc, _, apf, ap, config) and if flowCand(node, true, _, apf, config) then argAp = TAccessPathSome(ap) else argAp = TAccessPathNone() or // flow out of a callable exists(DataFlowCall call | - exists(CallContextNoCall innercc, DataFlowCallable c | - flowFwdOut(call, node, innercc, c, argAp, apf, ap, config) and + exists(DataFlowCallable c | + flowFwdOut(call, node, any(CallContextNoCall innercc), c, argAp, apf, ap, config) and if reducedViableImplInReturn(c, call) then cc = TReturn(c, call) else cc = TAnyCallContext() ) or @@ -1806,7 +1806,7 @@ private predicate flowFwdConsCand( pragma[nomagic] private predicate flowFwdIn( - DataFlowCall call, ParameterNode p, CallContext innercc, CallContext outercc, + DataFlowCall call, ParameterNode p, CallContext outercc, CallContext innercc, AccessPathOption argAp, AccessPathFront apf, AccessPath ap, Configuration config ) { exists(ArgumentNode arg, boolean allowsFieldFlow, DataFlowCallable c | @@ -1857,7 +1857,7 @@ private predicate flowFwdIsEntered( DataFlowCall call, CallContext cc, AccessPathOption argAp, AccessPath ap, Configuration config ) { exists(ParameterNode p, AccessPathFront apf | - flowFwdIn(call, p, _, cc, argAp, apf, ap, config) and + flowFwdIn(call, p, cc, _, argAp, apf, ap, config) and flowCand(p, true, TAccessPathFrontSome(_), apf, config) ) }