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, "
|
"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);
|
||||||
|
}
|
||||||
|
|
|
@ -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";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
/// @}
|
/// @}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue