Skip to content

Commit e877b16

Browse files
authored
Merge pull request github#12124 from hvitved/dataflow/stage1-dispatch
Data flow: Call context virtual dispatch pruning in stage 1
2 parents 34c6b24 + 0b8173e commit e877b16

File tree

51 files changed

+3338
-1463
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+3338
-1463
lines changed

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

Lines changed: 77 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -667,23 +667,78 @@ private module Stage1 implements StageSig {
667667
)
668668
or
669669
// flow into a callable
670-
exists(NodeEx arg |
671-
fwdFlow(arg, _, config) and
672-
viableParamArgEx(_, node, arg) and
673-
cc = true and
674-
not fullBarrier(node, config)
675-
)
670+
fwdFlowIn(_, _, _, node, config) and
671+
cc = true
676672
or
677673
// flow out of a callable
674+
fwdFlowOut(_, node, false, config) and
675+
cc = false
676+
or
677+
// flow through a callable
678678
exists(DataFlowCall call |
679-
fwdFlowOut(call, node, false, config) and
680-
cc = false
681-
or
682679
fwdFlowOutFromArg(call, node, config) and
683680
fwdFlowIsEntered(call, cc, config)
684681
)
685682
}
686683

684+
// inline to reduce the number of iterations
685+
pragma[inline]
686+
private predicate fwdFlowIn(
687+
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
688+
) {
689+
// call context cannot help reduce virtual dispatch
690+
fwdFlow(arg, cc, config) and
691+
viableParamArgEx(call, p, arg) and
692+
not fullBarrier(p, config) and
693+
(
694+
cc = false
695+
or
696+
cc = true and
697+
not reducedViableImplInCallContext(call, _, _)
698+
)
699+
or
700+
// call context may help reduce virtual dispatch
701+
exists(DataFlowCallable target |
702+
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
703+
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
704+
cc = true
705+
)
706+
}
707+
708+
/**
709+
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
710+
*/
711+
pragma[nomagic]
712+
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
713+
fwdFlowIn(call, _, cc, _, config)
714+
}
715+
716+
pragma[nomagic]
717+
private predicate fwdFlowInReducedViableImplInSomeCallContext(
718+
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
719+
) {
720+
fwdFlow(arg, true, config) and
721+
viableParamArgEx(call, p, arg) and
722+
reducedViableImplInCallContext(call, _, _) and
723+
target = p.getEnclosingCallable() and
724+
not fullBarrier(p, config)
725+
}
726+
727+
/**
728+
* Gets a viable dispatch target of `call` in the context `ctx`. This is
729+
* restricted to those `call`s for which a context might make a difference,
730+
* and to `ctx`s that are reachable in `fwdFlow`.
731+
*/
732+
pragma[nomagic]
733+
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
734+
DataFlowCall call, Configuration config
735+
) {
736+
exists(DataFlowCall ctx |
737+
fwdFlowIsEntered(ctx, _, config) and
738+
result = viableImplInCallContextExt(call, ctx)
739+
)
740+
}
741+
687742
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
688743

689744
pragma[nomagic]
@@ -726,7 +781,8 @@ private module Stage1 implements StageSig {
726781
)
727782
}
728783

729-
pragma[nomagic]
784+
// inline to reduce the number of iterations
785+
pragma[inline]
730786
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
731787
exists(ReturnPosition pos |
732788
fwdFlowReturnPosition(pos, cc, config) and
@@ -740,17 +796,6 @@ private module Stage1 implements StageSig {
740796
fwdFlowOut(call, out, true, config)
741797
}
742798

743-
/**
744-
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
745-
*/
746-
pragma[nomagic]
747-
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
748-
exists(ArgNodeEx arg |
749-
fwdFlow(arg, cc, config) and
750-
viableParamArgEx(call, _, arg)
751-
)
752-
}
753-
754799
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
755800
exists(NodeEx node1 |
756801
additionalLocalStateStep(node1, state1, _, state2, config) or
@@ -817,20 +862,21 @@ private module Stage1 implements StageSig {
817862
)
818863
or
819864
// flow into a callable
820-
exists(DataFlowCall call |
821-
revFlowIn(call, node, false, config) and
822-
toReturn = false
823-
or
824-
revFlowInToReturn(call, node, config) and
825-
revFlowIsReturned(call, toReturn, config)
826-
)
865+
revFlowIn(_, node, false, config) and
866+
toReturn = false
827867
or
828868
// flow out of a callable
829869
exists(ReturnPosition pos |
830870
revFlowOut(pos, config) and
831871
node.(RetNodeEx).getReturnPosition() = pos and
832872
toReturn = true
833873
)
874+
or
875+
// flow through a callable
876+
exists(DataFlowCall call |
877+
revFlowInToReturn(call, node, config) and
878+
revFlowIsReturned(call, toReturn, config)
879+
)
834880
}
835881

