diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index 530e8c3df..0602bb1f5 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -466,6 +466,9 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, const Token * closingParenthesis = tok->linkAt(1); for (const Token *innerTok = tok->tokAt(2); innerTok && innerTok != closingParenthesis; innerTok = innerTok->next()) { // TODO: replace with checkTokenInsideExpression() + const Token* const openingPar = isFunctionCall(innerTok); + if (!openingPar) + checkTokenInsideExpression(innerTok, varInfo); if (!isLocalVarNoAutoDealloc(innerTok, mTokenizer->isCPP())) continue; @@ -502,7 +505,6 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, } // check for function call - const Token * const openingPar = isFunctionCall(innerTok); if (openingPar) { const Library::AllocFunc* allocFunc = mSettings->library.getDeallocFuncInfo(innerTok); // innerTok is a function name @@ -805,7 +807,8 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, const Token * vtok = typeEndTok->tokAt(3); const VarInfo::AllocInfo allocation(af ? af->groupId : (arrayDelete ? NEW_ARRAY : NEW), VarInfo::OWNED, ftok); changeAllocStatus(varInfo, allocation, vtok, vtok); - } + } else if (Token::Match(tok, "%var% .")) + checkTokenInsideExpression(tok, varInfo); } ret(endToken, varInfo, true); return true; @@ -930,8 +933,7 @@ void CheckLeakAutoVar::changeAllocStatus(VarInfo &varInfo, const VarInfo::AllocI void CheckLeakAutoVar::functionCall(const Token *tokName, const Token *tokOpeningPar, VarInfo &varInfo, const VarInfo::AllocInfo& allocation, const Library::AllocFunc* af) { // Ignore function call? - if (mSettings->library.isLeakIgnore(mSettings->library.getFunctionName(tokName))) - return; + const bool isLeakIgnore = mSettings->library.isLeakIgnore(mSettings->library.getFunctionName(tokName)); if (mSettings->library.getReallocFuncInfo(tokName)) return; @@ -990,6 +992,8 @@ void CheckLeakAutoVar::functionCall(const Token *tokName, const Token *tokOpenin varAlloc.allocTok = arg; } } + else if (isLeakIgnore) + checkTokenInsideExpression(arg, varInfo); else changeAllocStatus(varInfo, dealloc.type == 0 ? allocation : dealloc, tokName, arg); } diff --git a/test/cfg/posix.c b/test/cfg/posix.c index 474f16024..27f296de9 100644 --- a/test/cfg/posix.c +++ b/test/cfg/posix.c @@ -859,7 +859,7 @@ void memleak_scandir(void) which is allocated via malloc(3). If filter is NULL, all entries are selected.*/ - // TODO: cppcheck-suppress memleak + // cppcheck-suppress memleak } void no_memleak_scandir(void) diff --git a/test/testcondition.cpp b/test/testcondition.cpp index b2dc0da31..d83c64980 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -5202,6 +5202,16 @@ private: " for (int i = 0; i < N; a[i++] = false);\n" "}\n"); ASSERT_EQUALS("", errout.str()); + + check("void f() {\n" // #8192 + " for (int i = 0; i > 10; ++i) {}\n" + "}\n"); + TODO_ASSERT_EQUALS("[test.cpp:2]: (style) Condition 'i>10' is always false\n", "", errout.str()); + + check("void f() {\n" + " for (int i = 1000; i < 20; ++i) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2]: (style) Condition 'i<20' is always false\n", errout.str()); } void alwaysTrueTryCatch() diff --git a/test/testleakautovar.cpp b/test/testleakautovar.cpp index ed6983ec3..d5cd3874d 100644 --- a/test/testleakautovar.cpp +++ b/test/testleakautovar.cpp @@ -112,6 +112,7 @@ private: TEST_CASE(deallocuse11); // #8302 TEST_CASE(deallocuse12); TEST_CASE(deallocuse13); + TEST_CASE(deallocuse14); TEST_CASE(doublefree1); TEST_CASE(doublefree2); @@ -924,6 +925,25 @@ private: errout.str()); } + void deallocuse14() { + check("struct S { void f(); };\n" // #10905 + "void g() {\n" + " S* s = new S;\n" + " delete s;\n" + " s->f();\n" + "}\n", true); + ASSERT_EQUALS("[test.cpp:5]: (error) Dereferencing 's' after it is deallocated / released\n", + errout.str()); + + check("void f() {\n" + " int *p = (int*)malloc(4);\n" + " free(p);\n" + " if (*p == 5) {}\n" + "}\n"); + ASSERT_EQUALS("[test.c:4]: (error) Dereferencing 'p' after it is deallocated / released\n", + errout.str()); + } + void doublefree1() { // #3895 check("void f(char *p) {\n" " if (x)\n" @@ -2996,7 +3016,14 @@ private: " free(p);\n" " strcpy(a, p);\n" "}"); - TODO_ASSERT_EQUALS("error (free,use)", "", errout.str()); + ASSERT_EQUALS("[test.cpp:3]: (error) Dereferencing 'p' after it is deallocated / released\n", errout.str()); + + check("void f(char *p, const char *q) {\n" // #11665 + " free(p);\n" + " strcpy(p, q);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3]: (error) Dereferencing 'p' after it is deallocated / released\n", + errout.str()); check("void f(char *p) {\n" // #3041 - assigning pointer when it's used " free(p);\n" diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index 397cefa1e..238bea68e 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -6335,6 +6335,21 @@ private: "}"); ASSERT_EQUALS("[test.cpp:15] -> [test.cpp:17]: (warning) Uninitialized variable: pwd\n", errout.str()); + valueFlowUninit("size_t Read(unsigned char* buffer, size_t len);\n" // #11540 + "void f() {\n" + " const int N = 100;\n" + " uint8_t data[N];\n" + " size_t data_size = 0;\n" + " for (int i = 0; i < 10; i++) {\n" + " if (!data_size)\n" + " data_size = Read(data, N);\n" + " if (!data_size)\n" + " return;\n" + " if (data[0] == 0x47) {}\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + // #12033 valueFlowUninit("void g(const char*p);\n" "void f() {\n"