Dataflow: Improve performance for dispatch-join in flow-through.

This commit is contained in:
Anders Schack-Mulligen
2021-05-18 11:15:55 +02:00
parent 0c970b5f1f
commit bb258813a1

View File

@@ -605,6 +605,15 @@ private module Stage1 {
)
}
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(Node node, boolean toReturn |
revFlow(node, toReturn, config) and
revFlowInToReturn(call, node, config) and
revFlowIsReturned(call, toReturn, config)
)
}
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
nodes = count(Node node | fwdFlow(node, config)) and
@@ -827,6 +836,16 @@ private module Stage2 {
PrevStage::revFlow(node, _, _, apa, config)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, node1, node2, allowsFieldFlow, config) and
PrevStage::callMayFlowThroughRev(call, config) and
PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(node1), _, config)
}
/**
* Holds if `node` is reachable with access path `ap` from a source in the
* configuration `config`.
@@ -893,13 +912,11 @@ private module Stage2 {
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, any(CcNoCall innercc), cc, argAp, ap, config)
or
exists(Ap argAp0 |
fwdFlowOutFromArg(call, node, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, argAp, argAp0, config)
)
fwdFlowOutNotFromArg(node, cc, argAp, ap, config)
or
exists(DataFlowCall call, Ap argAp0 |
fwdFlowOutFromArg(call, node, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, argAp, argAp0, config)
)
}
@@ -950,17 +967,14 @@ private module Stage2 {
)
}
/**
* Holds if flow may exit from `call` at `out` with access path `ap`. The
* inner call context is `innercc`, but `ccOut` is just the call context
* based on the return step. In the case of through-flow `ccOut` is discarded
* and replaced by the outer call context as tracked by `fwdFlowIsEntered`.
*/
pragma[nomagic]
private predicate fwdFlowOut(
DataFlowCall call, Node out, Cc innercc, Cc ccOut, ApOption argAp, Ap ap, Configuration config
private predicate fwdFlowOutNotFromArg(
Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
exists(
DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = getNodeEnclosingCallable(ret) and
@@ -975,7 +989,13 @@ private module Stage2 {
private predicate fwdFlowOutFromArg(
DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
) {
fwdFlowOut(call, out, any(CcCall ccc), _, apSome(argAp), ap, config)
exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
/**
@@ -1006,6 +1026,25 @@ private module Stage2 {
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
exists(Ap argAp0, Node node, Cc cc, ApOption argAp, Ap ap |
fwdFlow(node, cc, argAp, ap, config) and
fwdFlowOutFromArg(call, node, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, argAp, argAp0, config)
)
}
pragma[nomagic]
private predicate flowThroughIntoCall(
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, node1, node2, allowsFieldFlow, config) and
fwdFlow(node1, _, _, _, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(node2, _, _, pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1071,14 +1110,12 @@ private module Stage2 {
)
or
// flow into a callable
exists(DataFlowCall call |
revFlowIn(call, node, toReturn, returnAp, ap, config) and
toReturn = false
or
exists(Ap returnAp0 |
revFlowInToReturn(call, node, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
)
revFlowInNotToReturn(node, returnAp, ap, config) and
toReturn = false
or
exists(DataFlowCall call, Ap returnAp0 |
revFlowInToReturn(call, node, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
)
or
// flow out of a callable
@@ -1126,12 +1163,10 @@ private module Stage2 {
}
pragma[nomagic]
private predicate revFlowIn(
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1141,7 +1176,12 @@ private module Stage2 {
private predicate revFlowInToReturn(
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
/**
@@ -1211,6 +1251,15 @@ private module Stage2 {
)
}
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(Ap returnAp0, Node node, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(node, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, node, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
)
}
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
@@ -1459,6 +1508,16 @@ private module Stage3 {
)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, node1, node2, allowsFieldFlow, config) and
PrevStage::callMayFlowThroughRev(call, config) and
PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(node1), _, config)
}
/**
* Holds if `node` is reachable with access path `ap` from a source in the
* configuration `config`.
@@ -1532,13 +1591,11 @@ private module Stage3 {
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, any(CcNoCall innercc), cc, argAp, ap, config)
or
exists(Ap argAp0 |
fwdFlowOutFromArg(call, node, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, argAp, argAp0, config)
)
fwdFlowOutNotFromArg(node, cc, argAp, ap, config)
or
exists(DataFlowCall call, Ap argAp0 |
fwdFlowOutFromArg(call, node, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, argAp, argAp0, config)
)
}
@@ -1589,17 +1646,14 @@ private module Stage3 {
)
}
/**
* Holds if flow may exit from `call` at `out` with access path `ap`. The
* inner call context is `innercc`, but `ccOut` is just the call context
* based on the return step. In the case of through-flow `ccOut` is discarded
* and replaced by the outer call context as tracked by `fwdFlowIsEntered`.
*/
pragma[nomagic]
private predicate fwdFlowOut(
DataFlowCall call, Node out, Cc innercc, Cc ccOut, ApOption argAp, Ap ap, Configuration config
private predicate fwdFlowOutNotFromArg(
Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
exists(
DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = getNodeEnclosingCallable(ret) and
@@ -1614,7 +1668,13 @@ private module Stage3 {
private predicate fwdFlowOutFromArg(
DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
) {
fwdFlowOut(call, out, any(CcCall ccc), _, apSome(argAp), ap, config)
exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
/**
@@ -1645,6 +1705,25 @@ private module Stage3 {
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
exists(Ap argAp0, Node node, Cc cc, ApOption argAp, Ap ap |
fwdFlow(node, cc, argAp, ap, config) and
fwdFlowOutFromArg(call, node, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, argAp, argAp0, config)
)
}
pragma[nomagic]
private predicate flowThroughIntoCall(
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, node1, node2, allowsFieldFlow, config) and
fwdFlow(node1, _, _, _, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(node2, _, _, pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1710,14 +1789,12 @@ private module Stage3 {
)
or
// flow into a callable
exists(DataFlowCall call |
revFlowIn(call, node, toReturn, returnAp, ap, config) and
toReturn = false
or
exists(Ap returnAp0 |
revFlowInToReturn(call, node, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
)
revFlowInNotToReturn(node, returnAp, ap, config) and
toReturn = false
or
exists(DataFlowCall call, Ap returnAp0 |
revFlowInToReturn(call, node, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
)
or
// flow out of a callable
@@ -1765,12 +1842,10 @@ private module Stage3 {
}
pragma[nomagic]
private predicate revFlowIn(
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -1780,7 +1855,12 @@ private module Stage3 {
private predicate revFlowInToReturn(
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
/**
@@ -1850,6 +1930,15 @@ private module Stage3 {
)
}
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(Ap returnAp0, Node node, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(node, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, node, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
)
}
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
nodes = count(Node node | fwdFlow(node, _, _, _, config)) and
@@ -2120,8 +2209,6 @@ private module Stage4 {
bindingset[innercc, inner, call]
private predicate checkCallContextReturn(Cc innercc, DataFlowCallable inner, DataFlowCall call) {
resolveReturn(innercc, inner, call)
or
innercc.(CallContextCall).matchesCall(call)
}
bindingset[node, cc, config]
@@ -2174,6 +2261,16 @@ private module Stage4 {
)
}
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, ReturnNodeExt node1, Node node2, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, node1, node2, allowsFieldFlow, config) and
PrevStage::callMayFlowThroughRev(call, config) and
PrevStage::parameterMayFlowThrough(_, getNodeEnclosingCallable(node1), _, config)
}
/**
* Holds if `node` is reachable with access path `ap` from a source in the
* configuration `config`.
@@ -2247,13 +2344,11 @@ private module Stage4 {
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, any(CcNoCall innercc), cc, argAp, ap, config)
or
exists(Ap argAp0 |
fwdFlowOutFromArg(call, node, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, argAp, argAp0, config)
)
fwdFlowOutNotFromArg(node, cc, argAp, ap, config)
or
exists(DataFlowCall call, Ap argAp0 |
fwdFlowOutFromArg(call, node, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, argAp, argAp0, config)
)
}
@@ -2304,17 +2399,14 @@ private module Stage4 {
)
}
/**
* Holds if flow may exit from `call` at `out` with access path `ap`. The
* inner call context is `innercc`, but `ccOut` is just the call context
* based on the return step. In the case of through-flow `ccOut` is discarded
* and replaced by the outer call context as tracked by `fwdFlowIsEntered`.
*/
pragma[nomagic]
private predicate fwdFlowOut(
DataFlowCall call, Node out, Cc innercc, Cc ccOut, ApOption argAp, Ap ap, Configuration config
private predicate fwdFlowOutNotFromArg(
Node out, Cc ccOut, ApOption argAp, Ap ap, Configuration config
) {
exists(ReturnNodeExt ret, boolean allowsFieldFlow, DataFlowCallable inner |
exists(
DataFlowCall call, ReturnNodeExt ret, boolean allowsFieldFlow, CcNoCall innercc,
DataFlowCallable inner
|
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = getNodeEnclosingCallable(ret) and
@@ -2329,7 +2421,13 @@ private module Stage4 {
private predicate fwdFlowOutFromArg(
DataFlowCall call, Node out, Ap argAp, Ap ap, Configuration config
) {
fwdFlowOut(call, out, any(CcCall ccc), _, apSome(argAp), ap, config)
exists(ReturnNodeExt ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
/**
@@ -2360,6 +2458,25 @@ private module Stage4 {
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate callMayFlowThroughFwd(DataFlowCall call, Configuration config) {
exists(Ap argAp0, Node node, Cc cc, ApOption argAp, Ap ap |
fwdFlow(node, cc, argAp, ap, config) and
fwdFlowOutFromArg(call, node, argAp0, ap, config) and
fwdFlowIsEntered(call, cc, argAp, argAp0, config)
)
}
pragma[nomagic]
private predicate flowThroughIntoCall(
DataFlowCall call, ArgNode node1, ParamNode node2, boolean allowsFieldFlow, Configuration config
) {
flowIntoCall(call, node1, node2, allowsFieldFlow, config) and
fwdFlow(node1, _, _, _, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(node2, _, _, pragma[only_bind_into](config)) and
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2425,14 +2542,12 @@ private module Stage4 {
)
or
// flow into a callable
exists(DataFlowCall call |
revFlowIn(call, node, toReturn, returnAp, ap, config) and
toReturn = false
or
exists(Ap returnAp0 |
revFlowInToReturn(call, node, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
)
revFlowInNotToReturn(node, returnAp, ap, config) and
toReturn = false
or
exists(DataFlowCall call, Ap returnAp0 |
revFlowInToReturn(call, node, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
)
or
// flow out of a callable
@@ -2480,12 +2595,10 @@ private module Stage4 {
}
pragma[nomagic]
private predicate revFlowIn(
DataFlowCall call, ArgNode arg, boolean toReturn, ApOption returnAp, Ap ap, Configuration config
) {
private predicate revFlowInNotToReturn(ArgNode arg, ApOption returnAp, Ap ap, Configuration config) {
exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, toReturn, returnAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config)
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
@@ -2495,7 +2608,12 @@ private module Stage4 {
private predicate revFlowInToReturn(
DataFlowCall call, ArgNode arg, Ap returnAp, Ap ap, Configuration config
) {
revFlowIn(call, arg, true, apSome(returnAp), ap, config)
exists(ParamNode p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
)
}
/**
@@ -2565,6 +2683,15 @@ private module Stage4 {
)
}
pragma[nomagic]
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(Ap returnAp0, Node node, boolean toReturn, ApOption returnAp, Ap ap |
revFlow(node, toReturn, returnAp, ap, config) and
revFlowInToReturn(call, node, returnAp0, ap, config) and
revFlowIsReturned(call, toReturn, returnAp, returnAp0, config)
)
}
predicate stats(boolean fwd, int nodes, int fields, int conscand, int tuples, Configuration config) {
fwd = true and
nodes = count(Node node | fwdFlow(node, _, _, _, config)) and