Skip to content

Commit 1b7bbf6

Browse files
authored
Merge pull request #13083 from aschackmull/dataflow/typestrengthen
Dataflow: Strengthen tracked types.
2 parents 74ed9f5 + 68f1e40 commit 1b7bbf6

File tree

39 files changed

+1146
-672
lines changed

39 files changed

+1146
-672
lines changed

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

Lines changed: 103 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,8 +1135,8 @@ module Impl<FullStateConfigSig Config> {
11351135
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow
11361136
);
11371137

1138-
bindingset[node, state, t, ap]
1139-
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap);
1138+
bindingset[node, state, t0, ap]
1139+
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t);
11401140

11411141
bindingset[typ, contentType]
11421142
predicate typecheckStore(Typ typ, DataFlowType contentType);
@@ -1199,17 +1199,21 @@ module Impl<FullStateConfigSig Config> {
11991199
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
12001200
ApOption argAp, Typ t, Ap ap, ApApprox apa
12011201
) {
1202-
fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t, ap, apa) and
1203-
PrevStage::revFlow(node, state, apa) and
1204-
filter(node, state, t, ap)
1202+
fwdFlow1(node, state, cc, summaryCtx, argT, argAp, _, t, ap, apa)
12051203
}
12061204

1207-
pragma[inline]
1208-
additional predicate fwdFlow(
1205+
private predicate fwdFlow1(
12091206
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
1210-
ApOption argAp, Typ t, Ap ap
1207+
ApOption argAp, Typ t0, Typ t, Ap ap, ApApprox apa
12111208
) {
1212-
fwdFlow(node, state, cc, summaryCtx, argT, argAp, t, ap, _)
1209+
fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t0, ap, apa) and
1210+
PrevStage::revFlow(node, state, apa) and
1211+
filter(node, state, t0, ap, t)
1212+
}
1213+
1214+
pragma[nomagic]
1215+
private predicate typeStrengthen(Typ t0, Ap ap, Typ t) {
1216+
fwdFlow1(_, _, _, _, _, _, t0, t, ap, _) and t0 != t
12131217
}
12141218

12151219
pragma[assume_small_delta]
@@ -1339,6 +1343,11 @@ module Impl<FullStateConfigSig Config> {
13391343
private predicate fwdFlowConsCand(Typ t2, Ap cons, Content c, Typ t1, Ap tail) {
13401344
fwdFlowStore(_, t1, tail, c, t2, _, _, _, _, _, _) and
13411345
cons = apCons(c, t1, tail)
1346+
or
1347+
exists(Typ t0 |
1348+
typeStrengthen(t0, cons, t2) and
1349+
fwdFlowConsCand(t0, cons, c, t1, tail)
1350+
)
13421351
}
13431352

13441353
pragma[nomagic]
@@ -1359,7 +1368,7 @@ module Impl<FullStateConfigSig Config> {
13591368
ParamNodeOption summaryCtx, TypOption argT, ApOption argAp
13601369
) {
13611370
exists(ApHeadContent apc |
1362-
fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap) and
1371+
fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap, _) and
13631372
apc = getHeadContent(ap) and
13641373
readStepCand0(node1, apc, c, node2)
13651374
)
@@ -1520,14 +1529,14 @@ module Impl<FullStateConfigSig Config> {
15201529
NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap
15211530
) {
15221531
revFlow0(node, state, returnCtx, returnAp, ap) and
1523-
fwdFlow(node, state, _, _, _, _, _, ap)
1532+
fwdFlow(node, state, _, _, _, _, _, ap, _)
15241533
}
15251534

15261535
pragma[nomagic]
15271536
private predicate revFlow0(
15281537
NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap
15291538
) {
1530-
fwdFlow(node, state, _, _, _, _, _, ap) and
1539+
fwdFlow(node, state, _, _, _, _, _, ap, _) and
15311540
sinkNode(node, state) and
15321541
(
15331542
if hasSinkCallCtx()
@@ -1780,13 +1789,13 @@ module Impl<FullStateConfigSig Config> {
17801789
boolean fwd, int nodes, int fields, int conscand, int states, int tuples
17811790
) {
17821791
fwd = true and
1783-
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _)) and
1792+
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _, _)) and
17841793
fields = count(Content f0 | fwdConsCand(f0, _, _)) and
17851794
conscand = count(Content f0, Typ t, Ap ap | fwdConsCand(f0, t, ap)) and
1786-
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _)) and
1795+
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _, _)) and
17871796
tuples =
17881797
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
1789-
ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap))
1798+
ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap, _))
17901799
or
17911800
fwd = false and
17921801
nodes = count(NodeEx node | revFlow(node, _, _, _, _)) and
@@ -1963,10 +1972,10 @@ module Impl<FullStateConfigSig Config> {
19631972
)
19641973
}
19651974

