Merge branch 'master' of git@github.com:danmar/cppcheck
This commit is contained in:
commit
4b1f300660
|
@ -78,11 +78,10 @@ private:
|
||||||
|
|
||||||
std::string classInfo() const
|
std::string classInfo() const
|
||||||
{
|
{
|
||||||
return "Auto variables are deallocated when they go out of scope. "
|
return "A pointer to a variable is only valid as long as the variable is in scope.\n"
|
||||||
"A pointer to an auto variable is therefore only valid as long as the auto variable is in scope.\n"
|
|
||||||
"Check:\n"
|
"Check:\n"
|
||||||
" * returning a pointer to auto variable\n"
|
" * returning a pointer to variable\n"
|
||||||
" * assignment of an auto-variable to an effective parameter of a function\n";
|
" * assigning address of an variable to an effective parameter of a function\n";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -117,6 +117,9 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::GetAllocationType(const Token *tok2)
|
||||||
if (Token::Match(tok2, "fopen|tmpfile ("))
|
if (Token::Match(tok2, "fopen|tmpfile ("))
|
||||||
return File;
|
return File;
|
||||||
|
|
||||||
|
if (Token::Match(tok2, "open|openat|creat|mkstemp|mkostemp ("))
|
||||||
|
return Fd;
|
||||||
|
|
||||||
if (Token::simpleMatch(tok2, "popen ("))
|
if (Token::simpleMatch(tok2, "popen ("))
|
||||||
return Pipe;
|
return Pipe;
|
||||||
|
|
||||||
|
@ -188,6 +191,9 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::GetDeallocationType(const Token *tok
|
||||||
Token::simpleMatch(tok, "fcloseall ( )"))
|
Token::simpleMatch(tok, "fcloseall ( )"))
|
||||||
return File;
|
return File;
|
||||||
|
|
||||||
|
if (Token::simpleMatch(tok, std::string("close ( " + names + " )").c_str()))
|
||||||
|
return Fd;
|
||||||
|
|
||||||
if (Token::simpleMatch(tok, std::string("pclose ( " + names + " )").c_str()))
|
if (Token::simpleMatch(tok, std::string("pclose ( " + names + " )").c_str()))
|
||||||
return Pipe;
|
return Pipe;
|
||||||
|
|
||||||
|
@ -205,6 +211,7 @@ void CheckMemoryLeak::MemoryLeak(const Token *tok, const char varname[], AllocTy
|
||||||
{
|
{
|
||||||
if (alloctype == CheckMemoryLeak::File ||
|
if (alloctype == CheckMemoryLeak::File ||
|
||||||
alloctype == CheckMemoryLeak::Pipe ||
|
alloctype == CheckMemoryLeak::Pipe ||
|
||||||
|
alloctype == CheckMemoryLeak::Fd ||
|
||||||
alloctype == CheckMemoryLeak::Dir)
|
alloctype == CheckMemoryLeak::Dir)
|
||||||
resourceLeakError(tok, varname);
|
resourceLeakError(tok, varname);
|
||||||
else if (all)
|
else if (all)
|
||||||
|
@ -400,6 +407,12 @@ const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list<co
|
||||||
Token::Match(tok, "setvbuf|setbuf|setbuffer|setlinebuf|rewind"))
|
Token::Match(tok, "setvbuf|setbuf|setbuffer|setlinebuf|rewind"))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
// I/O functions that are not allocating nor deallocating memory..
|
||||||
|
if (Token::Match(tok, "read|readv|pread|readahead|write|writev|pwrite|lseek") ||
|
||||||
|
Token::Match(tok, "ioctl|fcntl|flock|lockf|ftruncate|fsync|fdatasync") ||
|
||||||
|
Token::Match(tok, "fstat|sync_file_range|posix_fallocate|posix_fadvise"))
|
||||||
|
return 0;
|
||||||
|
|
||||||
// Functions to work with directories that are not allocating nor
|
// Functions to work with directories that are not allocating nor
|
||||||
// deallocating memory..
|
// deallocating memory..
|
||||||
if (Token::Match(tok, "readdir|readdir_r|rewinddir|telldir|seekdir|scandir"))
|
if (Token::Match(tok, "readdir|readdir_r|rewinddir|telldir|seekdir|scandir"))
|
||||||
|
@ -695,6 +708,12 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
|
||||||
while (tok->str() != ")")
|
while (tok->str() != ")")
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
}
|
}
|
||||||
|
else if (Token::simpleMatch(tok, std::string("if ( " + varnameStr + " == -1 )").c_str()) ||
|
||||||
|
Token::simpleMatch(tok, std::string("if ( " + varnameStr + " < 0 )").c_str()))
|
||||||
|
{
|
||||||
|
// FIXME: ensure then this variable has int type and uses as file descriptor
|
||||||
|
addtoken("if(!var)");
|
||||||
|
}
|
||||||
else if (Token::simpleMatch(tok, "if (") && notvar(tok->tokAt(2), varnames, true))
|
else if (Token::simpleMatch(tok, "if (") && notvar(tok->tokAt(2), varnames, true))
|
||||||
{
|
{
|
||||||
addtoken("if(!var)");
|
addtoken("if(!var)");
|
||||||
|
@ -714,7 +733,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
|
||||||
if (parlevel <= 0)
|
if (parlevel <= 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (Token::Match(tok2, std::string("fclose|closedir ( " + varnameStr + " )").c_str()))
|
if (Token::Match(tok2, std::string("close|fclose|closedir ( " + varnameStr + " )").c_str()))
|
||||||
{
|
{
|
||||||
addtoken("dealloc");
|
addtoken("dealloc");
|
||||||
addtoken(";");
|
addtoken(";");
|
||||||
|
@ -988,6 +1007,22 @@ void CheckMemoryLeakInFunction::simplifycode(Token *tok, bool &all)
|
||||||
tok2 = tokEnd;
|
tok2 = tokEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If "--all" is given, remove all "callfunc"..
|
||||||
|
if (_settings->_showAll)
|
||||||
|
{
|
||||||
|
Token *tok2 = tok;
|
||||||
|
while (tok2)
|
||||||
|
{
|
||||||
|
if (tok2->str() == "callfunc")
|
||||||
|
{
|
||||||
|
tok2->deleteThis();
|
||||||
|
all = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
tok2 = tok2->next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// reduce the code..
|
// reduce the code..
|
||||||
bool done = false;
|
bool done = false;
|
||||||
while (! done)
|
while (! done)
|
||||||
|
@ -1337,6 +1372,14 @@ void CheckMemoryLeakInFunction::simplifycode(Token *tok, bool &all)
|
||||||
done = false;
|
done = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete "callfunc ;" that is followed by "use|if|callfunc"
|
||||||
|
// If the function doesn't throw exception or exit the application, then the "callfunc" is not needed
|
||||||
|
if (Token::Match(tok2, "callfunc ; use|if|callfunc"))
|
||||||
|
{
|
||||||
|
tok2->deleteThis();
|
||||||
|
done = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Delete second case in "case ; case ;"
|
// Delete second case in "case ; case ;"
|
||||||
while (Token::simpleMatch(tok2, "case ; case ;"))
|
while (Token::simpleMatch(tok2, "case ; case ;"))
|
||||||
{
|
{
|
||||||
|
@ -1620,6 +1663,11 @@ void CheckMemoryLeakInFunction::check()
|
||||||
const int varname_tok = (tok->tokAt(4)->str() != "const" ? 4 : 5);
|
const int varname_tok = (tok->tokAt(4)->str() != "const" ? 4 : 5);
|
||||||
checkScope(tok->next(), tok->strAt(varname_tok), classmember, sz);
|
checkScope(tok->next(), tok->strAt(varname_tok), classmember, sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (Token::Match(tok, "[{};] int %var% [;=]"))
|
||||||
|
{
|
||||||
|
checkScope(tok->next(), tok->strAt(2), classmember, sz);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ public:
|
||||||
CheckMemoryLeak() { }
|
CheckMemoryLeak() { }
|
||||||
|
|
||||||
/** What type of allocation are used.. the "Many" means that several types of allocation and deallocation are used */
|
/** What type of allocation are used.. the "Many" means that several types of allocation and deallocation are used */
|
||||||
enum AllocType { No, Malloc, gMalloc, New, NewArray, File, Pipe, Dir, Many };
|
enum AllocType { No, Malloc, gMalloc, New, NewArray, File, Fd, Pipe, Dir, Many };
|
||||||
|
|
||||||
void MemoryLeak(const Token *tok, const char varname[], AllocType alloctype, bool all);
|
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[]);
|
void MismatchError(const Token *Tok1, const std::list<const Token *> &callstack, const char varname[]);
|
||||||
|
|
|
@ -254,6 +254,7 @@ private:
|
||||||
TEST_CASE(unknownFunction1);
|
TEST_CASE(unknownFunction1);
|
||||||
TEST_CASE(unknownFunction2);
|
TEST_CASE(unknownFunction2);
|
||||||
TEST_CASE(unknownFunction3);
|
TEST_CASE(unknownFunction3);
|
||||||
|
TEST_CASE(unknownFunction4);
|
||||||
|
|
||||||
// VCL..
|
// VCL..
|
||||||
TEST_CASE(vcl1);
|
TEST_CASE(vcl1);
|
||||||
|
@ -273,6 +274,11 @@ private:
|
||||||
TEST_CASE(fcloseall_function);
|
TEST_CASE(fcloseall_function);
|
||||||
TEST_CASE(file_functions);
|
TEST_CASE(file_functions);
|
||||||
|
|
||||||
|
TEST_CASE(open_function);
|
||||||
|
TEST_CASE(creat_function);
|
||||||
|
TEST_CASE(close_function);
|
||||||
|
TEST_CASE(fd_functions);
|
||||||
|
|
||||||
TEST_CASE(opendir_function);
|
TEST_CASE(opendir_function);
|
||||||
TEST_CASE(fdopendir_function);
|
TEST_CASE(fdopendir_function);
|
||||||
TEST_CASE(closedir_function);
|
TEST_CASE(closedir_function);
|
||||||
|
@ -1951,6 +1957,18 @@ private:
|
||||||
ASSERT_EQUALS("[test.cpp:5]: (error) Memory leak: p\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:5]: (error) Memory leak: p\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void unknownFunction4()
|
||||||
|
{
|
||||||
|
check("void foo()\n"
|
||||||
|
"{\n"
|
||||||
|
" int *p = new int[100];\n"
|
||||||
|
" a();\n"
|
||||||
|
" if (b) return;\n"
|
||||||
|
" delete [] p;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:5]: (error) Memory leak: p\n", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void checkvcl(const char code[], const char _autoDealloc[])
|
void checkvcl(const char code[], const char _autoDealloc[])
|
||||||
|
@ -2164,6 +2182,96 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void open_function()
|
||||||
|
{
|
||||||
|
check("void f(const char *path)\n"
|
||||||
|
"{\n"
|
||||||
|
" int fd = open(path, O_RDONLY);\n"
|
||||||
|
"}\n", true);
|
||||||
|
ASSERT_EQUALS("[test.cpp:4]: (error) Resource leak: fd\n", errout.str());
|
||||||
|
|
||||||
|
check("void f(const char *path)\n"
|
||||||
|
"{\n"
|
||||||
|
" int fd = open(path, O_RDONLY);\n"
|
||||||
|
" if (fd == -1)\n"
|
||||||
|
" return;\n"
|
||||||
|
" close(fd);\n"
|
||||||
|
"}\n", true);
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("void f(const char *path)\n"
|
||||||
|
"{\n"
|
||||||
|
" int fd = open(path, O_RDONLY);\n"
|
||||||
|
" if (fd < 0)\n"
|
||||||
|
" return;\n"
|
||||||
|
" close(fd);\n"
|
||||||
|
"}\n", true);
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void creat_function()
|
||||||
|
{
|
||||||
|
check("void f(const char *path)\n"
|
||||||
|
"{\n"
|
||||||
|
" int fd = creat(path, S_IRWXU);\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:4]: (error) Resource leak: fd\n", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void close_function()
|
||||||
|
{
|
||||||
|
check("void f(const char *path)\n"
|
||||||
|
"{\n"
|
||||||
|
" int fd = open(path, O_RDONLY);\n"
|
||||||
|
" close(fd);\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("void f(const char *path)\n"
|
||||||
|
"{\n"
|
||||||
|
" int fd = creat(path, S_IRWXU);\n"
|
||||||
|
" close(fd);\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("void f(const char *path)\n"
|
||||||
|
"{\n"
|
||||||
|
" int fd = creat(path, S_IRWXU);\n"
|
||||||
|
" if (close(fd) < 0) {\n"
|
||||||
|
" perror(\"close\");\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void fd_functions()
|
||||||
|
{
|
||||||
|
check("void f(const char *path)\n"
|
||||||
|
"{\n"
|
||||||
|
" int fd = open(path, O_RDONLY);\n"
|
||||||
|
" read(fd, buf, count);\n"
|
||||||
|
" readv(fd, iov, iovcnt);\n"
|
||||||
|
" readahead(fd, offset, count);\n"
|
||||||
|
" pread(fd, buf, count, offset);\n"
|
||||||
|
" write(fd, buf, count);\n"
|
||||||
|
" writev(fd, iov, iovcnt);\n"
|
||||||
|
" pwrite(fd, buf, count, offset);\n"
|
||||||
|
" ioctl(fd, request);\n"
|
||||||
|
" posix_fallocate(fd, offset, len);\n"
|
||||||
|
" posix_fadvise(fd, offset, len, advise);\n"
|
||||||
|
" fsync(fd);\n"
|
||||||
|
" fdatasync(fd);\n"
|
||||||
|
" sync_file_range(fd, offset, nbytes, flags);\n"
|
||||||
|
" lseek(fd, offset, whence);\n"
|
||||||
|
" fcntl(fd, cmd);\n"
|
||||||
|
" flock(fd, op);\n"
|
||||||
|
" lockf(fd, cmd, len);\n"
|
||||||
|
" ftruncate(fd, len);\n"
|
||||||
|
" fstat(fd, buf);\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:23]: (error) Resource leak: fd\n", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
void opendir_function()
|
void opendir_function()
|
||||||
{
|
{
|
||||||
check("void f()\n"
|
check("void f()\n"
|
||||||
|
|
Loading…
Reference in New Issue