@@ -15,23 +15,44 @@ import cpp
1515import codingstandards.cpp.cert
1616import codingstandards.cpp.Iterators
1717
18- from ContainerIteratorAccess it
18+ /**
19+ * any `.size()` check above our access
20+ */
21+ predicate size_checked_above ( ContainerIteratorAccess it , IteratorSource source ) {
22+ exists ( STLContainer c , FunctionCall guardCall |
23+ c .getACallToSize ( ) = guardCall and
24+ guardCall = it .getAPredecessor * ( ) 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
29+ )
30+ }
31+
32+ /**
33+ * some loop check exists like: `iterator != end`
34+ * where a relevant`.end()` call flowed into end
35+ */
36+ predicate valid_end_bound_check ( ContainerIteratorAccess it , IteratorSource source ) {
37+ exists ( STLContainer c , Loop l , ContainerIteratorAccess otherAccess , IteratorSource end |
38+ end = c .getAnIteratorEndFunctionCall ( ) and
39+ //flow exists between end() and the loop condition
40+ DataFlow:: localFlow ( DataFlow:: exprNode ( end ) , DataFlow:: exprNode ( l .getCondition ( ) .getAChild ( ) ) ) and
41+ l .getCondition ( ) .getAChild ( ) = otherAccess and
42+ //make sure its the same iterator being checked as incremented
43+ otherAccess .getOwningContainer ( ) = it .getOwningContainer ( ) and
44+ //make sure its the same container providing its end as giving the iterator
45+ globalValueNumber ( end .getQualifier ( ) ) = globalValueNumber ( source .getQualifier ( ) )
46+ )
47+ }
48+
49+ from ContainerIteratorAccess it , IteratorSource source
1950where
2051 not isExcluded ( it , IteratorsPackage:: doNotUseAnAdditiveOperatorOnAnIteratorQuery ( ) ) and
2152 it .isAdditiveOperation ( ) and
2253 not exists ( RangeBasedForStmt fs | fs .getUpdate ( ) .getAChild * ( ) = it ) and
23- // we get the neraby assignment
24- not exists ( STLContainer c , FunctionCall nearbyAssigningIteratorCall , FunctionCall guardCall |
25- nearbyAssigningIteratorCall = it .getANearbyAssigningIteratorCall ( ) and
26- // we look for calls to size or end
27- ( guardCall = c .getACallToSize ( ) or guardCall = c .getAnIteratorEndFunctionCall ( ) ) and
28- // such that the call to size is before this
29- // access
30- guardCall = it .getAPredecessor * ( ) and
31- // and it uses the same qualifier as the one we were just assigned
32- nearbyAssigningIteratorCall .getQualifier ( ) .( VariableAccess ) .getTarget ( ) =
33- guardCall .getQualifier ( ) .( VariableAccess ) .getTarget ( ) and
34- // and the size call we match must be after the assignment call
35- nearbyAssigningIteratorCall .getASuccessor * ( ) = guardCall
36- )
54+ source = it .getANearbyAssigningIteratorCall ( ) and
55+ not size_compare_bounds_checked ( source , it ) and
56+ not valid_end_bound_check ( it , source ) and
57+ not size_checked_above ( it , source )
3758select it , "Increment of iterator may overflow since its bounds are not checked."
0 commit comments