CheckMemoryLeak: use library while checking whitelist functions

This commit is contained in:
Pavel Roschin 2014-02-05 11:18:39 +04:00
parent 6ac9e180e0
commit 0dd227419d
4 changed files with 56 additions and 9 deletions

View File

@ -18,7 +18,7 @@
<use>g_register_data</use> <use>g_register_data</use>
</memory> </memory>
<function name="g_strcmp"> <function name="g_strcmp0">
<leak-ignore/> <leak-ignore/>
<noreturn>false</noreturn> <noreturn>false</noreturn>
</function> </function>

View File

@ -558,10 +558,18 @@ bool CheckMemoryLeakInFunction::test_white_list(const std::string &funcname)
funcname)); 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()));
}
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(tok->str()) || if (test_white_list_with_lib(tok->str(), _settings)) {
(_settings->library.leakignore.find(tok->str()) != _settings->library.leakignore.end())) {
if (tok->str() == "asprintf" || if (tok->str() == "asprintf" ||
tok->str() == "delete" || tok->str() == "delete" ||
tok->str() == "fclose" || tok->str() == "fclose" ||
@ -1039,7 +1047,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(tok2->str())) { } else if (Token::Match(tok2, "%var% (") && !test_white_list_with_lib(tok2->str(), _settings)) {
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)) {
@ -1214,7 +1222,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(f.top()->str()) || !test_white_list_with_lib(f.top()->str(), _settings) ||
getDeallocationType(f.top(),varid)) { getDeallocationType(f.top(),varid)) {
use = true; use = true;
} }
@ -1300,7 +1308,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
if (noreturn.find(tok->str()) != noreturn.end()) if (noreturn.find(tok->str()) != noreturn.end())
addtoken(&rettail, tok, "exit"); addtoken(&rettail, tok, "exit");
else if (!test_white_list(tok->str())) { else if (!test_white_list_with_lib(tok->str(), _settings)) {
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) {
@ -2405,7 +2413,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(tok->str())) { if (!CheckMemoryLeakInFunction::test_white_list_with_lib(tok->str(), _settings)) {
return; return;
} }
} }
@ -2721,7 +2729,7 @@ void CheckMemoryLeakNoVar::check()
functionName == "fclose" || functionName == "fclose" ||
functionName == "realloc") functionName == "realloc")
break; break;
if (CheckMemoryLeakInFunction::test_white_list(functionName)) { if (CheckMemoryLeakInFunction::test_white_list_with_lib(functionName, _settings)) {
functionCallLeak(tok2, tok2->strAt(1), functionName); functionCallLeak(tok2, tok2->strAt(1), functionName);
break; break;
} }

View File

@ -204,6 +204,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);
static bool test_white_list_with_lib(const std::string &funcname, const Settings *settings);
/** @brief Perform checking */ /** @brief Perform checking */
void check(); void check();

View File

@ -6102,6 +6102,9 @@ private:
Settings settings; Settings settings;
settings.standards.posix = true; settings.standards.posix = true;
LOAD_LIB("gtk.cfg");
settings.library = _lib;
// Add some test allocation functions to the library. // Add some test allocation functions to the library.
// When not run as a unit test, these are read from // When not run as a unit test, these are read from
// an XML file (e.g. cfg/posix.cfg). // an XML file (e.g. cfg/posix.cfg).
@ -6136,17 +6139,30 @@ private:
" strcpy(a, strdup(p));\n" " strcpy(a, strdup(p));\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:2]: (error) Allocation with strdup, strcpy doesn't release it.\n", errout.str()); ASSERT_EQUALS("[test.cpp:2]: (error) Allocation with strdup, strcpy doesn't release it.\n", errout.str());
check("void x() {\n"
" g_strcpy(a, g_strdup(p));\n"
"}");
ASSERT_EQUALS("[test.cpp:2]: (error) Allocation with g_strdup, g_strcpy doesn't release it.\n", errout.str());
check("char *x() {\n" check("char *x() {\n"
" char *ret = strcpy(malloc(10), \"abc\");\n" " char *ret = strcpy(malloc(10), \"abc\");\n"
" return ret;\n" " return ret;\n"
"}"); "}");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check("gchar *x() {\n"
" gchar *ret = g_strcpy(g_malloc(10), \"abc\");\n"
" return ret;\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void x() {\n" check("void x() {\n"
" free(malloc(10));\n" " free(malloc(10));\n"
"}"); "}");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check("void x() {\n"
" g_free(g_malloc(10));\n"
"}");
ASSERT_EQUALS("", errout.str());
// user function.. // user function..
check("void set_error(const char *msg) {\n" check("void set_error(const char *msg) {\n"
@ -6156,6 +6172,13 @@ private:
" set_error(strdup(p));\n" " set_error(strdup(p));\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:5]: (error) Allocation with strdup, set_error doesn't release it.\n", errout.str()); ASSERT_EQUALS("[test.cpp:5]: (error) Allocation with strdup, set_error doesn't release it.\n", errout.str());
check("void set_error(const char *msg) {\n"
"}\n"
"\n"
"void x() {\n"
" set_error(g_strdup(p));\n"
"}");
ASSERT_EQUALS("[test.cpp:5]: (error) Allocation with g_strdup, set_error doesn't release it.\n", errout.str());
check("void f()\n" check("void f()\n"
"{\n" "{\n"
@ -6170,18 +6193,33 @@ private:
" if(TRUE || strcmp(strdup(a), b));\n" " if(TRUE || strcmp(strdup(a), b));\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (error) Allocation with strdup, strcmp doesn't release it.\n", errout.str()); ASSERT_EQUALS("[test.cpp:3]: (error) Allocation with strdup, strcmp doesn't release it.\n", errout.str());
check("void f()\n"
"{\n"
" if(TRUE || g_strcmp0(g_strdup(a), b));\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Allocation with g_strdup, g_strcmp0 doesn't release it.\n", errout.str());
check("void f()\n" check("void f()\n"
"{\n" "{\n"
" if(!strcmp(strdup(a), b) == 0);\n" " if(!strcmp(strdup(a), b) == 0);\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (error) Allocation with strdup, strcmp doesn't release it.\n", errout.str()); ASSERT_EQUALS("[test.cpp:3]: (error) Allocation with strdup, strcmp doesn't release it.\n", errout.str());
check("void f()\n"
"{\n"
" if(!g_strcmp0(g_strdup(a), b) == 0);\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Allocation with g_strdup, g_strcmp0 doesn't release it.\n", errout.str());
check("void f()\n" check("void f()\n"
"{\n" "{\n"
" 42, strcmp(strdup(a), b);\n" " 42, strcmp(strdup(a), b);\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (error) Allocation with strdup, strcmp doesn't release it.\n", errout.str()); ASSERT_EQUALS("[test.cpp:3]: (error) Allocation with strdup, strcmp doesn't release it.\n", errout.str());
check("void f()\n"
"{\n"
" 42, g_strcmp0(g_strdup(a), b);\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Allocation with g_strdup, g_strcmp0 doesn't release it.\n", errout.str());
} }
void missingAssignment() { void missingAssignment() {