Skip to content

Commit 649c2ce

Browse files
authored
Merge pull request github#6586 from hvitved/dataflow/stage2-precise-call-ctx-take2
Data flow: Add precise call contexts to stage 2
2 parents 0673355 + 296d10f commit 649c2ce

31 files changed

+616
-446
lines changed

cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -923,28 +923,29 @@ private module Stage2 {
923923

924924
ApOption apSome(Ap ap) { result = TBooleanSome(ap) }
925925

926-
class Cc = boolean;
927-
928-
class CcCall extends Cc {
929-
CcCall() { this = true }
926+
class Cc = CallContext;
930927

931-
/** Holds if this call context may be `call`. */
932-
predicate matchesCall(DataFlowCall call) { any() }
933-
}
928+
class CcCall = CallContextCall;
934929

935-
class CcNoCall extends Cc {
936-
CcNoCall() { this = false }
937-
}
930+
class CcNoCall = CallContextNoCall;
938931

939-
Cc ccNone() { result = false }
932+
Cc ccNone() { result instanceof CallContextAny }
940933

941934
private class LocalCc = Unit;
942935

943936
bindingset[call, c, outercc]
944-
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
937+
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) {
938+
checkCallContextCall(outercc, call, c) and
939+
if recordDataFlowCallSiteDispatch(call, c)
940+
then result = TSpecificCall(call)
941+
else result = TSomeCall()
942+
}
945943

946944
bindingset[call, c, innercc]
947-
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
945+
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) {
946+
checkCallContextReturn(innercc, c, call) and
947+
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
948+
}
948949

949950
bindingset[node, cc, config]
950951
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
@@ -1172,7 +1173,8 @@ private module Stage2 {
11721173
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
11731174
pragma[only_bind_into](config)) and
11741175
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
1175-
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
1176+
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
1177+
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
11761178
pragma[only_bind_into](config))
11771179
)
11781180
}
@@ -1860,7 +1862,8 @@ private module Stage3 {
18601862
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
18611863
pragma[only_bind_into](config)) and
18621864
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
1863-
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
1865+
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
1866+
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
18641867
pragma[only_bind_into](config))
18651868
)
18661869
}
@@ -2117,7 +2120,7 @@ private module Stage3 {
21172120
private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) {
21182121
exists(AccessPathFront apf |
21192122
Stage3::revFlow(node, true, _, apf, config) and
2120-
Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config)
2123+
Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config)
21212124
)
21222125
}
21232126

@@ -2618,7 +2621,8 @@ private module Stage4 {
26182621
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
26192622
pragma[only_bind_into](config)) and
26202623
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
2621-
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
2624+
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
2625+
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
26222626
pragma[only_bind_into](config))
26232627
)
26242628
}

cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -923,28 +923,29 @@ private module Stage2 {
923923

924924
ApOption apSome(Ap ap) { result = TBooleanSome(ap) }
925925

926-
class Cc = boolean;
927-
928-
class CcCall extends Cc {
929-
CcCall() { this = true }
926+
class Cc = CallContext;
930927

931-
/** Holds if this call context may be `call`. */
932-
predicate matchesCall(DataFlowCall call) { any() }
933-
}
928+
class CcCall = CallContextCall;
934929

935-
class CcNoCall extends Cc {
936-
CcNoCall() { this = false }
937-
}
930+
class CcNoCall = CallContextNoCall;
938931

939-
Cc ccNone() { result = false }
932+
Cc ccNone() { result instanceof CallContextAny }
940933

941934
private class LocalCc = Unit;
942935

943936
bindingset[call, c, outercc]
944-
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
937+
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) {
938+
checkCallContextCall(outercc, call, c) and
939+
if recordDataFlowCallSiteDispatch(call, c)
940+
then result = TSpecificCall(call)
941+
else result = TSomeCall()
942+
}
945943

946944
bindingset[call, c, innercc]
947-
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
945+
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) {
946+
checkCallContextReturn(innercc, c, call) and
947+
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
948+
}
948949

