Data flow: Sync files

This commit is contained in:
Tom Hvitved
2022-04-01 16:25:46 +02:00
parent 309fd937c1
commit c4fbc618a9
52 changed files with 3756 additions and 1812 deletions

View File

@@ -128,7 +128,7 @@ abstract class Configuration extends string {
* Holds if an arbitrary number of implicit read steps of content `c` may be
* taken at `node`.
*/
predicate allowImplicitRead(Node node, Content c) { none() }
predicate allowImplicitRead(Node node, ContentSet c) { none() }
/**
* Gets the virtual dispatch branching limit when calculating field flow.
@@ -525,8 +525,9 @@ private predicate additionalJumpStateStep(
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode()) and
pragma[nomagic]
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
readSet(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
or
exists(Node n |
@@ -536,12 +537,44 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
)
}
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
// inline to reduce fan-out via `getAReadContent`
pragma[inline]
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(ContentSet cs |
readSet(node1, cs, node2, config) and
c = cs.getAReadContent()
)
}
// inline to reduce fan-out via `getAReadContent`
pragma[inline]
private predicate clearsContentEx(NodeEx n, Content c) {
exists(ContentSet cs |
clearsContentCached(n.asNode(), cs) and
c = cs.getAReadContent()
)
}
pragma[nomagic]
private predicate storeSet(
NodeEx node1, ContentSet c, NodeEx node2, DataFlowType contentType, DataFlowType containerType,
Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
storeSet(node1.asNode(), c, node2.asNode(), contentType, containerType) and
stepFilter(node1, node2, config) and
read(_, c.getAStoreContent(), _, config)
}
// inline to reduce fan-out via `getAStoreContent`
pragma[inline]
private predicate store(
NodeEx node1, Content c, NodeEx node2, DataFlowType contentType, DataFlowType containerType,
Configuration config
) {
exists(ContentSet cs |
storeSet(node1, cs, node2, contentType, containerType, config) and
c = cs.getAStoreContent()
)
}
pragma[nomagic]
@@ -609,13 +642,13 @@ private module Stage1 {
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
storeSet(mid, _, node, _, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
exists(ContentSet c |
fwdFlowReadSet(c, node, cc, config) and
fwdFlowConsCandSet(c, config)
)
or
// flow into a callable
@@ -639,10 +672,10 @@ private module Stage1 {
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
pragma[nomagic]
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
read(mid, c, node, config)
readSet(mid, c, node, config)
)
}
@@ -651,15 +684,23 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowConsCand(Content c, Configuration config) {
exists(NodeEx mid, NodeEx node, TypedContent tc |
exists(NodeEx mid, NodeEx node |
not fullBarrier(node, config) and
useFieldFlow(config) and
fwdFlow(mid, _, config) and
store(mid, tc, node, _, config) and
c = tc.getContent()
store(mid, c, node, _, _, config)
)
}
/**
* Holds if `c` may be interpreted in a read as the target of some store,
* in the flow covered by `fwdFlow`.
*/
pragma[nomagic]
private predicate fwdFlowConsCandSet(ContentSet c, Configuration config) {
fwdFlowConsCand(c.getAReadContent(), config)
}
pragma[nomagic]
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
exists(RetNodeEx ret |
@@ -746,15 +787,15 @@ private module Stage1 {
)
or
// store
exists(Content c |
revFlowStore(c, node, toReturn, config) and
revFlowConsCand(c, config)
exists(ContentSet c |
revFlowStoreSet(c, node, toReturn, config) and
revFlowConsCandSet(c, config)
)
or
// read
exists(NodeEx mid, Content c |
read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
exists(NodeEx mid, ContentSet c |
readSet(node, c, mid, config) and
fwdFlowConsCandSet(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
or
@@ -789,12 +830,18 @@ private module Stage1 {
}
pragma[nomagic]
private predicate revFlowStore(Content c, NodeEx node, boolean toReturn, Configuration config) {
exists(NodeEx mid, TypedContent tc |
private predicate revFlowConsCandSet(ContentSet c, Configuration config) {
revFlowConsCand(c.getAStoreContent(), config)
}
pragma[nomagic]
private predicate revFlowStoreSet(
ContentSet c, NodeEx node, boolean toReturn, Configuration config
) {
exists(NodeEx mid |
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
store(node, tc, mid, _, config) and
c = tc.getContent()
fwdFlowConsCandSet(c, pragma[only_bind_into](config)) and
storeSet(node, c, mid, _, _, config)
)
}
@@ -802,9 +849,13 @@ private module Stage1 {
* Holds if `c` is the target of both a read and a store in the flow covered
* by `revFlow`.
*/
pragma[nomagic]
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
revFlowConsCand(c, conf) and
revFlowStore(c, _, _, conf)
exists(ContentSet cs |
revFlowStoreSet(cs, _, _, conf) and
c = cs.getAStoreContent()
)
}
pragma[nomagic]
@@ -889,20 +940,20 @@ private module Stage1 {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
exists(Content c, DataFlowType containerType |
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
store(node1, c, node2, contentType, containerType, config) and
revFlow(node2, pragma[only_bind_into](config)) and
store(node1, tc, node2, contentType, config) and
c = tc.getContent() and
tc = MkTypedContent(c, containerType) and
exists(ap1)
)
}
pragma[nomagic]
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
read(n1, c, n2, pragma[only_bind_into](config))
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
read(n1, c, n2, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config))
}
pragma[nomagic]
@@ -1614,7 +1665,7 @@ private module Stage2 {
Configuration config
) {
exists(Ap ap2, Content c |
store(node1, tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
@@ -1769,9 +1820,9 @@ private module LocalFlowBigStep {
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
Stage2::storeStepCand(_, _, _, node, _, config)
or
read(_, _, node, config)
Stage2::readStepCand(_, _, node, config)
or
node instanceof FlowCheckNode
or
@@ -1792,8 +1843,8 @@ private module LocalFlowBigStep {
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
store(node, _, next, _, config) or
read(node, _, next, config)
Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config)
)
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
@@ -1966,7 +2017,24 @@ private module Stage3 {
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
pragma[nomagic]
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
PrevStage::revFlow(node, config) and
clearsContentCached(node.asNode(), c)
}
pragma[nomagic]
private predicate clearContent(NodeEx node, Content c, Configuration config) {
exists(ContentSet cs |
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
c = cs.getAReadContent() and
clearSet(node, cs, pragma[only_bind_into](config))
)
}
pragma[nomagic]
private predicate clear(NodeEx node, Ap ap, Configuration config) {
clearContent(node, ap.getHead().getContent(), config)
}
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
@@ -1975,7 +2043,7 @@ private module Stage3 {
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
exists(state) and
exists(config) and
not clear(node, ap) and
not clear(node, ap, config) and
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
}
@@ -2403,7 +2471,7 @@ private module Stage3 {
Configuration config
) {
exists(Ap ap2, Content c |
store(node1, tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
@@ -3231,7 +3299,7 @@ private module Stage4 {
Configuration config
) {
exists(Ap ap2, Content c |
store(node1, tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
@@ -4242,8 +4310,8 @@ private module Subpaths {
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
storeSet(n1, _, n2, _, _, _) or
readSet(n1, _, n2, _)
)
}
@@ -4598,7 +4666,7 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentCached(node.asNode(), ap.getHead()) and
not clearsContentEx(node, ap.getHead()) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
@@ -4614,7 +4682,7 @@ private module FlowExploration {
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
not clearsContentEx(node, ap.getHead().getContent()) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
@@ -4893,10 +4961,11 @@ private module FlowExploration {
PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, NodeEx node,
PartialAccessPath ap2
) {
exists(NodeEx midNode, DataFlowType contentType |
exists(NodeEx midNode, Content c, DataFlowType contentType, DataFlowType containerType |
midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
store(midNode, tc, node, contentType, mid.getConfiguration()) and
store(midNode, c, node, contentType, containerType, mid.getConfiguration()) and
tc = MkTypedContent(c, containerType) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
@@ -4918,10 +4987,11 @@ private module FlowExploration {
PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, NodeEx node, CallContext cc,
Configuration config
) {
exists(NodeEx midNode |
exists(NodeEx midNode, Content c |
midNode = mid.getNodeEx() and
ap = mid.getAp() and
read(midNode, tc.getContent(), node, pragma[only_bind_into](config)) and
read(midNode, c, node, pragma[only_bind_into](config)) and
tc.getContent() = c and
ap.getHead() = tc and
pragma[only_bind_into](config) = mid.getConfiguration() and
cc = mid.getCallContext()
@@ -5171,13 +5241,12 @@ private module FlowExploration {
private predicate revPartialPathStoreStep(
PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, NodeEx node, Configuration config
) {
exists(NodeEx midNode, TypedContent tc |
exists(NodeEx midNode, DataFlowType contentType, DataFlowType containerType, TypedContent tc |
midNode = mid.getNodeEx() and
ap = mid.getAp() and
store(node, tc, midNode, _, config) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
store(node, c, midNode, contentType, containerType, config) and
tc = MkTypedContent(c, containerType) and
config = mid.getConfiguration()
)
}

View File

@@ -128,7 +128,7 @@ abstract class Configuration extends string {
* Holds if an arbitrary number of implicit read steps of content `c` may be
* taken at `node`.
*/
predicate allowImplicitRead(Node node, Content c) { none() }
predicate allowImplicitRead(Node node, ContentSet c) { none() }
/**
* Gets the virtual dispatch branching limit when calculating field flow.
@@ -525,8 +525,9 @@ private predicate additionalJumpStateStep(
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode()) and
pragma[nomagic]
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
readSet(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
or
exists(Node n |
@@ -536,12 +537,44 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
)
}
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
// inline to reduce fan-out via `getAReadContent`
pragma[inline]
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(ContentSet cs |
readSet(node1, cs, node2, config) and
c = cs.getAReadContent()
)
}
// inline to reduce fan-out via `getAReadContent`
pragma[inline]
private predicate clearsContentEx(NodeEx n, Content c) {
exists(ContentSet cs |
clearsContentCached(n.asNode(), cs) and
c = cs.getAReadContent()
)
}
pragma[nomagic]
private predicate storeSet(
NodeEx node1, ContentSet c, NodeEx node2, DataFlowType contentType, DataFlowType containerType,
Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
storeSet(node1.asNode(), c, node2.asNode(), contentType, containerType) and
stepFilter(node1, node2, config) and
read(_, c.getAStoreContent(), _, config)
}
// inline to reduce fan-out via `getAStoreContent`
pragma[inline]
private predicate store(
NodeEx node1, Content c, NodeEx node2, DataFlowType contentType, DataFlowType containerType,
Configuration config
) {
exists(ContentSet cs |
storeSet(node1, cs, node2, contentType, containerType, config) and
c = cs.getAStoreContent()
)
}
pragma[nomagic]
@@ -609,13 +642,13 @@ private module Stage1 {
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
storeSet(mid, _, node, _, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
exists(ContentSet c |
fwdFlowReadSet(c, node, cc, config) and
fwdFlowConsCandSet(c, config)
)
or
// flow into a callable
@@ -639,10 +672,10 @@ private module Stage1 {
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
pragma[nomagic]
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
read(mid, c, node, config)
readSet(mid, c, node, config)
)
}
@@ -651,15 +684,23 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowConsCand(Content c, Configuration config) {
exists(NodeEx mid, NodeEx node, TypedContent tc |
exists(NodeEx mid, NodeEx node |
not fullBarrier(node, config) and
useFieldFlow(config) and
fwdFlow(mid, _, config) and
store(mid, tc, node, _, config) and
c = tc.getContent()
store(mid, c, node, _, _, config)
)
}
/**
* Holds if `c` may be interpreted in a read as the target of some store,
* in the flow covered by `fwdFlow`.
*/
pragma[nomagic]
private predicate fwdFlowConsCandSet(ContentSet c, Configuration config) {
fwdFlowConsCand(c.getAReadContent(), config)
}
pragma[nomagic]
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
exists(RetNodeEx ret |
@@ -746,15 +787,15 @@ private module Stage1 {
)
or
// store
exists(Content c |
revFlowStore(c, node, toReturn, config) and
revFlowConsCand(c, config)
exists(ContentSet c |
revFlowStoreSet(c, node, toReturn, config) and
revFlowConsCandSet(c, config)
)
or
// read
exists(NodeEx mid, Content c |
read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
exists(NodeEx mid, ContentSet c |
readSet(node, c, mid, config) and
fwdFlowConsCandSet(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
or
@@ -789,12 +830,18 @@ private module Stage1 {
}
pragma[nomagic]
private predicate revFlowStore(Content c, NodeEx node, boolean toReturn, Configuration config) {
exists(NodeEx mid, TypedContent tc |
private predicate revFlowConsCandSet(ContentSet c, Configuration config) {
revFlowConsCand(c.getAStoreContent(), config)
}
pragma[nomagic]
private predicate revFlowStoreSet(
ContentSet c, NodeEx node, boolean toReturn, Configuration config
) {
exists(NodeEx mid |
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
store(node, tc, mid, _, config) and
c = tc.getContent()
fwdFlowConsCandSet(c, pragma[only_bind_into](config)) and
storeSet(node, c, mid, _, _, config)
)
}
@@ -802,9 +849,13 @@ private module Stage1 {
* Holds if `c` is the target of both a read and a store in the flow covered
* by `revFlow`.
*/
pragma[nomagic]
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
revFlowConsCand(c, conf) and
revFlowStore(c, _, _, conf)
exists(ContentSet cs |
revFlowStoreSet(cs, _, _, conf) and
c = cs.getAStoreContent()
)
}
pragma[nomagic]
@@ -889,20 +940,20 @@ private module Stage1 {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
exists(Content c, DataFlowType containerType |
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
store(node1, c, node2, contentType, containerType, config) and
revFlow(node2, pragma[only_bind_into](config)) and
store(node1, tc, node2, contentType, config) and
c = tc.getContent() and
tc = MkTypedContent(c, containerType) and
exists(ap1)
)
}
pragma[nomagic]
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
read(n1, c, n2, pragma[only_bind_into](config))
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
read(n1, c, n2, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config))
}
pragma[nomagic]
@@ -1614,7 +1665,7 @@ private module Stage2 {
Configuration config
) {
exists(Ap ap2, Content c |
store(node1, tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
@@ -1769,9 +1820,9 @@ private module LocalFlowBigStep {
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
Stage2::storeStepCand(_, _, _, node, _, config)
or
read(_, _, node, config)
Stage2::readStepCand(_, _, node, config)
or
node instanceof FlowCheckNode
or
@@ -1792,8 +1843,8 @@ private module LocalFlowBigStep {
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
store(node, _, next, _, config) or
read(node, _, next, config)
Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config)
)
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
@@ -1966,7 +2017,24 @@ private module Stage3 {
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
pragma[nomagic]
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
PrevStage::revFlow(node, config) and
clearsContentCached(node.asNode(), c)
}
pragma[nomagic]
private predicate clearContent(NodeEx node, Content c, Configuration config) {
exists(ContentSet cs |
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
c = cs.getAReadContent() and
clearSet(node, cs, pragma[only_bind_into](config))
)
}
pragma[nomagic]
private predicate clear(NodeEx node, Ap ap, Configuration config) {
clearContent(node, ap.getHead().getContent(), config)
}
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
@@ -1975,7 +2043,7 @@ private module Stage3 {
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
exists(state) and
exists(config) and
not clear(node, ap) and
not clear(node, ap, config) and
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
}
@@ -2403,7 +2471,7 @@ private module Stage3 {
Configuration config
) {
exists(Ap ap2, Content c |
store(node1, tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
@@ -3231,7 +3299,7 @@ private module Stage4 {
Configuration config
) {
exists(Ap ap2, Content c |
store(node1, tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
@@ -4242,8 +4310,8 @@ private module Subpaths {
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
storeSet(n1, _, n2, _, _, _) or
readSet(n1, _, n2, _)
)
}
@@ -4598,7 +4666,7 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentCached(node.asNode(), ap.getHead()) and
not clearsContentEx(node, ap.getHead()) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
@@ -4614,7 +4682,7 @@ private module FlowExploration {
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
not clearsContentEx(node, ap.getHead().getContent()) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
@@ -4893,10 +4961,11 @@ private module FlowExploration {
PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, NodeEx node,
PartialAccessPath ap2
) {
exists(NodeEx midNode, DataFlowType contentType |
exists(NodeEx midNode, Content c, DataFlowType contentType, DataFlowType containerType |
midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
store(midNode, tc, node, contentType, mid.getConfiguration()) and
store(midNode, c, node, contentType, containerType, mid.getConfiguration()) and
tc = MkTypedContent(c, containerType) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
@@ -4918,10 +4987,11 @@ private module FlowExploration {
PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, NodeEx node, CallContext cc,
Configuration config
) {
exists(NodeEx midNode |
exists(NodeEx midNode, Content c |
midNode = mid.getNodeEx() and
ap = mid.getAp() and
read(midNode, tc.getContent(), node, pragma[only_bind_into](config)) and
read(midNode, c, node, pragma[only_bind_into](config)) and
tc.getContent() = c and
ap.getHead() = tc and
pragma[only_bind_into](config) = mid.getConfiguration() and
cc = mid.getCallContext()
@@ -5171,13 +5241,12 @@ private module FlowExploration {
private predicate revPartialPathStoreStep(
PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, NodeEx node, Configuration config
) {
exists(NodeEx midNode, TypedContent tc |
exists(NodeEx midNode, DataFlowType contentType, DataFlowType containerType, TypedContent tc |
midNode = mid.getNodeEx() and
ap = mid.getAp() and
store(node, tc, midNode, _, config) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
store(node, c, midNode, contentType, containerType, config) and
tc = MkTypedContent(c, containerType) and
config = mid.getConfiguration()
)
}

View File

@@ -128,7 +128,7 @@ abstract class Configuration extends string {
* Holds if an arbitrary number of implicit read steps of content `c` may be
* taken at `node`.
*/
predicate allowImplicitRead(Node node, Content c) { none() }
predicate allowImplicitRead(Node node, ContentSet c) { none() }
/**
* Gets the virtual dispatch branching limit when calculating field flow.
@@ -525,8 +525,9 @@ private predicate additionalJumpStateStep(
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode()) and
pragma[nomagic]
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
readSet(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
or
exists(Node n |
@@ -536,12 +537,44 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
)
}
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
// inline to reduce fan-out via `getAReadContent`
pragma[inline]
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(ContentSet cs |
readSet(node1, cs, node2, config) and
c = cs.getAReadContent()
)
}
// inline to reduce fan-out via `getAReadContent`
pragma[inline]
private predicate clearsContentEx(NodeEx n, Content c) {
exists(ContentSet cs |
clearsContentCached(n.asNode(), cs) and
c = cs.getAReadContent()
)
}
pragma[nomagic]
private predicate storeSet(
NodeEx node1, ContentSet c, NodeEx node2, DataFlowType contentType, DataFlowType containerType,
Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
storeSet(node1.asNode(), c, node2.asNode(), contentType, containerType) and
stepFilter(node1, node2, config) and
read(_, c.getAStoreContent(), _, config)
}
// inline to reduce fan-out via `getAStoreContent`
pragma[inline]
private predicate store(
NodeEx node1, Content c, NodeEx node2, DataFlowType contentType, DataFlowType containerType,
Configuration config
) {
exists(ContentSet cs |
storeSet(node1, cs, node2, contentType, containerType, config) and
c = cs.getAStoreContent()
)
}
pragma[nomagic]
@@ -609,13 +642,13 @@ private module Stage1 {
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
storeSet(mid, _, node, _, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
exists(ContentSet c |
fwdFlowReadSet(c, node, cc, config) and
fwdFlowConsCandSet(c, config)
)
or
// flow into a callable
@@ -639,10 +672,10 @@ private module Stage1 {
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
pragma[nomagic]
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
read(mid, c, node, config)
readSet(mid, c, node, config)
)
}
@@ -651,15 +684,23 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowConsCand(Content c, Configuration config) {
exists(NodeEx mid, NodeEx node, TypedContent tc |
exists(NodeEx mid, NodeEx node |
not fullBarrier(node, config) and
useFieldFlow(config) and
fwdFlow(mid, _, config) and
store(mid, tc, node, _, config) and
c = tc.getContent()
store(mid, c, node, _, _, config)
)
}
/**
* Holds if `c` may be interpreted in a read as the target of some store,
* in the flow covered by `fwdFlow`.
*/
pragma[nomagic]
private predicate fwdFlowConsCandSet(ContentSet c, Configuration config) {
fwdFlowConsCand(c.getAReadContent(), config)
}
pragma[nomagic]
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
exists(RetNodeEx ret |
@@ -746,15 +787,15 @@ private module Stage1 {
)
or
// store
exists(Content c |
revFlowStore(c, node, toReturn, config) and
revFlowConsCand(c, config)
exists(ContentSet c |
revFlowStoreSet(c, node, toReturn, config) and
revFlowConsCandSet(c, config)
)
or
// read
exists(NodeEx mid, Content c |
read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
exists(NodeEx mid, ContentSet c |
readSet(node, c, mid, config) and
fwdFlowConsCandSet(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
or
@@ -789,12 +830,18 @@ private module Stage1 {
}
pragma[nomagic]
private predicate revFlowStore(Content c, NodeEx node, boolean toReturn, Configuration config) {
exists(NodeEx mid, TypedContent tc |
private predicate revFlowConsCandSet(ContentSet c, Configuration config) {
revFlowConsCand(c.getAStoreContent(), config)
}
pragma[nomagic]
private predicate revFlowStoreSet(
ContentSet c, NodeEx node, boolean toReturn, Configuration config
) {
exists(NodeEx mid |
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
store(node, tc, mid, _, config) and
c = tc.getContent()
fwdFlowConsCandSet(c, pragma[only_bind_into](config)) and
storeSet(node, c, mid, _, _, config)
)
}
@@ -802,9 +849,13 @@ private module Stage1 {
* Holds if `c` is the target of both a read and a store in the flow covered
* by `revFlow`.
*/
pragma[nomagic]
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
revFlowConsCand(c, conf) and
revFlowStore(c, _, _, conf)
exists(ContentSet cs |
revFlowStoreSet(cs, _, _, conf) and
c = cs.getAStoreContent()
)
}
pragma[nomagic]
@@ -889,20 +940,20 @@ private module Stage1 {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
exists(Content c, DataFlowType containerType |
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
store(node1, c, node2, contentType, containerType, config) and
revFlow(node2, pragma[only_bind_into](config)) and
store(node1, tc, node2, contentType, config) and
c = tc.getContent() and
tc = MkTypedContent(c, containerType) and
exists(ap1)
)
}
pragma[nomagic]
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
read(n1, c, n2, pragma[only_bind_into](config))
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
read(n1, c, n2, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config))
}
pragma[nomagic]
@@ -1614,7 +1665,7 @@ private module Stage2 {
Configuration config
) {
exists(Ap ap2, Content c |
store(node1, tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
@@ -1769,9 +1820,9 @@ private module LocalFlowBigStep {
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
Stage2::storeStepCand(_, _, _, node, _, config)
or
read(_, _, node, config)
Stage2::readStepCand(_, _, node, config)
or
node instanceof FlowCheckNode
or
@@ -1792,8 +1843,8 @@ private module LocalFlowBigStep {
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
store(node, _, next, _, config) or
read(node, _, next, config)
Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config)
)
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
@@ -1966,7 +2017,24 @@ private module Stage3 {
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
pragma[nomagic]
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
PrevStage::revFlow(node, config) and
clearsContentCached(node.asNode(), c)
}
pragma[nomagic]
private predicate clearContent(NodeEx node, Content c, Configuration config) {
exists(ContentSet cs |
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
c = cs.getAReadContent() and
clearSet(node, cs, pragma[only_bind_into](config))
)
}
pragma[nomagic]
private predicate clear(NodeEx node, Ap ap, Configuration config) {
clearContent(node, ap.getHead().getContent(), config)
}
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
@@ -1975,7 +2043,7 @@ private module Stage3 {
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
exists(state) and
exists(config) and
not clear(node, ap) and
not clear(node, ap, config) and
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
}
@@ -2403,7 +2471,7 @@ private module Stage3 {
Configuration config
) {
exists(Ap ap2, Content c |
store(node1, tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
@@ -3231,7 +3299,7 @@ private module Stage4 {
Configuration config
) {
exists(Ap ap2, Content c |
store(node1, tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
@@ -4242,8 +4310,8 @@ private module Subpaths {
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
storeSet(n1, _, n2, _, _, _) or
readSet(n1, _, n2, _)
)
}
@@ -4598,7 +4666,7 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentCached(node.asNode(), ap.getHead()) and
not clearsContentEx(node, ap.getHead()) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
@@ -4614,7 +4682,7 @@ private module FlowExploration {
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
not clearsContentEx(node, ap.getHead().getContent()) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
@@ -4893,10 +4961,11 @@ private module FlowExploration {
PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, NodeEx node,
PartialAccessPath ap2
) {
exists(NodeEx midNode, DataFlowType contentType |
exists(NodeEx midNode, Content c, DataFlowType contentType, DataFlowType containerType |
midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
store(midNode, tc, node, contentType, mid.getConfiguration()) and
store(midNode, c, node, contentType, containerType, mid.getConfiguration()) and
tc = MkTypedContent(c, containerType) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
@@ -4918,10 +4987,11 @@ private module FlowExploration {
PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, NodeEx node, CallContext cc,
Configuration config
) {
exists(NodeEx midNode |
exists(NodeEx midNode, Content c |
midNode = mid.getNodeEx() and
ap = mid.getAp() and
read(midNode, tc.getContent(), node, pragma[only_bind_into](config)) and
read(midNode, c, node, pragma[only_bind_into](config)) and
tc.getContent() = c and
ap.getHead() = tc and
pragma[only_bind_into](config) = mid.getConfiguration() and
cc = mid.getCallContext()
@@ -5171,13 +5241,12 @@ private module FlowExploration {
private predicate revPartialPathStoreStep(
PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, NodeEx node, Configuration config
) {
exists(NodeEx midNode, TypedContent tc |
exists(NodeEx midNode, DataFlowType contentType, DataFlowType containerType, TypedContent tc |
midNode = mid.getNodeEx() and
ap = mid.getAp() and
store(node, tc, midNode, _, config) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
store(node, c, midNode, contentType, containerType, config) and
tc = MkTypedContent(c, containerType) and
config = mid.getConfiguration()
)
}

View File

@@ -128,7 +128,7 @@ abstract class Configuration extends string {
* Holds if an arbitrary number of implicit read steps of content `c` may be
* taken at `node`.
*/
predicate allowImplicitRead(Node node, Content c) { none() }
predicate allowImplicitRead(Node node, ContentSet c) { none() }
/**
* Gets the virtual dispatch branching limit when calculating field flow.
@@ -525,8 +525,9 @@ private predicate additionalJumpStateStep(
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode()) and
pragma[nomagic]
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
readSet(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
or
exists(Node n |
@@ -536,12 +537,44 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
)
}
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
// inline to reduce fan-out via `getAReadContent`
pragma[inline]
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(ContentSet cs |
readSet(node1, cs, node2, config) and
c = cs.getAReadContent()
)
}
// inline to reduce fan-out via `getAReadContent`
pragma[inline]
private predicate clearsContentEx(NodeEx n, Content c) {
exists(ContentSet cs |
clearsContentCached(n.asNode(), cs) and
c = cs.getAReadContent()
)
}
pragma[nomagic]
private predicate storeSet(
NodeEx node1, ContentSet c, NodeEx node2, DataFlowType contentType, DataFlowType containerType,
Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
storeSet(node1.asNode(), c, node2.asNode(), contentType, containerType) and
stepFilter(node1, node2, config) and
read(_, c.getAStoreContent(), _, config)
}
// inline to reduce fan-out via `getAStoreContent`
pragma[inline]
private predicate store(
NodeEx node1, Content c, NodeEx node2, DataFlowType contentType, DataFlowType containerType,
Configuration config
) {
exists(ContentSet cs |
storeSet(node1, cs, node2, contentType, containerType, config) and
c = cs.getAStoreContent()
)
}
pragma[nomagic]
@@ -609,13 +642,13 @@ private module Stage1 {
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
storeSet(mid, _, node, _, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
exists(ContentSet c |
fwdFlowReadSet(c, node, cc, config) and
fwdFlowConsCandSet(c, config)
)
or
// flow into a callable
@@ -639,10 +672,10 @@ private module Stage1 {
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
pragma[nomagic]
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
read(mid, c, node, config)
readSet(mid, c, node, config)
)
}
@@ -651,15 +684,23 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowConsCand(Content c, Configuration config) {
exists(NodeEx mid, NodeEx node, TypedContent tc |
exists(NodeEx mid, NodeEx node |
not fullBarrier(node, config) and
useFieldFlow(config) and
fwdFlow(mid, _, config) and
store(mid, tc, node, _, config) and
c = tc.getContent()
store(mid, c, node, _, _, config)
)
}
/**
* Holds if `c` may be interpreted in a read as the target of some store,
* in the flow covered by `fwdFlow`.
*/
pragma[nomagic]
private predicate fwdFlowConsCandSet(ContentSet c, Configuration config) {
fwdFlowConsCand(c.getAReadContent(), config)
}
pragma[nomagic]
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
exists(RetNodeEx ret |
@@ -746,15 +787,15 @@ private module Stage1 {
)
or
// store
exists(Content c |
revFlowStore(c, node, toReturn, config) and
revFlowConsCand(c, config)
exists(ContentSet c |
revFlowStoreSet(c, node, toReturn, config) and
revFlowConsCandSet(c, config)
)
or
// read
exists(NodeEx mid, Content c |
read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
exists(NodeEx mid, ContentSet c |
readSet(node, c, mid, config) and
fwdFlowConsCandSet(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
or
@@ -789,12 +830,18 @@ private module Stage1 {
}
pragma[nomagic]
private predicate revFlowStore(Content c, NodeEx node, boolean toReturn, Configuration config) {
exists(NodeEx mid, TypedContent tc |
private predicate revFlowConsCandSet(ContentSet c, Configuration config) {
revFlowConsCand(c.getAStoreContent(), config)
}
pragma[nomagic]
private predicate revFlowStoreSet(
ContentSet c, NodeEx node, boolean toReturn, Configuration config
) {
exists(NodeEx mid |
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
store(node, tc, mid, _, config) and
c = tc.getContent()
fwdFlowConsCandSet(c, pragma[only_bind_into](config)) and
storeSet(node, c, mid, _, _, config)
)
}
@@ -802,9 +849,13 @@ private module Stage1 {
* Holds if `c` is the target of both a read and a store in the flow covered
* by `revFlow`.
*/
pragma[nomagic]
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
revFlowConsCand(c, conf) and
revFlowStore(c, _, _, conf)
exists(ContentSet cs |
revFlowStoreSet(cs, _, _, conf) and
c = cs.getAStoreContent()
)
}
pragma[nomagic]
@@ -889,20 +940,20 @@ private module Stage1 {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
exists(Content c, DataFlowType containerType |
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
store(node1, c, node2, contentType, containerType, config) and
revFlow(node2, pragma[only_bind_into](config)) and
store(node1, tc, node2, contentType, config) and
c = tc.getContent() and
tc = MkTypedContent(c, containerType) and
exists(ap1)
)
}
pragma[nomagic]
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
read(n1, c, n2, pragma[only_bind_into](config))
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
read(n1, c, n2, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config))
}
pragma[nomagic]
@@ -1614,7 +1665,7 @@ private module Stage2 {
Configuration config
) {
exists(Ap ap2, Content c |
store(node1, tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
@@ -1769,9 +1820,9 @@ private module LocalFlowBigStep {
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
Stage2::storeStepCand(_, _, _, node, _, config)
or
read(_, _, node, config)
Stage2::readStepCand(_, _, node, config)
or
node instanceof FlowCheckNode
or
@@ -1792,8 +1843,8 @@ private module LocalFlowBigStep {
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
store(node, _, next, _, config) or
read(node, _, next, config)
Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config)
)
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
@@ -1966,7 +2017,24 @@ private module Stage3 {
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
pragma[nomagic]
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
PrevStage::revFlow(node, config) and
clearsContentCached(node.asNode(), c)
}
pragma[nomagic]
private predicate clearContent(NodeEx node, Content c, Configuration config) {
exists(ContentSet cs |
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
c = cs.getAReadContent() and
clearSet(node, cs, pragma[only_bind_into](config))
)
}
pragma[nomagic]
private predicate clear(NodeEx node, Ap ap, Configuration config) {
clearContent(node, ap.getHead().getContent(), config)
}
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
@@ -1975,7 +2043,7 @@ private module Stage3 {
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
exists(state) and
exists(config) and
not clear(node, ap) and
not clear(node, ap, config) and
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
}
@@ -2403,7 +2471,7 @@ private module Stage3 {
Configuration config
) {
exists(Ap ap2, Content c |
store(node1, tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
@@ -3231,7 +3299,7 @@ private module Stage4 {
Configuration config
) {
exists(Ap ap2, Content c |
store(node1, tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
@@ -4242,8 +4310,8 @@ private module Subpaths {
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
storeSet(n1, _, n2, _, _, _) or
readSet(n1, _, n2, _)
)
}
@@ -4598,7 +4666,7 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentCached(node.asNode(), ap.getHead()) and
not clearsContentEx(node, ap.getHead()) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
@@ -4614,7 +4682,7 @@ private module FlowExploration {
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
not clearsContentEx(node, ap.getHead().getContent()) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
@@ -4893,10 +4961,11 @@ private module FlowExploration {
PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, NodeEx node,
PartialAccessPath ap2
) {
exists(NodeEx midNode, DataFlowType contentType |
exists(NodeEx midNode, Content c, DataFlowType contentType, DataFlowType containerType |
midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
store(midNode, tc, node, contentType, mid.getConfiguration()) and
store(midNode, c, node, contentType, containerType, mid.getConfiguration()) and
tc = MkTypedContent(c, containerType) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
@@ -4918,10 +4987,11 @@ private module FlowExploration {
PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, NodeEx node, CallContext cc,
Configuration config
) {
exists(NodeEx midNode |
exists(NodeEx midNode, Content c |
midNode = mid.getNodeEx() and
ap = mid.getAp() and
read(midNode, tc.getContent(), node, pragma[only_bind_into](config)) and
read(midNode, c, node, pragma[only_bind_into](config)) and
tc.getContent() = c and
ap.getHead() = tc and
pragma[only_bind_into](config) = mid.getConfiguration() and
cc = mid.getCallContext()
@@ -5171,13 +5241,12 @@ private module FlowExploration {
private predicate revPartialPathStoreStep(
PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, NodeEx node, Configuration config
) {
exists(NodeEx midNode, TypedContent tc |
exists(NodeEx midNode, DataFlowType contentType, DataFlowType containerType, TypedContent tc |
midNode = mid.getNodeEx() and
ap = mid.getAp() and
store(node, tc, midNode, _, config) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
store(node, c, midNode, contentType, containerType, config) and
tc = MkTypedContent(c, containerType) and
config = mid.getConfiguration()
)
}

View File

@@ -326,7 +326,7 @@ private module Cached {
predicate jumpStepCached(Node node1, Node node2) { jumpStep(node1, node2) }
cached
predicate clearsContentCached(Node n, Content c) { clearsContent(n, c) }
predicate clearsContentCached(Node n, ContentSet c) { clearsContent(n, c) }
cached
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
@@ -373,7 +373,7 @@ private module Cached {
// For reads, `x.f`, we want to check that the tracked type after the read (which
// is obtained by popping the head of the access path stack) is compatible with
// the type of `x.f`.
read(_, _, n)
readSet(_, _, n)
}
cached
@@ -469,7 +469,7 @@ private module Cached {
// read
exists(Node mid |
parameterValueFlowCand(p, mid, false) and
read(mid, _, node) and
readSet(mid, _, node) and
read = true
)
or
@@ -657,8 +657,10 @@ private module Cached {
* Holds if `arg` flows to `out` through a call using only
* value-preserving steps and a single read step, not taking call
* contexts into account, thus representing a getter-step.
*
* This predicate is exposed for testing only.
*/
predicate getterStep(ArgNode arg, Content c, Node out) {
predicate getterStep(ArgNode arg, ContentSet c, Node out) {
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
}
@@ -781,8 +783,19 @@ private module Cached {
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
}
private predicate store(
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
cached
predicate readSet(Node node1, ContentSet c, Node node2) { readStep(node1, c, node2) }
/**
* Holds if data can flow from `node1` to `node2` via a direct assignment to
* `c`.
*
* This includes reverse steps through reads when the result of the read has
* been stored into, in order to handle cases like `x.f1.f2 = y`.
*/
cached
predicate storeSet(
Node node1, ContentSet c, Node node2, DataFlowType contentType, DataFlowType containerType
) {
storeStep(node1, c, node2) and
contentType = getNodeDataFlowType(node1) and
@@ -794,27 +807,12 @@ private module Cached {
|
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
or
read(n2, c, n1) and
readSet(n2, c, n1) and
contentType = getNodeDataFlowType(n1) and
containerType = getNodeDataFlowType(n2)
)
}
cached
predicate read(Node node1, Content c, Node node2) { readStep(node1, c, node2) }
/**
* Holds if data can flow from `node1` to `node2` via a direct assignment to
* `f`.
*
* This includes reverse steps through reads when the result of the read has
* been stored into, in order to handle cases like `x.f1.f2 = y`.
*/
cached
predicate store(Node node1, TypedContent tc, Node node2, DataFlowType contentType) {
store(node1, tc.getContent(), node2, contentType, tc.getContainerType())
}
/**
* Holds if data can flow from `fromNode` to `toNode` because they are the post-update
* nodes of some function output and input respectively, where the output and input
@@ -902,7 +900,13 @@ private module Cached {
TDataFlowCallSome(DataFlowCall call)
cached
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
newtype TTypedContent =
MkTypedContent(Content c, DataFlowType t) {
exists(ContentSet cs |
storeSet(_, cs, _, _, t) and
c = cs.getAStoreContent()
)
}
cached
newtype TAccessPathFront =
@@ -932,16 +936,16 @@ class CastingNode extends Node {
}
private predicate readStepWithTypes(
Node n1, DataFlowType container, Content c, Node n2, DataFlowType content
Node n1, DataFlowType container, ContentSet c, Node n2, DataFlowType content
) {
read(n1, c, n2) and
readSet(n1, c, n2) and
container = getNodeDataFlowType(n1) and
content = getNodeDataFlowType(n2)
}
private newtype TReadStepTypesOption =
TReadStepTypesNone() or
TReadStepTypesSome(DataFlowType container, Content c, DataFlowType content) {
TReadStepTypesSome(DataFlowType container, ContentSet c, DataFlowType content) {
readStepWithTypes(_, container, c, _, content)
}
@@ -950,7 +954,7 @@ private class ReadStepTypesOption extends TReadStepTypesOption {
DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) }
Content getContent() { this = TReadStepTypesSome(_, result, _) }
ContentSet getContent() { this = TReadStepTypesSome(_, result, _) }
DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) }
@@ -1325,8 +1329,6 @@ abstract class AccessPathFront extends TAccessPathFront {
abstract boolean toBoolNonEmpty();
TypedContent getHead() { this = TFrontHead(result) }
predicate isClearedAt(Node n) { clearsContentCached(n, this.getHead().getContent()) }
}
class AccessPathFrontNil extends AccessPathFront, TFrontNil {

View File

@@ -128,7 +128,7 @@ abstract class Configuration extends string {
* Holds if an arbitrary number of implicit read steps of content `c` may be
* taken at `node`.
*/
predicate allowImplicitRead(Node node, Content c) { none() }
predicate allowImplicitRead(Node node, ContentSet c) { none() }
/**
* Gets the virtual dispatch branching limit when calculating field flow.
@@ -525,8 +525,9 @@ private predicate additionalJumpStateStep(
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode()) and
pragma[nomagic]
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
readSet(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
or
exists(Node n |
@@ -536,12 +537,44 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
)
}
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
// inline to reduce fan-out via `getAReadContent`
pragma[inline]
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(ContentSet cs |
readSet(node1, cs, node2, config) and
c = cs.getAReadContent()
)
}
// inline to reduce fan-out via `getAReadContent`
pragma[inline]
private predicate clearsContentEx(NodeEx n, Content c) {
exists(ContentSet cs |
clearsContentCached(n.asNode(), cs) and
c = cs.getAReadContent()
)
}
pragma[nomagic]
private predicate storeSet(
NodeEx node1, ContentSet c, NodeEx node2, DataFlowType contentType, DataFlowType containerType,
Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
storeSet(node1.asNode(), c, node2.asNode(), contentType, containerType) and
stepFilter(node1, node2, config) and
read(_, c.getAStoreContent(), _, config)
}
// inline to reduce fan-out via `getAStoreContent`
pragma[inline]
private predicate store(
NodeEx node1, Content c, NodeEx node2, DataFlowType contentType, DataFlowType containerType,
Configuration config
) {
exists(ContentSet cs |
storeSet(node1, cs, node2, contentType, containerType, config) and
c = cs.getAStoreContent()
)
}
pragma[nomagic]
@@ -609,13 +642,13 @@ private module Stage1 {
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
storeSet(mid, _, node, _, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
exists(ContentSet c |
fwdFlowReadSet(c, node, cc, config) and
fwdFlowConsCandSet(c, config)
)
or
// flow into a callable
@@ -639,10 +672,10 @@ private module Stage1 {
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
pragma[nomagic]
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
read(mid, c, node, config)
readSet(mid, c, node, config)
)
}
@@ -651,15 +684,23 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowConsCand(Content c, Configuration config) {
exists(NodeEx mid, NodeEx node, TypedContent tc |
exists(NodeEx mid, NodeEx node |
not fullBarrier(node, config) and
useFieldFlow(config) and
fwdFlow(mid, _, config) and
store(mid, tc, node, _, config) and
c = tc.getContent()
store(mid, c, node, _, _, config)
)
}
/**
* Holds if `c` may be interpreted in a read as the target of some store,
* in the flow covered by `fwdFlow`.
*/
pragma[nomagic]
private predicate fwdFlowConsCandSet(ContentSet c, Configuration config) {
fwdFlowConsCand(c.getAReadContent(), config)
}
pragma[nomagic]
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
exists(RetNodeEx ret |
@@ -746,15 +787,15 @@ private module Stage1 {
)
or
// store
exists(Content c |
revFlowStore(c, node, toReturn, config) and
revFlowConsCand(c, config)
exists(ContentSet c |
revFlowStoreSet(c, node, toReturn, config) and
revFlowConsCandSet(c, config)
)
or
// read
exists(NodeEx mid, Content c |
read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
exists(NodeEx mid, ContentSet c |
readSet(node, c, mid, config) and
fwdFlowConsCandSet(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
or
@@ -789,12 +830,18 @@ private module Stage1 {
}
pragma[nomagic]
private predicate revFlowStore(Content c, NodeEx node, boolean toReturn, Configuration config) {
exists(NodeEx mid, TypedContent tc |
private predicate revFlowConsCandSet(ContentSet c, Configuration config) {
revFlowConsCand(c.getAStoreContent(), config)
}
pragma[nomagic]
private predicate revFlowStoreSet(
ContentSet c, NodeEx node, boolean toReturn, Configuration config
) {
exists(NodeEx mid |
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
store(node, tc, mid, _, config) and
c = tc.getContent()
fwdFlowConsCandSet(c, pragma[only_bind_into](config)) and
storeSet(node, c, mid, _, _, config)
)
}
@@ -802,9 +849,13 @@ private module Stage1 {
* Holds if `c` is the target of both a read and a store in the flow covered
* by `revFlow`.
*/
pragma[nomagic]
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
revFlowConsCand(c, conf) and
revFlowStore(c, _, _, conf)
exists(ContentSet cs |
revFlowStoreSet(cs, _, _, conf) and
c = cs.getAStoreContent()
)
}
pragma[nomagic]
@@ -889,20 +940,20 @@ private module Stage1 {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
exists(Content c, DataFlowType containerType |
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
store(node1, c, node2, contentType, containerType, config) and
revFlow(node2, pragma[only_bind_into](config)) and
store(node1, tc, node2, contentType, config) and
c = tc.getContent() and
tc = MkTypedContent(c, containerType) and
exists(ap1)
)
}
pragma[nomagic]
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
read(n1, c, n2, pragma[only_bind_into](config))
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
read(n1, c, n2, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config))
}
pragma[nomagic]
@@ -1614,7 +1665,7 @@ private module Stage2 {
Configuration config
) {
exists(Ap ap2, Content c |
store(node1, tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
@@ -1769,9 +1820,9 @@ private module LocalFlowBigStep {
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
Stage2::storeStepCand(_, _, _, node, _, config)
or
read(_, _, node, config)
Stage2::readStepCand(_, _, node, config)
or
node instanceof FlowCheckNode
or
@@ -1792,8 +1843,8 @@ private module LocalFlowBigStep {
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
store(node, _, next, _, config) or
read(node, _, next, config)
Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config)
)
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
@@ -1966,7 +2017,24 @@ private module Stage3 {
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
pragma[nomagic]
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
PrevStage::revFlow(node, config) and
clearsContentCached(node.asNode(), c)
}
pragma[nomagic]
private predicate clearContent(NodeEx node, Content c, Configuration config) {
exists(ContentSet cs |
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
c = cs.getAReadContent() and
clearSet(node, cs, pragma[only_bind_into](config))
)
}
pragma[nomagic]
private predicate clear(NodeEx node, Ap ap, Configuration config) {
clearContent(node, ap.getHead().getContent(), config)
}
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
@@ -1975,7 +2043,7 @@ private module Stage3 {
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
exists(state) and
exists(config) and
not clear(node, ap) and
not clear(node, ap, config) and
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
}
@@ -2403,7 +2471,7 @@ private module Stage3 {
Configuration config
) {
exists(Ap ap2, Content c |
store(node1, tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
@@ -3231,7 +3299,7 @@ private module Stage4 {
Configuration config
) {
exists(Ap ap2, Content c |
store(node1, tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
@@ -4242,8 +4310,8 @@ private module Subpaths {
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
storeSet(n1, _, n2, _, _, _) or
readSet(n1, _, n2, _)
)
}
@@ -4598,7 +4666,7 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentCached(node.asNode(), ap.getHead()) and
not clearsContentEx(node, ap.getHead()) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
@@ -4614,7 +4682,7 @@ private module FlowExploration {
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
not clearsContentEx(node, ap.getHead().getContent()) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
@@ -4893,10 +4961,11 @@ private module FlowExploration {
PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, NodeEx node,
PartialAccessPath ap2
) {
exists(NodeEx midNode, DataFlowType contentType |
exists(NodeEx midNode, Content c, DataFlowType contentType, DataFlowType containerType |
midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
store(midNode, tc, node, contentType, mid.getConfiguration()) and
store(midNode, c, node, contentType, containerType, mid.getConfiguration()) and
tc = MkTypedContent(c, containerType) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
@@ -4918,10 +4987,11 @@ private module FlowExploration {
PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, NodeEx node, CallContext cc,
Configuration config
) {
exists(NodeEx midNode |
exists(NodeEx midNode, Content c |
midNode = mid.getNodeEx() and
ap = mid.getAp() and
read(midNode, tc.getContent(), node, pragma[only_bind_into](config)) and
read(midNode, c, node, pragma[only_bind_into](config)) and
tc.getContent() = c and
ap.getHead() = tc and
pragma[only_bind_into](config) = mid.getConfiguration() and
cc = mid.getCallContext()
@@ -5171,13 +5241,12 @@ private module FlowExploration {
private predicate revPartialPathStoreStep(
PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, NodeEx node, Configuration config
) {
exists(NodeEx midNode, TypedContent tc |
exists(NodeEx midNode, DataFlowType contentType, DataFlowType containerType, TypedContent tc |
midNode = mid.getNodeEx() and
ap = mid.getAp() and
store(node, tc, midNode, _, config) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
store(node, c, midNode, contentType, containerType, config) and
tc = MkTypedContent(c, containerType) and
config = mid.getConfiguration()
)
}

View File

@@ -181,7 +181,7 @@ abstract class Configuration extends DataFlow::Configuration {
this.isAdditionalTaintStep(node1, state1, node2, state2)
}
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
defaultImplicitTaintRead(node, c)
}

View File

@@ -181,7 +181,7 @@ abstract class Configuration extends DataFlow::Configuration {
this.isAdditionalTaintStep(node1, state1, node2, state2)
}
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
defaultImplicitTaintRead(node, c)
}

View File

@@ -128,7 +128,7 @@ abstract class Configuration extends string {
* Holds if an arbitrary number of implicit read steps of content `c` may be
* taken at `node`.
*/
predicate allowImplicitRead(Node node, Content c) { none() }
predicate allowImplicitRead(Node node, ContentSet c) { none() }
/**
* Gets the virtual dispatch branching limit when calculating field flow.
@@ -525,8 +525,9 @@ private predicate additionalJumpStateStep(
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode()) and
pragma[nomagic]
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
readSet(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
or
exists(Node n |
@@ -536,12 +537,44 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
)
}
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
// inline to reduce fan-out via `getAReadContent`
pragma[inline]
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(ContentSet cs |
readSet(node1, cs, node2, config) and
c = cs.getAReadContent()
)
}
// inline to reduce fan-out via `getAReadContent`
pragma[inline]
private predicate clearsContentEx(NodeEx n, Content c) {
exists(ContentSet cs |
clearsContentCached(n.asNode(), cs) and
c = cs.getAReadContent()
)
}
pragma[nomagic]
private predicate storeSet(
NodeEx node1, ContentSet c, NodeEx node2, DataFlowType contentType, DataFlowType containerType,
Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
storeSet(node1.asNode(), c, node2.asNode(), contentType, containerType) and
stepFilter(node1, node2, config) and
read(_, c.getAStoreContent(), _, config)
}
// inline to reduce fan-out via `getAStoreContent`
pragma[inline]
private predicate store(
NodeEx node1, Content c, NodeEx node2, DataFlowType contentType, DataFlowType containerType,
Configuration config
) {
exists(ContentSet cs |
storeSet(node1, cs, node2, contentType, containerType, config) and
c = cs.getAStoreContent()
)
}
pragma[nomagic]
@@ -609,13 +642,13 @@ private module Stage1 {
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
storeSet(mid, _, node, _, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
exists(ContentSet c |
fwdFlowReadSet(c, node, cc, config) and
fwdFlowConsCandSet(c, config)
)
or
// flow into a callable
@@ -639,10 +672,10 @@ private module Stage1 {
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
pragma[nomagic]
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
read(mid, c, node, config)
readSet(mid, c, node, config)
)
}
@@ -651,15 +684,23 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowConsCand(Content c, Configuration config) {
exists(NodeEx mid, NodeEx node, TypedContent tc |
exists(NodeEx mid, NodeEx node |
not fullBarrier(node, config) and
useFieldFlow(config) and
fwdFlow(mid, _, config) and
store(mid, tc, node, _, config) and
c = tc.getContent()
store(mid, c, node, _, _, config)
)
}
/**
* Holds if `c` may be interpreted in a read as the target of some store,
* in the flow covered by `fwdFlow`.
*/
pragma[nomagic]
private predicate fwdFlowConsCandSet(ContentSet c, Configuration config) {
fwdFlowConsCand(c.getAReadContent(), config)
}
pragma[nomagic]
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
exists(RetNodeEx ret |
@@ -746,15 +787,15 @@ private module Stage1 {
)
or
// store
exists(Content c |
revFlowStore(c, node, toReturn, config) and
revFlowConsCand(c, config)
exists(ContentSet c |
revFlowStoreSet(c, node, toReturn, config) and
revFlowConsCandSet(c, config)
)
or
// read
exists(NodeEx mid, Content c |
read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
exists(NodeEx mid, ContentSet c |
readSet(node, c, mid, config) and
fwdFlowConsCandSet(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
or
@@ -789,12 +830,18 @@ private module Stage1 {
}
pragma[nomagic]
private predicate revFlowStore(Content c, NodeEx node, boolean toReturn, Configuration config) {
exists(NodeEx mid, TypedContent tc |
private predicate revFlowConsCandSet(ContentSet c, Configuration config) {
revFlowConsCand(c.getAStoreContent(), config)
}
pragma[nomagic]
private predicate revFlowStoreSet(
ContentSet c, NodeEx node, boolean toReturn, Configuration config
) {
exists(NodeEx mid |
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
store(node, tc, mid, _, config) and
c = tc.getContent()
fwdFlowConsCandSet(c, pragma[only_bind_into](config)) and
storeSet(node, c, mid, _, _, config)
)
}
@@ -802,9 +849,13 @@ private module Stage1 {
* Holds if `c` is the target of both a read and a store in the flow covered
* by `revFlow`.
*/
pragma[nomagic]
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
revFlowConsCand(c, conf) and
revFlowStore(c, _, _, conf)
exists(ContentSet cs |
revFlowStoreSet(cs, _, _, conf) and
c = cs.getAStoreContent()
)
}
pragma[nomagic]
@@ -889,20 +940,20 @@ private module Stage1 {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
exists(Content c, DataFlowType containerType |
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
store(node1, c, node2, contentType, containerType, config) and
revFlow(node2, pragma[only_bind_into](config)) and
store(node1, tc, node2, contentType, config) and
c = tc.getContent() and
tc = MkTypedContent(c, containerType) and
exists(ap1)
)
}
pragma[nomagic]
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
read(n1, c, n2, pragma[only_bind_into](config))
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
read(n1, c, n2, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config))
}
pragma[nomagic]
@@ -1614,7 +1665,7 @@ private module Stage2 {
Configuration config
) {
exists(Ap ap2, Content c |
store(node1, tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
@@ -1769,9 +1820,9 @@ private module LocalFlowBigStep {
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
Stage2::storeStepCand(_, _, _, node, _, config)
or
read(_, _, node, config)
Stage2::readStepCand(_, _, node, config)
or
node instanceof FlowCheckNode
or
@@ -1792,8 +1843,8 @@ private module LocalFlowBigStep {
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
store(node, _, next, _, config) or
read(node, _, next, config)
Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config)
)
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
@@ -1966,7 +2017,24 @@ private module Stage3 {
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
pragma[nomagic]
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
PrevStage::revFlow(node, config) and
clearsContentCached(node.asNode(), c)
}
pragma[nomagic]
private predicate clearContent(NodeEx node, Content c, Configuration config) {
exists(ContentSet cs |
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
c = cs.getAReadContent() and
clearSet(node, cs, pragma[only_bind_into](config))
)
}
pragma[nomagic]
private predicate clear(NodeEx node, Ap ap, Configuration config) {
clearContent(node, ap.getHead().getContent(), config)
}
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
@@ -1975,7 +2043,7 @@ private module Stage3 {
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
exists(state) and
exists(config) and
not clear(node, ap) and
not clear(node, ap, config) and
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
}
@@ -2403,7 +2471,7 @@ private module Stage3 {
Configuration config
) {
exists(Ap ap2, Content c |
store(node1, tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
@@ -3231,7 +3299,7 @@ private module Stage4 {
Configuration config
) {
exists(Ap ap2, Content c |
store(node1, tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
@@ -4242,8 +4310,8 @@ private module Subpaths {
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
storeSet(n1, _, n2, _, _, _) or
readSet(n1, _, n2, _)
)
}
@@ -4598,7 +4666,7 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentCached(node.asNode(), ap.getHead()) and
not clearsContentEx(node, ap.getHead()) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
@@ -4614,7 +4682,7 @@ private module FlowExploration {
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
not clearsContentEx(node, ap.getHead().getContent()) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
@@ -4893,10 +4961,11 @@ private module FlowExploration {
PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, NodeEx node,
PartialAccessPath ap2
) {
exists(NodeEx midNode, DataFlowType contentType |
exists(NodeEx midNode, Content c, DataFlowType contentType, DataFlowType containerType |
midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
store(midNode, tc, node, contentType, mid.getConfiguration()) and
store(midNode, c, node, contentType, containerType, mid.getConfiguration()) and
tc = MkTypedContent(c, containerType) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
@@ -4918,10 +4987,11 @@ private module FlowExploration {
PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, NodeEx node, CallContext cc,
Configuration config
) {
exists(NodeEx midNode |
exists(NodeEx midNode, Content c |
midNode = mid.getNodeEx() and
ap = mid.getAp() and
read(midNode, tc.getContent(), node, pragma[only_bind_into](config)) and
read(midNode, c, node, pragma[only_bind_into](config)) and
tc.getContent() = c and
ap.getHead() = tc and
pragma[only_bind_into](config) = mid.getConfiguration() and
cc = mid.getCallContext()
@@ -5171,13 +5241,12 @@ private module FlowExploration {
private predicate revPartialPathStoreStep(
PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, NodeEx node, Configuration config
) {
exists(NodeEx midNode, TypedContent tc |
exists(NodeEx midNode, DataFlowType contentType, DataFlowType containerType, TypedContent tc |
midNode = mid.getNodeEx() and
ap = mid.getAp() and
store(node, tc, midNode, _, config) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
store(node, c, midNode, contentType, containerType, config) and
tc = MkTypedContent(c, containerType) and
config = mid.getConfiguration()
)
}

View File

@@ -128,7 +128,7 @@ abstract class Configuration extends string {
* Holds if an arbitrary number of implicit read steps of content `c` may be
* taken at `node`.
*/
predicate allowImplicitRead(Node node, Content c) { none() }
predicate allowImplicitRead(Node node, ContentSet c) { none() }
/**
* Gets the virtual dispatch branching limit when calculating field flow.
@@ -525,8 +525,9 @@ private predicate additionalJumpStateStep(
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode()) and
pragma[nomagic]
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
readSet(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
or
exists(Node n |
@@ -536,12 +537,44 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
)
}
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
// inline to reduce fan-out via `getAReadContent`
pragma[inline]
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(ContentSet cs |
readSet(node1, cs, node2, config) and
c = cs.getAReadContent()
)
}
// inline to reduce fan-out via `getAReadContent`
pragma[inline]
private predicate clearsContentEx(NodeEx n, Content c) {
exists(ContentSet cs |
clearsContentCached(n.asNode(), cs) and
c = cs.getAReadContent()
)
}
pragma[nomagic]
private predicate storeSet(
NodeEx node1, ContentSet c, NodeEx node2, DataFlowType contentType, DataFlowType containerType,
Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
storeSet(node1.asNode(), c, node2.asNode(), contentType, containerType) and
stepFilter(node1, node2, config) and
read(_, c.getAStoreContent(), _, config)
}
// inline to reduce fan-out via `getAStoreContent`
pragma[inline]
private predicate store(
NodeEx node1, Content c, NodeEx node2, DataFlowType contentType, DataFlowType containerType,
Configuration config
) {
exists(ContentSet cs |
storeSet(node1, cs, node2, contentType, containerType, config) and
c = cs.getAStoreContent()
)
}
pragma[nomagic]
@@ -609,13 +642,13 @@ private module Stage1 {
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
storeSet(mid, _, node, _, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
exists(ContentSet c |
fwdFlowReadSet(c, node, cc, config) and
fwdFlowConsCandSet(c, config)
)
or
// flow into a callable
@@ -639,10 +672,10 @@ private module Stage1 {
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
pragma[nomagic]
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
read(mid, c, node, config)
readSet(mid, c, node, config)
)
}
@@ -651,15 +684,23 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowConsCand(Content c, Configuration config) {
exists(NodeEx mid, NodeEx node, TypedContent tc |
exists(NodeEx mid, NodeEx node |
not fullBarrier(node, config) and
useFieldFlow(config) and
fwdFlow(mid, _, config) and
store(mid, tc, node, _, config) and
c = tc.getContent()
store(mid, c, node, _, _, config)
)
}
/**
* Holds if `c` may be interpreted in a read as the target of some store,
* in the flow covered by `fwdFlow`.
*/
pragma[nomagic]
private predicate fwdFlowConsCandSet(ContentSet c, Configuration config) {
fwdFlowConsCand(c.getAReadContent(), config)
}
pragma[nomagic]
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
exists(RetNodeEx ret |
@@ -746,15 +787,15 @@ private module Stage1 {
)
or
// store
exists(Content c |
revFlowStore(c, node, toReturn, config) and
revFlowConsCand(c, config)
exists(ContentSet c |
revFlowStoreSet(c, node, toReturn, config) and
revFlowConsCandSet(c, config)
)
or
// read
exists(NodeEx mid, Content c |
read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
exists(NodeEx mid, ContentSet c |
readSet(node, c, mid, config) and
fwdFlowConsCandSet(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
or
@@ -789,12 +830,18 @@ private module Stage1 {
}
pragma[nomagic]
private predicate revFlowStore(Content c, NodeEx node, boolean toReturn, Configuration config) {
exists(NodeEx mid, TypedContent tc |
private predicate revFlowConsCandSet(ContentSet c, Configuration config) {
revFlowConsCand(c.getAStoreContent(), config)
}
pragma[nomagic]
private predicate revFlowStoreSet(
ContentSet c, NodeEx node, boolean toReturn, Configuration config
) {
exists(NodeEx mid |
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
store(node, tc, mid, _, config) and
c = tc.getContent()
fwdFlowConsCandSet(c, pragma[only_bind_into](config)) and
storeSet(node, c, mid, _, _, config)
)
}
@@ -802,9 +849,13 @@ private module Stage1 {
* Holds if `c` is the target of both a read and a store in the flow covered
* by `revFlow`.
*/
pragma[nomagic]
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
revFlowConsCand(c, conf) and
revFlowStore(c, _, _, conf)
exists(ContentSet cs |
revFlowStoreSet(cs, _, _, conf) and
c = cs.getAStoreContent()
)
}
pragma[nomagic]
@@ -889,20 +940,20 @@ private module Stage1 {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
exists(Content c, DataFlowType containerType |
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
store(node1, c, node2, contentType, containerType, config) and
revFlow(node2, pragma[only_bind_into](config)) and
store(node1, tc, node2, contentType, config) and
c = tc.getContent() and
tc = MkTypedContent(c, containerType) and
exists(ap1)
)
}
pragma[nomagic]
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
read(n1, c, n2, pragma[only_bind_into](config))
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
read(n1, c, n2, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config))
}
pragma[nomagic]
@@ -1614,7 +1665,7 @@ private module Stage2 {
Configuration config
) {
exists(Ap ap2, Content c |
store(node1, tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
@@ -1769,9 +1820,9 @@ private module LocalFlowBigStep {
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
Stage2::storeStepCand(_, _, _, node, _, config)
or
read(_, _, node, config)
Stage2::readStepCand(_, _, node, config)
or
node instanceof FlowCheckNode
or
@@ -1792,8 +1843,8 @@ private module LocalFlowBigStep {
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
store(node, _, next, _, config) or
read(node, _, next, config)
Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config)
)
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
@@ -1966,7 +2017,24 @@ private module Stage3 {
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
pragma[nomagic]
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
PrevStage::revFlow(node, config) and
clearsContentCached(node.asNode(), c)
}
pragma[nomagic]
private predicate clearContent(NodeEx node, Content c, Configuration config) {
exists(ContentSet cs |
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
c = cs.getAReadContent() and
clearSet(node, cs, pragma[only_bind_into](config))
)
}
pragma[nomagic]
private predicate clear(NodeEx node, Ap ap, Configuration config) {
clearContent(node, ap.getHead().getContent(), config)
}
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
@@ -1975,7 +2043,7 @@ private module Stage3 {
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
exists(state) and
exists(config) and
not clear(node, ap) and
not clear(node, ap, config) and
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
}
@@ -2403,7 +2471,7 @@ private module Stage3 {
Configuration config
) {
exists(Ap ap2, Content c |
store(node1, tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
@@ -3231,7 +3299,7 @@ private module Stage4 {
Configuration config
) {
exists(Ap ap2, Content c |
store(node1, tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
@@ -4242,8 +4310,8 @@ private module Subpaths {
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
storeSet(n1, _, n2, _, _, _) or
readSet(n1, _, n2, _)
)
}
@@ -4598,7 +4666,7 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentCached(node.asNode(), ap.getHead()) and
not clearsContentEx(node, ap.getHead()) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
@@ -4614,7 +4682,7 @@ private module FlowExploration {
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
not clearsContentEx(node, ap.getHead().getContent()) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
@@ -4893,10 +4961,11 @@ private module FlowExploration {
PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, NodeEx node,
PartialAccessPath ap2
) {
exists(NodeEx midNode, DataFlowType contentType |
exists(NodeEx midNode, Content c, DataFlowType contentType, DataFlowType containerType |
midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
store(midNode, tc, node, contentType, mid.getConfiguration()) and
store(midNode, c, node, contentType, containerType, mid.getConfiguration()) and
tc = MkTypedContent(c, containerType) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
@@ -4918,10 +4987,11 @@ private module FlowExploration {
PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, NodeEx node, CallContext cc,
Configuration config
) {
exists(NodeEx midNode |
exists(NodeEx midNode, Content c |
midNode = mid.getNodeEx() and
ap = mid.getAp() and
read(midNode, tc.getContent(), node, pragma[only_bind_into](config)) and
read(midNode, c, node, pragma[only_bind_into](config)) and
tc.getContent() = c and
ap.getHead() = tc and
pragma[only_bind_into](config) = mid.getConfiguration() and
cc = mid.getCallContext()
@@ -5171,13 +5241,12 @@ private module FlowExploration {
private predicate revPartialPathStoreStep(
PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, NodeEx node, Configuration config
) {
exists(NodeEx midNode, TypedContent tc |
exists(NodeEx midNode, DataFlowType contentType, DataFlowType containerType, TypedContent tc |
midNode = mid.getNodeEx() and
ap = mid.getAp() and
store(node, tc, midNode, _, config) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
store(node, c, midNode, contentType, containerType, config) and
tc = MkTypedContent(c, containerType) and
config = mid.getConfiguration()
)
}

View File

@@ -128,7 +128,7 @@ abstract class Configuration extends string {
* Holds if an arbitrary number of implicit read steps of content `c` may be
* taken at `node`.
*/
predicate allowImplicitRead(Node node, Content c) { none() }
predicate allowImplicitRead(Node node, ContentSet c) { none() }
/**
* Gets the virtual dispatch branching limit when calculating field flow.
@@ -525,8 +525,9 @@ private predicate additionalJumpStateStep(
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode()) and
pragma[nomagic]
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
readSet(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
or
exists(Node n |
@@ -536,12 +537,44 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
)
}
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
// inline to reduce fan-out via `getAReadContent`
pragma[inline]
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(ContentSet cs |
readSet(node1, cs, node2, config) and
c = cs.getAReadContent()
)
}
// inline to reduce fan-out via `getAReadContent`
pragma[inline]
private predicate clearsContentEx(NodeEx n, Content c) {
exists(ContentSet cs |
clearsContentCached(n.asNode(), cs) and
c = cs.getAReadContent()
)
}
pragma[nomagic]
private predicate storeSet(
NodeEx node1, ContentSet c, NodeEx node2, DataFlowType contentType, DataFlowType containerType,
Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
storeSet(node1.asNode(), c, node2.asNode(), contentType, containerType) and
stepFilter(node1, node2, config) and
read(_, c.getAStoreContent(), _, config)
}
// inline to reduce fan-out via `getAStoreContent`
pragma[inline]
private predicate store(
NodeEx node1, Content c, NodeEx node2, DataFlowType contentType, DataFlowType containerType,
Configuration config
) {
exists(ContentSet cs |
storeSet(node1, cs, node2, contentType, containerType, config) and
c = cs.getAStoreContent()
)
}
pragma[nomagic]
@@ -609,13 +642,13 @@ private module Stage1 {
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
storeSet(mid, _, node, _, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
exists(ContentSet c |
fwdFlowReadSet(c, node, cc, config) and
fwdFlowConsCandSet(c, config)
)
or
// flow into a callable
@@ -639,10 +672,10 @@ private module Stage1 {
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
pragma[nomagic]
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
read(mid, c, node, config)
readSet(mid, c, node, config)
)
}
@@ -651,15 +684,23 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowConsCand(Content c, Configuration config) {
exists(NodeEx mid, NodeEx node, TypedContent tc |
exists(NodeEx mid, NodeEx node |
not fullBarrier(node, config) and
useFieldFlow(config) and
fwdFlow(mid, _, config) and
store(mid, tc, node, _, config) and
c = tc.getContent()
store(mid, c, node, _, _, config)
)
}
/**
* Holds if `c` may be interpreted in a read as the target of some store,
* in the flow covered by `fwdFlow`.
*/
pragma[nomagic]
private predicate fwdFlowConsCandSet(ContentSet c, Configuration config) {
fwdFlowConsCand(c.getAReadContent(), config)
}
pragma[nomagic]
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
exists(RetNodeEx ret |
@@ -746,15 +787,15 @@ private module Stage1 {
)
or
// store
exists(Content c |
revFlowStore(c, node, toReturn, config) and
revFlowConsCand(c, config)
exists(ContentSet c |
revFlowStoreSet(c, node, toReturn, config) and
revFlowConsCandSet(c, config)
)
or
// read
exists(NodeEx mid, Content c |
read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
exists(NodeEx mid, ContentSet c |
readSet(node, c, mid, config) and
fwdFlowConsCandSet(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
or
@@ -789,12 +830,18 @@ private module Stage1 {
}
pragma[nomagic]
private predicate revFlowStore(Content c, NodeEx node, boolean toReturn, Configuration config) {
exists(NodeEx mid, TypedContent tc |
private predicate revFlowConsCandSet(ContentSet c, Configuration config) {
revFlowConsCand(c.getAStoreContent(), config)
}
pragma[nomagic]
private predicate revFlowStoreSet(
ContentSet c, NodeEx node, boolean toReturn, Configuration config
) {
exists(NodeEx mid |
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
store(node, tc, mid, _, config) and
c = tc.getContent()
fwdFlowConsCandSet(c, pragma[only_bind_into](config)) and
storeSet(node, c, mid, _, _, config)
)
}
@@ -802,9 +849,13 @@ private module Stage1 {
* Holds if `c` is the target of both a read and a store in the flow covered
* by `revFlow`.
*/
pragma[nomagic]
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
revFlowConsCand(c, conf) and
revFlowStore(c, _, _, conf)
exists(ContentSet cs |
revFlowStoreSet(cs, _, _, conf) and
c = cs.getAStoreContent()
)
}
pragma[nomagic]
@@ -889,20 +940,20 @@ private module Stage1 {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
exists(Content c, DataFlowType containerType |
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
store(node1, c, node2, contentType, containerType, config) and
revFlow(node2, pragma[only_bind_into](config)) and
store(node1, tc, node2, contentType, config) and
c = tc.getContent() and
tc = MkTypedContent(c, containerType) and
exists(ap1)
)
}
pragma[nomagic]
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
read(n1, c, n2, pragma[only_bind_into](config))
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
read(n1, c, n2, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config))
}
pragma[nomagic]
@@ -1614,7 +1665,7 @@ private module Stage2 {
Configuration config
) {
exists(Ap ap2, Content c |
store(node1, tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
@@ -1769,9 +1820,9 @@ private module LocalFlowBigStep {
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
Stage2::storeStepCand(_, _, _, node, _, config)
or
read(_, _, node, config)
Stage2::readStepCand(_, _, node, config)
or
node instanceof FlowCheckNode
or
@@ -1792,8 +1843,8 @@ private module LocalFlowBigStep {
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
store(node, _, next, _, config) or
read(node, _, next, config)
Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config)
)
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
@@ -1966,7 +2017,24 @@ private module Stage3 {
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
pragma[nomagic]
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
PrevStage::revFlow(node, config) and
clearsContentCached(node.asNode(), c)
}
pragma[nomagic]
private predicate clearContent(NodeEx node, Content c, Configuration config) {
exists(ContentSet cs |
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
c = cs.getAReadContent() and
clearSet(node, cs, pragma[only_bind_into](config))
)
}
pragma[nomagic]
private predicate clear(NodeEx node, Ap ap, Configuration config) {
clearContent(node, ap.getHead().getContent(), config)
}
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
@@ -1975,7 +2043,7 @@ private module Stage3 {
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
exists(state) and
exists(config) and
not clear(node, ap) and
not clear(node, ap, config) and
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
}
@@ -2403,7 +2471,7 @@ private module Stage3 {
Configuration config
) {
exists(Ap ap2, Content c |
store(node1, tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
@@ -3231,7 +3299,7 @@ private module Stage4 {
Configuration config
) {
exists(Ap ap2, Content c |
store(node1, tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
@@ -4242,8 +4310,8 @@ private module Subpaths {
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
storeSet(n1, _, n2, _, _, _) or
readSet(n1, _, n2, _)
)
}
@@ -4598,7 +4666,7 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentCached(node.asNode(), ap.getHead()) and
not clearsContentEx(node, ap.getHead()) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
@@ -4614,7 +4682,7 @@ private module FlowExploration {
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
not clearsContentEx(node, ap.getHead().getContent()) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
@@ -4893,10 +4961,11 @@ private module FlowExploration {
PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, NodeEx node,
PartialAccessPath ap2
) {
exists(NodeEx midNode, DataFlowType contentType |
exists(NodeEx midNode, Content c, DataFlowType contentType, DataFlowType containerType |
midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
store(midNode, tc, node, contentType, mid.getConfiguration()) and
store(midNode, c, node, contentType, containerType, mid.getConfiguration()) and
tc = MkTypedContent(c, containerType) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
@@ -4918,10 +4987,11 @@ private module FlowExploration {
PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, NodeEx node, CallContext cc,
Configuration config
) {
exists(NodeEx midNode |
exists(NodeEx midNode, Content c |
midNode = mid.getNodeEx() and
ap = mid.getAp() and
read(midNode, tc.getContent(), node, pragma[only_bind_into](config)) and
read(midNode, c, node, pragma[only_bind_into](config)) and
tc.getContent() = c and
ap.getHead() = tc and
pragma[only_bind_into](config) = mid.getConfiguration() and
cc = mid.getCallContext()
@@ -5171,13 +5241,12 @@ private module FlowExploration {
private predicate revPartialPathStoreStep(
PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, NodeEx node, Configuration config
) {
exists(NodeEx midNode, TypedContent tc |
exists(NodeEx midNode, DataFlowType contentType, DataFlowType containerType, TypedContent tc |
midNode = mid.getNodeEx() and
ap = mid.getAp() and
store(node, tc, midNode, _, config) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
store(node, c, midNode, contentType, containerType, config) and
tc = MkTypedContent(c, containerType) and
config = mid.getConfiguration()
)
}

View File

@@ -128,7 +128,7 @@ abstract class Configuration extends string {
* Holds if an arbitrary number of implicit read steps of content `c` may be
* taken at `node`.
*/
predicate allowImplicitRead(Node node, Content c) { none() }
predicate allowImplicitRead(Node node, ContentSet c) { none() }
/**
* Gets the virtual dispatch branching limit when calculating field flow.
@@ -525,8 +525,9 @@ private predicate additionalJumpStateStep(
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode()) and
pragma[nomagic]
private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuration config) {
readSet(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
or
exists(Node n |
@@ -536,12 +537,44 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf
)
}
private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
// inline to reduce fan-out via `getAReadContent`
pragma[inline]
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
exists(ContentSet cs |
readSet(node1, cs, node2, config) and
c = cs.getAReadContent()
)
}
// inline to reduce fan-out via `getAReadContent`
pragma[inline]
private predicate clearsContentEx(NodeEx n, Content c) {
exists(ContentSet cs |
clearsContentCached(n.asNode(), cs) and
c = cs.getAReadContent()
)
}
pragma[nomagic]
private predicate storeSet(
NodeEx node1, ContentSet c, NodeEx node2, DataFlowType contentType, DataFlowType containerType,
Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
storeSet(node1.asNode(), c, node2.asNode(), contentType, containerType) and
stepFilter(node1, node2, config) and
read(_, c.getAStoreContent(), _, config)
}
// inline to reduce fan-out via `getAStoreContent`
pragma[inline]
private predicate store(
NodeEx node1, Content c, NodeEx node2, DataFlowType contentType, DataFlowType containerType,
Configuration config
) {
exists(ContentSet cs |
storeSet(node1, cs, node2, contentType, containerType, config) and
c = cs.getAStoreContent()
)
}
pragma[nomagic]
@@ -609,13 +642,13 @@ private module Stage1 {
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
storeSet(mid, _, node, _, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
exists(ContentSet c |
fwdFlowReadSet(c, node, cc, config) and
fwdFlowConsCandSet(c, config)
)
or
// flow into a callable
@@ -639,10 +672,10 @@ private module Stage1 {
private predicate fwdFlow(NodeEx node, Configuration config) { fwdFlow(node, _, config) }
pragma[nomagic]
private predicate fwdFlowRead(Content c, NodeEx node, Cc cc, Configuration config) {
private predicate fwdFlowReadSet(ContentSet c, NodeEx node, Cc cc, Configuration config) {
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
read(mid, c, node, config)
readSet(mid, c, node, config)
)
}
@@ -651,15 +684,23 @@ private module Stage1 {
*/
pragma[nomagic]
private predicate fwdFlowConsCand(Content c, Configuration config) {
exists(NodeEx mid, NodeEx node, TypedContent tc |
exists(NodeEx mid, NodeEx node |
not fullBarrier(node, config) and
useFieldFlow(config) and
fwdFlow(mid, _, config) and
store(mid, tc, node, _, config) and
c = tc.getContent()
store(mid, c, node, _, _, config)
)
}
/**
* Holds if `c` may be interpreted in a read as the target of some store,
* in the flow covered by `fwdFlow`.
*/
pragma[nomagic]
private predicate fwdFlowConsCandSet(ContentSet c, Configuration config) {
fwdFlowConsCand(c.getAReadContent(), config)
}
pragma[nomagic]
private predicate fwdFlowReturnPosition(ReturnPosition pos, Cc cc, Configuration config) {
exists(RetNodeEx ret |
@@ -746,15 +787,15 @@ private module Stage1 {
)
or
// store
exists(Content c |
revFlowStore(c, node, toReturn, config) and
revFlowConsCand(c, config)
exists(ContentSet c |
revFlowStoreSet(c, node, toReturn, config) and
revFlowConsCandSet(c, config)
)
or
// read
exists(NodeEx mid, Content c |
read(node, c, mid, config) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
exists(NodeEx mid, ContentSet c |
readSet(node, c, mid, config) and
fwdFlowConsCandSet(c, pragma[only_bind_into](config)) and
revFlow(mid, toReturn, pragma[only_bind_into](config))
)
or
@@ -789,12 +830,18 @@ private module Stage1 {
}
pragma[nomagic]
private predicate revFlowStore(Content c, NodeEx node, boolean toReturn, Configuration config) {
exists(NodeEx mid, TypedContent tc |
private predicate revFlowConsCandSet(ContentSet c, Configuration config) {
revFlowConsCand(c.getAStoreContent(), config)
}
pragma[nomagic]
private predicate revFlowStoreSet(
ContentSet c, NodeEx node, boolean toReturn, Configuration config
) {
exists(NodeEx mid |
revFlow(mid, toReturn, pragma[only_bind_into](config)) and
fwdFlowConsCand(c, pragma[only_bind_into](config)) and
store(node, tc, mid, _, config) and
c = tc.getContent()
fwdFlowConsCandSet(c, pragma[only_bind_into](config)) and
storeSet(node, c, mid, _, _, config)
)
}
@@ -802,9 +849,13 @@ private module Stage1 {
* Holds if `c` is the target of both a read and a store in the flow covered
* by `revFlow`.
*/
pragma[nomagic]
private predicate revFlowIsReadAndStored(Content c, Configuration conf) {
revFlowConsCand(c, conf) and
revFlowStore(c, _, _, conf)
exists(ContentSet cs |
revFlowStoreSet(cs, _, _, conf) and
c = cs.getAStoreContent()
)
}
pragma[nomagic]
@@ -889,20 +940,20 @@ private module Stage1 {
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, DataFlowType contentType,
Configuration config
) {
exists(Content c |
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
exists(Content c, DataFlowType containerType |
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
store(node1, c, node2, contentType, containerType, config) and
revFlow(node2, pragma[only_bind_into](config)) and
store(node1, tc, node2, contentType, config) and
c = tc.getContent() and
tc = MkTypedContent(c, containerType) and
exists(ap1)
)
}
pragma[nomagic]
predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) {
revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config)) and
read(n1, c, n2, pragma[only_bind_into](config))
revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and
read(n1, c, n2, pragma[only_bind_into](config)) and
revFlow(n2, pragma[only_bind_into](config))
}
pragma[nomagic]
@@ -1614,7 +1665,7 @@ private module Stage2 {
Configuration config
) {
exists(Ap ap2, Content c |
store(node1, tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
@@ -1769,9 +1820,9 @@ private module LocalFlowBigStep {
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
Stage2::storeStepCand(_, _, _, node, _, config)
or
read(_, _, node, config)
Stage2::readStepCand(_, _, node, config)
or
node instanceof FlowCheckNode
or
@@ -1792,8 +1843,8 @@ private module LocalFlowBigStep {
additionalJumpStep(node, next, config) or
flowIntoCallNodeCand1(_, node, next, config) or
flowOutOfCallNodeCand1(_, node, next, config) or
store(node, _, next, _, config) or
read(node, _, next, config)
Stage2::storeStepCand(node, _, _, next, _, config) or
Stage2::readStepCand(node, _, next, config)
)
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
@@ -1966,7 +2017,24 @@ private module Stage3 {
private predicate flowIntoCall = flowIntoCallNodeCand2/5;
pragma[nomagic]
private predicate clear(NodeEx node, Ap ap) { ap.isClearedAt(node.asNode()) }
predicate clearSet(NodeEx node, ContentSet c, Configuration config) {
PrevStage::revFlow(node, config) and
clearsContentCached(node.asNode(), c)
}
pragma[nomagic]
private predicate clearContent(NodeEx node, Content c, Configuration config) {
exists(ContentSet cs |
PrevStage::readStepCand(_, pragma[only_bind_into](c), _, pragma[only_bind_into](config)) and
c = cs.getAReadContent() and
clearSet(node, cs, pragma[only_bind_into](config))
)
}
pragma[nomagic]
private predicate clear(NodeEx node, Ap ap, Configuration config) {
clearContent(node, ap.getHead().getContent(), config)
}
pragma[nomagic]
private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode }
@@ -1975,7 +2043,7 @@ private module Stage3 {
private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) {
exists(state) and
exists(config) and
not clear(node, ap) and
not clear(node, ap, config) and
if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()
}
@@ -2403,7 +2471,7 @@ private module Stage3 {
Configuration config
) {
exists(Ap ap2, Content c |
store(node1, tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
@@ -3231,7 +3299,7 @@ private module Stage4 {
Configuration config
) {
exists(Ap ap2, Content c |
store(node1, tc, node2, contentType, config) and
PrevStage::storeStepCand(node1, _, tc, node2, contentType, config) and
revFlowStore(ap2, c, ap1, node1, _, tc, node2, _, _, config) and
revFlowConsCand(ap2, c, ap1, config)
)
@@ -4242,8 +4310,8 @@ private module Subpaths {
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, _, n2, _, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
storeSet(n1, _, n2, _, _, _) or
readSet(n1, _, n2, _)
)
}
@@ -4598,7 +4666,7 @@ private module FlowExploration {
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentCached(node.asNode(), ap.getHead()) and
not clearsContentEx(node, ap.getHead()) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
@@ -4614,7 +4682,7 @@ private module FlowExploration {
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentCached(node.asNode(), ap.getHead().getContent()) and
not clearsContentEx(node, ap.getHead().getContent()) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
@@ -4893,10 +4961,11 @@ private module FlowExploration {
PartialPathNodeFwd mid, PartialAccessPath ap1, TypedContent tc, NodeEx node,
PartialAccessPath ap2
) {
exists(NodeEx midNode, DataFlowType contentType |
exists(NodeEx midNode, Content c, DataFlowType contentType, DataFlowType containerType |
midNode = mid.getNodeEx() and
ap1 = mid.getAp() and
store(midNode, tc, node, contentType, mid.getConfiguration()) and
store(midNode, c, node, contentType, containerType, mid.getConfiguration()) and
tc = MkTypedContent(c, containerType) and
ap2.getHead() = tc and
ap2.len() = unbindInt(ap1.len() + 1) and
compatibleTypes(ap1.getType(), contentType)
@@ -4918,10 +4987,11 @@ private module FlowExploration {
PartialPathNodeFwd mid, PartialAccessPath ap, TypedContent tc, NodeEx node, CallContext cc,
Configuration config
) {
exists(NodeEx midNode |
exists(NodeEx midNode, Content c |
midNode = mid.getNodeEx() and
ap = mid.getAp() and
read(midNode, tc.getContent(), node, pragma[only_bind_into](config)) and
read(midNode, c, node, pragma[only_bind_into](config)) and
tc.getContent() = c and
ap.getHead() = tc and
pragma[only_bind_into](config) = mid.getConfiguration() and
cc = mid.getCallContext()
@@ -5171,13 +5241,12 @@ private module FlowExploration {
private predicate revPartialPathStoreStep(
PartialPathNodeRev mid, RevPartialAccessPath ap, Content c, NodeEx node, Configuration config
) {
exists(NodeEx midNode, TypedContent tc |
exists(NodeEx midNode, DataFlowType contentType, DataFlowType containerType, TypedContent tc |
midNode = mid.getNodeEx() and
ap = mid.getAp() and
store(node, tc, midNode, _, config) and
ap.getHead() = c and
config = mid.getConfiguration() and
tc.getContent() = c
store(node, c, midNode, contentType, containerType, config) and
tc = MkTypedContent(c, containerType) and
config = mid.getConfiguration()
)
}

View File

@@ -326,7 +326,7 @@ private module Cached {
predicate jumpStepCached(Node node1, Node node2) { jumpStep(node1, node2) }
cached
predicate clearsContentCached(Node n, Content c) { clearsContent(n, c) }
predicate clearsContentCached(Node n, ContentSet c) { clearsContent(n, c) }
cached
predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) }
@@ -373,7 +373,7 @@ private module Cached {
// For reads, `x.f`, we want to check that the tracked type after the read (which
// is obtained by popping the head of the access path stack) is compatible with
// the type of `x.f`.
read(_, _, n)
readSet(_, _, n)
}
cached
@@ -469,7 +469,7 @@ private module Cached {
// read
exists(Node mid |
parameterValueFlowCand(p, mid, false) and
read(mid, _, node) and
readSet(mid, _, node) and
read = true
)
or
@@ -657,8 +657,10 @@ private module Cached {
* Holds if `arg` flows to `out` through a call using only
* value-preserving steps and a single read step, not taking call
* contexts into account, thus representing a getter-step.
*
* This predicate is exposed for testing only.
*/
predicate getterStep(ArgNode arg, Content c, Node out) {
predicate getterStep(ArgNode arg, ContentSet c, Node out) {
argumentValueFlowsThrough(arg, TReadStepTypesSome(_, c, _), out)
}
@@ -781,8 +783,19 @@ private module Cached {
parameterValueFlow(p, n.getPreUpdateNode(), TReadStepTypesNone())
}
private predicate store(
Node node1, Content c, Node node2, DataFlowType contentType, DataFlowType containerType
cached
predicate readSet(Node node1, ContentSet c, Node node2) { readStep(node1, c, node2) }
/**
* Holds if data can flow from `node1` to `node2` via a direct assignment to
* `c`.
*
* This includes reverse steps through reads when the result of the read has
* been stored into, in order to handle cases like `x.f1.f2 = y`.
*/
cached
predicate storeSet(
Node node1, ContentSet c, Node node2, DataFlowType contentType, DataFlowType containerType
) {
storeStep(node1, c, node2) and
contentType = getNodeDataFlowType(node1) and
@@ -794,27 +807,12 @@ private module Cached {
|
argumentValueFlowsThrough(n2, TReadStepTypesSome(containerType, c, contentType), n1)
or
read(n2, c, n1) and
readSet(n2, c, n1) and
contentType = getNodeDataFlowType(n1) and
containerType = getNodeDataFlowType(n2)
)
}
cached
predicate read(Node node1, Content c, Node node2) { readStep(node1, c, node2) }
/**
* Holds if data can flow from `node1` to `node2` via a direct assignment to
* `f`.
*
* This includes reverse steps through reads when the result of the read has
* been stored into, in order to handle cases like `x.f1.f2 = y`.
*/
cached
predicate store(Node node1, TypedContent tc, Node node2, DataFlowType contentType) {
store(node1, tc.getContent(), node2, contentType, tc.getContainerType())
}
/**
* Holds if data can flow from `fromNode` to `toNode` because they are the post-update
* nodes of some function output and input respectively, where the output and input
@@ -902,7 +900,13 @@ private module Cached {
TDataFlowCallSome(DataFlowCall call)
cached
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, _, t) }
newtype TTypedContent =
MkTypedContent(Content c, DataFlowType t) {
exists(ContentSet cs |
storeSet(_, cs, _, _, t) and
c = cs.getAStoreContent()
)
}
cached
newtype TAccessPathFront =
@@ -932,16 +936,16 @@ class CastingNode extends Node {
}
private predicate readStepWithTypes(
Node n1, DataFlowType container, Content c, Node n2, DataFlowType content
Node n1, DataFlowType container, ContentSet c, Node n2, DataFlowType content
) {
read(n1, c, n2) and
readSet(n1, c, n2) and
container = getNodeDataFlowType(n1) and
content = getNodeDataFlowType(n2)
}
private newtype TReadStepTypesOption =
TReadStepTypesNone() or
TReadStepTypesSome(DataFlowType container, Content c, DataFlowType content) {
TReadStepTypesSome(DataFlowType container, ContentSet c, DataFlowType content) {
readStepWithTypes(_, container, c, _, content)
}
@@ -950,7 +954,7 @@ private class ReadStepTypesOption extends TReadStepTypesOption {
DataFlowType getContainerType() { this = TReadStepTypesSome(result, _, _) }
Content getContent() { this = TReadStepTypesSome(_, result, _) }
ContentSet getContent() { this = TReadStepTypesSome(_, result, _) }
DataFlowType getContentType() { this = TReadStepTypesSome(_, _, result) }
@@ -1325,8 +1329,6 @@ abstract class AccessPathFront extends TAccessPathFront {
abstract boolean toBoolNonEmpty();
TypedContent getHead() { this = TFrontHead(result) }
predicate isClearedAt(Node n) { clearsContentCached(n, this.getHead().getContent()) }
}
class AccessPathFrontNil extends AccessPathFront, TFrontNil {

View File

@@ -181,7 +181,7 @@ abstract class Configuration extends DataFlow::Configuration {
this.isAdditionalTaintStep(node1, state1, node2, state2)
}
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
defaultImplicitTaintRead(node, c)
}

View File

@@ -181,7 +181,7 @@ abstract class Configuration extends DataFlow::Configuration {
this.isAdditionalTaintStep(node1, state1, node2, state2)
}
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
defaultImplicitTaintRead(node, c)
}

View File

@@ -181,7 +181,7 @@ abstract class Configuration extends DataFlow::Configuration {
this.isAdditionalTaintStep(node1, state1, node2, state2)
}
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::Content c) {
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
(this.isSink(node) or this.isAdditionalTaintStep(node, _)) and
defaultImplicitTaintRead(node, c)
}