1966-
bindingset[node, state, t, ap]
1967-
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
1975+
bindingset[node, state, t0, ap]
1976+
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
19681977
PrevStage::revFlowState(state) and
1969-
exists(t) and
1978+
t0 = t and
19701979
exists(ap) and
19711980
not stateBarrier(node, state) and
19721981
(
@@ -2197,8 +2206,8 @@ module Impl<FullStateConfigSig Config> {
21972206
import BooleanCallContext
21982207

21992208
predicate localStep(
2200-
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
2201-
DataFlowType t, LocalCc lcc
2209+
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t,
2210+
LocalCc lcc
22022211
) {
22032212
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and
22042213
exists(lcc)
@@ -2218,10 +2227,16 @@ module Impl<FullStateConfigSig Config> {
22182227
)
22192228
}
22202229

2221-
bindingset[node, state, t, ap]
2222-
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
2230+
bindingset[node, state, t0, ap]
2231+
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
22232232
exists(state) and
2224-
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and
2233+
// We can get away with not using type strengthening here, since we aren't
2234+
// going to use the tracked types in the construction of Stage 4 access
2235+
// paths. For Stage 4 and onwards, the tracked types must be consistent as
2236+
// the cons candidates including types are used to construct subsequent
2237+
// access path approximations.
2238+
t0 = t and
2239+
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t0) else any()) and
22252240
(
22262241
notExpectsContent(node)
22272242
or
@@ -2241,6 +2256,16 @@ module Impl<FullStateConfigSig Config> {
22412256
import MkStage<Stage2>::Stage<Stage3Param>
22422257
}
22432258

2259+
bindingset[node, t0]
2260+
private predicate strengthenType(NodeEx node, DataFlowType t0, DataFlowType t) {
2261+
if castingNodeEx(node)
2262+
then
2263+
exists(DataFlowType nt | nt = node.getDataFlowType() |
2264+
if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0)
2265+
)
2266+
else t = t0
2267+
}
2268+
22442269
private module Stage4Param implements MkStage<Stage3>::StageParam {
22452270
private module PrevStage = Stage3;
22462271

@@ -2274,8 +2299,8 @@ module Impl<FullStateConfigSig Config> {
22742299

22752300
pragma[nomagic]
22762301
predicate localStep(
2277-
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
2278-
DataFlowType t, LocalCc lcc
2302+
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t,
2303+
LocalCc lcc
22792304
) {
22802305
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and
22812306
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and
@@ -2333,11 +2358,11 @@ module Impl<FullStateConfigSig Config> {
23332358
)
23342359
}
23352360

2336-
bindingset[node, state, t, ap]
2337-
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
2361+
bindingset[node, state, t0, ap]
2362+
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
23382363
exists(state) and
23392364
not clear(node, ap) and
2340-
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and
2365+
strengthenType(node, t0, t) and
23412366
(
23422367
notExpectsContent(node)
23432368
or
@@ -2365,7 +2390,7 @@ module Impl<FullStateConfigSig Config> {
23652390
exists(AccessPathFront apf |
23662391
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf) and
23672392
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, _, TAccessPathFrontSome(argApf), _,
2368-
apf)
2393+
apf, _)
23692394
)
23702395
}
23712396

@@ -2579,8 +2604,8 @@ module Impl<FullStateConfigSig Config> {
25792604
import LocalCallContext
25802605

25812606
predicate localStep(
2582-
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
2583-
DataFlowType t, LocalCc lcc
2607+
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t,
2608+
LocalCc lcc
25842609
) {
25852610
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, lcc) and
25862611
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and
@@ -2609,9 +2634,9 @@ module Impl<FullStateConfigSig Config> {
26092634
)
26102635
}
26112636

2612-
bindingset[node, state, t, ap]
2613-
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
2614-
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and
2637+
bindingset[node, state, t0, ap]
2638+
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
2639+
strengthenType(node, t0, t) and
26152640
exists(state) and
26162641
exists(ap)
26172642
}
@@ -2632,7 +2657,7 @@ module Impl<FullStateConfigSig Config> {
26322657
Stage5::parameterMayFlowThrough(p, _) and
26332658
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0) and
26342659
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()), _,
2635-
TAccessPathApproxSome(apa), _, apa0)
2660+
TAccessPathApproxSome(apa), _, apa0, _)
26362661
)
26372662
}
26382663

