diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index 85fafd9fb..4206a4ac2 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -1931,6 +1931,19 @@ void CheckBufferOverrun::negativeIndex() const Variable *var = _tokenizer->getSymbolDatabase()->getVariableFromVarId(tok2->previous()->varId()); if (var && var->isArray()) negativeIndexError(tok, index); + + // check if this variable is a member of a class/struct + else if (!var && Token::Match(tok2->tokAt(-3), "%var% .")) + { + var = _tokenizer->getSymbolDatabase()->getVariableFromVarId(tok2->tokAt(-3)->varId()); + if (var && var->type()) + { + // get the variable type from the class/struct + const Variable *var2 = var->type()->getVariable(tok2->previous()->str()); + if (var2 && var2->isArray()) + negativeIndexError(tok, index); + } + } } } } diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index e6a80b9f2..bf5f1f476 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1784,6 +1784,19 @@ const Token *Scope::checkVariable(const Token *tok, AccessControl varaccess) return tok; } +const Variable *Scope::getVariable(const std::string &varname) const +{ + std::list::const_iterator iter; + + for (iter = varlist.begin(); iter != varlist.end(); ++iter) + { + if (iter->name() == varname) + return &*iter; + } + + return NULL; +} + const Token* skipScopeIdentifiers(const Token* tok) { const Token* ret = tok; diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 5e8530850..75df8c8ea 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -521,6 +521,13 @@ public: */ const Token *checkVariable(const Token *tok, AccessControl varaccess); + /** + * @brief get variable from name + * @param varname name of variable + * @return pointer to variable + */ + const Variable *getVariable(const std::string &varname) const; + private: /** * @brief helper function for getVariableList() diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index a956e4c5e..18367ad3a 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -114,7 +114,8 @@ private: TEST_CASE(array_index_switch_in_for); TEST_CASE(array_index_for_in_for); // FP: #2634 TEST_CASE(array_index_calculation); - TEST_CASE(array_index_negative); + TEST_CASE(array_index_negative1); + TEST_CASE(array_index_negative2); // ticket #3063 TEST_CASE(array_index_for_decr); TEST_CASE(array_index_varnames); // FP: struct member. #1576 TEST_CASE(array_index_for_break); // FP: for,break @@ -1278,7 +1279,7 @@ private: ASSERT_EQUALS("[test.cpp:5]: (error) Array 'arr[5]' index 11 out of bounds\n", errout.str()); } - void array_index_negative() + void array_index_negative1() { // #948 - array index out of bound not detected 'a[-1] = 0' check("void f()\n" @@ -1318,6 +1319,16 @@ private: ASSERT_EQUALS("", errout.str()); } + void array_index_negative2() // ticket #3063 + { + check("struct TEST { char a[10]; };\n" + "void foo() {\n" + " TEST test;\n" + " test.a[-1] = 3;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (error) Array index -1 is out of bounds\n", errout.str()); + } + void array_index_for_decr() { check("void f()\n"