CheckMemoryLeakInFunction: Don't treat delete as delete operator for C code
Fixed GCC message in checkbufferoverrun.cpp
This commit is contained in:
parent
98e33a189f
commit
03e44d4aa0
|
@ -654,7 +654,7 @@ void CheckBufferOverrun::checkScope(const Token *tok, const std::vector<std::str
|
||||||
|
|
||||||
if (total_size > 0) {
|
if (total_size > 0) {
|
||||||
// Writing data into array..
|
// Writing data into array..
|
||||||
if (total_size > 0 && (declarationId > 0 && Token::Match(tok, "strcpy|strcat ( %varid% , %str% )", declarationId)) ||
|
if ((declarationId > 0 && Token::Match(tok, "strcpy|strcat ( %varid% , %str% )", declarationId)) ||
|
||||||
(declarationId == 0 && Token::Match(tok, ("strcpy|strcat ( " + varnames + " , %str% )").c_str()))) {
|
(declarationId == 0 && Token::Match(tok, ("strcpy|strcat ( " + varnames + " , %str% )").c_str()))) {
|
||||||
const std::size_t len = Token::getStrLength(tok->tokAt(varcount + 4));
|
const std::size_t len = Token::getStrLength(tok->tokAt(varcount + 4));
|
||||||
if (len >= (unsigned int)total_size) {
|
if (len >= (unsigned int)total_size) {
|
||||||
|
|
|
@ -64,7 +64,7 @@ static unsigned int countParameters(const Token *tok)
|
||||||
static const char * const call_func_white_list[] = {
|
static const char * const call_func_white_list[] = {
|
||||||
"_open", "_wopen", "access", "adjtime", "asctime", "asctime_r", "asprintf", "assert"
|
"_open", "_wopen", "access", "adjtime", "asctime", "asctime_r", "asprintf", "assert"
|
||||||
, "atof", "atoi", "atol", "chdir", "chmod", "chown"
|
, "atof", "atoi", "atol", "chdir", "chmod", "chown"
|
||||||
, "clearerr", "creat", "ctime", "ctime_r", "delete", "execl", "execle"
|
, "clearerr", "creat", "ctime", "ctime_r", "execl", "execle"
|
||||||
, "execlp", "execv", "execve", "fchmod", "fclose", "fcntl"
|
, "execlp", "execv", "execve", "fchmod", "fclose", "fcntl"
|
||||||
, "fdatasync", "feof", "ferror", "fflush", "fgetc", "fgetpos", "fgets"
|
, "fdatasync", "feof", "ferror", "fflush", "fgetc", "fgetpos", "fgets"
|
||||||
, "flock", "fmemopen", "fnmatch", "fopen", "fopencookie", "for", "fprintf", "fputc", "fputs", "fread", "free"
|
, "flock", "fmemopen", "fnmatch", "fopen", "fopencookie", "for", "fprintf", "fputc", "fputs", "fread", "free"
|
||||||
|
@ -239,6 +239,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getReallocationType(const Token *tok
|
||||||
|
|
||||||
CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok, unsigned int varid) const
|
CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok, unsigned int varid) const
|
||||||
{
|
{
|
||||||
|
if (tokenizer->isCPP()) {
|
||||||
if (Token::Match(tok, "delete %varid% ;", varid))
|
if (Token::Match(tok, "delete %varid% ;", varid))
|
||||||
return New;
|
return New;
|
||||||
|
|
||||||
|
@ -250,6 +251,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok
|
||||||
|
|
||||||
if (Token::Match(tok, "delete [ ] ( %varid% ) ;", varid))
|
if (Token::Match(tok, "delete [ ] ( %varid% ) ;", varid))
|
||||||
return NewArray;
|
return NewArray;
|
||||||
|
}
|
||||||
|
|
||||||
if (tok && tok->str() == "::")
|
if (tok && tok->str() == "::")
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
|
@ -283,6 +285,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok
|
||||||
|
|
||||||
CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok, const std::string &varname) const
|
CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok, const std::string &varname) const
|
||||||
{
|
{
|
||||||
|
if (tokenizer->isCPP()) {
|
||||||
if (Token::Match(tok, std::string("delete " + varname + " [,;]").c_str()))
|
if (Token::Match(tok, std::string("delete " + varname + " [,;]").c_str()))
|
||||||
return New;
|
return New;
|
||||||
|
|
||||||
|
@ -294,6 +297,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok
|
||||||
|
|
||||||
if (Token::Match(tok, std::string("delete [ ] ( " + varname + " ) [,;]").c_str()))
|
if (Token::Match(tok, std::string("delete [ ] ( " + varname + " ) [,;]").c_str()))
|
||||||
return NewArray;
|
return NewArray;
|
||||||
|
}
|
||||||
|
|
||||||
if (Token::simpleMatch(tok, std::string("free ( " + varname + " ) ;").c_str()) ||
|
if (Token::simpleMatch(tok, std::string("free ( " + varname + " ) ;").c_str()) ||
|
||||||
Token::simpleMatch(tok, std::string("kfree ( " + varname + " ) ;").c_str()) ||
|
Token::simpleMatch(tok, std::string("kfree ( " + varname + " ) ;").c_str()) ||
|
||||||
|
@ -523,25 +527,17 @@ bool CheckMemoryLeakInFunction::notvar(const Token *tok, unsigned int varid, boo
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool CheckMemoryLeakInFunction::test_white_list(const std::string &funcname)
|
bool CheckMemoryLeakInFunction::test_white_list(const std::string &funcname, const Settings *settings, bool cpp)
|
||||||
{
|
{
|
||||||
return (std::binary_search(call_func_white_list,
|
return (std::binary_search(call_func_white_list,
|
||||||
call_func_white_list+sizeof(call_func_white_list) / sizeof(call_func_white_list[0]),
|
call_func_white_list+sizeof(call_func_white_list) / sizeof(call_func_white_list[0]),
|
||||||
funcname));
|
funcname) || (settings->library.leakignore.find(funcname) != settings->library.leakignore.end()) || (cpp && funcname == "delete"));
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool CheckMemoryLeakInFunction::test_white_list_with_lib(const std::string &funcname, const Settings *settings)
|
|
||||||
{
|
|
||||||
return (std::binary_search(call_func_white_list,
|
|
||||||
call_func_white_list+sizeof(call_func_white_list) / sizeof(call_func_white_list[0]),
|
|
||||||
funcname) || (settings->library.leakignore.find(funcname) != settings->library.leakignore.end()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list<const Token *> callstack, const unsigned int varid, AllocType &alloctype, AllocType &dealloctype, bool &allocpar, unsigned int sz)
|
const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list<const Token *> callstack, const unsigned int varid, AllocType &alloctype, AllocType &dealloctype, bool &allocpar, unsigned int sz)
|
||||||
{
|
{
|
||||||
if (test_white_list_with_lib(tok->str(), _settings)) {
|
if (test_white_list(tok->str(), _settings, tokenizer->isCPP())) {
|
||||||
if (tok->str() == "asprintf" ||
|
if (tok->str() == "asprintf" ||
|
||||||
tok->str() == "delete" ||
|
tok->str() == "delete" ||
|
||||||
tok->str() == "fclose" ||
|
tok->str() == "fclose" ||
|
||||||
|
@ -1024,7 +1020,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
|
||||||
dep = true;
|
dep = true;
|
||||||
} else if (Token::Match(tok2, "! %varid%", varid)) {
|
} else if (Token::Match(tok2, "! %varid%", varid)) {
|
||||||
dep = true;
|
dep = true;
|
||||||
} else if (Token::Match(tok2, "%var% (") && !test_white_list_with_lib(tok2->str(), _settings)) {
|
} else if (Token::Match(tok2, "%var% (") && !test_white_list(tok2->str(), _settings, tokenizer->isCPP())) {
|
||||||
bool use = false;
|
bool use = false;
|
||||||
for (const Token *tok3 = tok2->tokAt(2); tok3; tok3 = tok3->nextArgument()) {
|
for (const Token *tok3 = tok2->tokAt(2); tok3; tok3 = tok3->nextArgument()) {
|
||||||
if (Token::Match(tok3->previous(), "(|, &| %varid% ,|)", varid)) {
|
if (Token::Match(tok3->previous(), "(|, &| %varid% ,|)", varid)) {
|
||||||
|
@ -1200,7 +1196,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
|
||||||
if (!Token::Match(tok2->previous(), "&|(") &&
|
if (!Token::Match(tok2->previous(), "&|(") &&
|
||||||
tok2->strAt(1) == "[") {
|
tok2->strAt(1) == "[") {
|
||||||
} else if (f.empty() ||
|
} else if (f.empty() ||
|
||||||
!test_white_list_with_lib(f.top()->str(), _settings) ||
|
!test_white_list(f.top()->str(), _settings, tokenizer->isCPP()) ||
|
||||||
getDeallocationType(f.top(),varid)) {
|
getDeallocationType(f.top(),varid)) {
|
||||||
use = true;
|
use = true;
|
||||||
}
|
}
|
||||||
|
@ -1286,7 +1282,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
|
||||||
if (_settings->library.isnoreturn(tok))
|
if (_settings->library.isnoreturn(tok))
|
||||||
addtoken(&rettail, tok, "exit");
|
addtoken(&rettail, tok, "exit");
|
||||||
|
|
||||||
else if (!test_white_list_with_lib(tok->str(), _settings)) {
|
else if (!test_white_list(tok->str(), _settings, tokenizer->isCPP())) {
|
||||||
const Token* const end2 = tok->linkAt(1);
|
const Token* const end2 = tok->linkAt(1);
|
||||||
for (const Token *tok2 = tok->tokAt(2); tok2 != end2; tok2 = tok2->next()) {
|
for (const Token *tok2 = tok->tokAt(2); tok2 != end2; tok2 = tok2->next()) {
|
||||||
if (tok2->varId() == varid) {
|
if (tok2->varId() == varid) {
|
||||||
|
@ -2402,7 +2398,7 @@ void CheckMemoryLeakInClass::variable(const Scope *scope, const Token *tokVarnam
|
||||||
|
|
||||||
// Function call .. possible deallocation
|
// Function call .. possible deallocation
|
||||||
else if (Token::Match(tok->previous(), "[{};] %var% (")) {
|
else if (Token::Match(tok->previous(), "[{};] %var% (")) {
|
||||||
if (!CheckMemoryLeakInFunction::test_white_list_with_lib(tok->str(), _settings)) {
|
if (!CheckMemoryLeakInFunction::test_white_list(tok->str(), _settings, tokenizer->isCPP())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2717,12 +2713,12 @@ void CheckMemoryLeakNoVar::check()
|
||||||
// Is it a function call..
|
// Is it a function call..
|
||||||
if (!Token::Match(tok3->tokAt(-2), "= %var% (")) {
|
if (!Token::Match(tok3->tokAt(-2), "= %var% (")) {
|
||||||
const std::string& functionName = tok3->strAt(-1);
|
const std::string& functionName = tok3->strAt(-1);
|
||||||
if (functionName == "delete" ||
|
if ((tokenizer->isCPP() && functionName == "delete") ||
|
||||||
functionName == "free" ||
|
functionName == "free" ||
|
||||||
functionName == "fclose" ||
|
functionName == "fclose" ||
|
||||||
functionName == "realloc")
|
functionName == "realloc")
|
||||||
break;
|
break;
|
||||||
if (CheckMemoryLeakInFunction::test_white_list_with_lib(functionName, _settings)) {
|
if (CheckMemoryLeakInFunction::test_white_list(functionName, _settings, tokenizer->isCPP())) {
|
||||||
functionCallLeak(tok2, tok2->strAt(1), functionName);
|
functionCallLeak(tok2, tok2->strAt(1), functionName);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,10 +47,11 @@ class Variable;
|
||||||
|
|
||||||
/** @brief Base class for memory leaks checking */
|
/** @brief Base class for memory leaks checking */
|
||||||
class CPPCHECKLIB CheckMemoryLeak {
|
class CPPCHECKLIB CheckMemoryLeak {
|
||||||
private:
|
protected:
|
||||||
/** For access to the tokens */
|
/** For access to the tokens */
|
||||||
const Tokenizer * const tokenizer;
|
const Tokenizer * const tokenizer;
|
||||||
|
|
||||||
|
private:
|
||||||
/** ErrorLogger used to report errors */
|
/** ErrorLogger used to report errors */
|
||||||
ErrorLogger * const errorLogger;
|
ErrorLogger * const errorLogger;
|
||||||
|
|
||||||
|
@ -202,8 +203,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Unit testing : testing the white list */
|
/** @brief Unit testing : testing the white list */
|
||||||
static bool test_white_list(const std::string &funcname);
|
static bool test_white_list(const std::string &funcname, const Settings *settings, bool cpp);
|
||||||
static bool test_white_list_with_lib(const std::string &funcname, const Settings *settings);
|
|
||||||
|
|
||||||
/** @brief Perform checking */
|
/** @brief Perform checking */
|
||||||
void check();
|
void check();
|
||||||
|
|
|
@ -128,7 +128,7 @@ private:
|
||||||
Settings settings1;
|
Settings settings1;
|
||||||
Settings settings2;
|
Settings settings2;
|
||||||
|
|
||||||
void check(const char code[], const Settings *settings = nullptr) {
|
void check(const char code[], const Settings *settings = nullptr, bool c = false) {
|
||||||
// Clear the error buffer..
|
// Clear the error buffer..
|
||||||
errout.str("");
|
errout.str("");
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ private:
|
||||||
// Tokenize..
|
// Tokenize..
|
||||||
Tokenizer tokenizer(settings, this);
|
Tokenizer tokenizer(settings, this);
|
||||||
std::istringstream istr(code);
|
std::istringstream istr(code);
|
||||||
tokenizer.tokenize(istr, "test.cpp");
|
tokenizer.tokenize(istr, c?"test.c":"test.cpp");
|
||||||
tokenizer.simplifyTokenList2();
|
tokenizer.simplifyTokenList2();
|
||||||
|
|
||||||
// Check for memory leaks..
|
// Check for memory leaks..
|
||||||
|
@ -365,6 +365,8 @@ private:
|
||||||
|
|
||||||
TEST_CASE(ptrptr);
|
TEST_CASE(ptrptr);
|
||||||
|
|
||||||
|
TEST_CASE(c_code);
|
||||||
|
|
||||||
// test that the cfg files are configured correctly
|
// test that the cfg files are configured correctly
|
||||||
TEST_CASE(posixcfg);
|
TEST_CASE(posixcfg);
|
||||||
TEST_CASE(posixcfg_mmap);
|
TEST_CASE(posixcfg_mmap);
|
||||||
|
@ -594,33 +596,39 @@ private:
|
||||||
ASSERT_EQUALS(";;catch{}", getcode("char *s; catch(err) { }", "s"));
|
ASSERT_EQUALS(";;catch{}", getcode("char *s; catch(err) { }", "s"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool test_white_list(const std::string& str, bool cpp = true) const {
|
||||||
|
return CheckMemoryLeakInFunction::test_white_list(str, &settings1, cpp);
|
||||||
|
}
|
||||||
|
|
||||||
void call_func() const {
|
void call_func() const {
|
||||||
// whitelist..
|
// whitelist..
|
||||||
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("qsort"));
|
ASSERT_EQUALS(true, test_white_list("qsort"));
|
||||||
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("scanf"));
|
ASSERT_EQUALS(true, test_white_list("scanf"));
|
||||||
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("sscanf"));
|
ASSERT_EQUALS(true, test_white_list("sscanf"));
|
||||||
|
|
||||||
// #1293
|
// #1293
|
||||||
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("time"));
|
ASSERT_EQUALS(true, test_white_list("time"));
|
||||||
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("asctime"));
|
ASSERT_EQUALS(true, test_white_list("asctime"));
|
||||||
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("asctime_r"));
|
ASSERT_EQUALS(true, test_white_list("asctime_r"));
|
||||||
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("ctime"));
|
ASSERT_EQUALS(true, test_white_list("ctime"));
|
||||||
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("ctime_r"));
|
ASSERT_EQUALS(true, test_white_list("ctime_r"));
|
||||||
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("gmtime"));
|
ASSERT_EQUALS(true, test_white_list("gmtime"));
|
||||||
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("gmtime_r"));
|
ASSERT_EQUALS(true, test_white_list("gmtime_r"));
|
||||||
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("localtime"));
|
ASSERT_EQUALS(true, test_white_list("localtime"));
|
||||||
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("localtime_r"));
|
ASSERT_EQUALS(true, test_white_list("localtime_r"));
|
||||||
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("memcmp"));
|
ASSERT_EQUALS(true, test_white_list("memcmp"));
|
||||||
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("gets"));
|
ASSERT_EQUALS(true, test_white_list("gets"));
|
||||||
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("vprintf"));
|
ASSERT_EQUALS(true, test_white_list("vprintf"));
|
||||||
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("vfprintf"));
|
ASSERT_EQUALS(true, test_white_list("vfprintf"));
|
||||||
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("vsprintf"));
|
ASSERT_EQUALS(true, test_white_list("vsprintf"));
|
||||||
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("snprintf"));
|
ASSERT_EQUALS(true, test_white_list("snprintf"));
|
||||||
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("vsnprintf"));
|
ASSERT_EQUALS(true, test_white_list("vsnprintf"));
|
||||||
|
|
||||||
|
ASSERT_EQUALS(true, test_white_list("delete", true));
|
||||||
|
ASSERT_EQUALS(false, test_white_list("delete", false));
|
||||||
|
|
||||||
static const char * const call_func_white_list[] = {
|
static const char * const call_func_white_list[] = {
|
||||||
"access", "asprintf", "atof", "atoi", "atol", "chdir", "chmod", "clearerr", "chown", "delete"
|
"access", "asprintf", "atof", "atoi", "atol", "chdir", "chmod", "clearerr", "chown"
|
||||||
, "fchmod", "fcntl", "fdatasync", "feof", "ferror", "fflush", "fgetc", "fgetpos", "fgets"
|
, "fchmod", "fcntl", "fdatasync", "feof", "ferror", "fflush", "fgetc", "fgetpos", "fgets"
|
||||||
, "flock", "for", "fprintf", "fputc", "fputs", "fread", "free", "freopen", "fscanf", "fseek"
|
, "flock", "for", "fprintf", "fputc", "fputs", "fread", "free", "freopen", "fscanf", "fseek"
|
||||||
, "fseeko", "fsetpos", "fstat", "fsync", "ftell", "ftello", "ftruncate"
|
, "fseeko", "fsetpos", "fstat", "fsync", "ftell", "ftello", "ftruncate"
|
||||||
|
@ -644,7 +652,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
for (unsigned int i = 0; i < (sizeof(call_func_white_list) / sizeof(char *)); ++i) {
|
for (unsigned int i = 0; i < (sizeof(call_func_white_list) / sizeof(char *)); ++i) {
|
||||||
bool ret = CheckMemoryLeakInFunction::test_white_list(call_func_white_list[i]);
|
bool ret = test_white_list(call_func_white_list[i]);
|
||||||
ASSERT_EQUALS("", ret ? "" : call_func_white_list[i]);
|
ASSERT_EQUALS("", ret ? "" : call_func_white_list[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4262,6 +4270,16 @@ 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 c_code() {
|
||||||
|
check("int main(void) {\n"
|
||||||
|
" struct llist *ll = malloc(sizeof(struct llist));\n"
|
||||||
|
" free(ll);\n"
|
||||||
|
" ll = NULL;\n"
|
||||||
|
" delete(ll, ll->top);\n"
|
||||||
|
"}", nullptr, true);
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
void gnucfg() {
|
void gnucfg() {
|
||||||
Settings settings;
|
Settings settings;
|
||||||
settings.standards.posix = true;
|
settings.standards.posix = true;
|
||||||
|
|
Loading…
Reference in New Issue