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()) if (tok->isStandardType())
return false; return false;
// return false if the type is a simple struct without member functions const Variable * var = _tokenizer->getSymbolDatabase()->getVariableFromVarId(varid);
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();
// Simple struct => return false // return false if the type is a simple record type without side effects
if (tok2 && tok2->str() == "}") // a type that has no side effects (no constructors and no members with constructors)
return false; /** @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; 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 (Token::Match(tok->tokAt(2), "new %type% [(;]"))
{ {
if (isclass(_tokenizer, tok->tokAt(3))) if (isclass(_tokenizer, tok->tokAt(3), varid))
{ {
alloc = No; alloc = No;
} }
} }
else if (Token::Match(tok->tokAt(2), "new ( nothrow ) %type%")) 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; alloc = No;
} }
} }
else if (Token::Match(tok->tokAt(2), "new ( std :: nothrow ) %type%")) 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; alloc = No;
} }

View File

@ -127,7 +127,7 @@ public:
* @param typestr type name * @param typestr type name
* @return true if the type name is the name of a class * @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 memleakError(const Token *tok, const std::string &varname);
void resourceLeakError(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" " Fred *f = new Fred();\n"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:5]: (error) Memory leak: f\n", errout.str()); 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() void allocfunc1()