@@ -2649,7 +2674,7 @@ module Impl<FullStateConfigSig Config> {
26492674
TSummaryCtxSome(ParamNodeEx p, FlowState state, DataFlowType t, AccessPath ap) {
26502675
exists(AccessPathApprox apa | ap.getApprox() = apa |
26512676
Stage5::parameterMayFlowThrough(p, apa) and
2652-
Stage5::fwdFlow(p, state, _, _, _, _, t, apa) and
2677+
Stage5::fwdFlow(p, state, _, _, Option<DataFlowType>::some(t), _, _, apa, _) and
26532678
Stage5::revFlow(p, state, _)
26542679
)
26552680
}
@@ -2820,9 +2845,7 @@ module Impl<FullStateConfigSig Config> {
28202845
ap = TAccessPathNil()
28212846
or
28222847
// ... or a step from an existing PathNode to another node.
2823-
pathStep(_, node, state, cc, sc, t, ap) and
2824-
Stage5::revFlow(node, state, ap.getApprox()) and
2825-
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any())
2848+
pathStep(_, node, state, cc, sc, t, ap)
28262849
} or
28272850
TPathNodeSink(NodeEx node, FlowState state) {
28282851
exists(PathNodeMid sink |
@@ -3340,13 +3363,24 @@ module Impl<FullStateConfigSig Config> {
33403363
ap = mid.getAp()
33413364
}
33423365

3366+
private predicate pathStep(
3367+
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t,
3368+
AccessPath ap
3369+
) {
3370+
exists(DataFlowType t0 |
3371+
pathStep0(mid, node, state, cc, sc, t0, ap) and
3372+
Stage5::revFlow(node, state, ap.getApprox()) and
3373+
strengthenType(node, t0, t)
3374+
)
3375+
}
3376+
33433377
/**
33443378
* Holds if data may flow from `mid` to `node`. The last step in or out of
33453379
* a callable is recorded by `cc`.
33463380
*/
33473381
pragma[assume_small_delta]
33483382
pragma[nomagic]
3349-
private predicate pathStep(
3383+
private predicate pathStep0(
33503384
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t,
33513385
AccessPath ap
33523386
) {
@@ -3964,7 +3998,7 @@ module Impl<FullStateConfigSig Config> {
39643998
ap = TPartialNil() and
39653999
exists(explorationLimit())
39664000
or
3967-
partialPathNodeMk0(node, state, cc, sc1, sc2, sc3, sc4, t, ap) and
4001+
partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and
39684002
distSrc(node.getEnclosingCallable()) <= explorationLimit()
39694003
} or
39704004
TPartialPathNodeRev(
@@ -3990,21 +4024,35 @@ module Impl<FullStateConfigSig Config> {
39904024
}
39914025

39924026
pragma[nomagic]
3993-
private predicate partialPathNodeMk0(
3994-
NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
3995-
TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap
4027+
private predicate partialPathStep(
4028+
PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1,
4029+
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap
39964030
) {
3997-
partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and
4031+
partialPathStep1(mid, node, state, cc, sc1, sc2, sc3, sc4, _, t, ap)
4032+
}
4033+
4034+
pragma[nomagic]
4035+
private predicate partialPathStep1(
4036+
PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1,
4037+
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t0, DataFlowType t,
4038+
PartialAccessPath ap
4039+
) {
4040+
partialPathStep0(mid, node, state, cc, sc1, sc2, sc3, sc4, t0, ap) and
39984041
not fullBarrier(node) and
39994042
not stateBarrier(node, state) and
40004043
not clearsContentEx(node, ap.getHead()) and
40014044
(
40024045
notExpectsContent(node) or
40034046
expectsContentEx(node, ap.getHead())
40044047
) and
4005-
if node.asNode() instanceof CastingNode
4006-
then compatibleTypes(node.getDataFlowType(), t)
4007-
else any()
4048+
strengthenType(node, t0, t)
4049+
}
4050+
4051+
pragma[nomagic]
4052+
private predicate partialPathTypeStrengthen(
4053+
DataFlowType t0, PartialAccessPath ap, DataFlowType t
4054+
) {
4055+
partialPathStep1(_, _, _, _, _, _, _, _, t0, t, ap) and t0 != t
40084056
}
40094057

40104058
/**
@@ -4183,7 +4231,8 @@ module Impl<FullStateConfigSig Config> {
41834231
}
41844232
}
41854233

4186-
private predicate partialPathStep(
4234+
pragma[nomagic]
4235+
private predicate partialPathStep0(
41874236
PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1,
41884237
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap
41894238
) {
@@ -4309,6 +4358,11 @@ module Impl<FullStateConfigSig Config> {
43094358
DataFlowType t1, PartialAccessPath ap1, Content c, DataFlowType t2, PartialAccessPath ap2
43104359
) {
43114360
partialPathStoreStep(_, t1, ap1, c, _, t2, ap2)
4361+
or
4362+
exists(DataFlowType t0 |
4363+
partialPathTypeStrengthen(t0, ap2, t2) and
4364+
apConsFwd(t1, ap1, c, t0, ap2)
4365+
)
43124366
}
43134367

43144368
pragma[nomagic]

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ predicate clearsContent(Node n, Content c) {
205205
*/
206206
predicate expectsContent(Node n, ContentSet c) { none() }
207207

208+
predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() }
209+
208210
/** Gets the type of `n` used for type pruning. */
209211
Type getNodeType(Node n) {
210212
suppressUnusedNode(n) and

0 commit comments

Comments
 (0)