memory allocation: check for mismatching size
This commit is contained in:
parent
bb71f9e83e
commit
3c289e52c5
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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() == "||") &&
|
||||
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 &&
|
||||
(tok2->str() == ")" || tok2->str() == "&&" || tok2->str() == "||"))
|
||||
{
|
||||
tok->next()->str((tok->next()->str() != "0") ? "true" : "false");
|
||||
tok->next()->str();
|
||||
ret = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"));
|
||||
|
|
Loading…
Reference in New Issue