diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index 2772ed99e..ac735a4af 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -600,16 +600,35 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken, endDeleterToken = typeEndTok->linkAt(2); } if (deleterToken) { + // Skip the decaying plus in expressions like +[](T*){} + if (deleterToken->str() == "+") { + deleterToken = deleterToken->next(); + } // Check if its a pointer to a function const Token * dtok = Token::findmatch(deleterToken, "& %name%", endDeleterToken); if (dtok) { af = _settings->library.dealloc(dtok->tokAt(1)); } else { + const Token * tscopeStart = nullptr; + const Token * tscopeEnd = nullptr; + // If the deleter is a lambda, check if it calls the dealloc function + if (deleterToken->str() == "[" && + Token::simpleMatch(deleterToken->link(), "] (") && + // TODO: Check for mutable keyword + Token::simpleMatch(deleterToken->link()->linkAt(1), ") {")) { + tscopeStart = deleterToken->link()->linkAt(1)->tokAt(1); + tscopeEnd = tscopeStart->link(); // If the deleter is a class, check if class calls the dealloc function - dtok = Token::findmatch(deleterToken, "%type%", endDeleterToken); - if (dtok && dtok->type()) { - const Scope * tscope = dtok->type()->classScope; - for (const Token *tok2 = tscope->bodyStart; tok2 != tscope->bodyEnd; tok2 = tok2->next()) { + } else if ((dtok = Token::findmatch(deleterToken, "%type%", endDeleterToken)) && dtok->type()) { + const Scope * tscope = dtok->type()->classScope; + if(tscope) { + tscopeStart = tscope->bodyStart; + tscopeEnd = tscope->bodyEnd; + } + } + + if(tscopeStart && tscopeEnd) { + for (const Token *tok2 = tscopeStart; tok2 != tscopeEnd; tok2 = tok2->next()) { af = _settings->library.dealloc(tok2); if (af) break; diff --git a/test/testleakautovar.cpp b/test/testleakautovar.cpp index 5cc651780..2938bd846 100644 --- a/test/testleakautovar.cpp +++ b/test/testleakautovar.cpp @@ -1255,6 +1255,44 @@ private: " std::unique_ptr xp(x, &destroy());\n" "}\n", true); ASSERT_EQUALS("", errout.str()); + + check("void f() {\n" + " FILE*f=fopen(fname,a);\n" + " std::shared_ptr fp{f, [](FILE* x) { fclose(x); }};\n" + "}", true); + ASSERT_EQUALS("", errout.str()); + + check("void f() {\n" + " FILE*f=fopen(fname,a);\n" + " std::shared_ptr fp{f, +[](FILE* x) { fclose(x); }};\n" + "}", true); + ASSERT_EQUALS("", errout.str()); + + check("void f() {\n" + " FILE*f=fopen(fname,a);\n" + " std::shared_ptr fp{f, [](FILE* x) { free(f); }};\n" + "}", true); + ASSERT_EQUALS("[test.cpp:3]: (error) Mismatching allocation and deallocation: f\n", errout.str()); + + check("void f() {\n" + " FILE*f=fopen(fname,a);\n" + " std::shared_ptr fp{f, [](FILE* x) {}};\n" + "}", true); + ASSERT_EQUALS("[test.cpp:3]: (error) Mismatching allocation and deallocation: f\n", errout.str()); + + check("class C;\n" + "void f() {\n" + " C* c = new C{};\n" + " std::shared_ptr a{c, [](C*) {}};\n" + "}", true); + ASSERT_EQUALS("", errout.str()); + + check("class C;\n" + "void f() {\n" + " C* c = new C{};\n" + " std::shared_ptr a{c, [](C* x) { delete x; }};\n" + "}", true); + ASSERT_EQUALS("", errout.str()); } void smartPointerRelease() { check("void f() {\n"