Dataflow: Strengthen tracked types.

This commit is contained in:
Anders Schack-Mulligen
2023-05-08 13:56:26 +02:00
parent 1d87f0793b
commit ad461a87b4
2 changed files with 82 additions and 23 deletions

View File

@@ -1135,8 +1135,8 @@ module Impl<FullStateConfigSig Config> {
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow
); );
bindingset[node, state, t, ap] bindingset[node, state, t0, ap]
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap); predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t);
bindingset[typ, contentType] bindingset[typ, contentType]
predicate typecheckStore(Typ typ, DataFlowType contentType); predicate typecheckStore(Typ typ, DataFlowType contentType);
@@ -1199,9 +1199,20 @@ module Impl<FullStateConfigSig Config> {
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT, NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
ApOption argAp, Typ t, Ap ap, ApApprox apa ApOption argAp, Typ t, Ap ap, ApApprox apa
) { ) {
fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t, ap, apa) and fwdFlow1(node, state, cc, summaryCtx, argT, argAp, _, t, ap, apa)
}
private predicate fwdFlow1(
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
ApOption argAp, Typ t0, Typ t, Ap ap, ApApprox apa
) {
fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t0, ap, apa) and
PrevStage::revFlow(node, state, apa) and PrevStage::revFlow(node, state, apa) and
filter(node, state, t, ap) filter(node, state, t0, ap, t)
}
private predicate typeStrengthen(Typ t0, Ap ap, Typ t) {
fwdFlow1(_, _, _, _, _, _, t0, t, ap, _) and t0 != t
} }
pragma[assume_small_delta] pragma[assume_small_delta]
@@ -1331,6 +1342,11 @@ module Impl<FullStateConfigSig Config> {
private predicate fwdFlowConsCand(Typ t2, Ap cons, Content c, Typ t1, Ap tail) { private predicate fwdFlowConsCand(Typ t2, Ap cons, Content c, Typ t1, Ap tail) {
fwdFlowStore(_, t1, tail, c, t2, _, _, _, _, _, _) and fwdFlowStore(_, t1, tail, c, t2, _, _, _, _, _, _) and
cons = apCons(c, t1, tail) cons = apCons(c, t1, tail)
or
exists(Typ t0 |
typeStrengthen(t0, cons, t2) and
fwdFlowConsCand(t0, cons, c, t1, tail)
)
} }
pragma[nomagic] pragma[nomagic]
@@ -1955,10 +1971,10 @@ module Impl<FullStateConfigSig Config> {
) )
} }
bindingset[node, state, t, ap] bindingset[node, state, t0, ap]
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
PrevStage::revFlowState(state) and PrevStage::revFlowState(state) and
exists(t) and t0 = t and
exists(ap) and exists(ap) and
not stateBarrier(node, state) and not stateBarrier(node, state) and
( (
@@ -2210,10 +2226,16 @@ module Impl<FullStateConfigSig Config> {
) )
} }
bindingset[node, state, t, ap] bindingset[node, state, t0, ap]
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
exists(state) and exists(state) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and // We can get away with not using type strengthening here, since we aren't
// going to use the tracked types in the construction of Stage 4 access
// paths. For Stage 4 and onwards, the tracked types must be consistent as
// the cons candidates including types are used to construct subsequent
// access path approximations.
t0 = t and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t0) else any()) and
( (
notExpectsContent(node) notExpectsContent(node)
or or
@@ -2325,11 +2347,18 @@ module Impl<FullStateConfigSig Config> {
) )
} }
bindingset[node, state, t, ap] bindingset[node, state, t0, ap]
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
exists(state) and exists(state) and
not clear(node, ap) and not clear(node, ap) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and (
if castingNodeEx(node)
then
exists(Typ nt | nt = node.getDataFlowType() |
if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0)
)
else t = t0
) and
( (
notExpectsContent(node) notExpectsContent(node)
or or
@@ -2601,9 +2630,16 @@ module Impl<FullStateConfigSig Config> {
) )
} }
bindingset[node, state, t, ap] bindingset[node, state, t0, ap]
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) { predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and (
if castingNodeEx(node)
then
exists(Typ nt | nt = node.getDataFlowType() |
if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0)
)
else t = t0
) and
exists(state) and exists(state) and
exists(ap) exists(ap)
} }
@@ -2812,9 +2848,7 @@ module Impl<FullStateConfigSig Config> {
ap = TAccessPathNil() ap = TAccessPathNil()
or or
// ... or a step from an existing PathNode to another node. // ... or a step from an existing PathNode to another node.
pathStep(_, node, state, cc, sc, t, ap) and pathStep(_, node, state, cc, sc, t, ap)
Stage5::revFlow(node, state, ap.getApprox()) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any())
} or } or
TPathNodeSink(NodeEx node, FlowState state) { TPathNodeSink(NodeEx node, FlowState state) {
exists(PathNodeMid sink | exists(PathNodeMid sink |
@@ -3332,13 +3366,31 @@ module Impl<FullStateConfigSig Config> {
ap = mid.getAp() ap = mid.getAp()
} }
private predicate pathStep(
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t,
AccessPath ap
) {
exists(DataFlowType t0 |
pathStep0(mid, node, state, cc, sc, t0, ap) and
Stage5::revFlow(node, state, ap.getApprox()) and
(
if castingNodeEx(node)
then
exists(DataFlowType nt | nt = node.getDataFlowType() |
if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0)
)
else t = t0
)
)
}
/** /**
* Holds if data may flow from `mid` to `node`. The last step in or out of * Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`. * a callable is recorded by `cc`.
*/ */
pragma[assume_small_delta] pragma[assume_small_delta]
pragma[nomagic] pragma[nomagic]
private predicate pathStep( private predicate pathStep0(
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t, PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t,
AccessPath ap AccessPath ap
) { ) {

View File

@@ -176,7 +176,7 @@ predicate expectsContent(Node n, ContentSet c) {
* possible flow. A single type is used for all numeric types to account for * possible flow. A single type is used for all numeric types to account for
* numeric conversions, and otherwise the erasure is used. * numeric conversions, and otherwise the erasure is used.
*/ */
DataFlowType getErasedRepr(Type t) { RefType getErasedRepr(Type t) {
exists(Type e | e = t.getErasure() | exists(Type e | e = t.getErasure() |
if e instanceof NumericOrCharType if e instanceof NumericOrCharType
then result.(BoxedType).getPrimitiveType().getName() = "double" then result.(BoxedType).getPrimitiveType().getName() = "double"
@@ -189,6 +189,15 @@ DataFlowType getErasedRepr(Type t) {
t instanceof NullType and result instanceof TypeObject t instanceof NullType and result instanceof TypeObject
} }
class DataFlowType extends SrcRefType {
DataFlowType() { this = getErasedRepr(_) }
}
pragma[nomagic]
predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) {
t1.getASourceSupertype+() = t2
}
pragma[noinline] pragma[noinline]
DataFlowType getNodeType(Node n) { DataFlowType getNodeType(Node n) {
result = getErasedRepr(n.getTypeBound()) result = getErasedRepr(n.getTypeBound())
@@ -259,8 +268,6 @@ class DataFlowCallable extends TDataFlowCallable {
class DataFlowExpr = Expr; class DataFlowExpr = Expr;
class DataFlowType = RefType;
private newtype TDataFlowCall = private newtype TDataFlowCall =
TCall(Call c) or TCall(Call c) or
TSummaryCall(SummarizedCallable c, Node receiver) { TSummaryCall(SummarizedCallable c, Node receiver) {