Skip to content

Commit d98ed2d

Browse files
committed
C++: Add alias and side effect models for more iterator functions.
1 parent 0e67aa5 commit d98ed2d

File tree

1 file changed

+146
-5
lines changed
  • cpp/ql/lib/semmle/code/cpp/models/implementations

1 file changed

+146
-5
lines changed

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

Lines changed: 146 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,14 +123,34 @@ 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+
// `buffer` must be `true` or `mustWrite` must be `false` to ensure that
145+
// the IR alias analysis doesn't think that `it++` doesn't completely override
146+
// the value of the iterator. Ideally, the IR alias analysis shouldn't deal with
147+
// iterators, but this is necessary for taintflow to get any results in our iterator tests.
148+
i = 0 and buffer = false and mustWrite = false
149+
}
150+
151+
override predicate parameterNeverEscapes(int index) { none() }
152+
153+
override predicate parameterEscapesOnlyViaReturn(int index) { index = 0 }
134154
}
135155

136156
/**
@@ -146,7 +166,7 @@ class IteratorCrementMemberOperator extends MemberFunction {
146166
}
147167

148168
private class IteratorCrementMemberOperatorModel extends IteratorCrementMemberOperator,
149-
DataFlowFunction, TaintFunction
169+
DataFlowFunction, TaintFunction, SideEffectFunction, AliasFunction
150170
{
151171
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
152172
input.isQualifierAddress() and
@@ -163,6 +183,26 @@ private class IteratorCrementMemberOperatorModel extends IteratorCrementMemberOp
163183
input.isQualifierObject() and
164184
output.isReturnValueDeref()
165185
}
186+
187+
override predicate hasOnlySpecificReadSideEffects() { any() }
188+
189+
override predicate hasOnlySpecificWriteSideEffects() { any() }
190+
191+
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
192+
i = -1 and buffer = false
193+
}
194+
195+
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
196+
// `buffer` must be `true` or `mustWrite` must be `false` to ensure that
197+
// the IR alias analysis doesn't think that `it++` doesn't completely override
198+
// the value of the iterator. Ideally, the IR alias analysis shouldn't deal with
199+
// iterators, but this is necessary for taintflow to get any results in our iterator tests.
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,24 @@ 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+
i = -1 and buffer = false and mustWrite = false
573+
}
574+
575+
override predicate parameterNeverEscapes(int index) { index = 0 }
576+
577+
override predicate parameterEscapesOnlyViaReturn(int index) { index = -1 }
437578
}
438579

439580
/**

0 commit comments

Comments
 (0)