Fixed #4908 (False positive: void * calculation (struct member, cast))

This commit is contained in:
Lucas Manuel Rodriguez 2013-07-20 17:20:16 +02:00 committed by Daniel Marjamäki
parent 0c5e39a813
commit 59f448da8a
2 changed files with 80 additions and 5 deletions

View File

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

View File

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