Skip to content

Commit 33f6b6a

Browse files
authored
Merge pull request #16175 from MathiasVP/more-iterator-models
C++: Add alias and side-effect models for more iterator functions
2 parents b9b2aa3 + 0ed0731 commit 33f6b6a

File tree

4 files changed

+785
-789
lines changed

4 files changed

+785
-789
lines changed

cpp/ql/lib/semmle/code/cpp/models/implementations/Iterator.qll

Lines changed: 148 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,14 +123,32 @@ class IteratorCrementNonMemberOperator extends Operator {
123123
}
124124

125125
private class IteratorCrementNonMemberOperatorModel extends IteratorCrementNonMemberOperator,
126-
DataFlowFunction
126+
DataFlowFunction, SideEffectFunction, AliasFunction
127127
{
128128
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
129129
input = getIteratorArgumentInput(this, 0) and
130130
output.isReturnValue()
131131
or
132132
input.isParameterDeref(0) and output.isReturnValueDeref()
133133
}
134+
135+
override predicate hasOnlySpecificReadSideEffects() { any() }
136+
137+
override predicate hasOnlySpecificWriteSideEffects() { any() }
138+
139+
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
140+
i = 0 and buffer = false
141+
}
142+
143+
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
144+
// See the comment on `IteratorCrementMemberOperatorModel::hasSpecificWriteSideEffect`
145+
// for an explanation of these values.
146+
i = 0 and buffer = false and mustWrite = false
147+
}
148+
149+
override predicate parameterNeverEscapes(int index) { none() }
150+
151+
override predicate parameterEscapesOnlyViaReturn(int index) { index = 0 }
134152
}
135153

136154
/**
@@ -146,7 +164,7 @@ class IteratorCrementMemberOperator extends MemberFunction {
146164
}
147165

148166
private class IteratorCrementMemberOperatorModel extends IteratorCrementMemberOperator,
149-
DataFlowFunction, TaintFunction
167+
DataFlowFunction, TaintFunction, SideEffectFunction, AliasFunction
150168
{
151169
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
152170
input.isQualifierAddress() and
@@ -163,6 +181,28 @@ private class IteratorCrementMemberOperatorModel extends IteratorCrementMemberOp
163181
input.isQualifierObject() and
164182
output.isReturnValueDeref()
165183
}
184+
185+
override predicate hasOnlySpecificReadSideEffects() { any() }
186+
187+
override predicate hasOnlySpecificWriteSideEffects() { any() }
188+
189+
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
190+
i = -1 and buffer = false
191+
}
192+
193+
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
194+
// We have two choices here: either `buffer` must be `true` or `mustWrite`
195+
// must be `false` to ensure that the IR alias analysis doesn't think that
196+
// `it++` completely override the value of the iterator.
197+
// We choose `mustWrite` must be `false`. In that case, the value of
198+
// `buffer` isn't super important (it just decides which kind of read side
199+
// effect will be emitted).
200+
i = -1 and buffer = false and mustWrite = false
201+
}
202+
203+
override predicate parameterNeverEscapes(int index) { index = -1 }
204+
205+
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
166206
}
167207

168208
/**
@@ -332,7 +372,7 @@ class IteratorAssignArithmeticOperator extends Function {
332372
* non-member and member versions, use `IteratorPointerDereferenceOperator`.
333373
*/
334374
class IteratorPointerDereferenceMemberOperator extends MemberFunction, TaintFunction,
335-
IteratorReferenceFunction
375+
IteratorReferenceFunction, AliasFunction, SideEffectFunction
336376
{
337377
IteratorPointerDereferenceMemberOperator() {
338378
this.getClassAndName("operator*") instanceof Iterator
@@ -345,6 +385,18 @@ class IteratorPointerDereferenceMemberOperator extends MemberFunction, TaintFunc
345385
input.isReturnValueDeref() and
346386
output.isQualifierObject()
347387
}
388+
389+
override predicate parameterNeverEscapes(int index) { index = -1 }
390+
391+
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
392+
393+
override predicate hasOnlySpecificReadSideEffects() { any() }
394+
395+
override predicate hasOnlySpecificWriteSideEffects() { any() }
396+
397+
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
398+
i = -1 and buffer = false
399+
}
348400
}
349401

