@@ -17,37 +17,53 @@ import codingstandards.cpp.Iterators
17
17
import semmle.code.cpp.controlflow.Dominance
18
18
19
19
/**
20
- * any `.size()` check above our access
20
+ * something like:
21
+ * `end = begin() + size()`
21
22
*/
22
- predicate sizeCheckedAbove ( ContainerIteratorAccess it , IteratorSource source ) {
23
- exists ( ContainerAccessWithoutRangeCheck:: ContainerSizeCall guardCall |
24
- strictlyDominates ( guardCall , it ) and
25
- //make sure its the same container providing its size as giving the iterator
26
- globalValueNumber ( guardCall .getQualifier ( ) ) = globalValueNumber ( source .getQualifier ( ) ) and
27
- // and the size call we match must be after the assignment call
28
- source .getASuccessor * ( ) = guardCall
23
+ Expr calculatedEndCheck ( AdditiveOperatorFunctionCall calc ) {
24
+ exists (
25
+ ContainerAccessWithoutRangeCheck:: ContainerSizeCall size ,
26
+ ContainerAccessWithoutRangeCheck:: ContainerBeginCall begin
27
+ |
28
+ calc .getTarget ( ) .hasName ( "operator+" ) and
29
+ DataFlow:: localFlow ( DataFlow:: exprNode ( size ) , DataFlow:: exprNode ( calc .getAChild * ( ) ) ) and
30
+ DataFlow:: localFlow ( DataFlow:: exprNode ( begin ) , DataFlow:: exprNode ( calc .getAChild * ( ) ) ) and
31
+ //make sure its the same container providing its size as giving the begin
32
+ globalValueNumber ( begin .getQualifier ( ) ) = globalValueNumber ( size .getQualifier ( ) ) and
33
+ result = begin .getQualifier ( )
29
34
)
30
35
}
31
36
37
+ Expr validEndCheck ( FunctionCall end ) {
38
+ end instanceof ContainerAccessWithoutRangeCheck:: ContainerEndCall and
39
+ result = end .getQualifier ( )
40
+ or
41
+ result = calculatedEndCheck ( end )
42
+ }
43
+
32
44
/**
33
45
* some guard exists like: `iterator != end`
34
46
* where a relevant`.end()` call flowed into end
35
47
*/
36
48
predicate validEndBoundCheck ( ContainerIteratorAccess it , IteratorSource source ) {
37
49
exists (
38
- ContainerAccessWithoutRangeCheck :: ContainerEndCall end , BasicBlock b , GuardCondition l ,
39
- ContainerIteratorAccess otherAccess
50
+ FunctionCall end , BasicBlock b , GuardCondition l , ContainerIteratorAccess otherAccess ,
51
+ Expr qualifierToCheck
40
52
|
53
+ //sufficient end guard
54
+ qualifierToCheck = validEndCheck ( end ) and
41
55
//guard controls the access
42
56
l .controls ( b , _) and
43
57
b .contains ( it ) and
44
- //guard is comprised of (anything flowing to) end check and an iterator access
58
+ //guard is comprised of end check and an iterator access
45
59
DataFlow:: localFlow ( DataFlow:: exprNode ( end ) , DataFlow:: exprNode ( l .getChild ( _) ) ) and
46
60
l .getChild ( _) = otherAccess and
47
61
//make sure its the same iterator being checked in the guard as accessed
48
62
otherAccess .getOwningContainer ( ) = it .getOwningContainer ( ) and
49
- //make sure its the same container providing its end as giving the iterator
50
- globalValueNumber ( end .getQualifier ( ) ) = globalValueNumber ( source .getQualifier ( ) )
63
+ //if its the end call itself (or its parts), make sure its the same container providing its end as giving the iterator
64
+ globalValueNumber ( qualifierToCheck ) = globalValueNumber ( source .getQualifier ( ) ) and
65
+ // and the guard call we match must be after the assignment call (to avoid valid guards protecting new iterator accesses further down)
66
+ source .getASuccessor * ( ) = l
51
67
)
52
68
}
53
69
58
74
not exists ( RangeBasedForStmt fs | fs .getUpdate ( ) .getAChild * ( ) = it ) and
59
75
source = it .getANearbyAssigningIteratorCall ( ) and
60
76
not validEndBoundCheck ( it , source ) and
61
- not sizeCheckedAbove ( it , source )
77
+ not sizeCompareBoundsChecked ( source , it )
62
78
select it , "Increment of iterator may overflow since its bounds are not checked."
0 commit comments