Check for memory leaks
This commit is contained in:
parent
cd169a6c27
commit
9896c237bb
153
main.cpp
153
main.cpp
|
@ -29,20 +29,21 @@ struct STATEMENT
|
||||||
enum etype {OBRACE, EBRACE, DECL, ASSIGN, NEW, DELETE, NEWARRAY, DELETEARRAY};
|
enum etype {OBRACE, EBRACE, DECL, ASSIGN, NEW, DELETE, NEWARRAY, DELETEARRAY};
|
||||||
etype Type;
|
etype Type;
|
||||||
unsigned int VarIndex;
|
unsigned int VarIndex;
|
||||||
|
TOKEN *Token;
|
||||||
};
|
};
|
||||||
std::list<STATEMENT> Statements;
|
std::list<STATEMENT> Statements;
|
||||||
void CreateStatementList();
|
void CreateStatementList();
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Memory leak..
|
||||||
|
void CheckMemoryLeak();
|
||||||
|
|
||||||
// Class
|
// Class
|
||||||
void CheckConstructors();
|
void CheckConstructors();
|
||||||
void CheckUnusedPrivateFunctions();
|
void CheckUnusedPrivateFunctions();
|
||||||
void CheckMemset();
|
void CheckMemset();
|
||||||
void CheckOperatorEq1(); // Warning upon "void operator=(.."
|
void CheckOperatorEq1(); // Warning upon "void operator=(.."
|
||||||
|
|
||||||
// Function
|
|
||||||
void CheckMovableVariableDeclaration();
|
|
||||||
|
|
||||||
// Casting
|
// Casting
|
||||||
void WarningOldStylePointerCast();
|
void WarningOldStylePointerCast();
|
||||||
|
|
||||||
|
@ -83,6 +84,11 @@ static void CppCheck(const char FileName[])
|
||||||
|
|
||||||
CreateStatementList();
|
CreateStatementList();
|
||||||
|
|
||||||
|
|
||||||
|
// Memory leak
|
||||||
|
CheckMemoryLeak();
|
||||||
|
|
||||||
|
|
||||||
//std::ofstream f("tokens.txt");
|
//std::ofstream f("tokens.txt");
|
||||||
//for (TOKEN *tok = tokens; tok; tok = tok->next)
|
//for (TOKEN *tok = tokens; tok; tok = tok->next)
|
||||||
// f << "[" << Files[tok->FileIndex] << ":" << tok->linenr << "]:" << tok->str << '\n';
|
// f << "[" << Files[tok->FileIndex] << ":" << tok->linenr << "]:" << tok->str << '\n';
|
||||||
|
@ -492,10 +498,11 @@ std::string FileLine(TOKEN *tok)
|
||||||
// Create statement list
|
// Create statement list
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
void AppendStatement(STATEMENT::etype Type, std::string Var="")
|
void AppendStatement(STATEMENT::etype Type, TOKEN *tok, std::string Var="")
|
||||||
{
|
{
|
||||||
STATEMENT NewStatement;
|
STATEMENT NewStatement;
|
||||||
NewStatement.Type = Type;
|
NewStatement.Type = Type;
|
||||||
|
NewStatement.Token = tok;
|
||||||
if (Var.empty())
|
if (Var.empty())
|
||||||
{
|
{
|
||||||
NewStatement.VarIndex = 0;
|
NewStatement.VarIndex = 0;
|
||||||
|
@ -559,12 +566,12 @@ void CreateStatementList()
|
||||||
{
|
{
|
||||||
if (tok->str[0] == '{')
|
if (tok->str[0] == '{')
|
||||||
{
|
{
|
||||||
AppendStatement(STATEMENT::OBRACE);
|
AppendStatement(STATEMENT::OBRACE, tok);
|
||||||
indentlevel++;
|
indentlevel++;
|
||||||
}
|
}
|
||||||
else if (tok->str[0] == '}')
|
else if (tok->str[0] == '}')
|
||||||
{
|
{
|
||||||
AppendStatement(STATEMENT::EBRACE);
|
AppendStatement(STATEMENT::EBRACE, tok);
|
||||||
indentlevel--;
|
indentlevel--;
|
||||||
}
|
}
|
||||||
else if (indentlevel >= 1)
|
else if (indentlevel >= 1)
|
||||||
|
@ -582,7 +589,7 @@ void CreateStatementList()
|
||||||
const char *str1 = getstr(tok2, 1);
|
const char *str1 = getstr(tok2, 1);
|
||||||
if (IsName(tok2->str) && strchr("[=,;",str1[0]))
|
if (IsName(tok2->str) && strchr("[=,;",str1[0]))
|
||||||
{
|
{
|
||||||
AppendStatement(STATEMENT::DECL, tok2->str);
|
AppendStatement(STATEMENT::DECL, tok2, tok2->str);
|
||||||
while (tok2 && !strchr(",;", tok2->str[0]))
|
while (tok2 && !strchr(",;", tok2->str[0]))
|
||||||
tok2 = tok2->next;
|
tok2 = tok2->next;
|
||||||
if (tok2->str[0] == ';')
|
if (tok2->str[0] == ';')
|
||||||
|
@ -632,16 +639,16 @@ void CreateStatementList()
|
||||||
TOKEN *rs = eq->next;
|
TOKEN *rs = eq->next;
|
||||||
|
|
||||||
if ( match(rs,"new type ;") )
|
if ( match(rs,"new type ;") )
|
||||||
AppendStatement(STATEMENT::NEW, varname.str());
|
AppendStatement(STATEMENT::NEW, tok2, varname.str());
|
||||||
|
|
||||||
else if ( match(rs, "new type (") )
|
else if ( match(rs, "new type (") )
|
||||||
AppendStatement(STATEMENT::NEW, varname.str());
|
AppendStatement(STATEMENT::NEW, tok2, varname.str());
|
||||||
|
|
||||||
else if ( match(rs, "new type [") )
|
else if ( match(rs, "new type [") )
|
||||||
AppendStatement(STATEMENT::NEWARRAY, varname.str());
|
AppendStatement(STATEMENT::NEWARRAY, tok2, varname.str());
|
||||||
|
|
||||||
else
|
else
|
||||||
AppendStatement(STATEMENT::ASSIGN, varname.str());
|
AppendStatement(STATEMENT::ASSIGN, tok2, varname.str());
|
||||||
|
|
||||||
tok2 = eq;
|
tok2 = eq;
|
||||||
}
|
}
|
||||||
|
@ -654,9 +661,9 @@ void CreateStatementList()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (match(tok2,"delete var ;"))
|
if (match(tok2,"delete var ;"))
|
||||||
AppendStatement(STATEMENT::DELETE, getstr(tok2,1));
|
AppendStatement(STATEMENT::DELETE, tok2, getstr(tok2,1));
|
||||||
if (match(tok2,"delete [ ] var ;"))
|
if (match(tok2,"delete [ ] var ;"))
|
||||||
AppendStatement(STATEMENT::DELETEARRAY, getstr(tok2,3));
|
AppendStatement(STATEMENT::DELETEARRAY, tok2, getstr(tok2,3));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -910,6 +917,126 @@ TOKEN * ClassChecking_VarList_RemoveAssigned(TOKEN *_tokens, struct VAR *varlist
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Memory leak..
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void CheckMemoryLeak()
|
||||||
|
{
|
||||||
|
struct _variable
|
||||||
|
{
|
||||||
|
int indentlevel;
|
||||||
|
unsigned int varindex;
|
||||||
|
enum {Any, Data, New, NewA} value;
|
||||||
|
};
|
||||||
|
std::vector<_variable *> varlist;
|
||||||
|
|
||||||
|
|
||||||
|
// Parse the statement list and locate memory leaks..
|
||||||
|
int indentlevel = 0;
|
||||||
|
std::list<STATEMENT>::const_iterator it;
|
||||||
|
for (it = Statements.begin(); it != Statements.end(); it++)
|
||||||
|
{
|
||||||
|
switch (it->Type)
|
||||||
|
{
|
||||||
|
case STATEMENT::OBRACE:
|
||||||
|
indentlevel++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATEMENT::EBRACE:
|
||||||
|
// Check if any variables go out of scope..
|
||||||
|
if (indentlevel >= 1)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < varlist.size(); i++)
|
||||||
|
{
|
||||||
|
if (varlist[i]->indentlevel != indentlevel)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// This is highly inaccurate at the moment
|
||||||
|
if (Debug)
|
||||||
|
{
|
||||||
|
if (varlist[i]->value == _variable::New || varlist[i]->value == _variable::NewA)
|
||||||
|
{
|
||||||
|
std::ostringstream ostr;
|
||||||
|
ostr << "Memory leak:" << VariableNames[varlist[i]->varindex];
|
||||||
|
ReportErr(ostr.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete this instance..
|
||||||
|
delete varlist[i];
|
||||||
|
varlist.erase(varlist.begin()+i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
indentlevel--;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATEMENT::DECL:
|
||||||
|
if (indentlevel > 0)
|
||||||
|
{
|
||||||
|
_variable *NewVar = new _variable;
|
||||||
|
NewVar->indentlevel = indentlevel;
|
||||||
|
NewVar->varindex = it->VarIndex;
|
||||||
|
varlist.push_back(NewVar);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATEMENT::NEW:
|
||||||
|
case STATEMENT::NEWARRAY:
|
||||||
|
case STATEMENT::DELETE:
|
||||||
|
case STATEMENT::DELETEARRAY:
|
||||||
|
for (unsigned int i = 0; i < varlist.size(); i++)
|
||||||
|
{
|
||||||
|
if ( varlist[i]->varindex == it->VarIndex )
|
||||||
|
{
|
||||||
|
bool isalloc = (varlist[i]->value==_variable::New || varlist[i]->value==_variable::NewA);
|
||||||
|
bool alloc = (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 a1 = (varlist[i]->value == _variable::NewA);
|
||||||
|
bool a2 = (it->Type == STATEMENT::DELETEARRAY);
|
||||||
|
|
||||||
|
if (a1 != a2)
|
||||||
|
{
|
||||||
|
std::ostringstream ostr;
|
||||||
|
ostr << FileLine(it->Token) << ": Mismatching allocation and deallocation";
|
||||||
|
ReportErr(ostr.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( it->Type == STATEMENT::NEW )
|
||||||
|
varlist[i]->value = _variable::New;
|
||||||
|
|
||||||
|
if ( it->Type == STATEMENT::NEWARRAY )
|
||||||
|
varlist[i]->value = _variable::NewA;
|
||||||
|
|
||||||
|
if ( it->Type == STATEMENT::DELETE )
|
||||||
|
varlist[i]->value = _variable::Any;
|
||||||
|
|
||||||
|
if ( it->Type == STATEMENT::DELETEARRAY )
|
||||||
|
varlist[i]->value = _variable::Any;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// Check that all class constructors are ok.
|
// Check that all class constructors are ok.
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
Loading…
Reference in New Issue