improved realloc checking '*p = realloc(*p,..'. Ticket: #1791

This commit is contained in:
Marek Zmysłowski 2011-10-11 22:07:14 +02:00 committed by Daniel Marjamäki
parent 00ae7dbda3
commit 07d8cd0a12
2 changed files with 64 additions and 4 deletions

View File

@ -2562,7 +2562,7 @@ void CheckMemoryLeakInFunction::checkReallocUsage()
const Token *tok = scope->classStart;
const Token *startOfFunction = tok;
// Search for the "var = realloc(var, 100);" pattern within this function
// Search for the "var = realloc(var, 100" pattern within this function
unsigned int indentlevel = 1;
for (tok = tok->next(); tok; tok = tok->next())
{
@ -2576,7 +2576,7 @@ void CheckMemoryLeakInFunction::checkReallocUsage()
}
if (tok->varId() > 0 &&
Token::Match(tok, "%var% = realloc|g_try_realloc ( %var% , %any% ) ;|}") &&
Token::Match(tok, "%var% = realloc|g_try_realloc ( %var% , %any%") &&
tok->varId() == tok->tokAt(4)->varId() &&
parameterVarIds.find(tok->varId()) == parameterVarIds.end())
{
@ -2585,10 +2585,11 @@ void CheckMemoryLeakInFunction::checkReallocUsage()
Token::findmatch(startOfFunction, "[{};] %varid% = %var% [;=]", tok->varId()))
continue;
const Token* tokEndRealloc = tok->tokAt(3)->link();
// Check that the allocation isn't followed immediately by an 'if (!var) { error(); }' that might handle failure
if (Token::Match(tok->tokAt(9), "if ( ! %varid% ) {", tok->varId()))
if (Token::Match(tokEndRealloc->tokAt(1), "; if ( ! %varid% ) {", tok->varId()))
{
const Token* tokEndBrace = tok->tokAt(14)->link();
const Token* tokEndBrace = tokEndRealloc->tokAt(7)->link();
if (tokEndBrace && Token::simpleMatch(tokEndBrace->tokAt(-2), ") ;") &&
Token::Match(tokEndBrace->tokAt(-2)->link()->tokAt(-2), "{|}|; %var% ("))
continue;
@ -2596,6 +2597,27 @@ void CheckMemoryLeakInFunction::checkReallocUsage()
memleakUponReallocFailureError(tok, tok->str());
}
else if (tok->tokAt(1)->varId() > 0 &&
(Token::Match(tok, "* %var% = realloc|g_try_realloc ( * %var% , %any%") &&
tok->tokAt(1)->varId() == tok->tokAt(6)->varId())&&
parameterVarIds.find(tok->tokAt(1)->varId()) == parameterVarIds.end())
{
// Check that another copy of the pointer wasn't saved earlier in the function
if (Token::findmatch(startOfFunction, "%var% = * %varid% ;", tok->tokAt(1)->varId()) ||
Token::findmatch(startOfFunction, "[{};] * %varid% = %var% [;=]", tok->tokAt(1)->varId()))
continue;
const Token* tokEndRealloc = tok->tokAt(4)->link();
// Check that the allocation isn't followed immediately by an 'if (!var) { error(); }' that might handle failure
if (Token::Match(tokEndRealloc->tokAt(1), "; if ( ! * %varid% ) {", tok->tokAt(1)->varId()))
{
const Token* tokEndBrace = tokEndRealloc->tokAt(8)->link();
if (tokEndBrace && Token::simpleMatch(tokEndBrace->tokAt(-2), ") ;") &&
Token::Match(tokEndBrace->tokAt(-2)->link()->tokAt(-2), "{|}|; %var% ("))
continue;
}
memleakUponReallocFailureError(tok->tokAt(1), tok->tokAt(1)->str());
}
}
}
}

View File

@ -264,6 +264,9 @@ private:
TEST_CASE(realloc9);
TEST_CASE(realloc10);
TEST_CASE(realloc11);
TEST_CASE(realloc12);
TEST_CASE(realloc13);
TEST_CASE(realloc14);
TEST_CASE(assign1);
TEST_CASE(assign2); // #2806 - FP when using redundant assignment
@ -2798,6 +2801,41 @@ private:
ASSERT_EQUALS("", errout.str());
}
void realloc12()
{
check("void foo(int x)\n"
"{\n"
" char *a = 0;\n"
" if ((a = realloc(a, x + 100)) == NULL)\n"
" return;\n"
" free(a);\n"
"}\n");
ASSERT_EQUALS("", errout.str());
}
void realloc13()
{
check("void foo()\n"
"{\n"
" char **str;\n"
" *str = realloc(*str,100);\n"
" free (*str);\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4]: (error) Common realloc mistake: \'str\' nulled but not freed upon failure\n", errout.str());
}
void realloc14()
{
check("void foo() {\n"
" char *p;\n"
" p = realloc(p, size + 1);\n"
" if (!p)\n"
" error();\n"
" usep(p);\n"
"}\n", false);
ASSERT_EQUALS("", errout.str());
}
void assign1()
{
check("void foo()\n"