Fixed #4646 (false positive: (style, inconclusive) Technically the member function 'C<T>::operator+=' can be const.)

This commit is contained in:
Robert Reif 2013-03-14 06:34:12 +01:00 committed by Daniel Marjamäki
parent f43ea5c491
commit 4b9b87e310
5 changed files with 110 additions and 8 deletions

View File

@ -945,13 +945,17 @@ void CheckBufferOverrun::checkScope(const Token *tok, const std::vector<std::str
// Array index..
if ((varid > 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<MathLib::bigint> 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<Variable>::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);
}

View File

@ -210,7 +210,10 @@ public:
void arrayIndexOutOfBoundsError(const Token *tok, const ArrayInfo &arrayInfo, const std::vector<MathLib::bigint> &index);
void arrayIndexInForLoop(const Token *tok, const ArrayInfo &arrayInfo);
private:
bool isArrayOfStruct(const Token* tok, int &position);
void arrayIndexOutOfBoundsError(const std::list<const Token *> &callstack, const ArrayInfo &arrayInfo, const std::vector<MathLib::bigint> &index);
void bufferOverrunError(const Token *tok, const std::string &varnames = "");
void bufferOverrunError(const std::list<const Token *> &callstack, const std::string &varnames = "");

View File

@ -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")) {

View File

@ -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());
}

View File

@ -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"