Fixed #1649 (add a warning for potential memory leaks when using realloc)

This commit is contained in:
Zachary Blair 2010-05-17 22:46:48 -07:00
parent 0d7474042a
commit 1539c0b3d2
4 changed files with 53 additions and 6 deletions

View File

@ -337,6 +337,11 @@ void CheckMemoryLeak::memleakError(const Token *tok, const std::string &varname)
reportErr(tok, Severity::error, "memleak", "Memory leak: " + varname); reportErr(tok, Severity::error, "memleak", "Memory leak: " + varname);
} }
void CheckMemoryLeak::memleakUponReallocFailureError(const Token *tok, const std::string &varname)
{
reportErr(tok, Severity::error, "memleakOnRealloc", "Memory leak: \"" + varname + "\" nulled but not freed upon failure");
}
void CheckMemoryLeak::resourceLeakError(const Token *tok, const std::string &varname) void CheckMemoryLeak::resourceLeakError(const Token *tok, const std::string &varname)
{ {
std::string errmsg("Resource leak"); std::string errmsg("Resource leak");
@ -2103,6 +2108,29 @@ void CheckMemoryLeakInFunction::checkScope(const Token *Tok1, const std::string
//---------------------------------------------------------------------------
// Check for memory leaks due to improper realloc() usage.
// Below, "a" may be set to null without being freed if realloc() cannot
// allocate the requested memory:
// a = malloc(10); a = realloc(a, 100);
//---------------------------------------------------------------------------
void CheckMemoryLeakInFunction::checkReallocUsage()
{
const Token *tok = _tokenizer->tokens();
for (; tok; tok = tok->next())
{
if (Token::Match(tok, "%var% = realloc|g_try_realloc ( %var% ,"))
{
if (tok->varId() == tok->tokAt(4)->varId())
{
memleakUponReallocFailureError(tok, tok->str());
}
}
}
}
//---------------------------------------------------------------------------

View File

@ -140,6 +140,7 @@ public:
void deallocuseError(const Token *tok, const std::string &varname); void deallocuseError(const Token *tok, const std::string &varname);
void mismatchSizeError(const Token *tok, const std::string &sz); void mismatchSizeError(const Token *tok, const std::string &sz);
void mismatchAllocDealloc(const std::list<const Token *> &callstack, const std::string &varname); void mismatchAllocDealloc(const std::list<const Token *> &callstack, const std::string &varname);
void memleakUponReallocFailureError(const Token *tok, const std::string &varname);
/** What type of allocated memory does the given function return? */ /** What type of allocated memory does the given function return? */
AllocType functionReturnType(const Token *tok) const; AllocType functionReturnType(const Token *tok) const;
@ -179,6 +180,7 @@ public:
void runSimplifiedChecks(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog) void runSimplifiedChecks(const Tokenizer *tokenizr, const Settings *settings, ErrorLogger *errLog)
{ {
CheckMemoryLeakInFunction checkMemoryLeak(tokenizr, settings, errLog); CheckMemoryLeakInFunction checkMemoryLeak(tokenizr, settings, errLog);
checkMemoryLeak.checkReallocUsage();
checkMemoryLeak.check(); checkMemoryLeak.check();
} }
@ -191,6 +193,11 @@ public:
/** @brief experimental: checking via ExecutionPath */ /** @brief experimental: checking via ExecutionPath */
void localleaks(); void localleaks();
/**
* Checking for a memory leak caused by improper realloc usage.
*/
void checkReallocUsage();
/** /**
* @brief %Check all variables in function scope * @brief %Check all variables in function scope
* @param tok The first '{' token of the function body * @param tok The first '{' token of the function body
@ -298,6 +305,7 @@ public:
mismatchSizeError(0, "sz"); mismatchSizeError(0, "sz");
std::list<const Token *> callstack; std::list<const Token *> callstack;
mismatchAllocDealloc(callstack, "varname"); mismatchAllocDealloc(callstack, "varname");
memleakUponReallocFailureError(0, "varname");
} }
/** /**

View File

@ -5187,6 +5187,15 @@ bool Tokenizer::simplifyKnownVariables()
break; break;
} }
// Variable used in realloc (see Ticket #1649)
if (Token::Match(tok3, "%var% = realloc ( %var% ,") &&
tok3->varId() == varid &&
tok3->tokAt(4)->varId() == varid)
{
tok3->tokAt(4)->str(value);
ret = true;
}
// Variable is used somehow in a non-defined pattern => bail out // Variable is used somehow in a non-defined pattern => bail out
if (tok3->varId() == varid) if (tok3->varId() == varid)
break; break;

View File

@ -216,7 +216,7 @@ private:
settings.inconclusive = showAll; settings.inconclusive = showAll;
tokenizer.fillFunctionList(); tokenizer.fillFunctionList();
CheckMemoryLeakInFunction checkMemoryLeak(&tokenizer, &settings, this); CheckMemoryLeakInFunction checkMemoryLeak(&tokenizer, &settings, this);
checkMemoryLeak.check(); checkMemoryLeak.runSimplifiedChecks(&tokenizer, &settings, this);
} }
@ -1085,7 +1085,7 @@ private:
" ;\n" " ;\n"
" free(buf);\n" " free(buf);\n"
"}\n"); "}\n");
TODO_ASSERT_EQUALS("[test.cpp:6]: (error) Memory leak: buf\n", errout.str()); ASSERT_EQUALS("[test.cpp:6]: (error) Memory leak: \"buf\" nulled but not freed upon failure\n", errout.str());
} }
void if11() void if11()
@ -1174,7 +1174,7 @@ private:
"\n" "\n"
" return a;\n" " return a;\n"
"}\n", true); "}\n", true);
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("[test.cpp:9]: (error) Memory leak: \"a\" nulled but not freed upon failure\n", errout.str());
} }
@ -1195,7 +1195,8 @@ private:
"\n" "\n"
" return a;\n" " return a;\n"
"}\n", true); "}\n", true);
ASSERT_EQUALS("[test.cpp:11]: (error) Memory leak: a\n", errout.str()); ASSERT_EQUALS("[test.cpp:9]: (error) Memory leak: \"a\" nulled but not freed upon failure\n"
"[test.cpp:11]: (error) Memory leak: a\n", errout.str());
} }
@ -1791,7 +1792,8 @@ private:
" char *a = (char *)malloc(10);\n" " char *a = (char *)malloc(10);\n"
" a = realloc(a, 100);\n" " a = realloc(a, 100);\n"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:5]: (error) Memory leak: a\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (error) Memory leak: \"a\" nulled but not freed upon failure\n"
"[test.cpp:5]: (error) Memory leak: a\n", errout.str());
} }
void realloc2() void realloc2()
@ -1803,7 +1805,7 @@ private:
" free(a);\n" " free(a);\n"
"}\n"); "}\n");
TODO_ASSERT_EQUALS("[test.cpp:5]: (error) Memory leak: a\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (error) Memory leak: \"a\" nulled but not freed upon failure\n", errout.str());
} }
void realloc3() void realloc3()