diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index 8597b5755f0..758b70ec316 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index 8597b5755f0..758b70ec316 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index 8597b5755f0..758b70ec316 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index 8597b5755f0..758b70ec316 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll index 728f7b56c42..f588a25a176 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll @@ -786,13 +786,18 @@ private module Cached { } /** - * Holds if the call context `call` either improves virtual dispatch in - * `callable` or if it allows us to prune unreachable nodes in `callable`. + * Holds if the call context `call` improves virtual dispatch in `callable`. */ cached - predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) { + predicate recordDataFlowCallSiteDispatch(DataFlowCall call, DataFlowCallable callable) { reducedViableImplInCallContext(_, callable, call) - or + } + + /** + * Holds if the call context `call` allows us to prune unreachable nodes in `callable`. + */ + cached + predicate recordDataFlowCallSiteUnreachable(DataFlowCall call, DataFlowCallable callable) { exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call)) } @@ -846,6 +851,15 @@ private module Cached { TAccessPathFrontSome(AccessPathFront apf) } +/** + * Holds if the call context `call` either improves virtual dispatch in + * `callable` or if it allows us to prune unreachable nodes in `callable`. + */ +predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) { + recordDataFlowCallSiteDispatch(call, callable) or + recordDataFlowCallSiteUnreachable(call, callable) +} + /** * A `Node` at which a cast can occur such that the type should be checked. */ diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index 8597b5755f0..758b70ec316 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index 8597b5755f0..758b70ec316 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index 8597b5755f0..758b70ec316 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index 8597b5755f0..758b70ec316 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index 8597b5755f0..758b70ec316 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll index 728f7b56c42..f588a25a176 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll @@ -786,13 +786,18 @@ private module Cached { } /** - * Holds if the call context `call` either improves virtual dispatch in - * `callable` or if it allows us to prune unreachable nodes in `callable`. + * Holds if the call context `call` improves virtual dispatch in `callable`. */ cached - predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) { + predicate recordDataFlowCallSiteDispatch(DataFlowCall call, DataFlowCallable callable) { reducedViableImplInCallContext(_, callable, call) - or + } + + /** + * Holds if the call context `call` allows us to prune unreachable nodes in `callable`. + */ + cached + predicate recordDataFlowCallSiteUnreachable(DataFlowCall call, DataFlowCallable callable) { exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call)) } @@ -846,6 +851,15 @@ private module Cached { TAccessPathFrontSome(AccessPathFront apf) } +/** + * Holds if the call context `call` either improves virtual dispatch in + * `callable` or if it allows us to prune unreachable nodes in `callable`. + */ +predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) { + recordDataFlowCallSiteDispatch(call, callable) or + recordDataFlowCallSiteUnreachable(call, callable) +} + /** * A `Node` at which a cast can occur such that the type should be checked. */ diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index 8597b5755f0..758b70ec316 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index 8597b5755f0..758b70ec316 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index 8597b5755f0..758b70ec316 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index 8597b5755f0..758b70ec316 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index 8597b5755f0..758b70ec316 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll index 728f7b56c42..f588a25a176 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll @@ -786,13 +786,18 @@ private module Cached { } /** - * Holds if the call context `call` either improves virtual dispatch in - * `callable` or if it allows us to prune unreachable nodes in `callable`. + * Holds if the call context `call` improves virtual dispatch in `callable`. */ cached - predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) { + predicate recordDataFlowCallSiteDispatch(DataFlowCall call, DataFlowCallable callable) { reducedViableImplInCallContext(_, callable, call) - or + } + + /** + * Holds if the call context `call` allows us to prune unreachable nodes in `callable`. + */ + cached + predicate recordDataFlowCallSiteUnreachable(DataFlowCall call, DataFlowCallable callable) { exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call)) } @@ -846,6 +851,15 @@ private module Cached { TAccessPathFrontSome(AccessPathFront apf) } +/** + * Holds if the call context `call` either improves virtual dispatch in + * `callable` or if it allows us to prune unreachable nodes in `callable`. + */ +predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) { + recordDataFlowCallSiteDispatch(call, callable) or + recordDataFlowCallSiteUnreachable(call, callable) +} + /** * A `Node` at which a cast can occur such that the type should be checked. */ diff --git a/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll b/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll index 80066392c1c..d0b4ef45ce8 100644 --- a/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll +++ b/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll @@ -508,7 +508,7 @@ private module Internal { override RuntimeCallable getADynamicTarget() { result = getAViableInherited() or - result = getAViableOverrider() and strictcount(getAViableOverrider()) < 1000 + result = getAViableOverrider() or // Simple case: target method cannot be overridden result = getAStaticTarget() and diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll index 8597b5755f0..758b70ec316 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index 8597b5755f0..758b70ec316 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index 8597b5755f0..758b70ec316 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index 8597b5755f0..758b70ec316 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index 8597b5755f0..758b70ec316 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll index 8597b5755f0..758b70ec316 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll index 728f7b56c42..f588a25a176 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @@ -786,13 +786,18 @@ private module Cached { } /** - * Holds if the call context `call` either improves virtual dispatch in - * `callable` or if it allows us to prune unreachable nodes in `callable`. + * Holds if the call context `call` improves virtual dispatch in `callable`. */ cached - predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) { + predicate recordDataFlowCallSiteDispatch(DataFlowCall call, DataFlowCallable callable) { reducedViableImplInCallContext(_, callable, call) - or + } + + /** + * Holds if the call context `call` allows us to prune unreachable nodes in `callable`. + */ + cached + predicate recordDataFlowCallSiteUnreachable(DataFlowCall call, DataFlowCallable callable) { exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call)) } @@ -846,6 +851,15 @@ private module Cached { TAccessPathFrontSome(AccessPathFront apf) } +/** + * Holds if the call context `call` either improves virtual dispatch in + * `callable` or if it allows us to prune unreachable nodes in `callable`. + */ +predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) { + recordDataFlowCallSiteDispatch(call, callable) or + recordDataFlowCallSiteUnreachable(call, callable) +} + /** * A `Node` at which a cast can occur such that the type should be checked. */ diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll index 8597b5755f0..758b70ec316 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll index 8597b5755f0..758b70ec316 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll index 8597b5755f0..758b70ec316 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll index 8597b5755f0..758b70ec316 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll index 8597b5755f0..758b70ec316 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll @@ -923,28 +923,29 @@ private module Stage2 { ApOption apSome(Ap ap) { result = TBooleanSome(ap) } - class Cc = boolean; + class Cc = CallContext; - class CcCall extends Cc { - CcCall() { this = true } + class CcCall = CallContextCall; - /** Holds if this call context may be `call`. */ - predicate matchesCall(DataFlowCall call) { any() } - } + class CcNoCall = CallContextNoCall; - class CcNoCall extends Cc { - CcNoCall() { this = false } - } - - Cc ccNone() { result = false } + Cc ccNone() { result instanceof CallContextAny } private class LocalCc = Unit; bindingset[call, c, outercc] - private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() } + private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { + checkCallContextCall(outercc, call, c) and + if recordDataFlowCallSiteDispatch(call, c) + then result = TSpecificCall(call) + else result = TSomeCall() + } bindingset[call, c, innercc] - private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() } + private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { + checkCallContextReturn(innercc, c, call) and + if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone() + } bindingset[node, cc, config] private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() } @@ -1172,7 +1173,8 @@ private module Stage2 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -1860,7 +1862,8 @@ private module Stage3 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } @@ -2117,7 +2120,7 @@ private module Stage3 { private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) { exists(AccessPathFront apf | Stage3::revFlow(node, true, _, apf, config) and - Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config) + Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config) ) } @@ -2618,7 +2621,8 @@ private module Stage4 { fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap, pragma[only_bind_into](config)) and fwdFlowOutFromArg(call, out, argAp0, ap, config) and - fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0, + fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc), + pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0), pragma[only_bind_into](config)) ) } diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll index 728f7b56c42..f588a25a176 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll @@ -786,13 +786,18 @@ private module Cached { } /** - * Holds if the call context `call` either improves virtual dispatch in - * `callable` or if it allows us to prune unreachable nodes in `callable`. + * Holds if the call context `call` improves virtual dispatch in `callable`. */ cached - predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) { + predicate recordDataFlowCallSiteDispatch(DataFlowCall call, DataFlowCallable callable) { reducedViableImplInCallContext(_, callable, call) - or + } + + /** + * Holds if the call context `call` allows us to prune unreachable nodes in `callable`. + */ + cached + predicate recordDataFlowCallSiteUnreachable(DataFlowCall call, DataFlowCallable callable) { exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call)) } @@ -846,6 +851,15 @@ private module Cached { TAccessPathFrontSome(AccessPathFront apf) } +/** + * Holds if the call context `call` either improves virtual dispatch in + * `callable` or if it allows us to prune unreachable nodes in `callable`. + */ +predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) { + recordDataFlowCallSiteDispatch(call, callable) or + recordDataFlowCallSiteUnreachable(call, callable) +} + /** * A `Node` at which a cast can occur such that the type should be checked. */