Refactoring the unit testing. Wrote special tests for CheckMemoryLeakInFunction::findleak

This commit is contained in:
Daniel Marjamäki 2009-08-23 15:48:25 +02:00
parent 99938353b4
commit 9da2ecf4f4
3 changed files with 121 additions and 63 deletions

View File

@ -1511,6 +1511,56 @@ void CheckMemoryLeakInFunction::simplifycode(Token *tok, bool &all)
const Token *CheckMemoryLeakInFunction::findleak(const Token *tokens, bool all)
{
const Token *result = 0;
// No allocation at all => no leaks
if (Token::findmatch(tokens, "alloc") == 0)
{
return NULL;
}
if ((result = Token::findmatch(tokens, "loop alloc ;")) != NULL)
{
return result;
}
if ((result = Token::findmatch(tokens, "alloc ; if break|continue|return ;")) != NULL
&& Token::findmatch(tokens, "dealloc ; alloc ; if continue ;") == NULL)
{
return result->tokAt(3);
}
if (all && (result = Token::findmatch(tokens, "alloc ; ifv break|continue|return ;")) != NULL)
{
return result->tokAt(3);
}
if ((result = Token::findmatch(tokens, "alloc ; alloc|assign|return callfunc| ;")) != NULL)
{
return result->tokAt(2);
}
if ((result = Token::findmatch(tokens, "alloc ; }")) != NULL)
{
if (result->tokAt(3) == NULL)
return result->tokAt(2);
}
// No deallocation / usage => report leak at the last token
if (!Token::findmatch(tokens, "dealloc|use"))
{
const Token *last = tokens;
while (last->next())
last = last->next();
return last;
}
return NULL;
}
@ -1583,48 +1633,16 @@ void CheckMemoryLeakInFunction::checkScope(const Token *Tok1, const std::string
return;
}
if ((result = Token::findmatch(tok, "loop alloc ;")) != NULL)
if ((result = findleak(tok, _settings->_showAll)) != NULL)
{
memoryLeak(result, varname, alloctype, all);
}
else if ((result = Token::findmatch(tok, "alloc ; if break|continue|return ;")) != NULL
&& Token::findmatch(tok, "dealloc ; alloc ; if continue ;") == NULL)
{
memoryLeak(result->tokAt(3), varname, alloctype, all);
}
else if (_settings->_showAll && (result = Token::findmatch(tok, "alloc ; ifv break|continue|return ;")) != NULL)
{
memoryLeak(result->tokAt(3), varname, alloctype, all);
}
else if ((result = Token::findmatch(tok, "alloc ; alloc|assign|return callfunc| ;")) != NULL)
{
memoryLeak(result->tokAt(2), varname, alloctype, all);
}
else if ((result = Token::findmatch(tok, "dealloc ; dealloc ;")) != NULL)
{
deallocDeallocError(result->tokAt(2), varname);
}
else if (! Token::findmatch(tok, "dealloc") &&
! Token::findmatch(tok, "use") &&
! Token::findmatch(tok, "return use ;"))
{
const Token *last = tok;
while (last->next())
last = last->next();
memoryLeak(last, varname, alloctype, all);
}
else if ((result = Token::findmatch(tok, "alloc ; }")) != NULL)
{
if (result->tokAt(3) == NULL)
memoryLeak(result->tokAt(2), varname, alloctype, all);
}
// detect cases that "simplifycode" don't handle well..
else if (_settings->_debug)
{

View File

@ -237,6 +237,8 @@ private:
*/
void simplifycode(Token *tok, bool &all);
static const Token *findleak(const Token *tokens, bool all);
/**
* Checking the variable varname
* @param Tok1 start token

View File

@ -18,8 +18,8 @@
#include "../src/tokenize.h"
#define private public
#include "../src/tokenize.h"
#include "../src/checkmemoryleak.h"
#undef private
#include "testsuite.h"
@ -125,7 +125,9 @@ private:
// Todo: check that call_func works correctly..
// Todo: check that simplifycode works correctly..
// Todo: check if simplified code contains errors..
// Check that errors are found..
TEST_CASE(findleak);
TEST_CASE(simple5);
TEST_CASE(simple7);
@ -138,8 +140,6 @@ private:
TEST_CASE(alloc_alloc_1);
TEST_CASE(ifelse1);
TEST_CASE(ifelse2);
TEST_CASE(ifelse3);
TEST_CASE(ifelse4);
TEST_CASE(ifelse5);
@ -378,6 +378,70 @@ private:
ASSERT_EQUALS(";;exit;", getcode("char *s; exit(0);", "s"));
}
// is there a leak in given code? if so, return the linenr
int dofindleak(const char code[], bool all = false) const
{
// Tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
// replace "if ( ! var )" => "if(!var)"
for (Token *tok = tokenizer._tokens; tok; tok = tok->next())
{
if (Token::simpleMatch(tok, "if ( var )"))
{
Token::eraseTokens(tok, tok->tokAt(4));
tok->str("if(var)");
}
else if (Token::simpleMatch(tok, "if ( ! var )"))
{
Token::eraseTokens(tok, tok->tokAt(5));
tok->str("if(!var)");
}
}
const Token *tok = CheckMemoryLeakInFunction::findleak(tokenizer.tokens(), all);
return (tok ? tok->linenr() : -1);
}
void findleak()
{
ASSERT_EQUALS(1, dofindleak("alloc;"));
ASSERT_EQUALS(1, dofindleak("; use; alloc; }"));
ASSERT_EQUALS(2, dofindleak("alloc;\n return;"));
ASSERT_EQUALS(-1, dofindleak("alloc; return use;"));
ASSERT_EQUALS(2, dofindleak("alloc;\n callfunc;"));
ASSERT_EQUALS(-1, dofindleak("alloc; use;"));
ASSERT_EQUALS(-1, dofindleak("assign; alloc; dealloc;"));
ASSERT_EQUALS(-1, dofindleak("assign; if alloc; dealloc;"));
// if alloc..
ASSERT_EQUALS(2, dofindleak("if alloc;\n return;"));
ASSERT_EQUALS(-1, dofindleak("if alloc;\n return use;"));
ASSERT_EQUALS(-1, dofindleak("if alloc;\n use;"));
// if..
ASSERT_EQUALS(-1, dofindleak("alloc; ifv { dealloc; }"));
ASSERT_EQUALS(2, dofindleak("alloc;\n if return;\n dealloc;"));
ASSERT_EQUALS(3, dofindleak("alloc;\n if\n return;\n dealloc;"));
ASSERT_EQUALS(-1, dofindleak("alloc; if { dealloc ; return; } dealloc;"));
ASSERT_EQUALS(-1, dofindleak("alloc; if { dealloc ; return; } dealloc;"));
ASSERT_EQUALS(-1, dofindleak("alloc; if { dealloc ; alloc; } dealloc;"));
ASSERT_EQUALS(-1, dofindleak("alloc;\n if(!var)\n { callfunc;\n return;\n }\n use;"));
// assign..
ASSERT_EQUALS(2, dofindleak("alloc;\n assign;\n dealloc;"));
ASSERT_EQUALS(-1, dofindleak("alloc;\n if(!var) assign;\n dealloc;"));
// Todo..
ASSERT_EQUALS(-1, dofindleak("; alloc;\n if { dealloc; }\n ;"));
TODO_ASSERT_EQUALS(3, dofindleak("; alloc;\n if { dealloc; }\n ;"));
ASSERT_EQUALS(-1, dofindleak("alloc;\n if assign;\n dealloc;"));
TODO_ASSERT_EQUALS(2, dofindleak("alloc;\n if assign;\n dealloc;"));
}
void simple5()
@ -524,34 +588,8 @@ private:
void ifelse1()
{
check("void f()\n"
"{\n"
" int *a = new int[10];\n"
" if (a)\n"
" {\n"
" delete [] a;\n"
" }\n"
"}\n");
ASSERT_EQUALS("", errout.str());
}
void ifelse2()
{
check("void f()\n"
"{\n"
" char *str = strdup(\"hello\");\n"
" if (somecondition)\n"
" {\n"
" return;\n"
" }\n"
" free(str);\n"
"}\n");
ASSERT_EQUALS("[test.cpp:6]: (error) Memory leak: str\n", errout.str());
}
void ifelse3()
{