Fixed #4876 (Checking for sizeof(void))

This commit is contained in:
Lucas Manuel Rodriguez 2013-07-05 21:07:07 +02:00 committed by Daniel Marjamäki
parent 61e1dd5096
commit 00886b4d06
3 changed files with 101 additions and 1 deletions

View File

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

View File

@ -58,6 +58,7 @@ public:
checkSizeof.checkSizeofForArrayParameter(); checkSizeof.checkSizeofForArrayParameter();
checkSizeof.checkSizeofForPointerSize(); checkSizeof.checkSizeofForPointerSize();
checkSizeof.checkSizeofForNumericParameter(); checkSizeof.checkSizeofForNumericParameter();
checkSizeof.sizeofVoid();
} }
/** @brief Run checks against the simplified token list */ /** @brief Run checks against the simplified token list */
@ -82,6 +83,9 @@ public:
/** @brief %Check for using sizeof with numeric given as function argument */ /** @brief %Check for using sizeof with numeric given as function argument */
void checkSizeofForNumericParameter(); void checkSizeofForNumericParameter();
/** @brief %Check for using sizeof(void) */
void sizeofVoid();
private: private:
// Error messages.. // Error messages..
void sizeofsizeofError(const Token* tok); void sizeofsizeofError(const Token* tok);
@ -91,6 +95,9 @@ private:
void sizeofForArrayParameterError(const Token* tok); void sizeofForArrayParameterError(const Token* tok);
void sizeofForPointerError(const Token* tok, const std::string &varname); void sizeofForPointerError(const Token* tok, const std::string &varname);
void sizeofForNumericParameterError(const Token* tok); 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 { void getErrorMessages(ErrorLogger* errorLogger, const Settings* settings) const {
CheckSizeof c(0, settings, errorLogger); CheckSizeof c(0, settings, errorLogger);
@ -102,6 +109,9 @@ private:
c.sizeofCalculationError(0, false); c.sizeofCalculationError(0, false);
c.multiplySizeofError(0); c.multiplySizeofError(0);
c.divideSizeofError(0); c.divideSizeofError(0);
c.sizeofVoidError(0);
c.sizeofDereferencedVoidPointerError(0, "varname");
c.arithOperationsOnVoidPointerError(0, "varname");
} }
static std::string myName() { static std::string myName() {
@ -116,7 +126,8 @@ private:
"* using sizeof(pointer) instead of the size of pointed data\n" "* using sizeof(pointer) instead of the size of pointed data\n"
"* look for 'sizeof sizeof ..'\n" "* look for 'sizeof sizeof ..'\n"
"* look for calculations inside 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";
} }
}; };
/// @} /// @}

View File

@ -39,6 +39,7 @@ private:
TEST_CASE(sizeofForArrayParameter); TEST_CASE(sizeofForArrayParameter);
TEST_CASE(sizeofForNumericParameter); TEST_CASE(sizeofForNumericParameter);
TEST_CASE(suspiciousSizeofCalculation); TEST_CASE(suspiciousSizeofCalculation);
TEST_CASE(sizeofVoid);
} }
void check(const char code[]) { void check(const char code[]) {
@ -47,6 +48,7 @@ private:
Settings settings; Settings settings;
settings.addEnabled("warning"); settings.addEnabled("warning");
settings.addEnabled("portability");
settings.inconclusive = true; settings.inconclusive = true;
// Tokenize.. // Tokenize..
@ -488,6 +490,50 @@ private:
"}"); "}");
ASSERT_EQUALS("", errout.str()); 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) REGISTER_TEST(TestSizeof)