836882
/**
@@ -886,11 +932,11 @@ private module Stage1 implements StageSig {
886932
additional predicate viableParamArgNodeCandFwd1(
887933
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
888934
) {
889-
viableParamArgEx(call, p, arg) and
890-
fwdFlow(arg, config)
935+
fwdFlowIn(call, arg, _, p, config)
891936
}
892937

893-
pragma[nomagic]
938+
// inline to reduce the number of iterations
939+
pragma[inline]
894940
private predicate revFlowIn(
895941
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
896942
) {

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

Lines changed: 77 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -667,23 +667,78 @@ private module Stage1 implements StageSig {
667667
)
668668
or
669669
// flow into a callable
670-
exists(NodeEx arg |
671-
fwdFlow(arg, _, config) and
672-
viableParamArgEx(_, node, arg) and
673-
cc = true and
674-
not fullBarrier(node, config)
675-
)
670+
fwdFlowIn(_, _, _, node, config) and
671+
cc = true
676672
or
677673
// flow out of a callable
674+
fwdFlowOut(_, node, false, config) and
675+
cc = false
676+
or
677+
// flow through a callable
678678
exists(DataFlowCall call |
679-
fwdFlowOut(call, node, false, config) and
680-
cc = false
681-
or
682679
fwdFlowOutFromArg(call, node, config) and
683680
fwdFlowIsEntered(call, cc, config)
684681
)
685682
}
686683

684+
// inline to reduce the number of iterations
685+
pragma[inline]
686+
private predicate fwdFlowIn(
687+
DataFlowCall call, NodeEx arg, Cc cc, ParamNodeEx p, Configuration config
688+
) {
689+
// call context cannot help reduce virtual dispatch
690+
fwdFlow(arg, cc, config) and
691+
viableParamArgEx(call, p, arg) and
692+
not fullBarrier(p, config) and
693+
(
694+
cc = false
695+
or
696+
cc = true and
697+
not reducedViableImplInCallContext(call, _, _)
698+
)
699+
or
700+
// call context may help reduce virtual dispatch
701+
exists(DataFlowCallable target |
702+
fwdFlowInReducedViableImplInSomeCallContext(call, arg, p, target, config) and
703+
target = viableImplInSomeFwdFlowCallContextExt(call, config) and
704+
cc = true
705+
)
706+
}
707+
708+
/**
709+
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
710+
*/
711+
pragma[nomagic]
712+
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
713+
fwdFlowIn(call, _, cc, _, config)
714+
}
715+
716+
pragma[nomagic]
717+
private predicate fwdFlowInReducedViableImplInSomeCallContext(
718+
DataFlowCall call, NodeEx arg, ParamNodeEx p, DataFlowCallable target, Configuration config
719+
) {
720+
fwdFlow(arg, true, config) and
721+
viableParamArgEx(call, p, arg) and
722+
reducedViableImplInCallContext(call, _, _) and
723+
target = p.getEnclosingCallable() and
724+
not fullBarrier(p, config)
725+
}
726+
727+
/**
728+
* Gets a viable dispatch target of `call` in the context `ctx`. This is
729+
* restricted to those `call`s for which a context might make a difference,
730+
* and to `ctx`s that are reachable in `fwdFlow`.
731+
*/
732+
pragma[nomagic]
733+
private DataFlowCallable viableImplInSomeFwdFlowCallContextExt(
734+
DataFlowCall call, Configuration config
735+
) {
736+
exists(DataFlowCall ctx |
737+
fwdFlowIsEntered(ctx, _, config) and
738+
result = viableImplInCallContextExt(call, ctx)
739+
)
740+
}
741+
687742
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
688743

689744
pragma[nomagic]
@@ -726,7 +781,8 @@ private module Stage1 implements StageSig {
726781
)
727782
}
728783

729-
pragma[nomagic]
784+
// inline to reduce the number of iterations
785+
pragma[inline]
730786
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
731787
exists(ReturnPosition pos |
732788
fwdFlowReturnPosition(pos, cc, config) and
@@ -740,17 +796,6 @@ private module Stage1 implements StageSig {
740796
fwdFlowOut(call, out, true, config)
741797
}
742798

743-
/**
744-
* Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
745-
*/
746-
pragma[nomagic]
747-
private predicate fwdFlowIsEntered(DataFlowCall call, Cc cc, Configuration config) {
748-
exists(ArgNodeEx arg |
749-
fwdFlow(arg, cc, config) and
750-
viableParamArgEx(call, _, arg)
751-
)
752-
}
753-
754799
private predicate stateStepFwd(FlowState state1, FlowState state2, Configuration config) {
755800
exists(NodeEx node1 |
756801
additionalLocalStateStep(node1, state1, _, state2, config) or
@@ -817,20 +862,21 @@ private module Stage1 implements StageSig {
817862
)
818863
or
819864
// flow into a callable
820-
exists(DataFlowCall call |
821-
revFlowIn(call, node, false, config) and
822-
toReturn = false
823-
or
824-
revFlowInToReturn(call, node, config) and
825-
revFlowIsReturned(call, toReturn, config)
826-
)
865+
revFlowIn(_, node, false, config) and
866+
toReturn = false
827867
or
828868
// flow out of a callable
829869
exists(ReturnPosition pos |
830870
revFlowOut(pos, config) and
831871
node.(RetNodeEx).getReturnPosition() = pos and
832872
toReturn = true
833873
)
874+
or
875+
// flow through a callable
876+
exists(DataFlowCall call |
877+
revFlowInToReturn(call, node, config) and
878+
revFlowIsReturned(call, toReturn, config)
879+
)
834880
}
835881

836882
/**
@@ -886,11 +932,11 @@ private module Stage1 implements StageSig {
886932
additional predicate viableParamArgNodeCandFwd1(
887933
DataFlowCall call, ParamNodeEx p, ArgNodeEx arg, Configuration config
888934
) {
889-
viableParamArgEx(call, p, arg) and
890-
fwdFlow(arg, config)
935+
fwdFlowIn(call, arg, _, p, config)
891936
}
892937

893-
pragma[nomagic]
938+
// inline to reduce the number of iterations
939+
pragma[inline]
894940
private predicate revFlowIn(
895941
DataFlowCall call, ArgNodeEx arg, boolean toReturn, Configuration config
896942
) {

0 commit comments

Comments
 (0)