diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index 7e6c4f2f5..c2e914c28 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -206,6 +206,30 @@ static bool isPointerReleased(const Token *startToken, const Token *endToken, no return false; } +static bool checkVariable(const Token *varTok, const bool isCpp) +{ + // not a local variable nor argument? + const Variable *var = varTok->variable(); + if (var && !var->isArgument() && (!var->isLocal() || var->isStatic())) + return false; + + // Don't check reference variables + if (var && var->isReference()) + return false; + + // non-pod variable + if (isCpp) { + if (!var) + return false; + // Possibly automatically deallocated memory + if (!var->typeStartToken()->isStandardType() && Token::Match(varTok, "%var% = new")) + return false; + if (!var->isPointer() && !var->typeStartToken()->isStandardType()) + return false; + } + return true; +} + /** checks if nameToken is a name of a function in a function call: * func(arg) * or @@ -318,26 +342,9 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken, leakIfAllocated(varTok, *varInfo); varInfo->erase(varTok->varId()); - // not a local variable nor argument? - const Variable *var = varTok->variable(); - if (var && !var->isArgument() && (!var->isLocal() || var->isStatic())) + if (!checkVariable(varTok, mTokenizer->isCPP())) continue; - // Don't check reference variables - if (var && var->isReference()) - continue; - - // non-pod variable - if (mTokenizer->isCPP()) { - if (!var) - continue; - // Possibly automatically deallocated memory - if (!var->typeStartToken()->isStandardType() && Token::Match(varTok, "%var% = new")) - continue; - if (!var->isPointer() && !var->typeStartToken()->isStandardType()) - continue; - } - // allocation? const Token *const fTok = tokRightAstOperand ? tokRightAstOperand->previous() : nullptr; if (Token::Match(fTok, "%type% (")) { @@ -375,6 +382,9 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken, for (const Token *innerTok = tok->tokAt(2); innerTok && innerTok != closingParenthesis; innerTok = innerTok->next()) { // TODO: replace with checkTokenInsideExpression() + if (!checkVariable(innerTok, mTokenizer->isCPP())) + continue; + if (Token::Match(innerTok, "%var% =") && innerTok->astParent() == innerTok->next()) { // allocation? // right ast part (after `=` operator) diff --git a/test/testleakautovar.cpp b/test/testleakautovar.cpp index 4780d83b3..8aea0b030 100644 --- a/test/testleakautovar.cpp +++ b/test/testleakautovar.cpp @@ -121,6 +121,7 @@ private: TEST_CASE(ifelse12); // #8340 - if ((*p = malloc(4)) == NULL) TEST_CASE(ifelse13); // #8392 TEST_CASE(ifelse14); // #9130 - if (x == (char*)NULL) + TEST_CASE(ifelse15); // #9206 - if (global_ptr = malloc(1)) // switch TEST_CASE(switch1); @@ -1364,6 +1365,23 @@ private: ASSERT_EQUALS("", errout.str()); } + void ifelse15() { // #9206 + check("struct SSS { int a; };\n" + "SSS* global_ptr;\n" + "void test_alloc() {\n" + " if ( global_ptr = new SSS()) {}\n" + " return;\n" + "}", true); + ASSERT_EQUALS("", errout.str()); + + check("FILE* hFile;\n" + "int openFile( void ) {\n" + " if ((hFile = fopen(\"1.txt\", \"wb\" )) == NULL) return 0;\n" + " return 1;\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } + void switch1() { check("void f() {\n" " char *p = 0;\n"