Fixed #4908 (False positive: void * calculation (struct member, cast))
This commit is contained in:
parent
0c5e39a813
commit
59f448da8a
|
@ -20,6 +20,7 @@
|
|||
//---------------------------------------------------------------------------
|
||||
#include "checksizeof.h"
|
||||
#include "symboldatabase.h"
|
||||
#include <algorithm>
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// Register this check class (by creating a static instance of it)
|
||||
|
@ -291,14 +292,40 @@ void CheckSizeof::sizeofVoid()
|
|||
(Token::Match(tok->tokAt(3)->variable()->typeStartToken(), "void * !!*")) &&
|
||||
(!tok->tokAt(3)->variable()->isArray())) { // sizeof(*p) where p is of type "void*"
|
||||
sizeofDereferencedVoidPointerError(tok, tok->strAt(3));
|
||||
} else if (Token::Match(tok, "%var% +|-|++|--") || Token::Match(tok, "+|-|++|-- %var%")) { // Arithmetic operations on variable of type "void*"
|
||||
} else if (Token::Match(tok, "%var% +|-|++|--") ||
|
||||
Token::Match(tok, "+|-|++|-- %var%")) { // Arithmetic operations on variable of type "void*"
|
||||
int index = (tok->isName()) ? 0 : 1;
|
||||
const Variable* var = tok->tokAt(index)->variable();
|
||||
if (var && Token::Match(var->typeStartToken(), "void *")) {
|
||||
if (Token::Match(tok->previous(), ") %var% +|-") && // Check for cast on operations with +|-
|
||||
!Token::Match(tok->previous()->link(), "( const| void *"))
|
||||
continue;
|
||||
arithOperationsOnVoidPointerError(tok, tok->strAt(index), var->typeStartToken()->stringifyList(var->typeEndToken()->next()));
|
||||
std::string varname = tok->str();
|
||||
// In case this 'void *' var is a member then go back to the main object
|
||||
const Token* tok2 = tok->tokAt(index);
|
||||
if (index == 0) {
|
||||
bool isMember = false;
|
||||
while (Token::Match(tok2->previous(), ".")) {
|
||||
isMember = true;
|
||||
if (Token::Match(tok2->tokAt(-2), ")"))
|
||||
tok2 = tok2->tokAt(-2)->link();
|
||||
else if (Token::Match(tok2->tokAt(-2), "]"))
|
||||
tok2 = tok2->tokAt(-2)->link()->previous();
|
||||
else
|
||||
tok2 = tok2->tokAt(-2);
|
||||
}
|
||||
if (isMember) {
|
||||
// Get 'struct.member' complete name (without spaces)
|
||||
varname = tok2->stringifyList(tok->tokAt(index)->next());
|
||||
varname.erase(remove_if(varname.begin(), varname.end(),
|
||||
static_cast<int (*)(int)>(std::isspace)), varname.end());
|
||||
}
|
||||
}
|
||||
// Check for cast on operations with '+|-'
|
||||
if (Token::Match(tok, "%var% +|-")) {
|
||||
// Check for cast expression
|
||||
if (Token::Match(tok2->previous(), ")") && !Token::Match(tok2->previous()->link(), "( const| void *"))
|
||||
continue;
|
||||
}
|
||||
arithOperationsOnVoidPointerError(tok, varname,
|
||||
var->typeStartToken()->stringifyList(var->typeEndToken()->next()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -558,6 +558,54 @@ private:
|
|||
" void* data2 = (void *)data + 1;\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:2]: (portability) 'data' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.\n", errout.str());
|
||||
|
||||
// #4908 (void pointer as a member of a struct/class)
|
||||
check("struct FOO {\n"
|
||||
" void *data;\n"
|
||||
"};\n"
|
||||
"char f(struct FOO foo) {\n"
|
||||
" char x = *((char*)(foo.data+1));\n"
|
||||
" foo.data++;\n"
|
||||
" return x;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("[test.cpp:5]: (portability) 'foo.data' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.\n"
|
||||
"[test.cpp:6]: (portability) 'foo.data' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.\n", errout.str());
|
||||
|
||||
check("struct FOO {\n"
|
||||
" void *data;\n"
|
||||
"};\n"
|
||||
"char f(struct FOO foo) {\n"
|
||||
" char x = *((char*)foo.data+1);\n"
|
||||
" return x;\n"
|
||||
"}\n"
|
||||
"char f2(struct FOO foo) {\n"
|
||||
" char x = *((char*)((FOO)foo).data + 1);\n"
|
||||
" return x;\n"
|
||||
"}\n"
|
||||
"char f3(struct FOO* foo) {\n"
|
||||
" char x = *((char*)foo->data + 1);\n"
|
||||
" return x;\n"
|
||||
"}\n"
|
||||
"struct BOO {\n"
|
||||
" FOO data;\n"
|
||||
"};\n"
|
||||
"void f4(struct BOO* boo) {\n"
|
||||
" char c = *((char*)boo->data.data + 1);\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("struct FOO {\n"
|
||||
" void *data;\n"
|
||||
"};\n"
|
||||
"char f(struct FOO* foo) {\n"
|
||||
" char x = *(foo[1].data + 1);\n"
|
||||
" return x;\n"
|
||||
"}\n"
|
||||
"void f2(struct FOO* foo) {\n"
|
||||
" (foo[0]).data++;\n"
|
||||
"}");
|
||||
TODO_ASSERT_EQUALS("[test.cpp:5]: (portability) 'foo[1].data' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.\n"
|
||||
"[test.cpp:9]: (portability) 'foo[0].data' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.\n", "", errout.str());
|
||||
}
|
||||
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue