diff --git a/src/checkbufferoverrun.cpp b/src/checkbufferoverrun.cpp index ec595fa9b..6e40a0971 100644 --- a/src/checkbufferoverrun.cpp +++ b/src/checkbufferoverrun.cpp @@ -555,12 +555,73 @@ void CheckBufferOverrunClass::CheckBufferOverrun_StructVariable() } //--------------------------------------------------------------------------- +void CheckBufferOverrunClass::STLSizeProblems() +{ + for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) + { + if (!Token::simpleMatch(tok, "for (")) + continue; + int indent = 1; + tok = tok->tokAt(2); + const Token *num = 0; + const Token *var = 0; + while (tok) + { + + if (tok->str() == "(") + ++indent; + if (tok->str() == ")") + { + --indent; + if (indent == 0) + break; + } + + if (Token::Match(tok, "; %var% <= %var% . size ( ) ;")) + { + num = tok->tokAt(1); + var = tok->tokAt(3); + } + + tok = tok->next(); + } + + tok = tok->next(); + if (!num || tok->str() != "{") + continue; + + std::string pattern = var->str() + " [ " + num->str() + " ]"; + while (tok) + { + + if (tok->str() == "{") + ++indent; + if (tok->str() == "}") + { + --indent; + if (indent == 0) + break; + } + + + if (Token::Match(tok, pattern.c_str())) + { + _errorLogger->outOfBounds(_tokenizer, tok, "When " + num->str() + " == size(), " + pattern); + } + + tok = tok->next(); + } + } + +} + void CheckBufferOverrunClass::bufferOverrun() { CheckBufferOverrun_LocalVariable(); CheckBufferOverrun_StructVariable(); + STLSizeProblems(); } //--------------------------------------------------------------------------- diff --git a/src/checkbufferoverrun.h b/src/checkbufferoverrun.h index e652e5cfd..5a9890c92 100644 --- a/src/checkbufferoverrun.h +++ b/src/checkbufferoverrun.h @@ -45,6 +45,12 @@ private: /** Check for buffer overruns - this is the function that performs the actual checking */ void CheckBufferOverrun_CheckScope(const Token *tok, const char *varname[], const int size, const int total_size, unsigned int varid); + /** + * Finds errors like this: + * for (unsigned ii = 0; ii <= foo.size(); ++ii) + */ + void STLSizeProblems(); + const Tokenizer *_tokenizer; const Settings _settings; ErrorLogger *_errorLogger; diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index 4c6faa912..1c8913b1f 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -93,6 +93,8 @@ private: TEST_CASE(varid1); TEST_CASE(varid2); + TEST_CASE(STLSize); + TEST_CASE(STLSizeNoErr); } @@ -471,7 +473,44 @@ private: ASSERT_EQUALS(std::string(""), errout.str()); } + void STLSize() + { + check("void foo()\n" + "{\n" + " std::vector foo;\n" + " for (unsigned int ii = 0; ii <= foo.size(); ++ii)\n" + " {\n" + " foo[ii] = 0;\n" + " }\n" + "}\n"); + ASSERT_EQUALS(std::string("[test.cpp:6]: (error) When ii == size(), foo [ ii ] is out of bounds\n"), errout.str()); + } + void STLSizeNoErr() + { + { + check("void foo()\n" + "{\n" + " std::vector foo;\n" + " for (unsigned int ii = 0; ii < foo.size(); ++ii)\n" + " {\n" + " foo[ii] = 0;\n" + " }\n" + "}\n"); + ASSERT_EQUALS(std::string(""), errout.str()); + } + + { + check("void foo()\n" + "{\n" + " std::vector foo;\n" + " for (unsigned int ii = 0; ii <= foo.size(); ++ii)\n" + " {\n" + " }\n" + "}\n"); + ASSERT_EQUALS(std::string(""), errout.str()); + } + } }; REGISTER_TEST(TestBufferOverrun)