diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp index 1ccbf66b2..7562b6f8e 100644 --- a/lib/checkmemoryleak.cpp +++ b/lib/checkmemoryleak.cpp @@ -2698,8 +2698,15 @@ void CheckMemoryLeakNoVar::checkForUnusedReturnValue(const Scope *scope) while (parent && parent->str() == "(" && !parent->astOperand2()) parent = parent->astParent(); - if (!parent || Token::Match(parent, "%comp%|!")) + if (!parent) { + // Check if we are in a C++11 constructor + const Token * closingBrace = Token::findmatch(tok, "}|;"); + if(closingBrace->str() == "}" && Token::Match(closingBrace->link()->tokAt(-1), "%name%")) + continue; returnValueNotUsedError(tok, tok->str()); + } else if (Token::Match(parent, "%comp%|!")) { + returnValueNotUsedError(tok, tok->str()); + } } } diff --git a/test/testmemleak.cpp b/test/testmemleak.cpp index cd461ae68..9a9ece2b0 100644 --- a/test/testmemleak.cpp +++ b/test/testmemleak.cpp @@ -5747,6 +5747,7 @@ private: // pass allocated memory to function using a smart pointer TEST_CASE(smartPointerFunctionParam); + TEST_CASE(resourceLeak); } void functionParameter() { @@ -5954,6 +5955,72 @@ private: "}"); ASSERT_EQUALS("", errout.str()); } + void resourceLeak() { + check("void foo() {\n" + " fopen(\"file.txt\", \"r\");\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2]: (error) Return value of allocation function 'fopen' is not stored.\n", errout.str()); + + check("struct Holder {\n" + " Holder(FILE* f) : file(f) {}\n" + " ~Holder() { fclose(file); }\n" + " FILE* file;\n" + "};\n" + "void foo() {\n" + " Holder h ( fopen(\"file.txt\", \"r\"));\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + check("struct Holder {\n" + " Holder(FILE* f) : file(f) {}\n" + " ~Holder() { fclose(file); }\n" + " FILE* file;\n" + "};\n" + "void foo() {\n" + " Holder ( fopen(\"file.txt\", \"r\"));\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + check("struct Holder {\n" + " Holder(FILE* f) : file(f) {}\n" + " ~Holder() { fclose(file); }\n" + " FILE* file;\n" + "};\n" + "void foo() {\n" + " Holder h { fopen(\"file.txt\", \"r\")};\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + check("struct Holder {\n" + " Holder(FILE* f) : file(f) {}\n" + " ~Holder() { fclose(file); }\n" + " FILE* file;\n" + "};\n" + "void foo() {\n" + " Holder h = fopen(\"file.txt\", \"r\");\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + check("struct Holder {\n" + " Holder(FILE* f) : file(f) {}\n" + " ~Holder() { fclose(file); }\n" + " FILE* file;\n" + "};\n" + "void foo() {\n" + " Holder { fopen(\"file.txt\", \"r\")};\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + check("struct Holder {\n" + " Holder(int i, FILE* f) : file(f) {}\n" + " ~Holder() { fclose(file); }\n" + " FILE* file;\n" + "};\n" + "void foo() {\n" + " Holder { 0, fopen(\"file.txt\", \"r\")};\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + } }; REGISTER_TEST(TestMemleakNoVar)