Fixed #264 (Memory Leak: alloc by assigning to a return value)
The fix was inspired by the previous patch submitted by hoangtuansu
This commit is contained in:
parent
195880807e
commit
433ff048a4
|
@ -252,7 +252,37 @@ void CheckMemoryLeak::mismatchAllocDealloc(const std::list<const Token *> &calls
|
|||
error(callstack, "error", "mismatchAllocDealloc", "Mismatching allocation and deallocation: " + varname);
|
||||
}
|
||||
|
||||
CheckMemoryLeak::AllocType CheckMemoryLeak::functionReturnType(const Token *tok) const
|
||||
{
|
||||
// Locate the start of the function..
|
||||
unsigned int parlevel = 0;
|
||||
while (tok)
|
||||
{
|
||||
if (tok->str() == "{" || tok->str() == "}")
|
||||
return No;
|
||||
|
||||
if (tok->str() == "(")
|
||||
{
|
||||
if (parlevel != 0)
|
||||
return No;
|
||||
++parlevel;
|
||||
}
|
||||
|
||||
else if (tok->str() == ")")
|
||||
{
|
||||
if (parlevel != 1)
|
||||
return No;
|
||||
if (Token::Match(tok, ") const| { return new %type% ; }"))
|
||||
return New;
|
||||
if (Token::Match(tok, ") const| { return new %type% [ %any% ] ; }"))
|
||||
return NewArray;
|
||||
break;
|
||||
}
|
||||
|
||||
tok = tok->next();
|
||||
}
|
||||
return No;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -355,6 +385,14 @@ const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list<co
|
|||
}
|
||||
callstack.push_back(tok);
|
||||
|
||||
// Check if this is a function that allocates memory..
|
||||
{
|
||||
const Token *ftok = _tokenizer->GetFunctionTokenByName(funcname.c_str());
|
||||
AllocType a = functionReturnType(ftok);
|
||||
if (a != No)
|
||||
return "alloc";
|
||||
}
|
||||
|
||||
// how many parameters is there in the function call?
|
||||
int numpar = countParameters(tok);
|
||||
if (numpar <= 0)
|
||||
|
|
|
@ -43,7 +43,7 @@ class Token;
|
|||
|
||||
class CheckMemoryLeak
|
||||
{
|
||||
protected:
|
||||
public:
|
||||
CheckMemoryLeak() { }
|
||||
|
||||
/** What type of allocation are used.. the "Many" means that several types of allocation and deallocation are used */
|
||||
|
@ -68,6 +68,9 @@ protected:
|
|||
// error message
|
||||
virtual void error(const Token *tok, const std::string &severity, const std::string &id, const std::string &msg) = 0;
|
||||
virtual void error(const std::list<const Token *> &callstack, const std::string &severity, const std::string &id, const std::string &msg) = 0;
|
||||
|
||||
/** What type of allocated memory does the given function return? */
|
||||
AllocType functionReturnType(const Token *tok) const;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -24,11 +24,61 @@
|
|||
#include "../src/checkmemoryleak.h"
|
||||
#include "testsuite.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
extern std::ostringstream errout;
|
||||
|
||||
|
||||
class TestMemleak : private TestFixture
|
||||
{
|
||||
public:
|
||||
TestMemleak() : TestFixture("TestMemleak")
|
||||
{ }
|
||||
|
||||
private:
|
||||
void run()
|
||||
{
|
||||
TEST_CASE(testFunctionReturnType);
|
||||
}
|
||||
|
||||
CheckMemoryLeak::AllocType functionReturnType(const char code[])
|
||||
{
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer;
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize(istr, "test.cpp");
|
||||
|
||||
return ((const CheckMemoryLeak *)0)->functionReturnType(tokenizer.tokens());
|
||||
}
|
||||
|
||||
void testFunctionReturnType()
|
||||
{
|
||||
{
|
||||
const char code[] = "const char *foo()\n"
|
||||
"{ return 0; }";
|
||||
ASSERT_EQUALS(CheckMemoryLeak::No, functionReturnType(code));
|
||||
}
|
||||
|
||||
{
|
||||
const char code[] = "Fred *newFred()\n"
|
||||
"{ return new Fred; }";
|
||||
ASSERT_EQUALS(CheckMemoryLeak::New, functionReturnType(code));
|
||||
}
|
||||
|
||||
{
|
||||
const char code[] = "char *foo()\n"
|
||||
"{ return new char[100]; }";
|
||||
ASSERT_EQUALS(CheckMemoryLeak::NewArray, functionReturnType(code));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static TestMemleak testMemleak;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class TestMemleakInFunction : public TestFixture
|
||||
{
|
||||
public:
|
||||
|
@ -145,6 +195,8 @@ private:
|
|||
TEST_CASE(func13);
|
||||
TEST_CASE(func14);
|
||||
|
||||
TEST_CASE(allocfunc1);
|
||||
|
||||
TEST_CASE(throw1);
|
||||
TEST_CASE(throw2);
|
||||
|
||||
|
@ -1366,38 +1418,20 @@ private:
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
void func3()
|
||||
{
|
||||
check( "static char *dmalloc()\n"
|
||||
"{\n"
|
||||
" char *p = new char[100];\n"
|
||||
" return p;\n"
|
||||
"}\n"
|
||||
"static void f()\n"
|
||||
"{\n"
|
||||
" char *p = dmalloc();\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:9]: Memory leak: p\n"), errout.str() );
|
||||
}
|
||||
void allocfunc1()
|
||||
{
|
||||
check("static char *a()\n"
|
||||
"{\n"
|
||||
" return new char[100];\n"
|
||||
"}\n"
|
||||
"static void b()\n"
|
||||
"{\n"
|
||||
" char *p = a();\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS(std::string("[test.cpp:8]: (error) Memory leak: p\n"), errout.str());
|
||||
}
|
||||
|
||||
|
||||
void func4()
|
||||
{
|
||||
check( "static char *dmalloc()\n"
|
||||
"{\n"
|
||||
" char *p = new char[100];\n"
|
||||
" return p;\n"
|
||||
"}\n"
|
||||
"static void f()\n"
|
||||
"{\n"
|
||||
" char *p = dmalloc();\n"
|
||||
" delete p;\n"
|
||||
"}\n" );
|
||||
ASSERT_EQUALS( std::string("[test.cpp:9]: Mismatching allocation and deallocation: p\n"), errout.str() );
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue