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 "checksizeof.h"
|
||||||
#include "symboldatabase.h"
|
#include "symboldatabase.h"
|
||||||
|
#include <algorithm>
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
// Register this check class (by creating a static instance of it)
|
// 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 * !!*")) &&
|
(Token::Match(tok->tokAt(3)->variable()->typeStartToken(), "void * !!*")) &&
|
||||||
(!tok->tokAt(3)->variable()->isArray())) { // sizeof(*p) where p is of type "void*"
|
(!tok->tokAt(3)->variable()->isArray())) { // sizeof(*p) where p is of type "void*"
|
||||||
sizeofDereferencedVoidPointerError(tok, tok->strAt(3));
|
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;
|
int index = (tok->isName()) ? 0 : 1;
|
||||||
const Variable* var = tok->tokAt(index)->variable();
|
const Variable* var = tok->tokAt(index)->variable();
|
||||||
if (var && Token::Match(var->typeStartToken(), "void *")) {
|
if (var && Token::Match(var->typeStartToken(), "void *")) {
|
||||||
if (Token::Match(tok->previous(), ") %var% +|-") && // Check for cast on operations with +|-
|
std::string varname = tok->str();
|
||||||
!Token::Match(tok->previous()->link(), "( const| void *"))
|
// In case this 'void *' var is a member then go back to the main object
|
||||||
continue;
|
const Token* tok2 = tok->tokAt(index);
|
||||||
arithOperationsOnVoidPointerError(tok, tok->strAt(index), var->typeStartToken()->stringifyList(var->typeEndToken()->next()));
|
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"
|
" 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());
|
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