Fixed #1315 (mismatched allocation and deallocaton not detected)
This commit is contained in:
parent
7ec27cb43b
commit
e49f7bfa0e
|
@ -360,9 +360,9 @@ void CheckMemoryLeak::mismatchSizeError(const Token *tok, const std::string &sz)
|
||||||
reportErr(tok, Severity::error, "mismatchSize", "The given size " + sz + " is mismatching");
|
reportErr(tok, Severity::error, "mismatchSize", "The given size " + sz + " is mismatching");
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckMemoryLeak::mismatchAllocDealloc(const std::list<const Token *> &callstack, const std::string &varname)
|
void CheckMemoryLeak::mismatchAllocDealloc(const std::list<const Token *> &callstack, const std::string &varname, bool all)
|
||||||
{
|
{
|
||||||
reportErr(callstack, Severity::error, "mismatchAllocDealloc", "Mismatching allocation and deallocation: " + varname);
|
reportErr(callstack, all ? Severity::possibleError : Severity::error, "mismatchAllocDealloc", "Mismatching allocation and deallocation: " + varname);
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckMemoryLeak::AllocType CheckMemoryLeak::functionReturnType(const Token *tok) const
|
CheckMemoryLeak::AllocType CheckMemoryLeak::functionReturnType(const Token *tok) const
|
||||||
|
@ -831,7 +831,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
|
||||||
if (alloc != Many && dealloctype != No && dealloctype != Many && dealloctype != alloc)
|
if (alloc != Many && dealloctype != No && dealloctype != Many && dealloctype != alloc)
|
||||||
{
|
{
|
||||||
callstack.push_back(tok);
|
callstack.push_back(tok);
|
||||||
mismatchAllocDealloc(callstack, Token::findmatch(_tokenizer->tokens(), "%varid%", varid)->str());
|
mismatchAllocDealloc(callstack, Token::findmatch(_tokenizer->tokens(), "%varid%", varid)->str(), false);
|
||||||
callstack.pop_back();
|
callstack.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -882,7 +882,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
|
||||||
if (dealloc != Many && alloctype != No && alloctype != Many && alloctype != dealloc)
|
if (dealloc != Many && alloctype != No && alloctype != Many && alloctype != dealloc)
|
||||||
{
|
{
|
||||||
callstack.push_back(tok);
|
callstack.push_back(tok);
|
||||||
mismatchAllocDealloc(callstack, Token::findmatch(_tokenizer->tokens(), "%varid%", varid)->str());
|
mismatchAllocDealloc(callstack, Token::findmatch(_tokenizer->tokens(), "%varid%", varid)->str(), false);
|
||||||
callstack.pop_back();
|
callstack.pop_back();
|
||||||
}
|
}
|
||||||
dealloctype = dealloc;
|
dealloctype = dealloc;
|
||||||
|
@ -2237,18 +2237,14 @@ void CheckMemoryLeakInFunction::check()
|
||||||
|
|
||||||
void CheckMemoryLeakInClass::check()
|
void CheckMemoryLeakInClass::check()
|
||||||
{
|
{
|
||||||
int indentlevel = 0;
|
|
||||||
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
|
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
|
||||||
{
|
{
|
||||||
if (tok->str() == "{")
|
if (tok->str() == "{")
|
||||||
++indentlevel;
|
tok = tok->link();
|
||||||
|
|
||||||
else if (tok->str() == "}")
|
else if (Token::Match(tok, "class %var% [{:]"))
|
||||||
--indentlevel;
|
|
||||||
|
|
||||||
else if (indentlevel == 0 && Token::Match(tok, "class %var% [{:]"))
|
|
||||||
{
|
{
|
||||||
std::vector<const char *> classname;
|
std::vector<std::string> classname;
|
||||||
classname.push_back(tok->strAt(1));
|
classname.push_back(tok->strAt(1));
|
||||||
parseClass(tok, classname);
|
parseClass(tok, classname);
|
||||||
}
|
}
|
||||||
|
@ -2256,7 +2252,7 @@ void CheckMemoryLeakInClass::check()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CheckMemoryLeakInClass::parseClass(const Token *tok1, std::vector<const char *> &classname)
|
void CheckMemoryLeakInClass::parseClass(const Token *tok1, std::vector<std::string> &classname)
|
||||||
{
|
{
|
||||||
// Go into class.
|
// Go into class.
|
||||||
while (tok1 && tok1->str() != "{")
|
while (tok1 && tok1->str() != "{")
|
||||||
|
@ -2311,12 +2307,12 @@ void CheckMemoryLeakInClass::parseClass(const Token *tok1, std::vector<const cha
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckMemoryLeakInClass::variable(const char classname[], const Token *tokVarname)
|
void CheckMemoryLeakInClass::variable(const std::string &classname, const Token *tokVarname)
|
||||||
{
|
{
|
||||||
if (!_settings->_showAll)
|
if (!_settings->_showAll)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const char *varname = tokVarname->strAt(0);
|
const std::string varname = tokVarname->strAt(0);
|
||||||
|
|
||||||
// Check if member variable has been allocated and deallocated..
|
// Check if member variable has been allocated and deallocated..
|
||||||
CheckMemoryLeak::AllocType Alloc = CheckMemoryLeak::No;
|
CheckMemoryLeak::AllocType Alloc = CheckMemoryLeak::No;
|
||||||
|
@ -2327,13 +2323,13 @@ void CheckMemoryLeakInClass::variable(const char classname[], const Token *tokVa
|
||||||
|
|
||||||
// Loop through all tokens. Inspect member functions
|
// Loop through all tokens. Inspect member functions
|
||||||
int indent_ = 0;
|
int indent_ = 0;
|
||||||
const Token *functionToken = Tokenizer::findClassFunction(_tokenizer->tokens(), classname, "~| %var%", indent_);
|
const Token *functionToken = Tokenizer::findClassFunction(_tokenizer->tokens(), classname.c_str(), "~| %var%", indent_);
|
||||||
while (functionToken)
|
while (functionToken)
|
||||||
{
|
{
|
||||||
const bool constructor(Token::Match(functionToken, (classname + std::string(" :: ") + classname + " (").c_str()));
|
const bool constructor(Token::Match(functionToken, (classname + " :: " + classname + " (").c_str()));
|
||||||
const bool destructor(functionToken->tokAt(2)->str() == "~");
|
const bool destructor(functionToken->tokAt(2)->str() == "~");
|
||||||
|
|
||||||
int indent = 0;
|
unsigned int indent = 0;
|
||||||
bool initlist = false;
|
bool initlist = false;
|
||||||
for (const Token *tok = functionToken; tok; tok = tok->next())
|
for (const Token *tok = functionToken; tok; tok = tok->next())
|
||||||
{
|
{
|
||||||
|
@ -2341,9 +2337,9 @@ void CheckMemoryLeakInClass::variable(const char classname[], const Token *tokVa
|
||||||
++indent;
|
++indent;
|
||||||
else if (tok->str() == "}")
|
else if (tok->str() == "}")
|
||||||
{
|
{
|
||||||
--indent;
|
if (indent <= 1)
|
||||||
if (indent <= 0)
|
|
||||||
break;
|
break;
|
||||||
|
--indent;
|
||||||
}
|
}
|
||||||
else if (indent == 0 && Token::simpleMatch(tok, ") :"))
|
else if (indent == 0 && Token::simpleMatch(tok, ") :"))
|
||||||
initlist = true;
|
initlist = true;
|
||||||
|
@ -2351,12 +2347,12 @@ void CheckMemoryLeakInClass::variable(const char classname[], const Token *tokVa
|
||||||
{
|
{
|
||||||
if (indent == 0)
|
if (indent == 0)
|
||||||
{
|
{
|
||||||
if (!Token::Match(tok, (":|, " + std::string(varname) + " (").c_str()))
|
if (!Token::Match(tok, (":|, " + varname + " (").c_str()))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate..
|
// Allocate..
|
||||||
if (indent == 0 || Token::Match(tok, (std::string(varname) + " =").c_str()))
|
if (indent == 0 || Token::Match(tok, (varname + " =").c_str()))
|
||||||
{
|
{
|
||||||
AllocType alloc = getAllocationType(tok->tokAt((indent > 0) ? 2 : 3), 0);
|
AllocType alloc = getAllocationType(tok->tokAt((indent > 0) ? 2 : 3), 0);
|
||||||
if (alloc != CheckMemoryLeak::No)
|
if (alloc != CheckMemoryLeak::No)
|
||||||
|
@ -2371,7 +2367,7 @@ void CheckMemoryLeakInClass::variable(const char classname[], const Token *tokVa
|
||||||
if (alloc != CheckMemoryLeak::Many && Dealloc != CheckMemoryLeak::No && Dealloc != CheckMemoryLeak::Many && Dealloc != alloc)
|
if (alloc != CheckMemoryLeak::Many && Dealloc != CheckMemoryLeak::No && Dealloc != CheckMemoryLeak::Many && Dealloc != alloc)
|
||||||
{
|
{
|
||||||
callstack.push_back(tok);
|
callstack.push_back(tok);
|
||||||
mismatchAllocDealloc(callstack, (std::string(classname) + "::" + varname).c_str());
|
mismatchAllocDealloc(callstack, classname + "::" + varname, true);
|
||||||
callstack.pop_back();
|
callstack.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2384,12 +2380,12 @@ void CheckMemoryLeakInClass::variable(const char classname[], const Token *tokVa
|
||||||
|
|
||||||
// Deallocate..
|
// Deallocate..
|
||||||
const char *varnames[3] = { "var", 0, 0 };
|
const char *varnames[3] = { "var", 0, 0 };
|
||||||
varnames[0] = varname;
|
varnames[0] = varname.c_str();
|
||||||
AllocType dealloc = getDeallocationType(tok, varnames);
|
AllocType dealloc = getDeallocationType(tok, varnames);
|
||||||
if (dealloc == No)
|
if (dealloc == No)
|
||||||
{
|
{
|
||||||
varnames[0] = "this";
|
varnames[0] = "this";
|
||||||
varnames[1] = varname;
|
varnames[1] = varname.c_str();
|
||||||
dealloc = getDeallocationType(tok, varnames);
|
dealloc = getDeallocationType(tok, varnames);
|
||||||
}
|
}
|
||||||
if (dealloc != CheckMemoryLeak::No)
|
if (dealloc != CheckMemoryLeak::No)
|
||||||
|
@ -2397,6 +2393,7 @@ void CheckMemoryLeakInClass::variable(const char classname[], const Token *tokVa
|
||||||
if (destructor)
|
if (destructor)
|
||||||
deallocInDestructor = true;
|
deallocInDestructor = true;
|
||||||
|
|
||||||
|
// several types of allocation/deallocation?
|
||||||
if (Dealloc != CheckMemoryLeak::No && Dealloc != dealloc)
|
if (Dealloc != CheckMemoryLeak::No && Dealloc != dealloc)
|
||||||
dealloc = CheckMemoryLeak::Many;
|
dealloc = CheckMemoryLeak::Many;
|
||||||
|
|
||||||
|
@ -2404,7 +2401,7 @@ void CheckMemoryLeakInClass::variable(const char classname[], const Token *tokVa
|
||||||
if (dealloc != CheckMemoryLeak::Many && Alloc != CheckMemoryLeak::No && Alloc != Many && Alloc != dealloc)
|
if (dealloc != CheckMemoryLeak::Many && Alloc != CheckMemoryLeak::No && Alloc != Many && Alloc != dealloc)
|
||||||
{
|
{
|
||||||
callstack.push_back(tok);
|
callstack.push_back(tok);
|
||||||
mismatchAllocDealloc(callstack, (std::string(classname) + "::" + varname).c_str());
|
mismatchAllocDealloc(callstack, classname + "::" + varname, true);
|
||||||
callstack.pop_back();
|
callstack.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2424,16 +2421,16 @@ void CheckMemoryLeakInClass::variable(const char classname[], const Token *tokVa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
functionToken = Tokenizer::findClassFunction(functionToken->next(), classname, "~| %var%", indent_);
|
functionToken = Tokenizer::findClassFunction(functionToken->next(), classname.c_str(), "~| %var%", indent_);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allocInConstructor && !deallocInDestructor)
|
if (allocInConstructor && !deallocInDestructor)
|
||||||
{
|
{
|
||||||
memoryLeak(tokVarname, (std::string(classname) + "::" + varname).c_str(), Alloc, true);
|
memoryLeak(tokVarname, (classname + "::" + varname).c_str(), Alloc, true);
|
||||||
}
|
}
|
||||||
else if (Alloc != CheckMemoryLeak::No && Dealloc == CheckMemoryLeak::No)
|
else if (Alloc != CheckMemoryLeak::No && Dealloc == CheckMemoryLeak::No)
|
||||||
{
|
{
|
||||||
memoryLeak(tokVarname, (std::string(classname) + "::" + varname).c_str(), Alloc, true);
|
memoryLeak(tokVarname, (classname + "::" + varname).c_str(), Alloc, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -123,7 +123,7 @@ public:
|
||||||
void deallocDeallocError(const Token *tok, const std::string &varname);
|
void deallocDeallocError(const Token *tok, const std::string &varname);
|
||||||
void deallocuseError(const Token *tok, const std::string &varname);
|
void deallocuseError(const Token *tok, const std::string &varname);
|
||||||
void mismatchSizeError(const Token *tok, const std::string &sz);
|
void mismatchSizeError(const Token *tok, const std::string &sz);
|
||||||
void mismatchAllocDealloc(const std::list<const Token *> &callstack, const std::string &varname);
|
void mismatchAllocDealloc(const std::list<const Token *> &callstack, const std::string &varname, bool all);
|
||||||
|
|
||||||
/** What type of allocated memory does the given function return? */
|
/** What type of allocated memory does the given function return? */
|
||||||
AllocType functionReturnType(const Token *tok) const;
|
AllocType functionReturnType(const Token *tok) const;
|
||||||
|
@ -272,7 +272,7 @@ private:
|
||||||
deallocuseError(0, "varname");
|
deallocuseError(0, "varname");
|
||||||
mismatchSizeError(0, "sz");
|
mismatchSizeError(0, "sz");
|
||||||
std::list<const Token *> callstack;
|
std::list<const Token *> callstack;
|
||||||
mismatchAllocDealloc(callstack, "varname");
|
mismatchAllocDealloc(callstack, "varname", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string name() const
|
std::string name() const
|
||||||
|
@ -314,8 +314,8 @@ public:
|
||||||
void check();
|
void check();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void parseClass(const Token *tok1, std::vector<const char *> &classname);
|
void parseClass(const Token *tok1, std::vector<std::string> &classname);
|
||||||
void variable(const char classname[], const Token *tokVarname);
|
void variable(const std::string &classname, const Token *tokVarname);
|
||||||
|
|
||||||
void getErrorMessages()
|
void getErrorMessages()
|
||||||
{ }
|
{ }
|
||||||
|
|
|
@ -2727,6 +2727,8 @@ private:
|
||||||
TEST_CASE(use);
|
TEST_CASE(use);
|
||||||
|
|
||||||
TEST_CASE(free_member_in_sub_func);
|
TEST_CASE(free_member_in_sub_func);
|
||||||
|
|
||||||
|
TEST_CASE(mismatch1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2778,7 +2780,7 @@ private:
|
||||||
" free(str1);\n"
|
" free(str1);\n"
|
||||||
"}\n", true);
|
"}\n", true);
|
||||||
|
|
||||||
ASSERT_EQUALS("[test.cpp:17]: (error) Mismatching allocation and deallocation: Fred::str1\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:17]: (possible error) Mismatching allocation and deallocation: Fred::str1\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void class3()
|
void class3()
|
||||||
|
@ -3080,6 +3082,34 @@ private:
|
||||||
"}\n", true);
|
"}\n", true);
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mismatch1()
|
||||||
|
{
|
||||||
|
check("class A\n"
|
||||||
|
"{\n"
|
||||||
|
"public:\n"
|
||||||
|
" A(int i);\n"
|
||||||
|
" ~A();\n"
|
||||||
|
"private:\n"
|
||||||
|
" char* pkt_buffer;\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"A::A(int i)\n"
|
||||||
|
"{\n"
|
||||||
|
" pkt_buffer = new char[8192];\n"
|
||||||
|
" if (i != 1) {\n"
|
||||||
|
" delete pkt_buffer;\n"
|
||||||
|
" pkt_buffer = 0;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n"
|
||||||
|
"\n"
|
||||||
|
"A::~A() {\n"
|
||||||
|
" delete [] pkt_buffer;\n"
|
||||||
|
"}\n", true);
|
||||||
|
ASSERT_EQUALS("[test.cpp:14]: (possible error) Mismatching allocation and deallocation: A::pkt_buffer\n", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static TestMemleakInClass testMemleakInClass;
|
static TestMemleakInClass testMemleakInClass;
|
||||||
|
|
Loading…
Reference in New Issue