CheckMemoryLeakInFunction: Don't treat delete as delete operator for C code

Fixed GCC message in checkbufferoverrun.cpp
This commit is contained in:
PKEuS 2015-01-30 20:55:53 +01:00
parent 98e33a189f
commit 03e44d4aa0
4 changed files with 75 additions and 61 deletions

View File

@ -654,7 +654,7 @@ void CheckBufferOverrun::checkScope(const Token *tok, const std::vector<std::str
if (total_size > 0) {
// 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()))) {
const std::size_t len = Token::getStrLength(tok->tokAt(varcount + 4));
if (len >= (unsigned int)total_size) {

View File

@ -64,7 +64,7 @@ static unsigned int countParameters(const Token *tok)
static const char * const call_func_white_list[] = {
"_open", "_wopen", "access", "adjtime", "asctime", "asctime_r", "asprintf", "assert"
, "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"
, "fdatasync", "feof", "ferror", "fflush", "fgetc", "fgetpos", "fgets"
, "flock", "fmemopen", "fnmatch", "fopen", "fopencookie", "for", "fprintf", "fputc", "fputs", "fread", "free"
@ -239,17 +239,19 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getReallocationType(const Token *tok
CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok, unsigned int varid) const
{
if (Token::Match(tok, "delete %varid% ;", varid))
return New;
if (tokenizer->isCPP()) {
if (Token::Match(tok, "delete %varid% ;", varid))
return New;
if (Token::Match(tok, "delete [ ] %varid% ;", varid))
return NewArray;
if (Token::Match(tok, "delete [ ] %varid% ;", varid))
return NewArray;
if (Token::Match(tok, "delete ( %varid% ) ;", varid))
return New;
if (Token::Match(tok, "delete ( %varid% ) ;", varid))
return New;
if (Token::Match(tok, "delete [ ] ( %varid% ) ;", varid))
return NewArray;
if (Token::Match(tok, "delete [ ] ( %varid% ) ;", varid))
return NewArray;
}
if (tok && tok->str() == "::")
tok = tok->next();
@ -283,17 +285,19 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok
CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok, const std::string &varname) const
{
if (Token::Match(tok, std::string("delete " + varname + " [,;]").c_str()))
return New;
if (tokenizer->isCPP()) {
if (Token::Match(tok, std::string("delete " + varname + " [,;]").c_str()))
return New;
if (Token::Match(tok, std::string("delete [ ] " + varname + " [,;]").c_str()))
return NewArray;
if (Token::Match(tok, std::string("delete [ ] " + varname + " [,;]").c_str()))
return NewArray;
if (Token::Match(tok, std::string("delete ( " + varname + " ) [,;]").c_str()))
return New;
if (Token::Match(tok, std::string("delete ( " + varname + " ) [,;]").c_str()))
return New;
if (Token::Match(tok, std::string("delete [ ] ( " + varname + " ) [,;]").c_str()))
return NewArray;
if (Token::Match(tok, std::string("delete [ ] ( " + varname + " ) [,;]").c_str()))
return NewArray;
}
if (Token::simpleMatch(tok, std::string("free ( " + 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,
call_func_white_list+sizeof(call_func_white_list) / sizeof(call_func_white_list[0]),
funcname));
}
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()));
funcname) || (settings->library.leakignore.find(funcname) != settings->library.leakignore.end()) || (cpp && funcname == "delete"));
}
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" ||
tok->str() == "delete" ||
tok->str() == "fclose" ||
@ -1024,7 +1020,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
dep = true;
} else if (Token::Match(tok2, "! %varid%", varid)) {
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;
for (const Token *tok3 = tok2->tokAt(2); tok3; tok3 = tok3->nextArgument()) {
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(), "&|(") &&
tok2->strAt(1) == "[") {
} 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)) {
use = true;
}
@ -1286,7 +1282,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
if (_settings->library.isnoreturn(tok))
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);
for (const Token *tok2 = tok->tokAt(2); tok2 != end2; tok2 = tok2->next()) {
if (tok2->varId() == varid) {
@ -2402,7 +2398,7 @@ void CheckMemoryLeakInClass::variable(const Scope *scope, const Token *tokVarnam
// Function call .. possible deallocation
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;
}
}
@ -2717,12 +2713,12 @@ void CheckMemoryLeakNoVar::check()
// Is it a function call..
if (!Token::Match(tok3->tokAt(-2), "= %var% (")) {
const std::string& functionName = tok3->strAt(-1);
if (functionName == "delete" ||
if ((tokenizer->isCPP() && functionName == "delete") ||
functionName == "free" ||
functionName == "fclose" ||
functionName == "realloc")
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);
break;
}

View File

@ -47,10 +47,11 @@ class Variable;
/** @brief Base class for memory leaks checking */
class CPPCHECKLIB CheckMemoryLeak {
private:
protected:
/** For access to the tokens */
const Tokenizer * const tokenizer;
private:
/** ErrorLogger used to report errors */
ErrorLogger * const errorLogger;
@ -202,8 +203,7 @@ public:
}
/** @brief Unit testing : testing the white list */
static bool test_white_list(const std::string &funcname);
static bool test_white_list_with_lib(const std::string &funcname, const Settings *settings);
static bool test_white_list(const std::string &funcname, const Settings *settings, bool cpp);
/** @brief Perform checking */
void check();

View File

@ -128,7 +128,7 @@ private:
Settings settings1;
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..
errout.str("");
@ -138,7 +138,7 @@ private:
// Tokenize..
Tokenizer tokenizer(settings, this);
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
tokenizer.tokenize(istr, c?"test.c":"test.cpp");
tokenizer.simplifyTokenList2();
// Check for memory leaks..
@ -365,6 +365,8 @@ private:
TEST_CASE(ptrptr);
TEST_CASE(c_code);
// test that the cfg files are configured correctly
TEST_CASE(posixcfg);
TEST_CASE(posixcfg_mmap);
@ -594,33 +596,39 @@ private:
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 {
// whitelist..
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("qsort"));
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("scanf"));
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("sscanf"));
ASSERT_EQUALS(true, test_white_list("qsort"));
ASSERT_EQUALS(true, test_white_list("scanf"));
ASSERT_EQUALS(true, test_white_list("sscanf"));
// #1293
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("time"));
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("asctime"));
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("asctime_r"));
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("ctime"));
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("ctime_r"));
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("gmtime"));
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("gmtime_r"));
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("localtime"));
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("localtime_r"));
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("memcmp"));
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("gets"));
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("vprintf"));
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("vfprintf"));
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("vsprintf"));
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("snprintf"));
ASSERT_EQUALS(true, CheckMemoryLeakInFunction::test_white_list("vsnprintf"));
ASSERT_EQUALS(true, test_white_list("time"));
ASSERT_EQUALS(true, test_white_list("asctime"));
ASSERT_EQUALS(true, test_white_list("asctime_r"));
ASSERT_EQUALS(true, test_white_list("ctime"));
ASSERT_EQUALS(true, test_white_list("ctime_r"));
ASSERT_EQUALS(true, test_white_list("gmtime"));
ASSERT_EQUALS(true, test_white_list("gmtime_r"));
ASSERT_EQUALS(true, test_white_list("localtime"));
ASSERT_EQUALS(true, test_white_list("localtime_r"));
ASSERT_EQUALS(true, test_white_list("memcmp"));
ASSERT_EQUALS(true, test_white_list("gets"));
ASSERT_EQUALS(true, test_white_list("vprintf"));
ASSERT_EQUALS(true, test_white_list("vfprintf"));
ASSERT_EQUALS(true, test_white_list("vsprintf"));
ASSERT_EQUALS(true, test_white_list("snprintf"));
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[] = {
"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"
, "flock", "for", "fprintf", "fputc", "fputs", "fread", "free", "freopen", "fscanf", "fseek"
, "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) {
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]);
}
}
@ -4262,6 +4270,16 @@ private:
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() {
Settings settings;
settings.standards.posix = true;