diff --git a/lib/checknullpointer.cpp b/lib/checknullpointer.cpp index e5f03cdf2..eb9c38f71 100644 --- a/lib/checknullpointer.cpp +++ b/lib/checknullpointer.cpp @@ -32,6 +32,16 @@ CheckNullPointer instance; //--------------------------------------------------------------------------- +/** Is string uppercase? */ +bool CheckNullPointer::isUpper(const std::string &str) +{ + for (unsigned int i = 0; i < str.length(); ++i) + { + if (str[i] >= 'a' && str[i] <= 'z') + return false; + } + return true; +} /** * @brief parse a function call and extract information about variable usage @@ -526,6 +536,17 @@ void CheckNullPointer::nullPointerByCheckAndDeRef() // - if there are logical operators // - if (x) { } else { ... } + // If the if-body ends with a unknown macro then bailout + { + // goto the end paranthesis + const Token *endpar = tok->next()->link(); + const Token *endbody = endpar ? endpar->next()->link() : 0; + if (endbody && + Token::Match(endbody->tokAt(-3), "[;{}] %var% ;") && + isUpper(endbody->tokAt(-2)->str())) + continue; + } + // vartok : token for the variable const Token *vartok = 0; if (Token::Match(tok, "if ( ! %var% ) {")) diff --git a/lib/checknullpointer.h b/lib/checknullpointer.h index 70927e70f..c1b134e91 100644 --- a/lib/checknullpointer.h +++ b/lib/checknullpointer.h @@ -60,6 +60,9 @@ public: checkNullPointer.executionPaths(); } + /** Is string uppercase? */ + static bool isUpper(const std::string &str); + /** * @brief parse a function call and extract information about variable usage * @param tok first token diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index 62b1ac33e..c1f5f28e6 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -33,18 +33,6 @@ CheckUninitVar instance; //--------------------------------------------------------------------------- -/** Is string uppercase? */ -static bool isUpper(const std::string &str) -{ - for (unsigned int i = 0; i < str.length(); ++i) - { - if (str[i] >= 'a' && str[i] <= 'z') - return false; - } - return true; -} - - /// @addtogroup Checks /// @{ @@ -679,7 +667,7 @@ private: } // ticket #2367 : unexpanded macro that uses sizeof|typeof? - else if (Token::Match(tok2, "%type% (") && isUpper(tok2->str())) + else if (Token::Match(tok2, "%type% (") && CheckNullPointer::isUpper(tok2->str())) { tok2 = tok2->next()->link(); if (!tok2) @@ -703,7 +691,7 @@ private: functionCall = functionCall ? functionCall->previous() : 0; if (functionCall) { - if (functionCall->isName() && !isUpper(functionCall->str()) && use_dead_pointer(checks, tok2)) + if (functionCall->isName() && !CheckNullPointer::isUpper(functionCall->str()) && use_dead_pointer(checks, tok2)) ExecutionPath::bailOutVar(checks, tok2->varId()); } } diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp index cd485e920..81263f9ce 100644 --- a/test/testnullpointer.cpp +++ b/test/testnullpointer.cpp @@ -859,6 +859,15 @@ private: " *p = 0;\n" "}\n"); ASSERT_EQUALS("[test.cpp:5]: (error) Possible null pointer dereference: p\n", errout.str()); + + // #2467 - unknown macro may terminate the application + check("void f(Fred *fred) {\n" + " if (fred == NULL) {\n" + " MACRO;\n" + " }\n" + " fred->a();\n" + "}"); + ASSERT_EQUALS("", errout.str()); } // Test CheckNullPointer::nullConstantDereference