350402
/**
@@ -361,7 +413,7 @@ class IteratorPointerDereferenceNonMemberOperator extends Operator, IteratorRefe
361413
}
362414

363415
private class IteratorPointerDereferenceNonMemberOperatorModel extends IteratorPointerDereferenceNonMemberOperator,
364-
TaintFunction
416+
TaintFunction, AliasFunction, SideEffectFunction
365417
{
366418
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
367419
input = getIteratorArgumentInput(this, 0) and
@@ -370,6 +422,18 @@ private class IteratorPointerDereferenceNonMemberOperatorModel extends IteratorP
370422
input.isReturnValueDeref() and
371423
output.isParameterDeref(0)
372424
}
425+
426+
override predicate parameterNeverEscapes(int index) { index = 0 }
427+
428+
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
429+
430+
override predicate hasOnlySpecificReadSideEffects() { any() }
431+
432+
override predicate hasOnlySpecificWriteSideEffects() { any() }
433+
434+
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
435+
i = 0 and buffer = false
436+
}
373437
}
374438

375439
/**
@@ -420,6 +484,71 @@ class IteratorAssignmentMemberOperator extends MemberFunction {
420484
}
421485
}
422486

487+
/**
488+
* A member `operator==` or `operator!=` function for an iterator type.
489+
*
490+
* Note that this class _only_ matches member functions. To find both
491+
* non-member and member versions, use `IteratorLogicalOperator`.
492+
*/
493+
class IteratorLogicalMemberOperator extends MemberFunction {
494+
IteratorLogicalMemberOperator() {
495+
this.getClassAndName(["operator!=", "operator=="]) instanceof Iterator
496+
}
497+
}
498+
499+
private class IteratorLogicalMemberOperatorModel extends IteratorLogicalMemberOperator,
500+
AliasFunction, SideEffectFunction
501+
{
502+
override predicate parameterNeverEscapes(int index) { index = [-1, 0] }
503+
504+
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
505+
506+
override predicate hasOnlySpecificReadSideEffects() { any() }
507+
508+
override predicate hasOnlySpecificWriteSideEffects() { any() }
509+
510+
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
511+
i = -1 and buffer = false
512+
}
513+
}
514+
515+
/**
516+
* A member `operator==` or `operator!=` function for an iterator type.
517+
*
518+
* Note that this class _only_ matches non-member functions. To find both
519+
* non-member and member versions, use `IteratorLogicalOperator`.
520+
*/
521+
class IteratorLogicalNonMemberOperator extends Function {
522+
IteratorLogicalNonMemberOperator() {
523+
this.hasName(["operator!=", "operator=="]) and
524+
exists(getIteratorArgumentInput(this, 0)) and
525+
exists(getIteratorArgumentInput(this, 1))
526+
}
527+
}
528+
529+
private class IteratorLogicalNonMemberOperatorModel extends IteratorLogicalNonMemberOperator,
530+
AliasFunction, SideEffectFunction
531+
{
532+
override predicate parameterNeverEscapes(int index) { index = [0, 1] }
533+
534+
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
535+
536+
override predicate hasOnlySpecificReadSideEffects() { any() }
537+
538+
override predicate hasOnlySpecificWriteSideEffects() { any() }
539+
}
540+
541+
/**
542+
* A (member or non-member) `operator==` or `operator!=` function for an iterator type.
543+
*/
544+
class IteratorLogicalOperator extends Function {
545+
IteratorLogicalOperator() {
546+
this instanceof IteratorLogicalNonMemberOperator
547+
or
548+
this instanceof IteratorLogicalMemberOperator
549+
}
550+
}
551+
423552
/**
424553
* An `operator=` member function of an iterator class that is not a copy or move assignment
425554
* operator.
@@ -428,12 +557,26 @@ class IteratorAssignmentMemberOperator extends MemberFunction {
428557
* `operator*` and use their own `operator=` to assign to the container.
429558
*/
430559
private class IteratorAssignmentMemberOperatorModel extends IteratorAssignmentMemberOperator,
431-
TaintFunction
560+
TaintFunction, SideEffectFunction, AliasFunction
432561
{
433562
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
434563
input.isParameterDeref(0) and
435564
output.isQualifierObject()
436565
}
566+
567+
override predicate hasOnlySpecificReadSideEffects() { any() }
568+
569+
override predicate hasOnlySpecificWriteSideEffects() { any() }
570+
571+
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
572+
// See the comment on `IteratorCrementMemberOperatorModel::hasSpecificWriteSideEffect`
573+
// for an explanation of these values.
574+
i = -1 and buffer = false and mustWrite = false
575+
}
576+
577+
override predicate parameterNeverEscapes(int index) { index = 0 }
578+
579+
override predicate parameterEscapesOnlyViaReturn(int index) { index = -1 }
437580
}
438581

439582
/**

0 commit comments

Comments
 (0)