@@ -17,37 +17,53 @@ import codingstandards.cpp.Iterators
1717import semmle.code.cpp.controlflow.Dominance
1818
1919/**
20- * any `.size()` check above our access
20+ * something like:
21+ * `end = begin() + size()`
2122 */
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 ( )
2934 )
3035}
3136
37+ Expr validEndCheck ( FunctionCall end ) {
38+ end instanceof ContainerAccessWithoutRangeCheck:: ContainerEndCall and
39+ result = end .getQualifier ( )
40+ or
41+ result = calculatedEndCheck ( end )
42+ }
43+
3244/**
3345 * some guard exists like: `iterator != end`
3446 * where a relevant`.end()` call flowed into end
3547 */
3648predicate validEndBoundCheck ( ContainerIteratorAccess it , IteratorSource source ) {
3749 exists (
38- ContainerAccessWithoutRangeCheck :: ContainerEndCall end , BasicBlock b , GuardCondition l ,
39- ContainerIteratorAccess otherAccess
50+ FunctionCall end , BasicBlock b , GuardCondition l , ContainerIteratorAccess otherAccess ,
51+ Expr qualifierToCheck
4052 |
53+ //sufficient end guard
54+ qualifierToCheck = validEndCheck ( end ) and
4155 //guard controls the access
4256 l .controls ( b , _) and
4357 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
4559 DataFlow:: localFlow ( DataFlow:: exprNode ( end ) , DataFlow:: exprNode ( l .getChild ( _) ) ) and
4660 l .getChild ( _) = otherAccess and
4761 //make sure its the same iterator being checked in the guard as accessed
4862 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
5167 )
5268}
5369
5874 not exists ( RangeBasedForStmt fs | fs .getUpdate ( ) .getAChild * ( ) = it ) and
5975 source = it .getANearbyAssigningIteratorCall ( ) and
6076 not validEndBoundCheck ( it , source ) and
61- not sizeCheckedAbove ( it , source )
77+ not sizeCompareBoundsChecked ( source , it )
6278select it , "Increment of iterator may overflow since its bounds are not checked."
0 commit comments