@@ -17,54 +17,66 @@ import codingstandards.cpp.Iterators
1717import semmle.code.cpp.controlflow.Dominance
1818
1919/**
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
2128 * An example derivation is:
2229 * `end = begin() + size()`
2330 */
24- Expr calculatedEndCheck ( AdditiveOperatorFunctionCall calc ) {
31+ Expr getDerivedReferenceToOnePassedTheEndElement ( Expr containerReference ) {
2532 exists (
2633 ContainerAccessWithoutRangeCheck:: ContainerSizeCall size ,
27- ContainerAccessWithoutRangeCheck:: ContainerBeginCall begin
34+ ContainerAccessWithoutRangeCheck:: ContainerBeginCall begin , AdditionOperatorFunctionCall calc
2835 |
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
3240 //make sure its the same container providing its size as giving the begin
3341 globalValueNumber ( begin .getQualifier ( ) ) = globalValueNumber ( size .getQualifier ( ) ) and
34- result = begin .getQualifier ( )
42+ containerReference = begin .getQualifier ( )
3543 )
3644}
3745
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 ( )
4153 or
42- result = calculatedEndCheck ( end )
54+ result = getDerivedReferenceToOnePassedTheEndElement ( containerReference )
4355}
4456
4557/**
4658 * some guard exists like: `iterator != end`
4759 * where a relevant`.end()` call flowed into end
4860 */
49- predicate validEndBoundCheck ( ContainerIteratorAccess it , IteratorSource source ) {
61+ predicate isUpperBoundEndCheckedIteratorAccess ( IteratorSource source , ContainerIteratorAccess it ) {
5062 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
5365 |
5466 //sufficient end guard
55- qualifierToCheck = validEndCheck ( end ) and
67+ referenceToOnePassedTheEndElement = getReferenceToOnePassedTheEndElement ( containerReferenceFromEndGuard ) and
5668 //guard controls the access
57- l .controls ( b , _) and
58- b .contains ( it ) and
69+ upperBoundCheck .controls ( basicBlockOfIteratorAccess , _) and
70+ basicBlockOfIteratorAccess .contains ( it ) and
5971 //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
6274 //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
6476 //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
6678 // 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
6880 )
6981}
7082
7486 it .isAdditiveOperation ( ) and
7587 not exists ( RangeBasedForStmt fs | fs .getUpdate ( ) .getAChild * ( ) = it ) and
7688 source = it .getANearbyAssigningIteratorCall ( ) and
77- not validEndBoundCheck ( it , source ) and
89+ not isUpperBoundEndCheckedIteratorAccess ( source , it ) and
7890 not sizeCompareBoundsChecked ( source , it )
7991select it , "Increment of iterator may overflow since its bounds are not checked."
0 commit comments