fix some more false negatives for #2904 (Memory leak not detected when creating a new class instance)

This commit is contained in:
Robert Reif 2011-07-14 20:45:27 -04:00
parent 997a3652d2
commit af1e51f648
3 changed files with 29 additions and 16 deletions

View File

@ -82,23 +82,21 @@ static int call_func_white_list_compare(const void *a, const void *b)
//---------------------------------------------------------------------------
bool CheckMemoryLeak::isclass(const Tokenizer *_tokenizer, const Token *tok) const
bool CheckMemoryLeak::isclass(const Tokenizer *_tokenizer, const Token *tok, unsigned int varid) const
{
if (tok->isStandardType())
return false;
// return false if the type is a simple struct without member functions
const std::string pattern("struct|class " + tok->str() + " {");
const Token *tok2 = Token::findmatch(_tokenizer->tokens(), pattern.c_str());
if (tok2)
{
while (tok2 && tok2->str() != "}" && tok2->str() != "(")
tok2 = tok2->next();
const Variable * var = _tokenizer->getSymbolDatabase()->getVariableFromVarId(varid);
// Simple struct => return false
if (tok2 && tok2->str() == "}")
// return false if the type is a simple record type without side effects
// a type that has no side effects (no constructors and no members with constructors)
/** @todo false negative: check base class for side effects */
/** @todo false negative: check constructors for side effects */
if (var && var->type() && var->type()->numConstructors == 0 &&
(var->type()->varlist.empty() || var->type()->needInitialization == Scope::True) &&
var->type()->derivedFrom.empty())
return false;
}
return true;
}
@ -1039,21 +1037,21 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
{
if (Token::Match(tok->tokAt(2), "new %type% [(;]"))
{
if (isclass(_tokenizer, tok->tokAt(3)))
if (isclass(_tokenizer, tok->tokAt(3), varid))
{
alloc = No;
}
}
else if (Token::Match(tok->tokAt(2), "new ( nothrow ) %type%"))
{
if (isclass(_tokenizer, tok->tokAt(6)))
if (isclass(_tokenizer, tok->tokAt(6), varid))
{
alloc = No;
}
}
else if (Token::Match(tok->tokAt(2), "new ( std :: nothrow ) %type%"))
{
if (isclass(_tokenizer, tok->tokAt(8)))
if (isclass(_tokenizer, tok->tokAt(8), varid))
{
alloc = No;
}

View File

@ -127,7 +127,7 @@ public:
* @param typestr type name
* @return true if the type name is the name of a class
*/
bool isclass(const Tokenizer *_tokenizer, const Token *typestr) const;
bool isclass(const Tokenizer *_tokenizer, const Token *typestr, unsigned int varid) const;
void memleakError(const Token *tok, const std::string &varname);
void resourceLeakError(const Token *tok, const std::string &varname);

View File

@ -2236,6 +2236,21 @@ private:
" Fred *f = new Fred();\n"
"}\n");
ASSERT_EQUALS("[test.cpp:5]: (error) Memory leak: f\n", errout.str());
check("class Fred { void foo(){ } };\n"
"void f(void) \n"
"{\n"
" Fred *f = new Fred();\n"
" delete f;\n"
"}\n");
ASSERT_EQUALS("", errout.str());
check("class Fred { void foo(){ } };\n"
"void f(void) \n"
"{\n"
" Fred *f = new Fred();\n"
"}\n");
ASSERT_EQUALS("[test.cpp:5]: (error) Memory leak: f\n", errout.str());
}
void allocfunc1()