@@ -17,54 +17,66 @@ import codingstandards.cpp.Iterators
17
17
import semmle.code.cpp.controlflow.Dominance
18
18
19
19
/**
20
- * Get a derived one passed the end element for `containerReference`.
20
+ * Models a call to an iterator's `operator+`
21
+ */
22
+ class AdditionOperatorFunctionCall extends AdditiveOperatorFunctionCall {
23
+ AdditionOperatorFunctionCall ( ) { this .getTarget ( ) .hasName ( "operator+" ) }
24
+ }
25
+
26
+ /**
27
+ * There exists a calculation for the reference one passed the end of some container
21
28
* An example derivation is:
22
29
* `end = begin() + size()`
23
30
*/
24
- Expr calculatedEndCheck ( AdditiveOperatorFunctionCall calc ) {
31
+ Expr getDerivedReferenceToOnePassedTheEndElement ( Expr containerReference ) {
25
32
exists (
26
33
ContainerAccessWithoutRangeCheck:: ContainerSizeCall size ,
27
- ContainerAccessWithoutRangeCheck:: ContainerBeginCall begin
34
+ ContainerAccessWithoutRangeCheck:: ContainerBeginCall begin , AdditionOperatorFunctionCall calc
28
35
|
29
- calc .getTarget ( ) .hasName ( "operator+" ) and
30
- DataFlow:: localFlow ( DataFlow:: exprNode ( size ) , DataFlow:: exprNode ( calc .getAChild * ( ) ) ) and
31
- DataFlow:: localFlow ( DataFlow:: exprNode ( begin ) , DataFlow:: exprNode ( calc .getAChild * ( ) ) ) and
36
+ result = calc
37
+ |
38
+ DataFlow:: localFlow ( DataFlow:: exprNode ( size ) , DataFlow:: exprNode ( calc .getAChild + ( ) ) ) and
39
+ DataFlow:: localFlow ( DataFlow:: exprNode ( begin ) , DataFlow:: exprNode ( calc .getAChild + ( ) ) ) and
32
40
//make sure its the same container providing its size as giving the begin
33
41
globalValueNumber ( begin .getQualifier ( ) ) = globalValueNumber ( size .getQualifier ( ) ) and
34
- result = begin .getQualifier ( )
42
+ containerReference = begin .getQualifier ( )
35
43
)
36
44
}
37
45
38
- Expr validEndCheck ( FunctionCall end ) {
39
- end instanceof ContainerAccessWithoutRangeCheck:: ContainerEndCall and
40
- result = end .getQualifier ( )
46
+ /**
47
+ * a wrapper predicate for a couple of types of permitted end bounds checks
48
+ */
49
+ Expr getReferenceToOnePassedTheEndElement ( Expr containerReference ) {
50
+ //a container end access - v.end()
51
+ result instanceof ContainerAccessWithoutRangeCheck:: ContainerEndCall and
52
+ containerReference = result .( FunctionCall ) .getQualifier ( )
41
53
or
42
- result = calculatedEndCheck ( end )
54
+ result = getDerivedReferenceToOnePassedTheEndElement ( containerReference )
43
55
}
44
56
45
57
/**
46
58
* some guard exists like: `iterator != end`
47
59
* where a relevant`.end()` call flowed into end
48
60
*/
49
- predicate validEndBoundCheck ( ContainerIteratorAccess it , IteratorSource source ) {
61
+ predicate isUpperBoundEndCheckedIteratorAccess ( IteratorSource source , ContainerIteratorAccess it ) {
50
62
exists (
51
- FunctionCall end , BasicBlock b , GuardCondition l , ContainerIteratorAccess otherAccess ,
52
- Expr qualifierToCheck
63
+ Expr referenceToOnePassedTheEndElement , BasicBlock basicBlockOfIteratorAccess , GuardCondition upperBoundCheck ,
64
+ ContainerIteratorAccess checkedIteratorAccess , Expr containerReferenceFromEndGuard
53
65
|
54
66
//sufficient end guard
55
- qualifierToCheck = validEndCheck ( end ) and
67
+ referenceToOnePassedTheEndElement = getReferenceToOnePassedTheEndElement ( containerReferenceFromEndGuard ) and
56
68
//guard controls the access
57
- l .controls ( b , _) and
58
- b .contains ( it ) and
69
+ upperBoundCheck .controls ( basicBlockOfIteratorAccess , _) and
70
+ basicBlockOfIteratorAccess .contains ( it ) and
59
71
//guard is comprised of end check and an iterator access
60
- DataFlow:: localFlow ( DataFlow:: exprNode ( end ) , DataFlow:: exprNode ( l .getChild ( _) ) ) and
61
- l .getChild ( _) = otherAccess and
72
+ DataFlow:: localFlow ( DataFlow:: exprNode ( referenceToOnePassedTheEndElement ) , DataFlow:: exprNode ( upperBoundCheck .getChild ( _) ) ) and
73
+ upperBoundCheck .getChild ( _) = checkedIteratorAccess and
62
74
//make sure its the same iterator being checked in the guard as accessed
63
- otherAccess .getOwningContainer ( ) = it .getOwningContainer ( ) and
75
+ checkedIteratorAccess .getOwningContainer ( ) = it .getOwningContainer ( ) and
64
76
//if its the end call itself (or its parts), make sure its the same container providing its end as giving the iterator
65
- globalValueNumber ( qualifierToCheck ) = globalValueNumber ( source .getQualifier ( ) ) and
77
+ globalValueNumber ( containerReferenceFromEndGuard ) = globalValueNumber ( source .getQualifier ( ) ) and
66
78
// and the guard call we match must be after the assignment call (to avoid valid guards protecting new iterator accesses further down)
67
- source .getASuccessor * ( ) = l
79
+ source .getASuccessor * ( ) = upperBoundCheck
68
80
)
69
81
}
70
82
74
86
it .isAdditiveOperation ( ) and
75
87
not exists ( RangeBasedForStmt fs | fs .getUpdate ( ) .getAChild * ( ) = it ) and
76
88
source = it .getANearbyAssigningIteratorCall ( ) and
77
- not validEndBoundCheck ( it , source ) and
89
+ not isUpperBoundEndCheckedIteratorAccess ( source , it ) and
78
90
not sizeCompareBoundsChecked ( source , it )
79
91
select it , "Increment of iterator may overflow since its bounds are not checked."
0 commit comments