@@ -63,7 +63,43 @@ static const struct CWE CWE834(834U); // Excessive Iteration
6363
6464static bool isElementAccessYield (const Library::Container::Yield& yield)
6565{
66- return yield == Library::Container::Yield::ITEM || yield == Library::Container::Yield::AT_INDEX;
66+ return contains ({Library::Container::Yield::ITEM, Library::Container::Yield::AT_INDEX}, yield);
67+ }
68+
69+ static bool containerYieldsElement (const Library::Container* container, const Token* parent)
70+ {
71+ if (Token::Match (parent, " . %name% (" )) {
72+ Library::Container::Yield yield = container->getYield (parent->strAt (1 ));
73+ if (isElementAccessYield (yield))
74+ return true ;
75+ }
76+ return false ;
77+ }
78+
79+ static const Token* getContainerIndex (const Library::Container* container, const Token* parent)
80+ {
81+ if (Token::Match (parent, " . %name% (" )) {
82+ Library::Container::Yield yield = container->getYield (parent->strAt (1 ));
83+ if (isElementAccessYield (yield) && !Token::simpleMatch (parent->tokAt (2 ), " ( )" ))
84+ return parent->tokAt (2 )->astOperand2 ();
85+ }
86+ if (!container->arrayLike_indexOp && !container->stdStringLike )
87+ return nullptr ;
88+ if (Token::simpleMatch (parent, " [" ))
89+ return parent->astOperand2 ();
90+ return nullptr ;
91+ }
92+
93+ static const Token* getContainerFromSize (const Library::Container* container, const Token* tok)
94+ {
95+ if (!tok)
96+ return nullptr ;
97+ if (Token::Match (tok->tokAt (-2 ), " . %name% (" )) {
98+ Library::Container::Yield yield = container->getYield (tok->strAt (-1 ));
99+ if (yield == Library::Container::Yield::SIZE)
100+ return tok->tokAt (-2 )->astOperand1 ();
101+ }
102+ return nullptr ;
67103}
68104
69105void CheckStl::outOfBounds ()
@@ -74,6 +110,14 @@ void CheckStl::outOfBounds()
74110 if (!container)
75111 continue ;
76112 const Token * parent = astParentSkipParens (tok);
113+ const Token* accessTok = parent;
114+ if (Token::simpleMatch (accessTok, " ." ) && Token::simpleMatch (accessTok->astParent (), " (" ))
115+ accessTok = accessTok->astParent ();
116+ if (astIsIterator (accessTok) && Token::simpleMatch (accessTok->astParent (), " +" ))
117+ accessTok = accessTok->astParent ();
118+ const Token* indexTok = getContainerIndex (container, parent);
119+ if (indexTok == tok)
120+ continue ;
77121 for (const ValueFlow::Value &value : tok->values ()) {
78122 if (!value.isContainerSizeValue ())
79123 continue ;
@@ -83,70 +127,60 @@ void CheckStl::outOfBounds()
83127 continue ;
84128 if (!value.errorSeverity () && !mSettings ->severity .isEnabled (Severity::warning))
85129 continue ;
86- if (Token::Match (parent, " . %name% (" ) && isElementAccessYield (container->getYield (parent->strAt (1 )))) {
87- if (value.intvalue == 0 ) {
88- outOfBoundsError (parent->tokAt (2 ), tok->expressionString (), &value, parent->strAt (1 ), nullptr );
89- continue ;
90- }
91-
92- const Token* indexTok = parent->tokAt (2 )->astOperand2 ();
93- if (!indexTok)
94- continue ;
95- std::vector<ValueFlow::Value> indexValues =
96- ValueFlow::isOutOfBounds (value, indexTok, mSettings ->severity .isEnabled (Severity::warning));
97- if (!indexValues.empty ()) {
98- outOfBoundsError (
99- parent, tok->expressionString (), &value, indexTok->expressionString (), &indexValues.front ());
100- continue ;
101- }
102- }
103- if (Token::Match (tok, " %name% . %name% (" ) && container->getYield (tok->strAt (2 )) == Library::Container::Yield::START_ITERATOR) {
104- const Token *fparent = tok->tokAt (3 )->astParent ();
105- const Token *other = nullptr ;
106- if (Token::simpleMatch (fparent, " +" ) && fparent->astOperand1 () == tok->tokAt (3 ))
107- other = fparent->astOperand2 ();
108- else if (Token::simpleMatch (fparent, " +" ) && fparent->astOperand2 () == tok->tokAt (3 ))
109- other = fparent->astOperand1 ();
110- if (other && other->hasKnownIntValue () && other->getKnownIntValue () > value.intvalue ) {
111- outOfBoundsError (fparent, tok->expressionString (), &value, other->expressionString (), &other->values ().back ());
112- continue ;
113- } else if (other && !other->hasKnownIntValue () && value.isKnown () && value.intvalue ==0 ) {
114- outOfBoundsError (fparent, tok->expressionString (), &value, other->expressionString (), nullptr );
115- continue ;
116- }
117- }
118- if (!container->arrayLike_indexOp && !container->stdStringLike )
119- continue ;
120- if (value.intvalue == 0 && Token::Match (parent, " [" ) && tok == parent->astOperand1 ()) {
121- outOfBoundsError (parent, tok->expressionString (), &value, " " , nullptr );
130+ if (value.intvalue == 0 && (indexTok || containerYieldsElement (container, parent))) {
131+ std::string indexExpr;
132+ if (indexTok && !indexTok->hasKnownValue ())
133+ indexExpr = indexTok->expressionString ();
134+ outOfBoundsError (accessTok, tok->expressionString (), &value, indexExpr, nullptr );
122135 continue ;
123136 }
124- if (container->arrayLike_indexOp && Token::Match (parent, " [" )) {
125- const Token* indexTok = parent->astOperand2 ();
126- if (!indexTok)
127- continue ;
137+ if (indexTok) {
128138 std::vector<ValueFlow::Value> indexValues =
129139 ValueFlow::isOutOfBounds (value, indexTok, mSettings ->severity .isEnabled (Severity::warning));
130140 if (!indexValues.empty ()) {
131141 outOfBoundsError (
132- parent , tok->expressionString (), &value, indexTok->expressionString (), &indexValues.front ());
142+ accessTok , tok->expressionString (), &value, indexTok->expressionString (), &indexValues.front ());
133143 continue ;
134144 }
135145 }
136146 }
147+ if (indexTok && !indexTok->hasKnownIntValue ()) {
148+ const ValueFlow::Value* value =
149+ ValueFlow::findValue (indexTok->values (), mSettings , [&](const ValueFlow::Value& v) {
150+ if (!v.isSymbolicValue ())
151+ return false ;
152+ if (v.isImpossible ())
153+ return false ;
154+ if (v.intvalue < 0 )
155+ return false ;
156+ const Token* containerTok = getContainerFromSize (container, v.tokvalue );
157+ if (!containerTok)
158+ return false ;
159+ return containerTok->exprId () == tok->exprId ();
160+ });
161+ if (!value)
162+ continue ;
163+ outOfBoundsError (accessTok, tok->expressionString (), nullptr , indexTok->expressionString (), value);
164+ }
137165 }
138166 }
139167}
140168
141- static std::string indexValueString (const ValueFlow::Value& indexValue)
169+ static std::string indexValueString (const ValueFlow::Value& indexValue, const std::string& containerName = " " )
142170{
143171 if (indexValue.isIteratorStartValue ())
144172 return " at position " + MathLib::toString (indexValue.intvalue ) + " from the beginning" ;
145173 if (indexValue.isIteratorEndValue ())
146174 return " at position " + MathLib::toString (-indexValue.intvalue ) + " from the end" ;
175+ std::string indexString = MathLib::toString (indexValue.intvalue );
176+ if (indexValue.isSymbolicValue ()) {
177+ indexString = containerName + " .size()" ;
178+ if (indexValue.intvalue != 0 )
179+ indexString += " +" + MathLib::toString (indexValue.intvalue );
180+ }
147181 if (indexValue.bound == ValueFlow::Value::Bound::Lower)
148- return " greater or equal to " + MathLib::toString (indexValue. intvalue ) ;
149- return MathLib::toString (indexValue. intvalue ) ;
182+ return " greater or equal to " + indexString ;
183+ return indexString ;
150184}
151185
152186void CheckStl::outOfBoundsError (const Token *tok, const std::string &containerName, const ValueFlow::Value *containerSize, const std::string &index, const ValueFlow::Value *indexValue)
@@ -158,9 +192,14 @@ void CheckStl::outOfBoundsError(const Token *tok, const std::string &containerNa
158192 const std::string expression = tok ? tok->expressionString () : (containerName+" [x]" );
159193
160194 std::string errmsg;
161- if (!containerSize)
162- errmsg = " Out of bounds access in expression '" + expression + " '" ;
163- else if (containerSize->intvalue == 0 ) {
195+ if (!containerSize) {
196+ if (indexValue && indexValue->condition )
197+ errmsg = ValueFlow::eitherTheConditionIsRedundant (indexValue->condition ) + " or '" + index +
198+ " ' can have the value " + indexValueString (*indexValue, containerName) + " . Expression '" +
199+ expression + " ' cause access out of bounds." ;
200+ else
201+ errmsg = " Out of bounds access in expression '" + expression + " '" ;
202+ } else if (containerSize->intvalue == 0 ) {
164203 if (containerSize->condition )
165204 errmsg = ValueFlow::eitherTheConditionIsRedundant (containerSize->condition ) + " or expression '" + expression + " ' cause access out of bounds." ;
166205 else if (indexValue == nullptr && !index.empty ())
@@ -1175,6 +1214,9 @@ void CheckStl::stlOutOfBounds()
11751214 continue ;
11761215 }
11771216
1217+ if (containerToken->hasKnownValue (ValueFlow::Value::ValueType::CONTAINER_SIZE))
1218+ continue ;
1219+
11781220 // Is it a array like container?
11791221 const Library::Container* container = containerToken->valueType () ? containerToken->valueType ()->container : nullptr ;
11801222 if (!container)
@@ -2183,6 +2225,9 @@ void CheckStl::checkDereferenceInvalidIterator2()
21832225 continue ;
21842226 }
21852227
2228+ if (Token::Match (tok, " %assign%" ))
2229+ continue ;
2230+
21862231 std::vector<ValueFlow::Value> contValues;
21872232 std::copy_if (tok->values ().begin (), tok->values ().end (), std::back_inserter (contValues), [&](const ValueFlow::Value& value) {
21882233 if (value.isImpossible ())
@@ -2201,9 +2246,13 @@ void CheckStl::checkDereferenceInvalidIterator2()
22012246 continue ;
22022247 if (!value.isIteratorValue ())
22032248 continue ;
2204- const bool isInvalidIterator = (value. isIteratorEndValue () && value. intvalue >= 0 ) || (value. isIteratorStartValue () && value. intvalue < 0 ) ;
2249+ bool isInvalidIterator = false ;
22052250 const ValueFlow::Value* cValue = nullptr ;
2206- if (!isInvalidIterator) {
2251+ if (value.isIteratorEndValue () && value.intvalue >= 0 ) {
2252+ isInvalidIterator = value.intvalue > 0 ;
2253+ } else if (value.isIteratorStartValue () && value.intvalue < 0 ) {
2254+ isInvalidIterator = true ;
2255+ } else {
22072256 auto it = std::find_if (contValues.begin (), contValues.end (), [&](const ValueFlow::Value& c) {
22082257 if (value.isIteratorStartValue () && value.intvalue >= c.intvalue )
22092258 return true ;
@@ -2214,17 +2263,41 @@ void CheckStl::checkDereferenceInvalidIterator2()
22142263 if (it == contValues.end ())
22152264 continue ;
22162265 cValue = &*it;
2266+ if (value.isIteratorStartValue () && value.intvalue > cValue->intvalue )
2267+ isInvalidIterator = true ;
22172268 }
22182269 bool inconclusive = false ;
22192270 bool unknown = false ;
2220- if (!CheckNullPointer::isPointerDeRef (tok, unknown, mSettings )) {
2271+ const Token* emptyAdvance = nullptr ;
2272+ const Token* advanceIndex = nullptr ;
2273+ if (cValue && cValue->intvalue == 0 ) {
2274+ if (Token::Match (tok->astParent (), " +|-" ) && astIsIntegral (tok->astSibling (), false )) {
2275+ if (tok->astSibling () && tok->astSibling ()->hasKnownIntValue ()) {
2276+ if (tok->astSibling ()->values ().front ().intvalue == 0 )
2277+ continue ;
2278+ } else {
2279+ advanceIndex = tok->astSibling ();
2280+ }
2281+ emptyAdvance = tok->astParent ();
2282+ } else if (Token::Match (tok->astParent (), " ++|--" )) {
2283+ emptyAdvance = tok->astParent ();
2284+ }
2285+ }
2286+ if (!CheckNullPointer::isPointerDeRef (tok, unknown, mSettings ) && !isInvalidIterator && !emptyAdvance) {
22212287 if (!unknown)
22222288 continue ;
22232289 inconclusive = true ;
22242290 }
22252291 if (cValue) {
22262292 const ValueFlow::Value& lValue = getLifetimeObjValue (tok, true );
2227- outOfBoundsError (tok, lValue.tokvalue ->expressionString (), cValue, tok->expressionString (), &value);
2293+ if (emptyAdvance)
2294+ outOfBoundsError (emptyAdvance,
2295+ lValue.tokvalue ->expressionString (),
2296+ cValue,
2297+ advanceIndex ? advanceIndex->expressionString () : " " ,
2298+ nullptr );
2299+ else
2300+ outOfBoundsError (tok, lValue.tokvalue ->expressionString (), cValue, tok->expressionString (), &value);
22282301 } else {
22292302 dereferenceInvalidIteratorError (tok, &value, inconclusive);
22302303 }
0 commit comments