memory allocation: check for mismatching size

This commit is contained in:
Daniel Marjamäki 2009-02-07 10:54:39 +00:00
parent bb71f9e83e
commit 3c289e52c5
6 changed files with 57 additions and 17 deletions

View File

@ -193,7 +193,7 @@ CheckMemoryLeakClass::AllocType CheckMemoryLeakClass::GetDeallocationType(const
}
//--------------------------------------------------------------------------
const char * CheckMemoryLeakClass::call_func(const Token *tok, std::list<const Token *> callstack, const char *varnames[], AllocType &alloctype, AllocType &dealloctype, bool &all)
const char * CheckMemoryLeakClass::call_func(const Token *tok, std::list<const Token *> callstack, const char *varnames[], AllocType &alloctype, AllocType &dealloctype, bool &all, unsigned int sz)
{
// Keywords that are not function calls..
if (Token::Match(tok, "if|for|while"))
@ -266,7 +266,7 @@ const char * CheckMemoryLeakClass::call_func(const Token *tok, std::list<const T
// Check if the function deallocates the variable..
while (ftok && (ftok->str() != "{"))
ftok = ftok->next();
Token *func = getcode(ftok->tokAt(1), callstack, parname, alloctype, dealloctype, false, all);
Token *func = getcode(ftok->tokAt(1), callstack, parname, alloctype, dealloctype, false, all, sz);
simplifycode(func);
const Token *func_ = func;
while (func_ && func_->str() == ";")
@ -327,7 +327,7 @@ bool CheckMemoryLeakClass::notvar(const Token *tok, const char *varnames[], bool
Token::simpleMatch(tok, std::string(varname + " == 0" + end).c_str()));
}
Token *CheckMemoryLeakClass::getcode(const Token *tok, std::list<const Token *> callstack, const char varname[], AllocType &alloctype, AllocType &dealloctype, bool classmember, bool &all)
Token *CheckMemoryLeakClass::getcode(const Token *tok, std::list<const Token *> callstack, const char varname[], AllocType &alloctype, AllocType &dealloctype, bool classmember, bool &all, unsigned int sz)
{
const char *varnames[2];
varnames[0] = varname;
@ -389,6 +389,13 @@ Token *CheckMemoryLeakClass::getcode(const Token *tok, std::list<const Token *>
AllocType alloc = GetAllocationType(tok->tokAt(2));
bool realloc = false;
if (sz > 1 &&
Token::Match(tok->tokAt(2), "malloc ( %num% )") &&
(atoi(tok->strAt(4)) % sz) != 0)
{
ErrorMessage::mismatchSize(_errorLogger, _tokenizer, tok->tokAt(4), tok->strAt(4));
}
if (alloc == No)
{
alloc = GetReallocationType(tok->tokAt(2));
@ -642,7 +649,7 @@ Token *CheckMemoryLeakClass::getcode(const Token *tok, std::list<const Token *>
else
{
const char *str = call_func(tok, callstack, varnames, alloctype, dealloctype, all);
const char *str = call_func(tok, callstack, varnames, alloctype, dealloctype, all, sz);
if (str)
addtoken(str);
}
@ -1150,7 +1157,7 @@ void CheckMemoryLeakClass::simplifycode(Token *tok)
// Check for memory leaks for a function variable.
void CheckMemoryLeakClass::CheckMemoryLeak_CheckScope(const Token *Tok1, const char varname[], bool classmember)
void CheckMemoryLeakClass::CheckMemoryLeak_CheckScope(const Token *Tok1, const char varname[], bool classmember, unsigned int sz)
{
std::list<const Token *> callstack;
@ -1161,7 +1168,7 @@ void CheckMemoryLeakClass::CheckMemoryLeak_CheckScope(const Token *Tok1, const c
const Token *result;
Token *tok = getcode(Tok1, callstack, varname, alloctype, dealloctype, classmember, all);
Token *tok = getcode(Tok1, callstack, varname, alloctype, dealloctype, classmember, all, sz);
//tok->printOut( "getcode result" );
// Simplify the code and check if freed memory is used..
@ -1318,11 +1325,15 @@ void CheckMemoryLeakClass::CheckMemoryLeak_InFunction()
// Declare a local variable => Check
if (indentlevel > 0 && infunc)
{
unsigned int sz = _tokenizer->SizeOfType(tok->strAt(1));
if (sz < 1)
sz = 1;
if (Token::Match(tok, "[{};] %type% * %var% [;=]"))
CheckMemoryLeak_CheckScope(tok->next(), tok->strAt(3), classmember);
CheckMemoryLeak_CheckScope(tok->next(), tok->strAt(3), classmember, sz);
else if (Token::Match(tok, "[{};] %type% %type% * %var% [;=]"))
CheckMemoryLeak_CheckScope(tok->next(), tok->strAt(4), classmember);
CheckMemoryLeak_CheckScope(tok->next(), tok->strAt(4), classmember, sz);
}
}
}
@ -1574,7 +1585,7 @@ Token * CheckMemoryLeakClass::functionParameterCode(const Token *ftok, int param
AllocType alloc = No, dealloc = No;
bool all = false;
std::list<const Token *> callstack;
Token *code = getcode(ftok, callstack, parname, alloc, dealloc, false, all);
Token *code = getcode(ftok, callstack, parname, alloc, dealloc, false, all, 1);
simplifycode(code);
return code;
}

View File

@ -62,7 +62,7 @@ private:
void CheckMemoryLeak_ClassMembers_ParseClass(const Token *tok1, std::vector<const char *> &classname);
void CheckMemoryLeak_ClassMembers();
void CheckMemoryLeak_InFunction();
void CheckMemoryLeak_CheckScope(const Token *Tok1, const char varname[], bool classmember);
void CheckMemoryLeak_CheckScope(const Token *Tok1, const char varname[], bool classmember, unsigned int sz);
/**
* Simplify code e.g. by replacing empty "{ }" with ";"
@ -89,7 +89,7 @@ private:
* @return Newly allocated token array. Caller needs to release reserved
* memory by calling Tokenizer::deleteTokens(returnValue);
*/
Token *getcode(const Token *tok, std::list<const Token *> callstack, const char varname[], AllocType &alloctype, AllocType &dealloctype, bool classmember, bool &all);
Token *getcode(const Token *tok, std::list<const Token *> callstack, const char varname[], AllocType &alloctype, AllocType &dealloctype, bool classmember, bool &all, unsigned int sz);
/**
* Check if there is a "!var" match inside a condition
@ -103,7 +103,7 @@ private:
bool MatchFunctionsThatReturnArg(const Token *tok, const std::string &varname);
void MemoryLeak(const Token *tok, const char varname[], AllocType alloctype, bool all);
void MismatchError(const Token *Tok1, const std::list<const Token *> &callstack, const char varname[]);
const char * call_func(const Token *tok, std::list<const Token *> callstack, const char *varnames[], AllocType &alloctype, AllocType &dealloctype, bool &all);
const char * call_func(const Token *tok, std::list<const Token *> callstack, const char *varnames[], AllocType &alloctype, AllocType &dealloctype, bool &all, unsigned int sz);
AllocType GetDeallocationType(const Token *tok, const char *varnames[]);
AllocType GetAllocationType(const Token *tok2);
AllocType GetReallocationType(const Token *tok2);

View File

@ -188,6 +188,15 @@ public:
return true;
}
static void mismatchSize(ErrorLogger *logger, const Tokenizer *tokenizer, const Token *Location, const std::string &sz)
{
_writemsg(logger, tokenizer, Location, "all", "The given size " + sz + " is mismatching", "mismatchSize");
}
static bool mismatchSize(const Settings &s)
{
return s._showAll;
}
static void cstyleCast(ErrorLogger *logger, const Tokenizer *tokenizer, const Token *Location)
{
_writemsg(logger, tokenizer, Location, "style", "C-style pointer casting", "cstyleCast");

View File

@ -1249,13 +1249,19 @@ bool Tokenizer::simplifyConditions()
}
// Change numeric constant in condition to "true" or "false"
const Token *tok2 = tok->tokAt(2);
if ((tok->str() == "(" || tok->str() == "&&" || tok->str() == "||") &&
Token::Match(tok->next(), "%num%") &&
tok2 &&
if (Token::Match(tok, "if|while ( %num%") &&
(tok->tokAt(3)->str() == ")" || tok->tokAt(3)->str() == "||" || tok->tokAt(3)->str() == "&&"))
{
tok->next()->next()->str((tok->tokAt(2)->str() != "0") ? "true" : "false");
ret = true;
}
Token *tok2 = tok->tokAt(2);
if (tok2 &&
(tok->str() == "&&" || tok->str() == "||") &&
Token::Match(tok->next(), "%num%") &&
(tok2->str() == ")" || tok2->str() == "&&" || tok2->str() == "||"))
{
tok->next()->str((tok->next()->str() != "0") ? "true" : "false");
tok->next()->str();
ret = true;
}

View File

@ -184,6 +184,8 @@ private:
TEST_CASE(strcat_result_assignment);
TEST_CASE(all1); // Extra checking when --all is given
TEST_CASE(malloc_constant_1); // Check that the malloc constant matches the type
}
@ -1807,6 +1809,17 @@ private:
ASSERT_EQUALS(std::string("[test.cpp:4]: (all) Memory leak: f\n"), errout.str());
}
void malloc_constant_1()
{
check("void foo()\n"
"{\n"
" int *p = malloc(3);\n"
" free(p);\n"
"}\n", false);
ASSERT_EQUALS(std::string("[test.cpp:3]: (all) The given size 3 is mismatching\n"), errout.str());
}
};
REGISTER_TEST(TestMemleak)

View File

@ -81,6 +81,7 @@ int main()
err.push_back(Message("resourceLeak", Message::error, "Resource leak: %1", "varname"));
err.push_back(Message("deallocDealloc", Message::error, "Deallocating a deallocated pointer: %1", "varname"));
err.push_back(Message("deallocuse", Message::error, "Using '%1' after it is deallocated / released", "varname"));
err.push_back(Message("mismatchSize", Message::all, "The given size %1 is mismatching", "sz"));
// checkother.cpp..
err.push_back(Message("cstyleCast", Message::style, "C-style pointer casting"));