Rewriting CheckMemoryLeak (Just Started)
This commit is contained in:
parent
60e454fa11
commit
b6868b7f1a
|
@ -2,7 +2,6 @@
|
||||||
#include "CheckMemoryLeak.h"
|
#include "CheckMemoryLeak.h"
|
||||||
|
|
||||||
#include "tokenize.h"
|
#include "tokenize.h"
|
||||||
#include "Statements.h"
|
|
||||||
|
|
||||||
#include "CommonCheck.h"
|
#include "CommonCheck.h"
|
||||||
|
|
||||||
|
@ -21,288 +20,100 @@ extern bool ShowAll;
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
struct _variable
|
static void CheckMemoryLeak_CheckScope( const TOKEN *Tok1, const char *varname[] )
|
||||||
{
|
{
|
||||||
int indentlevel;
|
// Goto end of statement..
|
||||||
unsigned int varindex;
|
const TOKEN *tok = Tok1;
|
||||||
enum {Any, Data, Malloc, New, NewA} value;
|
while (tok && tok->str[0] != ';')
|
||||||
int dealloc_level;
|
tok = tok->next;
|
||||||
};
|
|
||||||
|
|
||||||
|
int indentlevel = 0;
|
||||||
|
for ( ; tok; tok = tok->next )
|
||||||
|
{
|
||||||
|
if (tok->str[0]=='{')
|
||||||
|
indentlevel++;
|
||||||
|
|
||||||
|
else if (tok->str[0]=='}')
|
||||||
|
{
|
||||||
|
indentlevel--;
|
||||||
|
if ( indentlevel < 0 )
|
||||||
|
{
|
||||||
|
std::ostringstream errmsg;
|
||||||
|
errmsg << FileLine(Tok1) << ": Memory leak:" << varname[0];
|
||||||
|
ReportErr( errmsg.str() );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deallocated..
|
||||||
|
if ( Match(tok, "delete %var1% ;", varname) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( Match(tok, "delete [ ] %var1% ;", varname) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( Match(tok, "free ( %var1% ) ;", varname) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( Match(tok, "kfree ( %var1% ) ;", varname) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Used..
|
||||||
|
if ( strchr("=,(", tok->str[0]) && Match( tok->next, "%var1%", varname ) )
|
||||||
|
return;
|
||||||
|
if ( Match( tok, "return %var1%", varname ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// Checks for memory leaks inside function..
|
// Checks for memory leaks inside function..
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
static void _InFunction()
|
static void CheckMemoryLeak_InFunction()
|
||||||
{
|
{
|
||||||
std::vector<_variable *> varlist;
|
|
||||||
|
|
||||||
// if
|
|
||||||
int iflevel = 0;
|
|
||||||
bool endif = false;
|
|
||||||
std::vector<bool> iflist;
|
|
||||||
|
|
||||||
// loop
|
|
||||||
int looplevel = 0;
|
|
||||||
bool endloop = false;
|
|
||||||
std::vector<bool> looplist;
|
|
||||||
|
|
||||||
// switch
|
|
||||||
int switchlevel = 0;
|
|
||||||
bool endswitch = false;
|
|
||||||
std::vector<bool> switchlist;
|
|
||||||
|
|
||||||
// Parse the statement list and locate memory leaks..
|
|
||||||
int indentlevel = 0;
|
int indentlevel = 0;
|
||||||
std::list<STATEMENT>::const_iterator it;
|
for (const TOKEN *tok = tokens; tok; tok = tok->next)
|
||||||
for (it = Statements.begin(); it != Statements.end(); it++)
|
|
||||||
{
|
{
|
||||||
switch (it->Type)
|
if (tok->str[0]=='{')
|
||||||
|
indentlevel++;
|
||||||
|
|
||||||
|
else if (tok->str[0]=='}')
|
||||||
|
indentlevel--;
|
||||||
|
|
||||||
|
else if (indentlevel > 0 && Match(tok, "%var% = "))
|
||||||
{
|
{
|
||||||
case STATEMENT::OBRACE:
|
// What we may have...
|
||||||
indentlevel++;
|
// * var = (char *)malloc(10);
|
||||||
iflist.push_back(endif);
|
// * var = new char[10];
|
||||||
if (endif)
|
// * var = strdup("hello");
|
||||||
iflevel++;
|
const TOKEN *tok2 = gettok(tok, 2);
|
||||||
looplist.push_back(endloop);
|
if ( tok2 && tok2->str[0] == '(' )
|
||||||
if (endloop)
|
{
|
||||||
looplevel++;
|
while ( tok2 && tok2->str[0] != ')' )
|
||||||
switchlist.push_back(endswitch);
|
tok2 = tok2->next;
|
||||||
if (endswitch)
|
tok2 = tok2 ? tok2->next : NULL;
|
||||||
switchlevel++;
|
}
|
||||||
break;
|
if ( ! tok2 )
|
||||||
|
continue;
|
||||||
|
|
||||||
case STATEMENT::EBRACE:
|
// tok2 now points on "malloc", "new", "strdup" or something like that..
|
||||||
// Check if any variables go out of scope..
|
const char *allocfunc[] = {"malloc", "strdup", "kmalloc", "new", 0};
|
||||||
if (indentlevel >= 1)
|
for ( unsigned int i = 0; allocfunc[i]; i++ )
|
||||||
|
{
|
||||||
|
if ( strcmp(allocfunc[i], tok2->str) == 0 )
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < varlist.size(); i++)
|
const char *varname[2] = {0,0};
|
||||||
{
|
varname[0] = tok->str;
|
||||||
struct _variable *var = varlist[i];
|
CheckMemoryLeak_CheckScope(tok, varname);
|
||||||
|
|
||||||
if (var->dealloc_level == indentlevel)
|
|
||||||
var->dealloc_level = 0;
|
|
||||||
|
|
||||||
if (var->indentlevel != indentlevel)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (var->value == _variable::Malloc || var->value == _variable::New || var->value == _variable::NewA)
|
|
||||||
{
|
|
||||||
std::ostringstream ostr;
|
|
||||||
ostr << FileLine(it->Token) << ": Memory leak:" << VariableNames[varlist[i]->varindex];
|
|
||||||
ReportErr(ostr.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete this instance..
|
|
||||||
delete varlist[i];
|
|
||||||
varlist.erase(varlist.begin()+i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if level..
|
|
||||||
if ( ! iflist.empty() )
|
|
||||||
{
|
|
||||||
if (iflist.back())
|
|
||||||
iflevel--;
|
|
||||||
iflist.pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
// loop level..
|
|
||||||
if ( ! looplist.empty() )
|
|
||||||
{
|
|
||||||
if (looplist.back())
|
|
||||||
looplevel--;
|
|
||||||
looplist.pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
// switch level..
|
|
||||||
if ( ! switchlist.empty() )
|
|
||||||
{
|
|
||||||
if (switchlist.back())
|
|
||||||
switchlevel--;
|
|
||||||
switchlist.pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure the varlist is empty..
|
|
||||||
if (indentlevel <= 1)
|
|
||||||
varlist.clear();
|
|
||||||
|
|
||||||
if (indentlevel > 0)
|
|
||||||
indentlevel--;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case STATEMENT::DECL:
|
|
||||||
if (indentlevel > 0)
|
|
||||||
{
|
|
||||||
_variable *NewVar = new _variable;
|
|
||||||
memset(NewVar, 0, sizeof(_variable));
|
|
||||||
NewVar->indentlevel = indentlevel;
|
|
||||||
NewVar->varindex = it->VarIndex;
|
|
||||||
varlist.push_back(NewVar);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case STATEMENT::IF:
|
|
||||||
case STATEMENT::ELSEIF:
|
|
||||||
case STATEMENT::ELSE:
|
|
||||||
// Conditional statements..
|
|
||||||
iflevel++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case STATEMENT::ENDIF:
|
|
||||||
iflevel--;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Not very interested in these..
|
|
||||||
case STATEMENT::LOOP:
|
|
||||||
case STATEMENT::ENDLOOP:
|
|
||||||
case STATEMENT::SWITCH:
|
|
||||||
case STATEMENT::ENDSWITCH:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case STATEMENT::MALLOC:
|
|
||||||
case STATEMENT::NEW:
|
|
||||||
case STATEMENT::NEWARRAY:
|
|
||||||
case STATEMENT::FREE:
|
|
||||||
case STATEMENT::DELETE:
|
|
||||||
case STATEMENT::DELETEARRAY:
|
|
||||||
// Don't handle conditional allocation at the moment..
|
|
||||||
if (iflevel>0 && (it->Type==STATEMENT::MALLOC || it->Type==STATEMENT::NEW || it->Type==STATEMENT::NEWARRAY))
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < varlist.size(); i++)
|
|
||||||
{
|
|
||||||
if ( varlist[i]->varindex == it->VarIndex )
|
|
||||||
{
|
|
||||||
bool isalloc = (varlist[i]->value==_variable::Malloc || varlist[i]->value==_variable::New || varlist[i]->value==_variable::NewA);
|
|
||||||
bool alloc = (it->Type==STATEMENT::MALLOC || it->Type==STATEMENT::NEW || it->Type==STATEMENT::NEWARRAY);
|
|
||||||
|
|
||||||
// Already allocated and then allocated again..
|
|
||||||
//bool err = (isalloc & alloc);
|
|
||||||
|
|
||||||
if (isalloc && !alloc)
|
|
||||||
{
|
|
||||||
// Check that the deallocation matches..
|
|
||||||
bool err = false;
|
|
||||||
|
|
||||||
err |= (varlist[i]->value==_variable::Malloc && it->Type!=STATEMENT::FREE);
|
|
||||||
err |= (varlist[i]->value==_variable::New && it->Type!=STATEMENT::DELETE);
|
|
||||||
err |= (varlist[i]->value==_variable::NewA && it->Type!=STATEMENT::DELETEARRAY);
|
|
||||||
|
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
std::ostringstream ostr;
|
|
||||||
ostr << FileLine(it->Token) << ": Mismatching allocation and deallocation '" << VariableNames[varlist[i]->varindex] << "'";
|
|
||||||
ReportErr(ostr.str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( it->Type == STATEMENT::MALLOC )
|
|
||||||
varlist[i]->value = _variable::Malloc;
|
|
||||||
|
|
||||||
else if ( it->Type == STATEMENT::NEW )
|
|
||||||
varlist[i]->value = _variable::New;
|
|
||||||
|
|
||||||
else if ( it->Type == STATEMENT::NEWARRAY )
|
|
||||||
varlist[i]->value = _variable::NewA;
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Deallocation...
|
|
||||||
if (indentlevel > varlist[i]->indentlevel)
|
|
||||||
varlist[i]->dealloc_level = indentlevel;
|
|
||||||
else
|
|
||||||
varlist[i]->value = _variable::Any;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
|
|
||||||
case STATEMENT::ASSIGN:
|
|
||||||
case STATEMENT::USE:
|
|
||||||
for (unsigned int i = 0; i < varlist.size(); i++)
|
|
||||||
{
|
|
||||||
if ( varlist[i]->varindex == it->VarIndex )
|
|
||||||
{
|
|
||||||
varlist[i]->value = _variable::Data;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case STATEMENT::RETURN:
|
|
||||||
for (unsigned int i = 0; i < varlist.size(); i++)
|
|
||||||
{
|
|
||||||
struct _variable *var = varlist[i];
|
|
||||||
|
|
||||||
if ( var->varindex == it->VarIndex )
|
|
||||||
{
|
|
||||||
var->value = _variable::Any;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (var->dealloc_level != indentlevel &&
|
|
||||||
(var->value==_variable::New ||
|
|
||||||
var->value==_variable::NewA ||
|
|
||||||
var->value==_variable::Malloc ) )
|
|
||||||
{
|
|
||||||
std::ostringstream ostr;
|
|
||||||
ostr << FileLine(it->Token) << ": Memory leak:" << VariableNames[varlist[i]->varindex];
|
|
||||||
ReportErr(ostr.str());
|
|
||||||
var->value = _variable::Any;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case STATEMENT::CONTINUE:
|
|
||||||
case STATEMENT::BREAK:
|
|
||||||
// Memory leak if variable is allocated..
|
|
||||||
if (looplevel>0)
|
|
||||||
{
|
|
||||||
// Find the last loop..
|
|
||||||
for (int i = looplist.size() - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
if (switchlist[i])
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!looplist[i])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int loop_indentlevel = i + 1;
|
|
||||||
|
|
||||||
for (i = 0; i < (int)varlist.size(); i++)
|
|
||||||
{
|
|
||||||
if (varlist[i]->indentlevel < loop_indentlevel)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (varlist[i]->value==_variable::Malloc ||
|
|
||||||
varlist[i]->value==_variable::New ||
|
|
||||||
varlist[i]->value==_variable::NewA )
|
|
||||||
{
|
|
||||||
std::ostringstream ostr;
|
|
||||||
ostr << FileLine(it->Token) << ": Memory leak:" << VariableNames[varlist[i]->varindex];
|
|
||||||
ReportErr(ostr.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
endif = (it->Type == STATEMENT::ENDIF);
|
|
||||||
endloop = (it->Type == STATEMENT::ENDLOOP);
|
|
||||||
endswitch = (it->Type == STATEMENT::ENDSWITCH);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
@ -310,188 +121,12 @@ static void _InFunction()
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// Check that all class members are deallocated..
|
// Checks for memory leaks in classes..
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
static void _ClassMembers_CheckVar(const char *classname, const char *varname)
|
static void CheckMemoryLeak_ClassMembers()
|
||||||
{
|
{
|
||||||
// Check how the variable 'varname' is allocated..
|
|
||||||
enum {No, New, NewA, Malloc} Alloc, Dealloc;
|
|
||||||
Alloc = Dealloc = No;
|
|
||||||
for (TOKEN *func = tokens; func; func = func->next)
|
|
||||||
{
|
|
||||||
if (strcmp(func->str, classname))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (strcmp(getstr(func, 1), "::") != 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ((strcmp(getstr(func,2),"~")==0 &&
|
|
||||||
strcmp(getstr(func,3),classname)==0 &&
|
|
||||||
strcmp(getstr(func,4),"(")==0) ||
|
|
||||||
(strcmp(getstr(func, 3), "(") != 0))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
|
|
||||||
int indentlevel = 0;
|
|
||||||
for (TOKEN *tok = func; tok; tok = tok->next)
|
|
||||||
{
|
|
||||||
if (tok->str[0] == '{')
|
|
||||||
{
|
|
||||||
indentlevel++;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (tok->str[0] == '}')
|
|
||||||
{
|
|
||||||
indentlevel--;
|
|
||||||
if (indentlevel == 0)
|
|
||||||
{
|
|
||||||
func = tok;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (indentlevel==0 && tok->str[0] == ';')
|
|
||||||
{
|
|
||||||
func = tok;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (indentlevel > 0)
|
|
||||||
{
|
|
||||||
// Deallocation..
|
|
||||||
if (strcmp(tok->str,"delete")==0 || strcmp(tok->str,"free")==0)
|
|
||||||
{
|
|
||||||
bool err = false;
|
|
||||||
|
|
||||||
if (Match(tok, "delete %var% ;") &&
|
|
||||||
strcmp(getstr(tok,1),varname)==0)
|
|
||||||
{
|
|
||||||
err |= ( Alloc != No && Alloc != New );
|
|
||||||
Dealloc = New;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (Match(tok, "delete [ ] %var% ;") &&
|
|
||||||
strcmp(getstr(tok,3),varname)==0)
|
|
||||||
{
|
|
||||||
err |= ( Alloc != No && Alloc != NewA );
|
|
||||||
Dealloc = NewA;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (Match(tok, "free ( %var% )") &&
|
|
||||||
strcmp(getstr(tok,2),varname)==0)
|
|
||||||
{
|
|
||||||
err |= ( Alloc != No && Alloc != Malloc );
|
|
||||||
Dealloc = Malloc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
std::ostringstream ostr;
|
|
||||||
ostr << FileLine(tok) << ": Mismatching deallocation for '" << classname << "::" << varname << "'";
|
|
||||||
ReportErr(ostr.str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Allocation...
|
|
||||||
if ( strcmp(tok->str, varname) != 0 )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ( strcmp(getstr(tok,1), "=") != 0 )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
bool err = false;
|
|
||||||
|
|
||||||
if ( strcmp(getstr(tok,2), "new") == 0 )
|
|
||||||
{
|
|
||||||
if ( Match(tok, "%var% = new %type% ;") ||
|
|
||||||
Match(tok, "%var% = new %type% (") )
|
|
||||||
{
|
|
||||||
if ( ! ShowAll && ! IsStandardType(getstr(tok,3)) )
|
|
||||||
continue;
|
|
||||||
err |= ( Dealloc != No && Dealloc != New );
|
|
||||||
Alloc = New;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if ( Match(tok, "%var% = new %type% [") )
|
|
||||||
{
|
|
||||||
if ( ! ShowAll && ! IsStandardType(getstr(tok,3)) )
|
|
||||||
continue;
|
|
||||||
err |= ( Dealloc != No && Dealloc != NewA );
|
|
||||||
Alloc = NewA;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if ( Match(tok, "%var% = strdup (") ||
|
|
||||||
Match(tok, "%var% = ( %type% * ) malloc ("))
|
|
||||||
{
|
|
||||||
if ( ! ShowAll &&
|
|
||||||
tok->next->next->str[0] == '(' &&
|
|
||||||
! IsStandardType(getstr(tok,3)) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
err |= ( Dealloc != No && Dealloc != Malloc );
|
|
||||||
Alloc = Malloc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
std::ostringstream ostr;
|
|
||||||
ostr << FileLine(tok) << ": Mismatching allocation for '" << classname << "::" << varname << "'";
|
|
||||||
ReportErr(ostr.str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( Alloc != Dealloc && Dealloc == No )
|
|
||||||
{
|
|
||||||
std::ostringstream ostr;
|
|
||||||
ostr << "Memory leak for '" << classname << "::" << varname << "'";
|
|
||||||
ReportErr(ostr.str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _ClassMembers()
|
|
||||||
{
|
|
||||||
for (TOKEN *ClassDecl = tokens; ClassDecl; ClassDecl = ClassDecl->next)
|
|
||||||
{
|
|
||||||
// Is this a class declaration?
|
|
||||||
// -------------------------------------
|
|
||||||
if ( ! Match(ClassDecl, "class %var% {") )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const char *classname = getstr(ClassDecl, 1);
|
|
||||||
|
|
||||||
// Locate member variables..
|
|
||||||
int indentlevel = 0;
|
|
||||||
for (TOKEN *ClassVar = ClassDecl; ClassVar; ClassVar = ClassVar->next)
|
|
||||||
{
|
|
||||||
if ( ClassVar->str[0] == '{' )
|
|
||||||
indentlevel++;
|
|
||||||
|
|
||||||
else if ( ClassVar->str[0] == '}' )
|
|
||||||
{
|
|
||||||
indentlevel--;
|
|
||||||
if (indentlevel == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (indentlevel == 1)
|
|
||||||
{
|
|
||||||
if ( Match(ClassVar, "%type% * %var% ;") )
|
|
||||||
{
|
|
||||||
const char *varname = getstr(ClassVar, 2);
|
|
||||||
|
|
||||||
// Check the variable usage..
|
|
||||||
_ClassMembers_CheckVar(classname, varname);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -501,15 +136,11 @@ static void _ClassMembers()
|
||||||
|
|
||||||
void CheckMemoryLeak()
|
void CheckMemoryLeak()
|
||||||
{
|
{
|
||||||
// Create statement list.
|
|
||||||
Statements.clear();
|
|
||||||
CreateStatementList();
|
|
||||||
|
|
||||||
// Check for memory leaks inside functions..
|
// Check for memory leaks inside functions..
|
||||||
_InFunction();
|
CheckMemoryLeak_InFunction();
|
||||||
|
|
||||||
// Check that all class members are deallocated..
|
// Check that all class members are deallocated..
|
||||||
_ClassMembers();
|
CheckMemoryLeak_ClassMembers();
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
178
tests.cpp
178
tests.cpp
|
@ -4,7 +4,6 @@
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
#include "tokenize.h" // <- Tokenizer
|
#include "tokenize.h" // <- Tokenizer
|
||||||
#include "Statements.h"
|
|
||||||
#include "CommonCheck.h"
|
#include "CommonCheck.h"
|
||||||
|
|
||||||
#include "CheckBufferOverrun.h"
|
#include "CheckBufferOverrun.h"
|
||||||
|
@ -22,7 +21,6 @@ bool Debug = false;
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
static unsigned int FailCount, SuccessCount;
|
static unsigned int FailCount, SuccessCount;
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
static void internal_statementlist();
|
|
||||||
static void buffer_overrun();
|
static void buffer_overrun();
|
||||||
static void constructors();
|
static void constructors();
|
||||||
static void operator_eq();
|
static void operator_eq();
|
||||||
|
@ -40,9 +38,6 @@ int main()
|
||||||
// Don't filter out duplicate error messages..
|
// Don't filter out duplicate error messages..
|
||||||
OnlyReportUniqueErrors = false;
|
OnlyReportUniqueErrors = false;
|
||||||
|
|
||||||
// Check that the statement list is created correctly
|
|
||||||
internal_statementlist();
|
|
||||||
|
|
||||||
// Check that buffer overruns are detected
|
// Check that buffer overruns are detected
|
||||||
buffer_overrun();
|
buffer_overrun();
|
||||||
|
|
||||||
|
@ -111,177 +106,6 @@ static void check(void (chk)(),
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
static void statementlist()
|
|
||||||
{
|
|
||||||
CreateStatementList();
|
|
||||||
OutputStatementList( errout );
|
|
||||||
}
|
|
||||||
|
|
||||||
static void internal_statementlist()
|
|
||||||
{
|
|
||||||
const char code1[] = "void f()\n"
|
|
||||||
"{\n"
|
|
||||||
" a = 1;\n"
|
|
||||||
" b[2] = 3;\n"
|
|
||||||
" c[4][5].min = 6;\n"
|
|
||||||
" d.min = 7;\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
const char sl1[] = "{\n"
|
|
||||||
"assign a\n"
|
|
||||||
"assign b[2]\n"
|
|
||||||
"assign c[4][5].min\n"
|
|
||||||
"assign d.min\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
check( statementlist, __LINE__, code1, sl1 );
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const char code2[] = "void f()\n"
|
|
||||||
"{\n"
|
|
||||||
" int a;\n"
|
|
||||||
" int b = 2, c, *d = NULL;\n"
|
|
||||||
" int e = g(p1,p2);\n"
|
|
||||||
" char str[10];\n"
|
|
||||||
" return a;\n"
|
|
||||||
" delete a;\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
const char sl2[] = "{\n"
|
|
||||||
"decl a\n"
|
|
||||||
"decl b\n"
|
|
||||||
"assign b\n"
|
|
||||||
"decl c\n"
|
|
||||||
"decl d\n"
|
|
||||||
"assign d\n"
|
|
||||||
"use NULL\n"
|
|
||||||
"decl e\n"
|
|
||||||
"assign e\n"
|
|
||||||
"use p1\n"
|
|
||||||
"use p2\n"
|
|
||||||
"decl str\n"
|
|
||||||
"return a\n"
|
|
||||||
"delete a\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
check( statementlist, __LINE__, code2, sl2 );
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const char code3[] = "void f()\n"
|
|
||||||
"{\n"
|
|
||||||
" if (ab)\n"
|
|
||||||
" {\n"
|
|
||||||
" }\n"
|
|
||||||
" else if (cd)\n"
|
|
||||||
" {\n"
|
|
||||||
" }\n"
|
|
||||||
" else\n"
|
|
||||||
" {\n"
|
|
||||||
" }\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
const char sl3[] = "{\n"
|
|
||||||
"if\n"
|
|
||||||
"use ab\n"
|
|
||||||
"endif\n"
|
|
||||||
"{\n"
|
|
||||||
"}\n"
|
|
||||||
"elseif\n"
|
|
||||||
"use cd\n"
|
|
||||||
"endif\n"
|
|
||||||
"{\n"
|
|
||||||
"}\n"
|
|
||||||
"else\n"
|
|
||||||
"endif\n"
|
|
||||||
"{\n"
|
|
||||||
"}\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
check( statementlist, __LINE__, code3, sl3 );
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const char code4[] = "void f()\n"
|
|
||||||
"{\n"
|
|
||||||
" for (int i = 0; i < j; i++)\n"
|
|
||||||
" {\n"
|
|
||||||
" if (condition)\n"
|
|
||||||
" continue;\n"
|
|
||||||
" break;\n"
|
|
||||||
" }\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
const char sl4[] = "{\n"
|
|
||||||
"loop\n"
|
|
||||||
"assign i\n"
|
|
||||||
"use i\n"
|
|
||||||
"use i\n"
|
|
||||||
"use j\n"
|
|
||||||
"use i\n"
|
|
||||||
"endloop\n"
|
|
||||||
"{\n"
|
|
||||||
"if\n"
|
|
||||||
"use condition\n"
|
|
||||||
"continue\n"
|
|
||||||
"endif\n"
|
|
||||||
"break\n"
|
|
||||||
"}\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
check( statementlist, __LINE__, code4, sl4 );
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const char code5[] = "void f()\n"
|
|
||||||
"{\n"
|
|
||||||
" a = new char[10];\n"
|
|
||||||
" fred = new Fred;\n"
|
|
||||||
" fred = new Fred();\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
const char sl5[] = "{\n"
|
|
||||||
"new[] a\n"
|
|
||||||
"use char[10]\n"
|
|
||||||
"new fred\n"
|
|
||||||
"use Fred\n"
|
|
||||||
"new fred\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
check( statementlist, __LINE__, code5, sl5 );
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const char code6[] = "void f()\n"
|
|
||||||
"{\n"
|
|
||||||
" a = b;\n"
|
|
||||||
" c = func(d,e);\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
const char sl6[] = "{\n"
|
|
||||||
"assign a\n"
|
|
||||||
"use b\n"
|
|
||||||
"assign c\n"
|
|
||||||
"use d\n"
|
|
||||||
"use e\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
check( statementlist, __LINE__, code6, sl6 );
|
|
||||||
|
|
||||||
}
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
static void buffer_overrun()
|
static void buffer_overrun()
|
||||||
{
|
{
|
||||||
// test1: numeric array index
|
// test1: numeric array index
|
||||||
|
@ -607,7 +431,7 @@ static void memleak_in_function()
|
||||||
"{\n"
|
"{\n"
|
||||||
" int *a = new int[10];\n"
|
" int *a = new int[10];\n"
|
||||||
"}\n";
|
"}\n";
|
||||||
check( CheckMemoryLeak, __LINE__, test1, "[test.cpp:4]: Memory leak:a\n" );
|
check( CheckMemoryLeak, __LINE__, test1, "[test.cpp:3]: Memory leak:a\n" );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue