Merge branch 'master' of git@github.com:danmar/cppcheck

This commit is contained in:
Kimmo Varis 2009-06-22 11:58:15 +03:00
commit 4b1f300660
4 changed files with 161 additions and 6 deletions

View File

@ -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";
} }
}; };

View File

@ -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);
}
} }
} }
} }

View File

@ -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[]);

View File

@ -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"