diff --git a/lib/checksizeof.cpp b/lib/checksizeof.cpp index 2e403f1e9..c047ece98 100644 --- a/lib/checksizeof.cpp +++ b/lib/checksizeof.cpp @@ -295,7 +295,10 @@ void CheckSizeof::sizeofVoid() 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()); + 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())); } } } @@ -315,9 +318,9 @@ void CheckSizeof::sizeofDereferencedVoidPointerError(const Token *tok, const std reportError(tok, Severity::portability, "sizeofDereferencedVoidPointer", message + "\n" + verbose); } -void CheckSizeof::arithOperationsOnVoidPointerError(const Token* tok, const std::string &varname) +void CheckSizeof::arithOperationsOnVoidPointerError(const Token* tok, const std::string &varname, const std::string &vartype) { - const std::string message = "'" + varname + "' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined."; + const std::string message = "'" + varname + "' is of type '" + vartype + "'. 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); } diff --git a/lib/checksizeof.h b/lib/checksizeof.h index 78c9794c7..cf27769d6 100644 --- a/lib/checksizeof.h +++ b/lib/checksizeof.h @@ -97,7 +97,7 @@ private: 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 arithOperationsOnVoidPointerError(const Token* tok, const std::string &varname, const std::string &vartype); void getErrorMessages(ErrorLogger* errorLogger, const Settings* settings) const { CheckSizeof c(0, settings, errorLogger); @@ -111,7 +111,7 @@ private: c.divideSizeofError(0); c.sizeofVoidError(0); c.sizeofDereferencedVoidPointerError(0, "varname"); - c.arithOperationsOnVoidPointerError(0, "varname"); + c.arithOperationsOnVoidPointerError(0, "varname", "vartype"); } static std::string myName() { diff --git a/test/testsizeof.cpp b/test/testsizeof.cpp index 707ceb550..d2fb4bc9c 100644 --- a/test/testsizeof.cpp +++ b/test/testsizeof.cpp @@ -531,6 +531,33 @@ private: " int j = sizeof(*p1);\n" "}"); ASSERT_EQUALS("", errout.str()); + + // Calculations on void* with casts + + check("void f(void *data) {\n" + " *((unsigned char *)data + 1) = 0;\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + check("void f(void *data) {\n" + " *((unsigned char *)(data) + 1) = 0;\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + check("void f(void *data) {\n" + " unsigned char* c = (unsigned char *)(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()); + + check("void f(void *data) {\n" + " unsigned char* c = (unsigned char *)data++;\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()); + + check("void f(void *data) {\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()); } };