Skip to content

Commit aa83cc1

Browse files
committed
Data flow: Sync files
1 parent a0d1004 commit aa83cc1

File tree

21 files changed

+4776
-4086
lines changed

21 files changed

+4776
-4086
lines changed

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

Lines changed: 247 additions & 215 deletions
Large diffs are not rendered by default.

cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll

Lines changed: 247 additions & 215 deletions
Large diffs are not rendered by default.

cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll

Lines changed: 247 additions & 215 deletions
Large diffs are not rendered by default.

cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll

Lines changed: 247 additions & 215 deletions
Large diffs are not rendered by default.

cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll

Lines changed: 110 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -209,97 +209,99 @@ private module Cached {
209209
* value-preserving steps, not taking call contexts into account.
210210
*
211211
* `contentIn` describes the content of `p` that can flow to `node`
212-
* (if any).
212+
* (if any), `t2` is the type of the tracked value, and `t1` is the
213+
* type before reading `contentIn` (`= t2` when no content is read).
213214
*/
214-
predicate parameterValueFlow(ParameterNode p, Node node, ContentOption contentIn) {
215-
parameterValueFlow0(p, node, contentIn) and
215+
predicate parameterValueFlow(
216+
ParameterNode p, Node node, ContentOption contentIn, DataFlowType t1, DataFlowType t2
217+
) {
218+
parameterValueFlow0(p, node, contentIn, t1, t2) and
216219
if node instanceof CastingNode
217-
then
218-
// normal flow through
219-
contentIn = TContentNone() and
220-
compatibleTypes(getErasedNodeTypeBound(p), getErasedNodeTypeBound(node))
221-
or
222-
// getter
223-
exists(Content fIn |
224-
contentIn.getContent() = fIn and
225-
compatibleTypes(fIn.getType(), getErasedNodeTypeBound(node))
226-
)
220+
then compatibleTypes(t2, getErasedNodeTypeBound(node))
227221
else any()
228222
}
229223

230224
pragma[nomagic]
231-
private predicate parameterValueFlow0(ParameterNode p, Node node, ContentOption contentIn) {
225+
private predicate parameterValueFlow0(
226+
ParameterNode p, Node node, ContentOption contentIn, DataFlowType t1, DataFlowType t2
227+
) {
232228
p = node and
233229
Cand::cand(p, _) and
234-
contentIn = TContentNone()
230+
contentIn = TContentNone() and
231+
t1 = getErasedNodeTypeBound(p) and
232+
t2 = t1
235233
or
236234
// local flow
237235
exists(Node mid |
238-
parameterValueFlow(p, mid, contentIn) and
236+
parameterValueFlow(p, mid, contentIn, t1, t2) and
239237
LocalFlowBigStep::localFlowBigStep(mid, node)
240238
)
241239
or
242240
// read
243-
exists(Node mid, Content f |
244-
parameterValueFlow(p, mid, TContentNone()) and
245-
readStep(mid, f, node) and
246-
contentIn.getContent() = f and
241+
exists(Node mid |
242+
parameterValueFlow(p, mid, TContentNone(), _, t1) and
243+
readStep(mid, contentIn.getContent(), node) and
247244
Cand::parameterValueFlowReturnCand(p, _, true) and
248-
compatibleTypes(getErasedNodeTypeBound(p), f.getContainerType())
245+
compatibleTypes(t1, getErasedNodeTypeBound(mid)) and
246+
t2 = getErasedNodeTypeBound(node)
249247
)
250248
or
251249
// flow through: no prior read
252-
exists(ArgumentNode arg |
253-
parameterValueFlowArg(p, arg, TContentNone()) and
254-
argumentValueFlowsThrough(arg, contentIn, node)
250+
exists(ArgumentNode arg, DataFlowType t0_, DataFlowType t1_, DataFlowType t2_ |
251+
parameterValueFlowArg(p, arg, TContentNone(), _, t0_) and
252+
argumentValueFlowsThrough(arg, contentIn, node, t1_, t2_) and
253+
if contentIn = TContentNone()
254+
then t1 = t0_ and t2 = t1
255+
else (
256+
t1 = t1_ and
257+
t2 = t2_
258+
)
255259
)
256260
or
257261
// flow through: no read inside method
258262
exists(ArgumentNode arg |
259-
parameterValueFlowArg(p, arg, contentIn) and
260-
argumentValueFlowsThrough(arg, TContentNone(), node)
263+
parameterValueFlowArg(p, arg, contentIn, t1, t2) and
264+
argumentValueFlowsThrough(arg, TContentNone(), node, _, _)
261265
)
262266
}
263267

264268
pragma[nomagic]
265269
private predicate parameterValueFlowArg(
266-
ParameterNode p, ArgumentNode arg, ContentOption contentIn
270+
ParameterNode p, ArgumentNode arg, ContentOption contentIn, DataFlowType t1, DataFlowType t2
267271
) {
268-
parameterValueFlow(p, arg, contentIn) and
272+
parameterValueFlow(p, arg, contentIn, t1, t2) and
269273
Cand::argumentValueFlowsThroughCand(arg, _, _)
270274
}
271275

272276
pragma[nomagic]
273277
private predicate argumentValueFlowsThrough0(
274-
DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn
278+
DataFlowCall call, ArgumentNode arg, ReturnKind kind, ContentOption contentIn,
279+
DataFlowType t1, DataFlowType t2
275280
) {
276281
exists(ParameterNode param | viableParamArg(call, param, arg) |
277-
parameterValueFlowReturn(param, kind, contentIn)
282+
parameterValueFlowReturn(param, kind, contentIn, t1, t2)
278283
)
279284
}
280285

281286
/**
282287
* Holds if `arg` flows to `out` through a call using only value-preserving steps,
283288
* not taking call contexts into account.
284289
*
285-
* `contentIn` describes the content of `arg` that can flow to `out` (if any).
290+
* `contentIn` describes the content of `arg` that can flow to `out` (if any),
291+
* `t2` is the type of the tracked value, and `t1` is the type before reading
292+
* `contentIn` (`= t2` when no content is read).
286293
*/
287294
pragma[nomagic]
288-
predicate argumentValueFlowsThrough(ArgumentNode arg, ContentOption contentIn, Node out) {
295+
predicate argumentValueFlowsThrough(
296+
ArgumentNode arg, ContentOption contentIn, Node out, DataFlowType t1, DataFlowType t2
297+
) {
289298
exists(DataFlowCall call, ReturnKind kind |
290-
argumentValueFlowsThrough0(call, arg, kind, contentIn) and
291-
out = getAnOutNode(call, kind)
292-
|
293-
// normal flow through
294-
contentIn = TContentNone() and
295-
compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out))
296-
or
297-
// getter
298-
exists(Content fIn |
299-
contentIn.getContent() = fIn and
300-
compatibleTypes(getErasedNodeTypeBound(arg), fIn.getContainerType()) and
301-
compatibleTypes(fIn.getType(), getErasedNodeTypeBound(out))
302-
)
299+
argumentValueFlowsThrough0(call, arg, kind, contentIn, t1, t2) and
300+
out = getAnOutNode(call, kind) and
301+
compatibleTypes(t2, getErasedNodeTypeBound(out)) and
302+
if contentIn = TContentNone()
303+
then compatibleTypes(getErasedNodeTypeBound(arg), getErasedNodeTypeBound(out))
304+
else compatibleTypes(getErasedNodeTypeBound(arg), t1)
303305
)
304306
}
305307

@@ -308,13 +310,14 @@ private module Cached {
308310
* callable using only value-preserving steps.
309311
*
310312
* `contentIn` describes the content of `p` that can flow to the return
311-
* node (if any).
313+
* node (if any), `t2` is the type of the tracked value, and `t1` is the
314+
* type before reading `contentIn` (`= t2` when no content is read).
312315
*/
313316
private predicate parameterValueFlowReturn(
314-
ParameterNode p, ReturnKind kind, ContentOption contentIn
317+
ParameterNode p, ReturnKind kind, ContentOption contentIn, DataFlowType t1, DataFlowType t2
315318
) {
316319
exists(ReturnNode ret |
317-
parameterValueFlow(p, ret, contentIn) and
320+
parameterValueFlow(p, ret, contentIn, t1, t2) and
318321
kind = ret.getKind()
319322
)
320323
}
@@ -329,7 +332,23 @@ private module Cached {
329332
*/
330333
cached
331334
predicate parameterValueFlowsToPreUpdate(ParameterNode p, PostUpdateNode n) {
332-
parameterValueFlow(p, n.getPreUpdateNode(), TContentNone())
335+
parameterValueFlow(p, n.getPreUpdateNode(), TContentNone(), _, _)
336+
}
337+
338+
private predicate store(Node node1, Content c, Node node2, DataFlowType containerType) {
339+
storeStep(node1, c, node2) and
340+
readStep(_, c, _) and
341+
containerType = getErasedNodeTypeBound(node2)
342+
or
343+
exists(Node n1, Node n2 |
344+
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
345+
n2 = node2.(PostUpdateNode).getPreUpdateNode()
346+
|
347+
argumentValueFlowsThrough(n2, TContentSome(c), n1, containerType, _)
348+
or
349+
readStep(n2, c, n1) and
350+
containerType = getErasedNodeTypeBound(n2)
351+
)
333352
}
334353

335354
/**
@@ -340,17 +359,8 @@ private module Cached {
340359
* been stored into, in order to handle cases like `x.f1.f2 = y`.
341360
*/
342361
cached
343-
predicate store(Node node1, Content f, Node node2) {
344-
storeStep(node1, f, node2) and readStep(_, f, _)
345-
or
346-
exists(Node n1, Node n2 |
347-
n1 = node1.(PostUpdateNode).getPreUpdateNode() and
348-
n2 = node2.(PostUpdateNode).getPreUpdateNode()
349-
|
350-
argumentValueFlowsThrough(n2, TContentSome(f), n1)
351-
or
352-
readStep(n2, f, n1)
353-
)
362+
predicate store(Node node1, TypedContent tc, Node node2) {
363+
store(node1, tc.getContent(), node2, tc.getContainerType())
354364
}
355365

356366
import FlowThrough
@@ -397,10 +407,13 @@ private module Cached {
397407
TBooleanNone() or
398408
TBooleanSome(boolean b) { b = true or b = false }
399409

410+
cached
411+
newtype TTypedContent = MkTypedContent(Content c, DataFlowType t) { store(_, c, _, t) }
412+
400413
cached
401414
newtype TAccessPathFront =
402415
TFrontNil(DataFlowType t) or
403-
TFrontHead(Content f)
416+
TFrontHead(TypedContent tc)
404417

405418
cached
406419
newtype TAccessPathFrontOption =
@@ -415,13 +428,17 @@ class CastingNode extends Node {
415428
CastingNode() {
416429
this instanceof ParameterNode or
417430
this instanceof CastNode or
418-
this instanceof OutNodeExt
431+
this instanceof OutNodeExt or
432+
// For reads, `x.f`, we want to check that the tracked type after the read (which
433+
// is obtained by popping the head of the access path stack) is compatible with
434+
// the type of `x.f`.
435+
readStep(_, _, this)
419436
}
420437
}
421438

422439
newtype TContentOption =
423440
TContentNone() or
424-
TContentSome(Content f)
441+
TContentSome(Content c)
425442

426443
private class ContentOption extends TContentOption {
427444
Content getContent() { this = TContentSome(result) }
@@ -692,6 +709,23 @@ class BooleanOption extends TBooleanOption {
692709
}
693710
}
694711

712+
/** Content tagged with the type of a containing object. */
713+
class TypedContent extends MkTypedContent {
714+
private Content c;
715+
private DataFlowType t;
716+
717+
TypedContent() { this = MkTypedContent(c, t) }
718+
719+
/** Gets the content. */
720+
Content getContent() { result = c }
721+
722+
/** Gets the container type. */
723+
DataFlowType getContainerType() { result = t }
724+
725+
/** Gets a textual representation of this content. */
726+
string toString() { result = c.toString() }
727+
}
728+
695729
/**
696730
* The front of an access path. This is either a head or a nil.
697731
*/
@@ -702,25 +736,29 @@ abstract class AccessPathFront extends TAccessPathFront {
702736

703737
abstract boolean toBoolNonEmpty();
704738

705-
predicate headUsesContent(Content f) { this = TFrontHead(f) }
739+
predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) }
706740
}
707741

708742
class AccessPathFrontNil extends AccessPathFront, TFrontNil {
709-
override string toString() {
710-
exists(DataFlowType t | this = TFrontNil(t) | result = ppReprType(t))
711-
}
743+
private DataFlowType t;
712744

713-
override DataFlowType getType() { this = TFrontNil(result) }
745+
AccessPathFrontNil() { this = TFrontNil(t) }
746+
747+
override string toString() { result = ppReprType(t) }
748+
749+
override DataFlowType getType() { result = t }
714750

715751
override boolean toBoolNonEmpty() { result = false }
716752
}
717753

718754
class AccessPathFrontHead extends AccessPathFront, TFrontHead {
719-
override string toString() { exists(Content f | this = TFrontHead(f) | result = f.toString()) }
755+
private TypedContent tc;
720756

721-
override DataFlowType getType() {
722-
exists(Content head | this = TFrontHead(head) | result = head.getContainerType())
723-
}
757+
AccessPathFrontHead() { this = TFrontHead(tc) }
758+
759+
override string toString() { result = tc.toString() }
760+
761+
override DataFlowType getType() { result = tc.getContainerType() }
724762

725763
override boolean toBoolNonEmpty() { result = true }
726764
}

0 commit comments

Comments
 (0)