improved realloc checking '*p = realloc(*p,..'. Ticket: #1791
This commit is contained in:
parent
00ae7dbda3
commit
07d8cd0a12
|
@ -2562,7 +2562,7 @@ void CheckMemoryLeakInFunction::checkReallocUsage()
|
||||||
const Token *tok = scope->classStart;
|
const Token *tok = scope->classStart;
|
||||||
const Token *startOfFunction = tok;
|
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;
|
unsigned int indentlevel = 1;
|
||||||
for (tok = tok->next(); tok; tok = tok->next())
|
for (tok = tok->next(); tok; tok = tok->next())
|
||||||
{
|
{
|
||||||
|
@ -2576,7 +2576,7 @@ void CheckMemoryLeakInFunction::checkReallocUsage()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tok->varId() > 0 &&
|
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() &&
|
tok->varId() == tok->tokAt(4)->varId() &&
|
||||||
parameterVarIds.find(tok->varId()) == parameterVarIds.end())
|
parameterVarIds.find(tok->varId()) == parameterVarIds.end())
|
||||||
{
|
{
|
||||||
|
@ -2585,10 +2585,11 @@ void CheckMemoryLeakInFunction::checkReallocUsage()
|
||||||
Token::findmatch(startOfFunction, "[{};] %varid% = %var% [;=]", tok->varId()))
|
Token::findmatch(startOfFunction, "[{};] %varid% = %var% [;=]", tok->varId()))
|
||||||
continue;
|
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
|
// 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), ") ;") &&
|
if (tokEndBrace && Token::simpleMatch(tokEndBrace->tokAt(-2), ") ;") &&
|
||||||
Token::Match(tokEndBrace->tokAt(-2)->link()->tokAt(-2), "{|}|; %var% ("))
|
Token::Match(tokEndBrace->tokAt(-2)->link()->tokAt(-2), "{|}|; %var% ("))
|
||||||
continue;
|
continue;
|
||||||
|
@ -2596,6 +2597,27 @@ void CheckMemoryLeakInFunction::checkReallocUsage()
|
||||||
|
|
||||||
memleakUponReallocFailureError(tok, tok->str());
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -264,6 +264,9 @@ private:
|
||||||
TEST_CASE(realloc9);
|
TEST_CASE(realloc9);
|
||||||
TEST_CASE(realloc10);
|
TEST_CASE(realloc10);
|
||||||
TEST_CASE(realloc11);
|
TEST_CASE(realloc11);
|
||||||
|
TEST_CASE(realloc12);
|
||||||
|
TEST_CASE(realloc13);
|
||||||
|
TEST_CASE(realloc14);
|
||||||
|
|
||||||
TEST_CASE(assign1);
|
TEST_CASE(assign1);
|
||||||
TEST_CASE(assign2); // #2806 - FP when using redundant assignment
|
TEST_CASE(assign2); // #2806 - FP when using redundant assignment
|
||||||
|
@ -2798,6 +2801,41 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
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()
|
void assign1()
|
||||||
{
|
{
|
||||||
check("void foo()\n"
|
check("void foo()\n"
|
||||||
|
|
Loading…
Reference in New Issue