Fixed #4876 (Checking for sizeof(void))
This commit is contained in:
parent
61e1dd5096
commit
00886b4d06
|
@ -278,3 +278,46 @@ void CheckSizeof::divideSizeofError(const Token *tok)
|
|||
"Division of result of sizeof() on pointer type. sizeof() returns the size of the pointer, "
|
||||
"not the size of the memory area it points to.", true);
|
||||
}
|
||||
|
||||
void CheckSizeof::sizeofVoid()
|
||||
{
|
||||
if (!_settings->isEnabled("portability"))
|
||||
return;
|
||||
|
||||
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
|
||||
if (Token::simpleMatch(tok, "sizeof ( )")) { // "sizeof(void)" gets simplified to sizeof ( )
|
||||
sizeofVoidError(tok);
|
||||
} else if (Token::Match(tok, "sizeof ( * %var% )") && tok->tokAt(3)->variable() &&
|
||||
(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*"
|
||||
int index = (tok->isName()) ? 0 : 1;
|
||||
const Variable* var = tok->tokAt(index)->variable();
|
||||
if (var && Token::Match(var->typeStartToken(), "void *")) {
|
||||
arithOperationsOnVoidPointerError(tok, tok->tokAt(index)->str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CheckSizeof::sizeofVoidError(const Token *tok)
|
||||
{
|
||||
const std::string message = "Behaviour of 'sizeof(void)' is not covered by the ISO C standard.";
|
||||
const std::string verbose = message + " A value for 'sizeof(void)' is defined only as part of a GNU C extension, which defines 'sizeof(void)' to be 1.";
|
||||
reportError(tok, Severity::portability, "sizeofVoid", message + "\n" + verbose);
|
||||
}
|
||||
|
||||
void CheckSizeof::sizeofDereferencedVoidPointerError(const Token *tok, const std::string &varname)
|
||||
{
|
||||
const std::string message = "'*" + varname + "' is of type 'void', the behaviour of 'sizeof(void)' is not covered by the ISO C standard.";
|
||||
const std::string verbose = message + " A value for 'sizeof(void)' is defined only as part of a GNU C extension, which defines 'sizeof(void)' to be 1.";
|
||||
reportError(tok, Severity::portability, "sizeofDereferencedVoidPointer", message + "\n" + verbose);
|
||||
}
|
||||
|
||||
void CheckSizeof::arithOperationsOnVoidPointerError(const Token* tok, const std::string &varname)
|
||||
{
|
||||
const std::string message = "'" + varname + "' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.";
|
||||
const std::string verbose = message + " Arithmetic operations on 'void *' is a GNU C extension, which defines the 'sizeof(void)' to be 1.";
|
||||
reportError(tok, Severity::portability, "arithOperationsOnVoidPointer", message + "\n" + verbose);
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ public:
|
|||
checkSizeof.checkSizeofForArrayParameter();
|
||||
checkSizeof.checkSizeofForPointerSize();
|
||||
checkSizeof.checkSizeofForNumericParameter();
|
||||
checkSizeof.sizeofVoid();
|
||||
}
|
||||
|
||||
/** @brief Run checks against the simplified token list */
|
||||
|
@ -82,6 +83,9 @@ public:
|
|||
/** @brief %Check for using sizeof with numeric given as function argument */
|
||||
void checkSizeofForNumericParameter();
|
||||
|
||||
/** @brief %Check for using sizeof(void) */
|
||||
void sizeofVoid();
|
||||
|
||||
private:
|
||||
// Error messages..
|
||||
void sizeofsizeofError(const Token* tok);
|
||||
|
@ -91,6 +95,9 @@ private:
|
|||
void sizeofForArrayParameterError(const Token* tok);
|
||||
void sizeofForPointerError(const Token* tok, const std::string &varname);
|
||||
void sizeofForNumericParameterError(const Token* tok);
|
||||
void sizeofVoidError(const Token *tok);
|
||||
void sizeofDereferencedVoidPointerError(const Token *tok, const std::string &varname);
|
||||
void arithOperationsOnVoidPointerError(const Token* tok, const std::string &varname);
|
||||
|
||||
void getErrorMessages(ErrorLogger* errorLogger, const Settings* settings) const {
|
||||
CheckSizeof c(0, settings, errorLogger);
|
||||
|
@ -102,6 +109,9 @@ private:
|
|||
c.sizeofCalculationError(0, false);
|
||||
c.multiplySizeofError(0);
|
||||
c.divideSizeofError(0);
|
||||
c.sizeofVoidError(0);
|
||||
c.sizeofDereferencedVoidPointerError(0, "varname");
|
||||
c.arithOperationsOnVoidPointerError(0, "varname");
|
||||
}
|
||||
|
||||
static std::string myName() {
|
||||
|
@ -116,7 +126,8 @@ private:
|
|||
"* using sizeof(pointer) instead of the size of pointed data\n"
|
||||
"* look for 'sizeof sizeof ..'\n"
|
||||
"* look for calculations inside sizeof()\n"
|
||||
"* look for suspicious calculations with sizeof()\n";
|
||||
"* look for suspicious calculations with sizeof()\n"
|
||||
"* using 'sizeof(void)' which is undefined\n";
|
||||
}
|
||||
};
|
||||
/// @}
|
||||
|
|
|
@ -39,6 +39,7 @@ private:
|
|||
TEST_CASE(sizeofForArrayParameter);
|
||||
TEST_CASE(sizeofForNumericParameter);
|
||||
TEST_CASE(suspiciousSizeofCalculation);
|
||||
TEST_CASE(sizeofVoid);
|
||||
}
|
||||
|
||||
void check(const char code[]) {
|
||||
|
@ -47,6 +48,7 @@ private:
|
|||
|
||||
Settings settings;
|
||||
settings.addEnabled("warning");
|
||||
settings.addEnabled("portability");
|
||||
settings.inconclusive = true;
|
||||
|
||||
// Tokenize..
|
||||
|
@ -488,6 +490,50 @@ private:
|
|||
"}");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void sizeofVoid() {
|
||||
check("void f() {\n"
|
||||
" int size = sizeof(void);\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:2]: (portability) Behaviour of 'sizeof(void)' is not covered by the ISO C standard.\n", errout.str());
|
||||
|
||||
check("void f() {\n"
|
||||
" void* p;\n"
|
||||
" int size = sizeof(*p);\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:3]: (portability) '*p' is of type 'void', the behaviour of 'sizeof(void)' is not covered by the ISO C standard.\n", errout.str());
|
||||
|
||||
check("void f() {\n"
|
||||
" void* p = malloc(10);\n"
|
||||
" int* p2 = p + 4;\n"
|
||||
" int* p3 = p - 1;\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:3]: (portability) 'p' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.\n"
|
||||
"[test.cpp:4]: (portability) 'p' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.\n", errout.str());
|
||||
|
||||
check("void f() {\n"
|
||||
" void* p1 = malloc(10);\n"
|
||||
" void* p2 = malloc(5);\n"
|
||||
" p1--;\n"
|
||||
" p2++;\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:4]: (portability) 'p1' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.\n"
|
||||
"[test.cpp:5]: (portability) 'p2' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.\n", errout.str());
|
||||
|
||||
check("void f() {\n"
|
||||
" void** p1;\n"
|
||||
" int j = sizeof(*p1);\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("void f() {\n"
|
||||
" void* p1[5];\n"
|
||||
" int j = sizeof(*p1);\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
REGISTER_TEST(TestSizeof)
|
||||
|
||||
|
|
Loading…
Reference in New Issue