fix some more false negatives for #2904 (Memory leak not detected when creating a new class instance)
This commit is contained in:
parent
997a3652d2
commit
af1e51f648
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue