Symbol database: better handling of inline functions. Ticket: #2219

This commit is contained in:
Robert Reif 2010-12-05 20:26:52 +01:00 committed by Daniel Marjamäki
parent b25e6ff24c
commit 626a814241
2 changed files with 293 additions and 10 deletions

View File

@ -2786,17 +2786,15 @@ void CheckMemoryLeakInClass::checkPublicFunctions(const SymbolDatabase::SpaceInf
// If they allocate member variables, they should also deallocate // If they allocate member variables, they should also deallocate
std::list<SymbolDatabase::Func>::const_iterator func; std::list<SymbolDatabase::Func>::const_iterator func;
// TODO: parse into any function scope that is not a constructor
for (func = spaceinfo->functionList.begin(); func != spaceinfo->functionList.end(); ++func) for (func = spaceinfo->functionList.begin(); func != spaceinfo->functionList.end(); ++func)
{ {
/** @todo false negative: why do we only check inline functions? */ if (func->type != SymbolDatabase::Func::Constructor &&
if (func->access == SymbolDatabase::Public && func->hasBody && func->isInline) func->access == SymbolDatabase::Public && func->hasBody)
{ {
const Token *tok2 = func->token; const Token *tok2 = func->token;
while (tok2->str() != "{") while (tok2->str() != "{")
tok2 = tok2->next(); tok2 = tok2->next();
/** @todo false negative: why do we only check for this specific case? */ if (Token::Match(tok2, "{|}|; %varid% =", varid))
if (Token::Match(tok2, "{ %varid% =", varid))
{ {
const CheckMemoryLeak::AllocType alloc = getAllocationType(tok2->tokAt(3), varid); const CheckMemoryLeak::AllocType alloc = getAllocationType(tok2->tokAt(3), varid);
if (alloc != CheckMemoryLeak::No) if (alloc != CheckMemoryLeak::No)

View File

@ -3209,8 +3209,25 @@ private:
" delete [] str2;\n" " delete [] str2;\n"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:4]: (error) Memory leak: Fred::str1\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (error) Memory leak: Fred::str1\n", errout.str());
}
check("class Fred\n"
"{\n"
"private:\n"
" char *str1;\n"
" char *str2;\n"
"public:\n"
" Fred()\n"
" {\n"
" str1 = new char[10];\n"
" str2 = new char[10];\n"
" }\n"
" ~Fred()\n"
" {\n"
" delete [] str2;\n"
" }\n"
"};\n");
ASSERT_EQUALS("[test.cpp:4]: (error) Memory leak: Fred::str1\n", errout.str());
}
void class2() void class2()
{ {
@ -3233,6 +3250,22 @@ private:
" free(str1);\n" " free(str1);\n"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:17]: (error) Mismatching allocation and deallocation: Fred::str1\n", errout.str()); ASSERT_EQUALS("[test.cpp:17]: (error) Mismatching allocation and deallocation: Fred::str1\n", errout.str());
check("class Fred\n"
"{\n"
"private:\n"
" char *str1;\n"
"public:\n"
" Fred()\n"
" {\n"
" str1 = new char[10];\n"
" }\n"
" ~Fred()\n"
" {\n"
" free(str1);\n"
" }\n"
"};\n");
ASSERT_EQUALS("[test.cpp:12]: (error) Mismatching allocation and deallocation: Fred::str1\n", errout.str());
} }
void class3() void class3()
@ -3271,6 +3304,35 @@ private:
"}\n"); "}\n");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check("class Token;\n"
"\n"
"class Tokenizer\n"
"{\n"
"private:\n"
" Token *_tokens;\n"
"\n"
"public:\n"
" Tokenizer()\n"
" {\n"
" _tokens = new Token;\n"
" }\n"
" ~Tokenizer()\n"
" {\n"
" deleteTokens(_tokens);\n"
" }\n"
" void deleteTokens(Token *tok)\n"
" {\n"
" while (tok)\n"
" {\n"
" Token *next = tok->next();\n"
" delete tok;\n"
" tok = next;\n"
" }\n"
" }\n"
"};\n");
ASSERT_EQUALS("", errout.str());
} }
void class4() void class4()
@ -3295,6 +3357,23 @@ private:
" addAbc( p );\n" " addAbc( p );\n"
"}\n"); "}\n");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check("struct ABC;\n"
"class Fred\n"
"{\n"
"private:\n"
" void addAbc(ABC* abc)\n"
" {\n"
" AbcPosts->Add(abc);\n"
" }\n"
"public:\n"
" void click()\n"
" {\n"
" ABC *p = new ABC;\n"
" addAbc( p );\n"
" }\n"
"};\n");
ASSERT_EQUALS("", errout.str());
} }
void class6() void class6()
@ -3312,6 +3391,18 @@ private:
" hello();\n" " hello();\n"
"}\n"); "}\n");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check("class Fred\n"
"{\n"
"public:\n"
" void foo()\n"
" { \n"
" char *str = new char[100];\n"
" delete [] str;\n"
" hello();\n"
" }\n"
"};\n");
ASSERT_EQUALS("", errout.str());
} }
void class7() void class7()
@ -3333,6 +3424,21 @@ private:
" delete this->i;\n" " delete this->i;\n"
"}\n"); "}\n");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check("class Fred\n"
"{\n"
"public:\n"
" int *i;\n"
" Fred()\n"
" {\n"
" this->i = new int;\n"
" }\n"
" ~Fred()\n"
" {\n"
" delete this->i;\n"
" }\n"
"};\n");
ASSERT_EQUALS("", errout.str());
} }
void class8() void class8()
@ -3351,6 +3457,19 @@ private:
" doNothing(c);\n" " doNothing(c);\n"
"}\n"); "}\n");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check("class A\n"
"{\n"
"public:\n"
" void a()\n"
" {\n"
" int* c = new int(1);\n"
" delete c;\n"
" doNothing(c);\n"
" }\n"
" void doNothing() { }\n"
"};\n");
ASSERT_EQUALS("", errout.str());
} }
void class9() void class9()
@ -3369,10 +3488,31 @@ private:
"A::~A()\n" "A::~A()\n"
"{ delete (p); }\n"); "{ delete (p); }\n");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check("class A\n"
"{\n"
"public:\n"
" int * p;\n"
" A()\n"
" { p = new int; }\n"
" ~A()\n"
" { delete (p); }\n"
"};\n");
ASSERT_EQUALS("", errout.str());
} }
void class10() void class10()
{ {
check("class A\n"
"{\n"
"public:\n"
" int * p;\n"
" A();\n"
"};\n"
"A::A()\n"
"{ p = new int; }\n");
ASSERT_EQUALS("[test.cpp:4]: (error) Memory leak: A::p\n", errout.str());
check("class A\n" check("class A\n"
"{\n" "{\n"
"public:\n" "public:\n"
@ -3384,6 +3524,15 @@ private:
void class11() void class11()
{ {
check("class A\n"
"{\n"
"public:\n"
" int * p;\n"
" A() : p(new int[10])\n"
" { }"
"};\n");
ASSERT_EQUALS("[test.cpp:4]: (error) Memory leak: A::p\n", errout.str());
check("class A\n" check("class A\n"
"{\n" "{\n"
"public:\n" "public:\n"
@ -3416,6 +3565,20 @@ private:
"void A::cleanup()\n" "void A::cleanup()\n"
"{ delete [] p; }\n"); "{ delete [] p; }\n");
ASSERT_EQUALS("[test.cpp:4]: (error) Memory leak: A::p\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (error) Memory leak: A::p\n", errout.str());
check("class A\n"
"{\n"
"private:\n"
" int *p;\n"
"public:\n"
" A()\n"
" { p = new int[10]; }\n"
" ~A()\n"
" { }\n"
" void cleanup()\n"
" { delete [] p; }\n"
"};\n");
ASSERT_EQUALS("[test.cpp:4]: (error) Memory leak: A::p\n", errout.str());
} }
void class13() void class13()
@ -3438,7 +3601,21 @@ private:
"\n" "\n"
"void A::foo()\n" "void A::foo()\n"
"{ p = new int[10]; delete [] p; }\n"); "{ p = new int[10]; delete [] p; }\n");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("[test.cpp:17]: (warning) Possible leak in public function. The pointer 'p' is not deallocated before it is allocated.\n", errout.str());
check("class A\n"
"{\n"
"private:\n"
" int *p;\n"
"public:\n"
" A()\n"
" { }\n"
" ~A()\n"
" { }\n"
" void foo()\n"
" { p = new int[10]; delete [] p; }\n"
"};\n");
ASSERT_EQUALS("[test.cpp:11]: (warning) Possible leak in public function. The pointer 'p' is not deallocated before it is allocated.\n", errout.str());
} }
void class14() void class14()
@ -3452,7 +3629,19 @@ private:
"\n" "\n"
"void A::init()\n" "void A::init()\n"
"{ p = new int[10]; }\n"); "{ p = new int[10]; }\n");
ASSERT_EQUALS("[test.cpp:3]: (error) Memory leak: A::p\n", errout.str()); ASSERT_EQUALS("[test.cpp:9]: (warning) Possible leak in public function. The pointer 'p' is not deallocated before it is allocated.\n"
"[test.cpp:3]: (error) Memory leak: A::p\n", errout.str());
check("class A\n"
"{\n"
" int *p;\n"
"public:\n"
" void init()\n"
" { p = new int[10]; }\n"
"};\n");
ASSERT_EQUALS("[test.cpp:6]: (warning) Possible leak in public function. The pointer 'p' is not deallocated before it is allocated.\n"
"[test.cpp:3]: (error) Memory leak: A::p\n", errout.str());
check("class A\n" check("class A\n"
"{\n" "{\n"
@ -3463,7 +3652,19 @@ private:
"\n" "\n"
"void A::init()\n" "void A::init()\n"
"{ p = new int; }\n"); "{ p = new int; }\n");
ASSERT_EQUALS("[test.cpp:3]: (error) Memory leak: A::p\n", errout.str()); ASSERT_EQUALS("[test.cpp:9]: (warning) Possible leak in public function. The pointer 'p' is not deallocated before it is allocated.\n"
"[test.cpp:3]: (error) Memory leak: A::p\n", errout.str());
check("class A\n"
"{\n"
" int *p;\n"
"public:\n"
" void init()\n"
" { p = new int; }\n"
"};\n");
ASSERT_EQUALS("[test.cpp:6]: (warning) Possible leak in public function. The pointer 'p' is not deallocated before it is allocated.\n"
"[test.cpp:3]: (error) Memory leak: A::p\n", errout.str());
check("class A\n" check("class A\n"
"{\n" "{\n"
@ -3474,7 +3675,18 @@ private:
"\n" "\n"
"void A::init()\n" "void A::init()\n"
"{ p = malloc(sizeof(int)*10); }\n"); "{ p = malloc(sizeof(int)*10); }\n");
ASSERT_EQUALS("[test.cpp:3]: (error) Memory leak: A::p\n", errout.str()); ASSERT_EQUALS("[test.cpp:9]: (warning) Possible leak in public function. The pointer 'p' is not deallocated before it is allocated.\n"
"[test.cpp:3]: (error) Memory leak: A::p\n", errout.str());
check("class A\n"
"{\n"
" int *p;\n"
"public:\n"
" void init()\n"
" { p = malloc(sizeof(int)*10); }\n"
"};\n");
ASSERT_EQUALS("[test.cpp:6]: (warning) Possible leak in public function. The pointer 'p' is not deallocated before it is allocated.\n"
"[test.cpp:3]: (error) Memory leak: A::p\n", errout.str());
} }
void class15() void class15()
@ -3490,6 +3702,17 @@ private:
"{ p = new int[10]; }"); "{ p = new int[10]; }");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check("class A\n"
"{\n"
" int *p;\n"
"public:\n"
" A()\n"
" { p = new int[10]; }\n"
" ~A() { delete [] p; }\n"
"};\n");
ASSERT_EQUALS("", errout.str());
check("class A\n" check("class A\n"
"{\n" "{\n"
" int *p;\n" " int *p;\n"
@ -3501,6 +3724,17 @@ private:
"{ p = new int; }"); "{ p = new int; }");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check("class A\n"
"{\n"
" int *p;\n"
"public:\n"
" A()\n"
" { p = new int; }\n"
" ~A() { delete p; }\n"
"};\n");
ASSERT_EQUALS("", errout.str());
check("class A\n" check("class A\n"
"{\n" "{\n"
" int *p;\n" " int *p;\n"
@ -3511,6 +3745,16 @@ private:
"A::A()\n" "A::A()\n"
"{ p = malloc(sizeof(int)*10); }"); "{ p = malloc(sizeof(int)*10); }");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check("class A\n"
"{\n"
" int *p;\n"
"public:\n"
" A()\n"
" { p = malloc(sizeof(int)*10); }\n"
" ~A() { free(p); }\n"
"};\n");
ASSERT_EQUALS("", errout.str());
} }
void class16() void class16()
@ -3543,6 +3787,33 @@ private:
" delete [] A::pd;\n" " delete [] A::pd;\n"
"}\n"); "}\n");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
TODO_ASSERT_EQUALS("[test.cpp:9]: (warning) Possible leak in public function. The pointer 'pd' is not deallocated before it is allocated.\n", errout.str());
check("class A {\n"
"private:\n"
" char *pd;\n"
"public:\n"
" void foo()\n"
" {\n"
" pd = new char[12];\n"
" delete [] pd;\n"
" }\n"
"};\n");
ASSERT_EQUALS("[test.cpp:6]: (warning) Possible leak in public function. The pointer 'pd' is not deallocated before it is allocated.\n", errout.str());
check("class A {\n"
"private:\n"
" char *pd;\n"
"public:\n"
" void foo();\n"
"};\n"
"\n"
"void A::foo()\n"
"{\n"
" pd = new char[12];\n"
" delete [] pd;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:9]: (warning) Possible leak in public function. The pointer 'pd' is not deallocated before it is allocated.\n", errout.str());
} }
void class18() void class18()
@ -3560,6 +3831,20 @@ private:
" char *a;\n" " char *a;\n"
"};\n"); "};\n");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check("class A : public x\n"
"{\n"
"public:\n"
" A();\n"
"private:\n"
" char *a;\n"
"};\n"
"A::A()\n"
"{\n"
" a = new char[10];\n"
" foo(a);\n"
"}\n");
ASSERT_EQUALS("", errout.str());
} }
void class19() void class19()