diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index 545019071..abd9b0efe 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -945,13 +945,17 @@ void CheckBufferOverrun::checkScope(const Token *tok, const std::vector 0 && ((tok->str() == "return" || (!tok->isName() && !Token::Match(tok, "[.&]"))) && Token::Match(tok->next(), "%varid% [ %num% ]", varid))) || - (varid == 0 && ((tok->str() == "return" || (!tok->isName() && !Token::Match(tok, "[.&]"))) && Token::Match(tok->next(), (varnames + " [ %num% ]").c_str())))) { + (varid == 0 && ((tok->str() == "return" || (!tok->isName() && !Token::Match(tok, "[.&]"))) && (Token::Match(tok->next(), (varnames + " [ %num% ]").c_str()) || Token::Match(tok->next(), (varname[0] +" [ %num% ] . " + varname[1] + " [ %num% ]").c_str()))))) { std::vector indexes; const Token *tok2 = tok->tokAt(2 + varc); for (; Token::Match(tok2, "[ %num% ]"); tok2 = tok2->tokAt(3)) { const MathLib::bigint index = MathLib::toLongNumber(tok2->strAt(1)); indexes.push_back(index); } + for (; Token::Match(tok2->tokAt(3), "[ %num% ]"); tok2 = tok2->tokAt(3)) { + const MathLib::bigint index = MathLib::toLongNumber(tok2->strAt(4)); + indexes.push_back(index); + } if (indexes.size() == arrayInfo.num().size()) { // Check if the indexes point outside the whole array.. @@ -1312,6 +1316,29 @@ void CheckBufferOverrun::checkScope(const Token *tok, const ArrayInfo &arrayInfo } } +//--------------------------------------------------------------------------- +// Checking member variables of structs.. +//--------------------------------------------------------------------------- +bool CheckBufferOverrun::isArrayOfStruct(const Token* tok, int &position) +{ + if (Token::Match(tok->next(), "%var% [ %num% ] ")) { + tok = tok->tokAt(4); + int i = 1; + while (true) { + if (Token::Match(tok->next(), "[ %num% ] ")) { + i++; + tok = tok->tokAt(4); + } else + break; + } + if (Token::Match(tok->next(),";")) { + position = i; + return true; + } + } + return false; +} + void CheckBufferOverrun::checkReadlinkBufferUsage(const Token* tok, const Token *scope_begin, const MathLib::bigint total_size, const bool is_readlinkat) { const Token* bufParam = tok->tokAt(2)->nextArgument(); @@ -1485,6 +1512,8 @@ void CheckBufferOverrun::checkStructVariable() std::list::const_iterator var; for (var = scope->varlist.begin(); var != scope->varlist.end(); ++var) { // find all array variables + int numOfDimension = -1; + if (var->isArray()) { // create ArrayInfo from the array variable ArrayInfo arrayInfo(&*var, _tokenizer); @@ -1530,6 +1559,17 @@ void CheckBufferOverrun::checkStructVariable() if (Token::Match(tok3->next(), "%var% ;")) varname[0] = tok3->strAt(1); + else if (isArrayOfStruct(tok3,numOfDimension)) { + varname[0] = tok3->strAt(1); + + int pos = 2; + for (int k = 0 ; k < numOfDimension; k++) { + for (int index = pos; index < (pos + 3); index++) + tok3->strAt(index); + pos += 3; + } + } + // Declare pointer or reference: Fred *fred1 else if (Token::Match(tok3->next(), "*|& %var% [,);=]")) varname[0] = tok3->strAt(2); @@ -1619,6 +1659,7 @@ void CheckBufferOverrun::checkStructVariable() std::string varnames; // use class and member name for messages for (unsigned int k = 0; k < varname.size(); ++k) varnames += (k == 0 ? "" : ".") + varname[k]; + temp.varname(varnames); checkScope(CheckTok, varname, temp); } diff --git a/lib/checkbufferoverrun.h b/lib/checkbufferoverrun.h index ee5647369..e6ea30bc5 100644 --- a/lib/checkbufferoverrun.h +++ b/lib/checkbufferoverrun.h @@ -210,7 +210,10 @@ public: void arrayIndexOutOfBoundsError(const Token *tok, const ArrayInfo &arrayInfo, const std::vector &index); void arrayIndexInForLoop(const Token *tok, const ArrayInfo &arrayInfo); + private: + + bool isArrayOfStruct(const Token* tok, int &position); void arrayIndexOutOfBoundsError(const std::list &callstack, const ArrayInfo &arrayInfo, const std::vector &index); void bufferOverrunError(const Token *tok, const std::string &varnames = ""); void bufferOverrunError(const std::list &callstack, const std::string &varnames = ""); diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 4c0843d53..11bc17625 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1661,7 +1661,7 @@ void SymbolDatabase::printOut(const char *title) const } std::cout << std::endl; - std::cout << " definedType: " << scope->definedType; + std::cout << " definedType: " << scope->definedType << std::endl; std::cout << " nestedList[" << scope->nestedList.size() << "] = ("; @@ -2165,8 +2165,12 @@ const Token *Scope::checkVariable(const Token *tok, AccessControl varaccess) } // friend? - if (Token::Match(tok, "friend %type%") && tok->next()->varId() == 0) - return Token::findsimplematch(tok->tokAt(2), ";"); + if (Token::Match(tok, "friend %type%") && tok->next()->varId() == 0) { + const Token *next = Token::findmatch(tok->tokAt(2), ";|{"); + if (next && next->str() == "{") + next = next->link(); + return next; + } // skip const|static|mutable|extern while (Token::Match(tok, "const|static|mutable|extern")) { diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index 90a2fcc21..d285f96c8 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -1429,23 +1429,64 @@ private: " var[ 0 ].arr[ 0 ] = 0;\n" " var[ 0 ].arr[ 1 ] = 1;\n" " var[ 0 ].arr[ 2 ] = 2;\n" - " y = var[ 0 ].arr[ 3 ];\n" + " y = var[ 0 ].arr[ 3 ];\n" // <-- array access out of bounds " return y;\n" "}\n"); - TODO_ASSERT_EQUALS("[test.cpp:10]: (error) Array 'var[0].arr[3]' index 3 out of bounds.\n","", errout.str()); + ASSERT_EQUALS("[test.cpp:10]: (error) Array 'var.arr[3]' accessed at index 3, which is out of bounds.\n", errout.str()); check("int f( )\n" "{\n" " struct {\n" " int arr[ 3 ];\n" " } var[ 1 ];\n" - " int y;\n" + " int y=1;\n" " var[ 0 ].arr[ 0 ] = 0;\n" " var[ 0 ].arr[ 1 ] = 1;\n" " var[ 0 ].arr[ 2 ] = 2;\n" " y = var[ 0 ].arr[ 2 ];\n" " return y;\n" - "}\n"); + "}"); + ASSERT_EQUALS("", errout.str()); + + + check("int f( ){ \n" + "struct Struct{\n" + " int arr[ 3 ];\n" + "};\n" + "int y;\n" + "Struct var;\n" + "var.arr[ 0 ] = 0;\n" + "var.arr[ 1 ] = 1;\n" + "var.arr[ 2 ] = 2;\n" + "var.arr[ 3 ] = 3;\n" // <-- array access out of bounds + "y=var.arr[ 3 ];\n" // <-- array access out of bounds + "return y;\n" + "}"); + ASSERT_EQUALS("[test.cpp:10]: (error) Array 'var.arr[3]' accessed at index 3, which is out of bounds.\n" + "[test.cpp:11]: (error) Array 'var.arr[3]' accessed at index 3, which is out of bounds.\n", errout.str()); + + + check("void f( ) {\n" + "struct S{\n" + " int var[ 3 ];\n" + "} ;\n" + "S var[2];\n" + "var[0].var[ 0 ] = 0;\n" + "var[0].var[ 1 ] = 1;\n" + "var[0].var[ 2 ] = 2;\n" + "var[0].var[ 4 ] = 4;\n" // <-- array access out of bounds + "}"); + ASSERT_EQUALS("[test.cpp:9]: (error) Array 'var.var[3]' accessed at index 4, which is out of bounds.\n", errout.str()); + + check("void f( ) {\n" + "struct S{\n" + " int var[ 3 ];\n" + "} ;\n" + "S var[2];\n" + "var[0].var[ 0 ] = 0;\n" + "var[0].var[ 1 ] = 1;\n" + "var[0].var[ 2 ] = 2;\n" + "}"); ASSERT_EQUALS("", errout.str()); } diff --git a/test/testclass.cpp b/test/testclass.cpp index 583b0674e..dffee9851 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -143,6 +143,7 @@ private: TEST_CASE(const56); // ticket #3149 TEST_CASE(const57); // tickets #2669 and #2477 TEST_CASE(const58); // ticket #2698 + TEST_CASE(const59); // ticket #4646 TEST_CASE(const_handleDefaultParameters); TEST_CASE(const_passThisToMemberOfOtherClass); TEST_CASE(assigningPointerToPointerIsNotAConstOperation); @@ -4697,6 +4698,18 @@ private: ASSERT_EQUALS("[test.cpp:3]: (style, inconclusive) Technically the member function 'MyObject::foo' can be const.\n", errout.str()); } + void const59() { // ticket #4646 + checkConst("class C {\n" + "public:\n" + " inline void operator += (const int &x ) { re += x; }\n" + " friend inline void exp(C & c, const C & x) { }\n" + "protected:\n" + " int re;\n" + " int im;\n" + "};"); + ASSERT_EQUALS("", errout.str()); + } + void const_handleDefaultParameters() { checkConst("struct Foo {\n" " void foo1(int i, int j = 0) {\n"