Move and refactor the CheckMemoryLeak::isclass

This commit is contained in:
Daniel Marjamäki 2019-07-17 08:59:09 +02:00
parent 8513fb81d2
commit 5800692fa1
4 changed files with 43 additions and 30 deletions

View File

@ -53,6 +53,29 @@ static const CWE CWE415(415U);
static const int NEW_ARRAY = -2;
static const int NEW = -1;
/**
* @brief Is variable type some class with automatic deallocation?
* @param vartok variable token
* @return true unless it can be seen there is no automatic deallocation
*/
static bool isAutoDealloc(const Variable *var)
{
if (var->valueType() && var->valueType()->type != ValueType::Type::RECORD && var->valueType()->type != ValueType::Type::UNKNOWN_TYPE)
return false;
// 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->typeScope() && var->typeScope()->numConstructors == 0 &&
(var->typeScope()->varlist.empty() || var->type()->needInitialization == Type::True) &&
var->type()->derivedFrom.empty())
return false;
return true;
}
//---------------------------------------------------------------------------
void VarInfo::print()
@ -222,7 +245,7 @@ static bool checkVariable(const Token *varTok, const bool isCpp)
if (!var)
return false;
// Possibly automatically deallocated memory
if (!var->typeStartToken()->isStandardType() && Token::Match(varTok, "%var% = new"))
if (isAutoDealloc(var) && Token::Match(varTok, "%var% = new"))
return false;
if (!var->isPointer() && !var->typeStartToken()->isStandardType())
return false;

View File

@ -94,26 +94,6 @@ static const std::set<std::string> call_func_white_list = {
//---------------------------------------------------------------------------
bool CheckMemoryLeak::isclass(const Token *tok, unsigned int varid) const
{
if (tok->isStandardType())
return false;
const Variable * var = mTokenizer_->getSymbolDatabase()->getVariableFromVarId(varid);
// 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->typeScope() && var->typeScope()->numConstructors == 0 &&
(var->typeScope()->varlist.empty() || var->type()->needInitialization == Type::True) &&
var->type()->derivedFrom.empty())
return false;
return true;
}
//---------------------------------------------------------------------------
CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2, unsigned int varid, std::list<const Function*> *callstack) const
{
// What we may have...

View File

@ -114,14 +114,6 @@ public:
*/
static AllocType getReallocationType(const Token *tok2, unsigned int varid);
/**
* @brief Is a typename the name of a class?
* @param tok type token
* @param varid variable id
* @return true if the type name is the name of a class
*/
bool isclass(const Token *tok, unsigned int varid) const;
/**
* Report that there is a memory leak (new/malloc/etc)
* @param tok token where memory is leaked

View File

@ -68,6 +68,8 @@ private:
TEST_CASE(assign18);
TEST_CASE(assign19);
TEST_CASE(isAutoDealloc);
TEST_CASE(realloc1);
TEST_CASE(realloc2);
TEST_CASE(realloc3);
@ -93,7 +95,6 @@ private:
TEST_CASE(doublefree8);
TEST_CASE(doublefree9);
// exit
TEST_CASE(exit1);
TEST_CASE(exit2);
@ -399,6 +400,23 @@ private:
ASSERT_EQUALS("", errout.str());
}
void isAutoDealloc() {
check("void f() {\n"
" char *p = new char[100];"
"}", true);
ASSERT_EQUALS("[test.cpp:2]: (error) Memory leak: p\n", errout.str());
check("void f() {\n"
" Fred *fred = new Fred;"
"}", true);
ASSERT_EQUALS("", errout.str());
check("void f() {\n"
" std::string *str = new std::string;"
"}", true);
TODO_ASSERT_EQUALS("[test.cpp:2]: (error) Memory leak: str\n", "", errout.str());
}
void realloc1() {
check("void f() {\n"
" void *p = malloc(10);\n"