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
|
||||
|
||||
void CheckMemoryLeakNoVar::check()
|
||||
|
|
|
@ -201,9 +201,6 @@ public:
|
|||
/** @brief Perform checking */
|
||||
void check();
|
||||
|
||||
/** @brief experimental: checking via ExecutionPath */
|
||||
void localleaks();
|
||||
|
||||
/**
|
||||
* Checking for a memory leak caused by improper realloc usage.
|
||||
*/
|
||||
|
|
|
@ -27,107 +27,6 @@
|
|||
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
|
||||
{
|
||||
public:
|
||||
|
|
Loading…
Reference in New Issue