949950
bindingset[node, cc, config]
950951
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
@@ -1172,7 +1173,8 @@ private module Stage2 {
11721173
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
11731174
pragma[only_bind_into](config)) and
11741175
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
1175-
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
1176+
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
1177+
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
11761178
pragma[only_bind_into](config))
11771179
)
11781180
}
@@ -1860,7 +1862,8 @@ private module Stage3 {
18601862
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
18611863
pragma[only_bind_into](config)) and
18621864
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
1863-
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
1865+
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
1866+
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
18641867
pragma[only_bind_into](config))
18651868
)
18661869
}
@@ -2117,7 +2120,7 @@ private module Stage3 {
21172120
private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) {
21182121
exists(AccessPathFront apf |
21192122
Stage3::revFlow(node, true, _, apf, config) and
2120-
Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config)
2123+
Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config)
21212124
)
21222125
}
21232126

@@ -2618,7 +2621,8 @@ private module Stage4 {
26182621
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
26192622
pragma[only_bind_into](config)) and
26202623
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
2621-
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
2624+
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
2625+
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
26222626
pragma[only_bind_into](config))
26232627
)
26242628
}

cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -923,28 +923,29 @@ private module Stage2 {
923923

924924
ApOption apSome(Ap ap) { result = TBooleanSome(ap) }
925925

926-
class Cc = boolean;
927-
928-
class CcCall extends Cc {
929-
CcCall() { this = true }
926+
class Cc = CallContext;
930927

931-
/** Holds if this call context may be `call`. */
932-
predicate matchesCall(DataFlowCall call) { any() }
933-
}
928+
class CcCall = CallContextCall;
934929

935-
class CcNoCall extends Cc {
936-
CcNoCall() { this = false }
937-
}
930+
class CcNoCall = CallContextNoCall;
938931

939-
Cc ccNone() { result = false }
932+
Cc ccNone() { result instanceof CallContextAny }
940933

941934
private class LocalCc = Unit;
942935

943936
bindingset[call, c, outercc]
944-
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
937+
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) {
938+
checkCallContextCall(outercc, call, c) and
939+
if recordDataFlowCallSiteDispatch(call, c)
940+
then result = TSpecificCall(call)
941+
else result = TSomeCall()
942+
}
945943

946944
bindingset[call, c, innercc]
947-
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
945+
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) {
946+
checkCallContextReturn(innercc, c, call) and
947+
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
948+
}
948949

949950
bindingset[node, cc, config]
950951
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
@@ -1172,7 +1173,8 @@ private module Stage2 {
11721173
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
11731174
pragma[only_bind_into](config)) and
11741175
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
1175-
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
1176+
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
1177+
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
11761178
pragma[only_bind_into](config))
11771179
)
11781180
}
@@ -1860,7 +1862,8 @@ private module Stage3 {
18601862
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
18611863
pragma[only_bind_into](config)) and
18621864
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
1863-
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
1865+
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
1866+
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
18641867
pragma[only_bind_into](config))
18651868
)
18661869
}
@@ -2117,7 +2120,7 @@ private module Stage3 {
21172120
private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) {
21182121
exists(AccessPathFront apf |
21192122
Stage3::revFlow(node, true, _, apf, config) and
2120-
Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config)
2123+
Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config)
21212124
)
21222125
}
21232126

@@ -2618,7 +2621,8 @@ private module Stage4 {
26182621
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
26192622
pragma[only_bind_into](config)) and
26202623
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
2621-
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
2624+
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
2625+
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
26222626
pragma[only_bind_into](config))
26232627
)
26242628
}

cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -923,28 +923,29 @@ private module Stage2 {
923923

924924
ApOption apSome(Ap ap) { result = TBooleanSome(ap) }
925925

926-
class Cc = boolean;
927-
928-
class CcCall extends Cc {
929-
CcCall() { this = true }
926+
class Cc = CallContext;
930927

931-
/** Holds if this call context may be `call`. */
932-
predicate matchesCall(DataFlowCall call) { any() }
933-
}
928+
class CcCall = CallContextCall;
934929

935-
class CcNoCall extends Cc {
936-
CcNoCall() { this = false }
937-
}
930+
class CcNoCall = CallContextNoCall;
938931

939-
Cc ccNone() { result = false }
932+
Cc ccNone() { result instanceof CallContextAny }
940933

941934
private class LocalCc = Unit;
942935

943936
bindingset[call, c, outercc]
944-
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) { any() }
937+
private CcCall getCallContextCall(DataFlowCall call, DataFlowCallable c, Cc outercc) {
938+
checkCallContextCall(outercc, call, c) and
939+
if recordDataFlowCallSiteDispatch(call, c)
940+
then result = TSpecificCall(call)
941+
else result = TSomeCall()
942+
}
945943

