Memory leaks: Removed the experimental checking using ExecutionPath.
This commit is contained in:
parent
b705a9cbdd
commit
26864dd011
@ -3040,173 +3040,6 @@ void CheckMemoryLeakStructMember::check()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** @brief Experimental class for detecting memory leaks. The ExecutionPath functionality is used */
|
|
||||||
class CheckLocalLeaks : public ExecutionPath
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/** Startup constructor */
|
|
||||||
CheckLocalLeaks(Check *c) : ExecutionPath(c, 0), allocated(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Debugging : print checks */
|
|
||||||
static void printOut(const std::list<ExecutionPath *> &checks)
|
|
||||||
{
|
|
||||||
std::ostringstream ostr;
|
|
||||||
ostr << "CheckLocalLeaks::printOut" << std::endl;
|
|
||||||
for (std::list<ExecutionPath *>::const_iterator it = checks.begin(); it != checks.end(); ++it)
|
|
||||||
{
|
|
||||||
CheckLocalLeaks *c = dynamic_cast<CheckLocalLeaks *>(*it);
|
|
||||||
if (c)
|
|
||||||
{
|
|
||||||
ostr << std::hex << c << ": varId=" << c->varId << " allocated=" << (c->allocated ? "true" : "false") << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::cout << ostr.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
ExecutionPath *copy()
|
|
||||||
{
|
|
||||||
return new CheckLocalLeaks(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** start checking of given variable */
|
|
||||||
CheckLocalLeaks(Check *c, unsigned int v, const std::string &s) : ExecutionPath(c, v), allocated(false), varname(s)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/** is other execution path equal? */
|
|
||||||
bool is_equal(const ExecutionPath *e) const
|
|
||||||
{
|
|
||||||
const CheckLocalLeaks *c = static_cast<const CheckLocalLeaks *>(e);
|
|
||||||
return (allocated == c->allocated && varname == c->varname);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Is variable allocated? */
|
|
||||||
bool allocated;
|
|
||||||
|
|
||||||
/** Name of variable */
|
|
||||||
const std::string varname;
|
|
||||||
|
|
||||||
/** no implementation => compiler error if used */
|
|
||||||
void operator=(const CheckLocalLeaks &);
|
|
||||||
|
|
||||||
/** Allocation is detected */
|
|
||||||
static void alloc(std::list<ExecutionPath *> &checks, const unsigned int varid)
|
|
||||||
{
|
|
||||||
if (varid == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
std::list<ExecutionPath *>::iterator it;
|
|
||||||
for (it = checks.begin(); it != checks.end(); ++it)
|
|
||||||
{
|
|
||||||
CheckLocalLeaks *C = dynamic_cast<CheckLocalLeaks *>(*it);
|
|
||||||
if (C && C->varId == varid)
|
|
||||||
C->allocated = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Deallocation is detected */
|
|
||||||
static void dealloc(std::list<ExecutionPath *> &checks, const Token *tok)
|
|
||||||
{
|
|
||||||
if (tok->varId() == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
std::list<ExecutionPath *>::iterator it;
|
|
||||||
for (it = checks.begin(); it != checks.end(); ++it)
|
|
||||||
{
|
|
||||||
CheckLocalLeaks *C = dynamic_cast<CheckLocalLeaks *>(*it);
|
|
||||||
if (C && C->varId == tok->varId())
|
|
||||||
C->allocated = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** return */
|
|
||||||
static void ret(const std::list<ExecutionPath *> &checks, const Token *tok)
|
|
||||||
{
|
|
||||||
std::list<ExecutionPath *>::const_iterator it;
|
|
||||||
for (it = checks.begin(); it != checks.end(); ++it)
|
|
||||||
{
|
|
||||||
CheckLocalLeaks *C = dynamic_cast<CheckLocalLeaks *>(*it);
|
|
||||||
if (C && C->allocated)
|
|
||||||
{
|
|
||||||
CheckMemoryLeakInFunction *checkMemleak = reinterpret_cast<CheckMemoryLeakInFunction *>(C->owner);
|
|
||||||
if (checkMemleak)
|
|
||||||
{
|
|
||||||
checkMemleak->memleakError(tok, C->varname);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** parse the tokens */
|
|
||||||
const Token *parse(const Token &tok, std::list<ExecutionPath *> &checks) const
|
|
||||||
{
|
|
||||||
//std::cout << "CheckLocalLeaks::parse " << tok.str() << std::endl;
|
|
||||||
//printOut(checks);
|
|
||||||
|
|
||||||
if (!Token::Match(tok.previous(), "[;{}]"))
|
|
||||||
return &tok;
|
|
||||||
|
|
||||||
if (Token::Match(&tok, "%type% * %var% ;"))
|
|
||||||
{
|
|
||||||
const Token * vartok = tok.tokAt(2);
|
|
||||||
if (vartok->varId() != 0)
|
|
||||||
checks.push_back(new CheckLocalLeaks(owner, vartok->varId(), vartok->str()));
|
|
||||||
return vartok->next();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Token::Match(&tok, "%var% = new"))
|
|
||||||
{
|
|
||||||
alloc(checks, tok.varId());
|
|
||||||
|
|
||||||
// goto end of statement
|
|
||||||
const Token *tok2 = &tok;
|
|
||||||
while (tok2 && tok2->str() != ";")
|
|
||||||
tok2 = tok2->next();
|
|
||||||
return tok2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Token::Match(&tok, "delete %var% ;"))
|
|
||||||
{
|
|
||||||
dealloc(checks, tok.next());
|
|
||||||
return tok.tokAt(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Token::Match(&tok, "delete [ ] %var% ;"))
|
|
||||||
{
|
|
||||||
dealloc(checks, tok.tokAt(3));
|
|
||||||
return tok.tokAt(4);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tok.str() == "return")
|
|
||||||
{
|
|
||||||
ret(checks, &tok);
|
|
||||||
}
|
|
||||||
|
|
||||||
return &tok;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** going out of scope - all execution paths end */
|
|
||||||
void end(const std::list<ExecutionPath *> &checks, const Token *tok) const
|
|
||||||
{
|
|
||||||
ret(checks, tok);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void CheckMemoryLeakInFunction::localleaks()
|
|
||||||
{
|
|
||||||
// Check this scope..
|
|
||||||
CheckLocalLeaks c(this);
|
|
||||||
checkExecutionPaths(_tokenizer->tokens(), &c);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "checkuninitvar.h" // CheckUninitVar::analyse
|
#include "checkuninitvar.h" // CheckUninitVar::analyse
|
||||||
|
|
||||||
void CheckMemoryLeakNoVar::check()
|
void CheckMemoryLeakNoVar::check()
|
||||||
|
@ -201,9 +201,6 @@ public:
|
|||||||
/** @brief Perform checking */
|
/** @brief Perform checking */
|
||||||
void check();
|
void check();
|
||||||
|
|
||||||
/** @brief experimental: checking via ExecutionPath */
|
|
||||||
void localleaks();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checking for a memory leak caused by improper realloc usage.
|
* Checking for a memory leak caused by improper realloc usage.
|
||||||
*/
|
*/
|
||||||
|
@ -27,107 +27,6 @@
|
|||||||
extern std::ostringstream errout;
|
extern std::ostringstream errout;
|
||||||
|
|
||||||
|
|
||||||
class TestLocalLeaks : private TestFixture
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TestLocalLeaks() : TestFixture("TestLocalLeaks")
|
|
||||||
{ }
|
|
||||||
|
|
||||||
private:
|
|
||||||
void run()
|
|
||||||
{
|
|
||||||
TEST_CASE(test1);
|
|
||||||
TEST_CASE(test2);
|
|
||||||
TEST_CASE(test3);
|
|
||||||
TEST_CASE(test4);
|
|
||||||
TEST_CASE(test5);
|
|
||||||
}
|
|
||||||
|
|
||||||
void check(const char code[])
|
|
||||||
{
|
|
||||||
// Clear the error buffer..
|
|
||||||
errout.str("");
|
|
||||||
|
|
||||||
Settings settings;
|
|
||||||
|
|
||||||
// Tokenize..
|
|
||||||
Tokenizer tokenizer(&settings, this);
|
|
||||||
std::istringstream istr(code);
|
|
||||||
tokenizer.tokenize(istr, "test.cpp");
|
|
||||||
tokenizer.setVarId();
|
|
||||||
tokenizer.simplifyTokenList();
|
|
||||||
|
|
||||||
// Check for memory leaks..
|
|
||||||
CheckMemoryLeakInFunction checkMemoryLeak(&tokenizer, &settings, this);
|
|
||||||
checkMemoryLeak.localleaks();
|
|
||||||
}
|
|
||||||
|
|
||||||
void test1()
|
|
||||||
{
|
|
||||||
check("void foo()\n"
|
|
||||||
"{\n"
|
|
||||||
" char *p = new char[100];\n"
|
|
||||||
"}\n");
|
|
||||||
ASSERT_EQUALS("[test.cpp:4]: (error) Memory leak: p\n", errout.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void test2()
|
|
||||||
{
|
|
||||||
check("void foo()\n"
|
|
||||||
"{\n"
|
|
||||||
" char *p = new char[100];\n"
|
|
||||||
" delete [] p;\n"
|
|
||||||
"}\n");
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void test3()
|
|
||||||
{
|
|
||||||
check("void foo(int x)\n"
|
|
||||||
"{\n"
|
|
||||||
" char *p = 0;\n"
|
|
||||||
" if (x == 1)\n"
|
|
||||||
" p = new char[100];\n"
|
|
||||||
" if (x == 2)\n"
|
|
||||||
" delete [] p;\n"
|
|
||||||
"}\n");
|
|
||||||
TODO_ASSERT_EQUALS("[test.cpp:8]: (error) Memory leak: p\n", errout.str());
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void test4()
|
|
||||||
{
|
|
||||||
check("void foo(int x)\n"
|
|
||||||
"{\n"
|
|
||||||
" char *p = 0;\n"
|
|
||||||
" if (x == 1)\n"
|
|
||||||
" p = new char[100];\n"
|
|
||||||
" if (x == 1)\n"
|
|
||||||
" delete [] p;\n"
|
|
||||||
"}\n");
|
|
||||||
ASSERT_EQUALS("", errout.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void test5() //#ticket 1879
|
|
||||||
{
|
|
||||||
check("void test()\n"
|
|
||||||
"{\n"
|
|
||||||
" int *a = new int[10];\n"
|
|
||||||
" try\n"
|
|
||||||
" {\n"
|
|
||||||
" }\n"
|
|
||||||
" catch(...)\n"
|
|
||||||
" {\n"
|
|
||||||
" }\n"
|
|
||||||
"}\n");
|
|
||||||
ASSERT_EQUALS("[test.cpp:10]: (error) Memory leak: a\n",errout.str());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static TestLocalLeaks testLocalLeaks;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class TestMemleak : private TestFixture
|
class TestMemleak : private TestFixture
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user