From cd36f8ed0a1144667b95416a249e290b127d3cc3 Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Mon, 12 Aug 2019 12:53:59 +0200 Subject: [PATCH] Fix #9253: leakNoVarFunctionCall: do not warn if freopen opens standard stream (#2076) This fixes false positives from daca@home where freopen is used to reopen a standard stream. There is no longer a warning for void f() { assert(freopen("/dev/null", "r", stdin)); } --- lib/checkmemoryleak.cpp | 25 +++++++++++++++++-------- lib/checkmemoryleak.h | 5 +++++ test/testmemleak.cpp | 5 +++++ 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp index 736f735a2..5a37a7f3e 100644 --- a/lib/checkmemoryleak.cpp +++ b/lib/checkmemoryleak.cpp @@ -259,6 +259,19 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok return No; } +bool CheckMemoryLeak::isReopenStandardStream(const Token *tok) const +{ + if (getReallocationType(tok, 0) == File) { + const Library::AllocFunc *f = mSettings_->library.getReallocFuncInfo(tok); + if (f && f->reallocArg > 0 && f->reallocArg <= numberOfArguments(tok)) { + const Token* arg = getArguments(tok).at(f->reallocArg - 1); + if (Token::Match(arg, "stdin|stdout|stderr")) + return true; + } + } + return false; +} + //-------------------------------------------------------------------------- @@ -979,6 +992,8 @@ void CheckMemoryLeakNoVar::check() functionName == "fclose" || functionName == "realloc") break; + if (isReopenStandardStream(tok->next())) + continue; if (CheckMemoryLeakInFunction::test_white_list(functionName, mSettings, mTokenizer->isCPP())) { functionCallLeak(tok, tok->strAt(1), functionName); break; @@ -1006,14 +1021,8 @@ void CheckMemoryLeakNoVar::checkForUnusedReturnValue(const Scope *scope) if (tok != tok->next()->astOperand1()) continue; - if (getReallocationType(tok, 0) == File) { - const Library::AllocFunc *f = mSettings->library.getReallocFuncInfo(tok); - if (f && f->reallocArg > 0 && f->reallocArg <= numberOfArguments(tok)) { - const Token* arg = getArguments(tok).at(f->reallocArg - 1); - if (Token::Match(arg, "stdin|stdout|stderr")) - continue; - } - } + if (isReopenStandardStream(tok)) + continue; // get ast parent, skip casts const Token *parent = tok->next()->astParent(); diff --git a/lib/checkmemoryleak.h b/lib/checkmemoryleak.h index 91ab1859f..203668d05 100644 --- a/lib/checkmemoryleak.h +++ b/lib/checkmemoryleak.h @@ -114,6 +114,11 @@ public: */ AllocType getReallocationType(const Token *tok2, nonneg int varid) const; + /** + * Check if token reopens a standard stream + * @param tok token to check + */ + bool isReopenStandardStream(const Token *tok) const; /** * Report that there is a memory leak (new/malloc/etc) * @param tok token where memory is leaked diff --git a/test/testmemleak.cpp b/test/testmemleak.cpp index 9e902ae6c..4932bfc3d 100644 --- a/test/testmemleak.cpp +++ b/test/testmemleak.cpp @@ -2139,6 +2139,11 @@ private: " 42, strcmp(strdup(a), b);\n" "}"); ASSERT_EQUALS("[test.cpp:3]: (error) Allocation with strdup, strcmp doesn't release it.\n", errout.str()); + + check("void f() {\n" + " assert(freopen(\"/dev/null\", \"r\", stdin));\n" + "}"); + ASSERT_EQUALS("", errout.str()); } void missingAssignment() {