946944
bindingset[call, c, innercc]
947-
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
945+
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) {
946+
checkCallContextReturn(innercc, c, call) and
947+
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
948+
}
948949

949950
bindingset[node, cc, config]
950951
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
@@ -1172,7 +1173,8 @@ private module Stage2 {
11721173
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
11731174
pragma[only_bind_into](config)) and
11741175
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
1175-
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
1176+
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
1177+
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
11761178
pragma[only_bind_into](config))
11771179
)
11781180
}
@@ -1860,7 +1862,8 @@ private module Stage3 {
18601862
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
18611863
pragma[only_bind_into](config)) and
18621864
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
1863-
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
1865+
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
1866+
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
18641867
pragma[only_bind_into](config))
18651868
)
18661869
}
@@ -2117,7 +2120,7 @@ private module Stage3 {
21172120
private predicate flowCandSummaryCtx(NodeEx node, AccessPathFront argApf, Configuration config) {
21182121
exists(AccessPathFront apf |
21192122
Stage3::revFlow(node, true, _, apf, config) and
2120-
Stage3::fwdFlow(node, true, TAccessPathFrontSome(argApf), apf, config)
2123+
Stage3::fwdFlow(node, any(Stage3::CcCall ccc), TAccessPathFrontSome(argApf), apf, config)
21212124
)
21222125
}
21232126

@@ -2618,7 +2621,8 @@ private module Stage4 {
26182621
fwdFlow(out, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), ap,
26192622
pragma[only_bind_into](config)) and
26202623
fwdFlowOutFromArg(call, out, argAp0, ap, config) and
2621-
fwdFlowIsEntered(call, pragma[only_bind_into](cc), pragma[only_bind_into](argAp), argAp0,
2624+
fwdFlowIsEntered(pragma[only_bind_into](call), pragma[only_bind_into](cc),
2625+
pragma[only_bind_into](argAp), pragma[only_bind_into](argAp0),
26222626
pragma[only_bind_into](config))
26232627
)
26242628
}

cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -786,13 +786,18 @@ private module Cached {
786786
}
787787

788788
/**
789-
* Holds if the call context `call` either improves virtual dispatch in
790-
* `callable` or if it allows us to prune unreachable nodes in `callable`.
789+
* Holds if the call context `call` improves virtual dispatch in `callable`.
791790
*/
792791
cached
793-
predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
792+
predicate recordDataFlowCallSiteDispatch(DataFlowCall call, DataFlowCallable callable) {
794793
reducedViableImplInCallContext(_, callable, call)
795-
or
794+
}
795+
796+
/**
797+
* Holds if the call context `call` allows us to prune unreachable nodes in `callable`.
798+
*/
799+
cached
800+
predicate recordDataFlowCallSiteUnreachable(DataFlowCall call, DataFlowCallable callable) {
796801
exists(Node n | getNodeEnclosingCallable(n) = callable | isUnreachableInCallCached(n, call))
797802
}
798803

@@ -846,6 +851,15 @@ private module Cached {
846851
TAccessPathFrontSome(AccessPathFront apf)
847852
}
848853

854+
/**
855+
* Holds if the call context `call` either improves virtual dispatch in
856+
* `callable` or if it allows us to prune unreachable nodes in `callable`.
857+
*/
858+
predicate recordDataFlowCallSite(DataFlowCall call, DataFlowCallable callable) {
859+
recordDataFlowCallSiteDispatch(call, callable) or
860+
recordDataFlowCallSiteUnreachable(call, callable)
861+
}
862+
849863
/**
850864
* A `Node` at which a cast can occur such that the type should be checked.
851865
*/

0 commit comments

Comments
 (0)