Fixed #4646 (false positive: (style, inconclusive) Technically the member function 'C<T>::operator+=' can be const.)
This commit is contained in:
parent
f43ea5c491
commit
4b9b87e310
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 = "");
|
||||
|
|
|
@ -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")) {
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue