2008-12-18 22:28:57 +01:00
/*
2009-01-21 21:04:20 +01:00
* Cppcheck - A tool for static C / C + + code analysis
2019-02-09 07:24:06 +01:00
* Copyright ( C ) 2007 - 2019 Cppcheck team .
2008-12-18 22:28:57 +01:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2009-09-27 17:08:31 +02:00
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2008-12-18 22:28:57 +01:00
*/
2009-10-25 12:49:06 +01:00
# include "checkmemoryleak.h"
2014-02-06 09:22:07 +01:00
# include "preprocessor.h"
2017-05-27 04:33:47 +02:00
# include "settings.h"
# include "simplecpp.h"
# include "standards.h"
# include "symboldatabase.h"
# include "testsuite.h"
# include "token.h"
# include "tokenize.h"
# include "tokenlist.h"
# include <list>
# include <ostream>
# include <string>
# include <vector>
struct InternalError ;
2008-12-18 22:28:57 +01:00
2009-06-15 17:44:59 +02:00
2011-10-13 20:53:06 +02:00
class TestMemleak : private TestFixture {
2009-06-15 17:44:59 +02:00
public :
2014-11-20 14:20:09 +01:00
TestMemleak ( ) : TestFixture ( " TestMemleak " ) {
2013-08-07 16:27:37 +02:00
}
2009-06-15 17:44:59 +02:00
private :
2015-10-07 18:33:57 +02:00
Settings settings ;
2019-01-12 15:45:25 +01:00
void run ( ) OVERRIDE {
2009-06-15 17:44:59 +02:00
TEST_CASE ( testFunctionReturnType ) ;
2010-01-26 20:10:52 +01:00
TEST_CASE ( open ) ;
2009-06-15 17:44:59 +02:00
}
2014-11-20 14:20:09 +01:00
CheckMemoryLeak : : AllocType functionReturnType ( const char code [ ] ) {
2010-12-01 18:00:55 +01:00
// Clear the error buffer..
errout . str ( " " ) ;
2009-06-15 17:44:59 +02:00
// Tokenize..
2010-12-01 18:00:55 +01:00
Tokenizer tokenizer ( & settings , this ) ;
2009-06-15 17:44:59 +02:00
std : : istringstream istr ( code ) ;
tokenizer . tokenize ( istr , " test.cpp " ) ;
2018-09-24 15:08:16 +02:00
const CheckMemoryLeak c ( & tokenizer , this , & settings ) ;
2013-06-29 12:55:24 +02:00
return c . functionReturnType ( & tokenizer . getSymbolDatabase ( ) - > scopeList . front ( ) . functionList . front ( ) ) ;
2009-06-15 17:44:59 +02:00
}
2014-11-20 14:20:09 +01:00
void testFunctionReturnType ( ) {
2009-06-15 17:44:59 +02:00
{
const char code [ ] = " const char *foo() \n "
" { return 0; } " ;
ASSERT_EQUALS ( CheckMemoryLeak : : No , functionReturnType ( code ) ) ;
}
{
const char code [ ] = " Fred *newFred() \n "
" { return new Fred; } " ;
ASSERT_EQUALS ( CheckMemoryLeak : : New , functionReturnType ( code ) ) ;
}
{
const char code [ ] = " char *foo() \n "
" { return new char[100]; } " ;
ASSERT_EQUALS ( CheckMemoryLeak : : NewArray , functionReturnType ( code ) ) ;
}
2009-06-15 21:13:39 +02:00
{
const char code [ ] = " char *foo() \n "
" { \n "
" char *p = new char[100]; \n "
" return p; \n "
" } " ;
ASSERT_EQUALS ( CheckMemoryLeak : : NewArray , functionReturnType ( code ) ) ;
}
2009-06-15 17:44:59 +02:00
}
2010-01-26 20:10:52 +01:00
2014-11-20 14:20:09 +01:00
void open ( ) {
2010-01-26 20:10:52 +01:00
const char code [ ] = " class A { \n "
" static int open() { \n "
" return 1; \n "
" } \n "
" \n "
" A() { \n "
" int ret = open(); \n "
" } \n "
" }; \n " ;
2010-12-01 18:00:55 +01:00
// Clear the error buffer..
errout . str ( " " ) ;
Tokenizer tokenizer ( & settings , this ) ;
2010-01-26 20:10:52 +01:00
std : : istringstream istr ( code ) ;
tokenizer . tokenize ( istr , " test.cpp " ) ;
// there is no allocation
2011-10-28 22:30:33 +02:00
const Token * tok = Token : : findsimplematch ( tokenizer . tokens ( ) , " ret = " ) ;
2019-06-30 21:39:22 +02:00
const CheckMemoryLeak check ( & tokenizer , nullptr , & settings ) ;
2010-01-26 20:10:52 +01:00
ASSERT_EQUALS ( CheckMemoryLeak : : No , check . getAllocationType ( tok - > tokAt ( 2 ) , 1 ) ) ;
}
2009-06-15 17:44:59 +02:00
} ;
2015-10-07 14:30:01 +02:00
REGISTER_TEST ( TestMemleak )
2009-06-15 17:44:59 +02:00
2011-10-13 20:53:06 +02:00
class TestMemleakInClass : public TestFixture {
2009-06-08 20:20:43 +02:00
public :
2014-11-20 14:20:09 +01:00
TestMemleakInClass ( ) : TestFixture ( " TestMemleakInClass " ) {
2013-08-07 16:27:37 +02:00
}
2009-06-08 20:20:43 +02:00
private :
2015-10-07 18:33:57 +02:00
Settings settings ;
2010-04-18 21:14:25 +02:00
/**
* Tokenize and execute leak check for given code
* @ param code Source code
*/
2014-11-20 14:20:09 +01:00
void check ( const char code [ ] ) {
2010-12-01 18:00:55 +01:00
// Clear the error buffer..
errout . str ( " " ) ;
2009-06-08 20:20:43 +02:00
// Tokenize..
2010-12-01 18:00:55 +01:00
Tokenizer tokenizer ( & settings , this ) ;
2009-06-08 20:20:43 +02:00
std : : istringstream istr ( code ) ;
tokenizer . tokenize ( istr , " test.cpp " ) ;
2013-12-30 17:45:28 +01:00
tokenizer . simplifyTokenList2 ( ) ;
2009-06-08 20:20:43 +02:00
// Check for memory leaks..
CheckMemoryLeakInClass checkMemoryLeak ( & tokenizer , & settings , this ) ;
checkMemoryLeak . check ( ) ;
}
2019-01-12 15:45:25 +01:00
void run ( ) OVERRIDE {
2015-10-07 18:33:57 +02:00
settings . addEnabled ( " warning " ) ;
settings . addEnabled ( " style " ) ;
2015-11-19 17:33:52 +01:00
LOAD_LIB_2 ( settings . library , " std.cfg " ) ;
2009-06-08 20:20:43 +02:00
TEST_CASE ( class1 ) ;
TEST_CASE ( class2 ) ;
TEST_CASE ( class3 ) ;
TEST_CASE ( class4 ) ;
TEST_CASE ( class6 ) ;
TEST_CASE ( class7 ) ;
TEST_CASE ( class8 ) ;
TEST_CASE ( class9 ) ;
TEST_CASE ( class10 ) ;
TEST_CASE ( class11 ) ;
2009-10-22 21:51:58 +02:00
TEST_CASE ( class12 ) ;
2009-10-23 20:04:47 +02:00
TEST_CASE ( class13 ) ;
2010-01-27 22:05:04 +01:00
TEST_CASE ( class14 ) ;
2010-03-19 16:57:23 +01:00
TEST_CASE ( class15 ) ;
2010-06-12 13:37:44 +02:00
TEST_CASE ( class16 ) ;
2010-06-13 10:43:23 +02:00
TEST_CASE ( class17 ) ;
2010-06-16 19:28:47 +02:00
TEST_CASE ( class18 ) ;
2010-11-23 18:41:07 +01:00
TEST_CASE ( class19 ) ; // ticket #2219
2010-12-07 07:08:05 +01:00
TEST_CASE ( class20 ) ;
2011-01-30 08:38:20 +01:00
TEST_CASE ( class21 ) ; // ticket #2517
2011-08-16 20:39:17 +02:00
TEST_CASE ( class22 ) ; // ticket #3012
2011-11-28 20:08:29 +01:00
TEST_CASE ( class23 ) ; // ticket #3303
2012-05-29 21:13:34 +02:00
TEST_CASE ( class24 ) ; // ticket #3806 - false positive in copy constructor
2013-02-24 08:14:25 +01:00
TEST_CASE ( class25 ) ; // ticket #4367 - false positive implementation for destructor is not seen
2009-06-08 20:20:43 +02:00
2009-10-06 18:25:00 +02:00
TEST_CASE ( staticvar ) ;
2009-06-08 20:20:43 +02:00
TEST_CASE ( free_member_in_sub_func ) ;
2010-01-27 21:02:13 +01:00
TEST_CASE ( mismatch1 ) ;
2014-04-10 16:11:11 +02:00
TEST_CASE ( mismatch2 ) ; // #5659
2010-05-15 19:40:32 +02:00
// allocating member variable in public function
TEST_CASE ( func1 ) ;
TEST_CASE ( func2 ) ;
2009-06-08 20:20:43 +02:00
}
2014-11-20 14:20:09 +01:00
void class1 ( ) {
2009-06-08 20:20:43 +02:00
check ( " class Fred \n "
" { \n "
" private: \n "
" char *str1; \n "
" char *str2; \n "
" public: \n "
" Fred(); \n "
" ~Fred(); \n "
" }; \n "
" \n "
" Fred::Fred() \n "
" { \n "
" str1 = new char[10]; \n "
" str2 = new char[10]; \n "
" } \n "
" \n "
" Fred::~Fred() \n "
" { \n "
" delete [] str2; \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2012-09-10 17:27:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style) Class 'Fred' is unsafe, 'Fred::str1' can leak by wrong usage. \n " , errout . str ( ) ) ;
2009-06-08 20:20:43 +02:00
2010-12-05 20:26:52 +01:00
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 "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2012-09-10 17:27:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style) Class 'Fred' is unsafe, 'Fred::str1' can leak by wrong usage. \n " , errout . str ( ) ) ;
2010-12-05 20:26:52 +01:00
}
2009-06-08 20:20:43 +02:00
2014-11-20 14:20:09 +01:00
void class2 ( ) {
2009-06-08 20:20:43 +02:00
check ( " class Fred \n "
" { \n "
" private: \n "
" char *str1; \n "
" public: \n "
" Fred(); \n "
" ~Fred(); \n "
" }; \n "
" \n "
" Fred::Fred() \n "
" { \n "
" str1 = new char[10]; \n "
" } \n "
" \n "
" Fred::~Fred() \n "
" { \n "
" free(str1); \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2010-06-13 19:00:11 +02:00
ASSERT_EQUALS ( " [test.cpp:17]: (error) Mismatching allocation and deallocation: Fred::str1 \n " , errout . str ( ) ) ;
2010-12-05 20:26:52 +01:00
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 "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2010-12-05 20:26:52 +01:00
ASSERT_EQUALS ( " [test.cpp:12]: (error) Mismatching allocation and deallocation: Fred::str1 \n " , errout . str ( ) ) ;
2009-06-08 20:20:43 +02:00
}
2014-11-20 14:20:09 +01:00
void class3 ( ) {
2009-06-08 20:20:43 +02:00
check ( " class Token; \n "
" \n "
" class Tokenizer \n "
" { \n "
" private: \n "
" Token *_tokens; \n "
" \n "
" public: \n "
" Tokenizer(); \n "
" ~Tokenizer(); \n "
" void deleteTokens(Token *tok); \n "
" }; \n "
" \n "
" Tokenizer::Tokenizer() \n "
" { \n "
" _tokens = new Token; \n "
" } \n "
" \n "
" Tokenizer::~Tokenizer() \n "
" { \n "
" deleteTokens(_tokens); \n "
" } \n "
" \n "
" void Tokenizer::deleteTokens(Token *tok) \n "
" { \n "
" while (tok) \n "
" { \n "
" Token *next = tok->next(); \n "
" delete tok; \n "
" tok = next; \n "
" } \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2009-06-08 20:20:43 +02:00
2009-10-24 15:07:14 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-12-05 20:26:52 +01:00
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 "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2010-12-05 20:26:52 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-06-08 20:20:43 +02:00
}
2014-11-20 14:20:09 +01:00
void class4 ( ) {
2009-06-08 20:20:43 +02:00
check ( " struct ABC; \n "
" class Fred \n "
" { \n "
" private: \n "
" void addAbc(ABC *abc); \n "
" public: \n "
" void click(); \n "
" }; \n "
" \n "
" void Fred::addAbc(ABC* abc) \n "
" { \n "
" AbcPosts->Add(abc); \n "
" } \n "
" \n "
" void Fred::click() \n "
" { \n "
" ABC *p = new ABC; \n "
" addAbc( p ); \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2009-06-08 20:20:43 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-12-05 20:26:52 +01:00
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 "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2010-12-05 20:26:52 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-06-08 20:20:43 +02:00
}
2014-11-20 14:20:09 +01:00
void class6 ( ) {
2009-06-08 20:20:43 +02:00
check ( " class Fred \n "
" { \n "
" public: \n "
" void foo(); \n "
" }; \n "
" \n "
" void Fred::foo() \n "
" { \n "
" char *str = new char[100]; \n "
" delete [] str; \n "
" hello(); \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2009-06-08 20:20:43 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-12-05 20:26:52 +01:00
check ( " class Fred \n "
" { \n "
" public: \n "
" void foo() \n "
2012-12-06 19:19:22 +01:00
" { \n "
2010-12-05 20:26:52 +01:00
" char *str = new char[100]; \n "
" delete [] str; \n "
" hello(); \n "
" } \n "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2010-12-05 20:26:52 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-06-08 20:20:43 +02:00
}
2014-11-20 14:20:09 +01:00
void class7 ( ) {
2009-06-08 20:20:43 +02:00
check ( " class Fred \n "
" { \n "
" public: \n "
" int *i; \n "
" Fred(); \n "
" ~Fred(); \n "
" }; \n "
" \n "
" Fred::Fred() \n "
" { \n "
" this->i = new int; \n "
" } \n "
" Fred::~Fred() \n "
" { \n "
" delete this->i; \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2009-06-08 20:20:43 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-12-05 20:26:52 +01:00
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 "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2010-12-05 20:26:52 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-06-08 20:20:43 +02:00
}
2014-11-20 14:20:09 +01:00
void class8 ( ) {
2009-06-08 20:20:43 +02:00
check ( " class A \n "
" { \n "
" public: \n "
" void a(); \n "
" void doNothing() { } \n "
" }; \n "
" \n "
" void A::a() \n "
" { \n "
" int* c = new int(1); \n "
" delete c; \n "
" doNothing(c); \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2009-06-08 20:20:43 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-12-05 20:26:52 +01:00
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 "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2010-12-05 20:26:52 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-06-08 20:20:43 +02:00
}
2014-11-20 14:20:09 +01:00
void class9 ( ) {
2009-06-08 20:20:43 +02:00
check ( " class A \n "
" { \n "
" public: \n "
" int * p; \n "
" A(); \n "
" ~A(); \n "
" }; \n "
" \n "
" A::A() \n "
" { p = new int; } \n "
" \n "
" A::~A() \n "
2013-03-20 15:36:16 +01:00
" { delete (p); } " ) ;
2009-06-08 20:20:43 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-12-05 20:26:52 +01:00
check ( " class A \n "
" { \n "
" public: \n "
" int * p; \n "
" A() \n "
" { p = new int; } \n "
" ~A() \n "
" { delete (p); } \n "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2010-12-05 20:26:52 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-06-08 20:20:43 +02:00
}
2014-11-20 14:20:09 +01:00
void class10 ( ) {
2010-12-05 20:26:52 +01:00
check ( " class A \n "
" { \n "
" public: \n "
" int * p; \n "
" A(); \n "
" }; \n "
" A::A() \n "
2013-03-20 15:36:16 +01:00
" { p = new int; } " ) ;
2012-09-10 17:27:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style) Class 'A' is unsafe, 'A::p' can leak by wrong usage. \n " , errout . str ( ) ) ;
2010-12-05 20:26:52 +01:00
2009-06-08 20:20:43 +02:00
check ( " class A \n "
" { \n "
" public: \n "
" int * p; \n "
" A() { p = new int; } \n "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2012-09-10 17:27:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style) Class 'A' is unsafe, 'A::p' can leak by wrong usage. \n " , errout . str ( ) ) ;
2009-06-08 20:20:43 +02:00
}
2014-11-20 14:20:09 +01:00
void class11 ( ) {
2010-12-05 20:26:52 +01:00
check ( " class A \n "
" { \n "
" public: \n "
" int * p; \n "
" A() : p(new int[10]) \n "
" { } "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2012-09-10 17:27:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style) Class 'A' is unsafe, 'A::p' can leak by wrong usage. \n " , errout . str ( ) ) ;
2010-12-05 20:26:52 +01:00
2009-06-08 20:20:43 +02:00
check ( " class A \n "
" { \n "
" public: \n "
" int * p; \n "
" A(); \n "
" }; \n "
" A::A() : p(new int[10]) \n "
2010-05-29 19:29:59 +02:00
" { } " ) ;
2012-09-10 17:27:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style) Class 'A' is unsafe, 'A::p' can leak by wrong usage. \n " , errout . str ( ) ) ;
2009-06-08 20:20:43 +02:00
}
2014-11-20 14:20:09 +01:00
void class12 ( ) {
2009-10-22 21:51:58 +02:00
check ( " class A \n "
" { \n "
" private: \n "
" int *p; \n "
" public: \n "
" A(); \n "
" ~A(); \n "
" void cleanup(); "
" }; \n "
" \n "
" A::A() \n "
" { p = new int[10]; } \n "
" \n "
" A::~A() \n "
" { } \n "
" \n "
" void A::cleanup() \n "
2013-03-20 15:36:16 +01:00
" { delete [] p; } " ) ;
2012-09-10 17:27:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style) Class 'A' is unsafe, 'A::p' can leak by wrong usage. \n " , errout . str ( ) ) ;
2010-12-05 20:26:52 +01:00
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 "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2012-09-10 17:27:41 +02:00
ASSERT_EQUALS ( " [test.cpp:4]: (style) Class 'A' is unsafe, 'A::p' can leak by wrong usage. \n " , errout . str ( ) ) ;
2009-10-22 21:51:58 +02:00
}
2014-11-20 14:20:09 +01:00
void class13 ( ) {
2009-10-23 20:04:47 +02:00
check ( " class A \n "
" { \n "
" private: \n "
" int *p; \n "
" public: \n "
" A(); \n "
" ~A(); \n "
" void foo(); "
" }; \n "
" \n "
" A::A() \n "
" { } \n "
" \n "
" A::~A() \n "
" { } \n "
" \n "
" void A::foo() \n "
2013-03-20 15:36:16 +01:00
" { p = new int[10]; delete [] p; } " ) ;
2010-12-05 20:26:52 +01:00
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 "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2010-12-05 20:26:52 +01:00
ASSERT_EQUALS ( " [test.cpp:11]: (warning) Possible leak in public function. The pointer 'p' is not deallocated before it is allocated. \n " , errout . str ( ) ) ;
2009-10-23 20:04:47 +02:00
}
2014-11-20 14:20:09 +01:00
void class14 ( ) {
2010-01-27 22:05:04 +01:00
check ( " class A \n "
" { \n "
" int *p; \n "
" public: \n "
" void init(); \n "
" }; \n "
" \n "
" void A::init() \n "
2013-03-20 15:36:16 +01:00
" { p = new int[10]; } " ) ;
2010-12-05 20:26:52 +01:00
ASSERT_EQUALS ( " [test.cpp:9]: (warning) Possible leak in public function. The pointer 'p' is not deallocated before it is allocated. \n "
2012-09-10 17:27:41 +02:00
" [test.cpp:3]: (style) Class 'A' is unsafe, 'A::p' can leak by wrong usage. \n " , errout . str ( ) ) ;
2010-12-05 20:26:52 +01:00
check ( " class A \n "
" { \n "
" int *p; \n "
" public: \n "
" void init() \n "
" { p = new int[10]; } \n "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2010-12-05 20:26:52 +01:00
ASSERT_EQUALS ( " [test.cpp:6]: (warning) Possible leak in public function. The pointer 'p' is not deallocated before it is allocated. \n "
2012-09-10 17:27:41 +02:00
" [test.cpp:3]: (style) Class 'A' is unsafe, 'A::p' can leak by wrong usage. \n " , errout . str ( ) ) ;
2010-12-05 20:26:52 +01:00
2010-06-11 13:33:10 +02:00
check ( " class A \n "
" { \n "
" int *p; \n "
" public: \n "
" void init(); \n "
" }; \n "
" \n "
" void A::init() \n "
2013-03-20 15:36:16 +01:00
" { p = new int; } " ) ;
2010-12-05 20:26:52 +01:00
ASSERT_EQUALS ( " [test.cpp:9]: (warning) Possible leak in public function. The pointer 'p' is not deallocated before it is allocated. \n "
2012-09-10 17:27:41 +02:00
" [test.cpp:3]: (style) Class 'A' is unsafe, 'A::p' can leak by wrong usage. \n " , errout . str ( ) ) ;
2010-12-05 20:26:52 +01:00
check ( " class A \n "
" { \n "
" int *p; \n "
" public: \n "
" void init() \n "
" { p = new int; } \n "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2010-12-05 20:26:52 +01:00
ASSERT_EQUALS ( " [test.cpp:6]: (warning) Possible leak in public function. The pointer 'p' is not deallocated before it is allocated. \n "
2012-09-10 17:27:41 +02:00
" [test.cpp:3]: (style) Class 'A' is unsafe, 'A::p' can leak by wrong usage. \n " , errout . str ( ) ) ;
2010-12-05 20:26:52 +01:00
2010-06-11 13:33:10 +02:00
check ( " class A \n "
" { \n "
" int *p; \n "
" public: \n "
" void init(); \n "
" }; \n "
" \n "
" void A::init() \n "
2013-03-20 15:36:16 +01:00
" { p = malloc(sizeof(int)*10); } " ) ;
2010-12-05 20:26:52 +01:00
ASSERT_EQUALS ( " [test.cpp:9]: (warning) Possible leak in public function. The pointer 'p' is not deallocated before it is allocated. \n "
2012-09-10 17:27:41 +02:00
" [test.cpp:3]: (style) Class 'A' is unsafe, 'A::p' can leak by wrong usage. \n " , errout . str ( ) ) ;
2010-12-05 20:26:52 +01:00
check ( " class A \n "
" { \n "
" int *p; \n "
" public: \n "
" void init() \n "
" { p = malloc(sizeof(int)*10); } \n "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2010-12-05 20:26:52 +01:00
ASSERT_EQUALS ( " [test.cpp:6]: (warning) Possible leak in public function. The pointer 'p' is not deallocated before it is allocated. \n "
2012-09-10 17:27:41 +02:00
" [test.cpp:3]: (style) Class 'A' is unsafe, 'A::p' can leak by wrong usage. \n " , errout . str ( ) ) ;
2010-01-27 22:05:04 +01:00
}
2014-11-20 14:20:09 +01:00
void class15 ( ) {
2010-03-19 16:57:23 +01:00
check ( " class A \n "
" { \n "
" int *p; \n "
" public: \n "
" A(); \n "
" ~A() { delete [] p; } \n "
" }; \n "
" A::A() \n "
2010-05-29 19:29:59 +02:00
" { p = new int[10]; } " ) ;
2010-03-19 16:57:23 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-06-11 13:33:10 +02:00
2010-12-05 20:26:52 +01:00
check ( " class A \n "
" { \n "
" int *p; \n "
" public: \n "
" A() \n "
" { p = new int[10]; } \n "
" ~A() { delete [] p; } \n "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2010-12-05 20:26:52 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-06-11 13:33:10 +02:00
check ( " class A \n "
" { \n "
" int *p; \n "
" public: \n "
" A(); \n "
" ~A() { delete p; } \n "
" }; \n "
" A::A() \n "
" { p = new int; } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-12-05 20:26:52 +01:00
check ( " class A \n "
" { \n "
" int *p; \n "
" public: \n "
" A() \n "
" { p = new int; } \n "
" ~A() { delete p; } \n "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2010-12-05 20:26:52 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-06-11 13:33:10 +02:00
check ( " class A \n "
" { \n "
" int *p; \n "
" public: \n "
" A(); \n "
" ~A() { free(p); } \n "
" }; \n "
" A::A() \n "
" { p = malloc(sizeof(int)*10); } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-12-05 20:26:52 +01:00
check ( " class A \n "
" { \n "
" int *p; \n "
" public: \n "
" A() \n "
" { p = malloc(sizeof(int)*10); } \n "
" ~A() { free(p); } \n "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2010-12-05 20:26:52 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-03-19 16:57:23 +01:00
}
2014-11-20 14:20:09 +01:00
void class16 ( ) {
2010-06-12 13:37:44 +02:00
// Ticket #1510
check ( " class A \n "
" { \n "
" int *a; \n "
" int *b; \n "
" public: \n "
" A() { a = b = new int[10]; } \n "
" ~A() { delete [] a; } \n "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2010-06-12 13:37:44 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2009-06-08 20:20:43 +02:00
2014-11-20 14:20:09 +01:00
void class17 ( ) {
2010-06-13 10:43:23 +02:00
// Ticket #1557
check ( " class A { \n "
" private: \n "
" char *pd; \n "
" public: \n "
" void foo(); \n "
" }; \n "
" \n "
" void A::foo() \n "
" { \n "
" A::pd = new char[12]; \n "
" delete [] A::pd; \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2015-08-16 14:22:46 +02:00
ASSERT_EQUALS ( " [test.cpp:10]: (warning) Possible leak in public function. The pointer 'pd' is not deallocated before it is allocated. \n " , errout . str ( ) ) ;
2010-12-05 20:26:52 +01:00
check ( " class A { \n "
" private: \n "
" char *pd; \n "
" public: \n "
" void foo() \n "
" { \n "
" pd = new char[12]; \n "
" delete [] pd; \n "
" } \n "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2015-08-16 14:22:46 +02:00
ASSERT_EQUALS ( " [test.cpp:7]: (warning) Possible leak in public function. The pointer 'pd' is not deallocated before it is allocated. \n " , errout . str ( ) ) ;
2010-12-05 20:26:52 +01:00
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 "
2013-03-20 15:36:16 +01:00
" } " ) ;
2015-08-16 14:22:46 +02:00
ASSERT_EQUALS ( " [test.cpp:10]: (warning) Possible leak in public function. The pointer 'pd' is not deallocated before it is allocated. \n " , errout . str ( ) ) ;
2010-06-13 10:43:23 +02:00
}
2014-11-20 14:20:09 +01:00
void class18 ( ) {
2010-06-16 19:28:47 +02:00
// Ticket #853
check ( " class A : public x \n "
" { \n "
" public: \n "
" A() \n "
" { \n "
" a = new char[10]; \n "
" foo(a); \n "
" } \n "
" private: \n "
" char *a; \n "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2010-06-16 19:28:47 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-12-05 20:26:52 +01:00
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 "
2013-03-20 15:36:16 +01:00
" } " ) ;
2010-12-05 20:26:52 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-06-16 19:28:47 +02:00
}
2014-11-20 14:20:09 +01:00
void class19 ( ) {
2010-11-23 18:41:07 +01:00
// Ticket #2219
check ( " class Foo \n "
" { \n "
" private: \n "
" TRadioButton* rp1; \n "
" TRadioButton* rp2; \n "
" public: \n "
" Foo(); \n "
" }; \n "
" Foo::Foo() \n "
" { \n "
" rp1 = new TRadioButton(this); \n "
" rp2 = new TRadioButton(this); \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2010-11-23 18:41:07 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-12-04 07:29:12 +01:00
check ( " class TRadioButton { }; \n "
" class Foo \n "
" { \n "
" private: \n "
" TRadioButton* rp1; \n "
" TRadioButton* rp2; \n "
" public: \n "
" Foo(); \n "
" }; \n "
" Foo::Foo() \n "
" { \n "
" rp1 = new TRadioButton; \n "
" rp2 = new TRadioButton; \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2012-09-10 17:27:41 +02:00
ASSERT_EQUALS ( " [test.cpp:5]: (style) Class 'Foo' is unsafe, 'Foo::rp1' can leak by wrong usage. \n "
" [test.cpp:6]: (style) Class 'Foo' is unsafe, 'Foo::rp2' can leak by wrong usage. \n " , errout . str ( ) ) ;
2010-12-04 07:29:12 +01:00
check ( " class TRadioButton { }; \n "
" class Foo \n "
" { \n "
" private: \n "
" TRadioButton* rp1; \n "
" TRadioButton* rp2; \n "
" public: \n "
" Foo(); \n "
" ~Foo(); \n "
" }; \n "
" Foo::Foo() \n "
" { \n "
" rp1 = new TRadioButton; \n "
" rp2 = new TRadioButton; \n "
" } \n "
" Foo::~Foo() \n "
" { \n "
" delete rp1; \n "
" delete rp2; \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2010-12-04 07:29:12 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-12-07 07:08:05 +01:00
}
2014-11-20 14:20:09 +01:00
void class20 ( ) {
2010-12-07 07:08:05 +01:00
check ( " namespace ns1 { \n "
" 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 "
2013-03-20 15:36:16 +01:00
" } " ) ;
2012-09-10 17:27:41 +02:00
ASSERT_EQUALS ( " [test.cpp:5]: (style) Class 'Fred' is unsafe, 'Fred::str1' can leak by wrong usage. \n " , errout . str ( ) ) ;
2010-12-07 07:08:05 +01:00
check ( " namespace ns1 { \n "
" class Fred \n "
" { \n "
" private: \n "
" char *str1; \n "
" char *str2; \n "
" public: \n "
" Fred(); \n "
" ~Fred(); \n "
" }; \n "
" \n "
" Fred::Fred() \n "
" { \n "
" str1 = new char[10]; \n "
" str2 = new char[10]; \n "
" } \n "
" \n "
" Fred::~Fred() \n "
" { \n "
" delete [] str2; \n "
" } \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2012-09-10 17:27:41 +02:00
ASSERT_EQUALS ( " [test.cpp:5]: (style) Class 'Fred' is unsafe, 'Fred::str1' can leak by wrong usage. \n " , errout . str ( ) ) ;
2010-12-07 07:08:05 +01:00
check ( " namespace ns1 { \n "
" class Fred \n "
" { \n "
" private: \n "
" char *str1; \n "
" char *str2; \n "
" public: \n "
" Fred(); \n "
" ~Fred(); \n "
" }; \n "
" } \n "
" ns1::Fred::Fred() \n "
" { \n "
" str1 = new char[10]; \n "
" str2 = new char[10]; \n "
" } \n "
" \n "
" ns1::Fred::~Fred() \n "
" { \n "
" delete [] str2; \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2012-09-10 17:27:41 +02:00
ASSERT_EQUALS ( " [test.cpp:5]: (style) Class 'Fred' is unsafe, 'Fred::str1' can leak by wrong usage. \n " , errout . str ( ) ) ;
2010-12-07 07:08:05 +01:00
check ( " namespace ns1 { \n "
" namespace ns2 { \n "
" class Fred \n "
" { \n "
" private: \n "
" char *str1; \n "
" char *str2; \n "
" public: \n "
" Fred(); \n "
" ~Fred(); \n "
" }; \n "
" } \n "
" } \n "
" ns1::ns2::Fred::Fred() \n "
" { \n "
" str1 = new char[10]; \n "
" str2 = new char[10]; \n "
" } \n "
" \n "
" ns1::ns2::Fred::~Fred() \n "
" { \n "
" delete [] str2; \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2012-09-10 17:27:41 +02:00
ASSERT_EQUALS ( " [test.cpp:6]: (style) Class 'Fred' is unsafe, 'Fred::str1' can leak by wrong usage. \n " , errout . str ( ) ) ;
2010-12-07 07:08:05 +01:00
check ( " namespace ns1 { \n "
" namespace ns2 { \n "
" namespace ns3 { \n "
" class Fred \n "
" { \n "
" private: \n "
" char *str1; \n "
" char *str2; \n "
" public: \n "
" Fred(); \n "
" ~Fred(); \n "
" }; \n "
" } \n "
" } \n "
" } \n "
" ns1::ns2::ns3::Fred::Fred() \n "
" { \n "
" str1 = new char[10]; \n "
" str2 = new char[10]; \n "
" } \n "
" \n "
" ns1::ns2::ns3::Fred::~Fred() \n "
" { \n "
" delete [] str2; \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2012-09-10 17:27:41 +02:00
ASSERT_EQUALS ( " [test.cpp:7]: (style) Class 'Fred' is unsafe, 'Fred::str1' can leak by wrong usage. \n " , errout . str ( ) ) ;
2010-11-23 18:41:07 +01:00
}
2014-11-20 14:20:09 +01:00
void class21 ( ) { // ticket #2517
2011-01-30 08:38:20 +01:00
check ( " struct B { }; \n "
" struct C \n "
" { \n "
" B * b; \n "
" C(B * x) : b(x) { } \n "
" }; \n "
" class A \n "
" { \n "
" B *b; \n "
" C *c; \n "
" public: \n "
" A() : b(new B()), c(new C(b)) { } \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2012-09-10 17:27:41 +02:00
ASSERT_EQUALS ( " [test.cpp:9]: (style) Class 'A' is unsafe, 'A::b' can leak by wrong usage. \n "
" [test.cpp:10]: (style) Class 'A' is unsafe, 'A::c' can leak by wrong usage. \n " , errout . str ( ) ) ;
2011-01-30 08:38:20 +01:00
check ( " struct B { }; \n "
" struct C \n "
" { \n "
" B * b; \n "
" C(B * x) : b(x) { } \n "
" }; \n "
" class A \n "
" { \n "
" B *b; \n "
" C *c; \n "
" public: \n "
" A() \n "
" { \n "
" b = new B(); \n "
" c = new C(b); \n "
" } \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2012-09-10 17:27:41 +02:00
ASSERT_EQUALS ( " [test.cpp:9]: (style) Class 'A' is unsafe, 'A::b' can leak by wrong usage. \n "
" [test.cpp:10]: (style) Class 'A' is unsafe, 'A::c' can leak by wrong usage. \n " , errout . str ( ) ) ;
2011-01-30 08:38:20 +01:00
}
2014-11-20 14:20:09 +01:00
void class22 ( ) { // ticket #3012 - false positive
2011-08-16 20:39:17 +02:00
check ( " class Fred { \n "
" private: \n "
" int * a; \n "
" private: \n "
" Fred() { a = new int; } \n "
" ~Fred() { (delete(a), (a)=NULL); } \n "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2011-08-16 20:39:17 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void class23 ( ) { // ticket #3303 - false positive
2011-11-28 20:08:29 +01:00
check ( " class CDataImpl { \n "
" public: \n "
" CDataImpl() { m_refcount = 1; } \n "
" void Release() { if (--m_refcount == 0) delete this; } \n "
" private: \n "
" int m_refcount; \n "
" }; \n "
" \n "
" class CData { \n "
" public: \n "
" CData() : m_impl(new CDataImpl()) { } \n "
" ~CData() { if (m_impl) m_impl->Release(); } \n "
" private: \n "
" CDataImpl *m_impl; \n "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2011-11-28 20:08:29 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void class24 ( ) { // ticket #3806 - false positive in copy constructor
2012-05-29 21:13:34 +02:00
check ( " class Fred { \n "
" private: \n "
" int * a; \n "
" public: \n "
" Fred(const Fred &fred) { a = new int; } \n "
" ~Fred() { delete a; } \n "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2012-05-29 21:13:34 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void class25 ( ) { // ticket #4367 - false positive when implementation for destructor is not seen
2013-02-24 08:14:25 +01:00
check ( " class Fred { \n "
" private: \n "
" int * a; \n "
" public: \n "
" Fred() { a = new int; } \n "
" ~Fred(); \n "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2013-02-24 08:14:25 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void staticvar ( ) {
2009-10-06 18:25:00 +02:00
check ( " class A \n "
" { \n "
" private: \n "
" static int * p; \n "
" public: "
" A() \n "
" { \n "
" if (!p) \n "
" p = new int[100]; \n "
" } \n "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2009-10-06 18:25:00 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void free_member_in_sub_func ( ) {
2009-07-05 21:37:53 +02:00
// Member function
2009-06-08 20:20:43 +02:00
check ( " class Tokenizer \n "
" { \n "
" public: \n "
" Tokenizer(); \n "
" ~Tokenizer(); \n "
" \n "
" private: \n "
" int *_tokens; \n "
" static void deleteTokens(int *tok); \n "
" }; \n "
" \n "
" Tokenizer::Tokenizer() \n "
" { \n "
" _tokens = new int; \n "
" } \n "
" \n "
" Tokenizer::~Tokenizer() \n "
" { \n "
" deleteTokens(_tokens); \n "
" _tokens = 0; \n "
" } \n "
" \n "
" void Tokenizer::deleteTokens(int *tok) \n "
" { \n "
" delete tok; \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2009-10-24 15:07:14 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-07-05 21:37:53 +02:00
// Global function
check ( " void deleteTokens(int *tok) \n "
" { \n "
" delete tok; \n "
" } \n "
" class Tokenizer \n "
" { \n "
" public: \n "
" Tokenizer(); \n "
" ~Tokenizer(); \n "
" \n "
" private: \n "
" int *_tokens; \n "
" }; \n "
" \n "
" Tokenizer::Tokenizer() \n "
" { \n "
" _tokens = new int; \n "
" } \n "
" \n "
" Tokenizer::~Tokenizer() \n "
" { \n "
" deleteTokens(_tokens); \n "
" _tokens = 0; \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2009-10-24 15:07:14 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-06-08 20:20:43 +02:00
}
2010-01-27 21:02:13 +01:00
2014-11-20 14:20:09 +01:00
void mismatch1 ( ) {
2010-01-27 21:02:13 +01:00
check ( " class A \n "
" { \n "
" public: \n "
" A(int i); \n "
" ~A(); \n "
" private: \n "
" char* pkt_buffer; \n "
" }; \n "
" \n "
" A::A(int i) \n "
" { \n "
" pkt_buffer = new char[8192]; \n "
" if (i != 1) { \n "
" delete pkt_buffer; \n "
" pkt_buffer = 0; \n "
" } \n "
" } \n "
" \n "
" A::~A() { \n "
" delete [] pkt_buffer; \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2010-06-13 19:00:11 +02:00
ASSERT_EQUALS ( " [test.cpp:14]: (error) Mismatching allocation and deallocation: A::pkt_buffer \n " , errout . str ( ) ) ;
2010-01-27 21:02:13 +01:00
}
2014-11-20 14:20:09 +01:00
void mismatch2 ( ) { // #5659
2014-04-10 16:11:11 +02:00
check ( " namespace NS \n "
" { \n "
" class Foo \n "
" { \n "
" public: \n "
" void fct(); \n "
" \n "
" private: \n "
" char* data_; \n "
" }; \n "
" } \n "
" \n "
" using namespace NS; \n "
" \n "
" void Foo::fct() \n "
" { \n "
" data_ = new char[42]; \n "
" delete data_; \n "
" data_ = 0; \n "
" } \n " ) ;
2015-08-16 14:22:46 +02:00
ASSERT_EQUALS ( " [test.cpp:17]: (warning) Possible leak in public function. The pointer 'data_' is not deallocated before it is allocated. \n "
2014-04-11 05:40:37 +02:00
" [test.cpp:18]: (error) Mismatching allocation and deallocation: Foo::data_ \n " , errout . str ( ) ) ;
check ( " namespace NS \n "
" { \n "
" class Foo \n "
" { \n "
" public: \n "
" void fct(int i); \n "
" \n "
" private: \n "
" char* data_; \n "
" }; \n "
" } \n "
" \n "
" using namespace NS; \n "
" \n "
" void Foo::fct(int i) \n "
" { \n "
" data_ = new char[42]; \n "
" delete data_; \n "
" data_ = 0; \n "
" } \n " ) ;
2015-08-16 14:22:46 +02:00
ASSERT_EQUALS ( " [test.cpp:17]: (warning) Possible leak in public function. The pointer 'data_' is not deallocated before it is allocated. \n "
2014-04-10 16:11:11 +02:00
" [test.cpp:18]: (error) Mismatching allocation and deallocation: Foo::data_ \n " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void func1 ( ) {
2010-05-15 19:40:32 +02:00
check ( " class Fred \n "
" { \n "
" private: \n "
" char *s; \n "
" public: \n "
" Fred() { s = 0; } \n "
" ~Fred() { free(s); } \n "
" void xy() \n "
" { s = malloc(100); } \n "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2010-10-17 14:41:00 +02:00
ASSERT_EQUALS ( " [test.cpp:9]: (warning) Possible leak in public function. The pointer 's' is not deallocated before it is allocated. \n " , errout . str ( ) ) ;
2010-01-27 21:02:13 +01:00
2010-05-15 19:40:32 +02:00
check ( " class Fred \n "
" { \n "
" public: \n "
" Fred() { s = 0; } \n "
" ~Fred() { free(s); } \n "
" void xy() \n "
" { s = malloc(100); } \n "
" private: \n "
" char *s; \n "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2011-03-19 09:04:03 +01:00
ASSERT_EQUALS ( " [test.cpp:7]: (warning) Possible leak in public function. The pointer 's' is not deallocated before it is allocated. \n " , errout . str ( ) ) ;
2010-05-15 19:40:32 +02:00
}
2014-11-20 14:20:09 +01:00
void func2 ( ) {
2010-05-15 19:40:32 +02:00
check ( " class Fred \n "
" { \n "
" private: \n "
" char *s; \n "
" public: \n "
" Fred() { s = 0; } \n "
" ~Fred() { free(s); } \n "
" const Fred & operator = (const Fred &f) \n "
" { s = malloc(100); } \n "
2013-03-20 15:36:16 +01:00
" }; " ) ;
2010-10-17 14:41:00 +02:00
ASSERT_EQUALS ( " [test.cpp:9]: (warning) Possible leak in public function. The pointer 's' is not deallocated before it is allocated. \n " , errout . str ( ) ) ;
2010-05-15 19:40:32 +02:00
}
2009-06-08 20:20:43 +02:00
} ;
2008-12-18 22:28:57 +01:00
2015-10-07 14:30:01 +02:00
REGISTER_TEST ( TestMemleakInClass )
2008-12-18 22:28:57 +01:00
2009-06-16 22:01:04 +02:00
2011-10-13 20:53:06 +02:00
class TestMemleakStructMember : public TestFixture {
2009-06-16 22:01:04 +02:00
public :
2014-11-20 14:20:09 +01:00
TestMemleakStructMember ( ) : TestFixture ( " TestMemleakStructMember " ) {
2013-08-07 16:27:37 +02:00
}
2009-06-16 22:01:04 +02:00
private :
2015-10-07 18:33:57 +02:00
Settings settings ;
2016-01-31 10:08:00 +01:00
void check ( const char code [ ] , bool isCPP = true ) {
2010-12-01 18:00:55 +01:00
// Clear the error buffer..
errout . str ( " " ) ;
2009-06-16 22:01:04 +02:00
// Tokenize..
2010-12-01 18:00:55 +01:00
Tokenizer tokenizer ( & settings , this ) ;
2009-06-16 22:01:04 +02:00
std : : istringstream istr ( code ) ;
2016-01-31 10:08:00 +01:00
tokenizer . tokenize ( istr , isCPP ? " test.cpp " : " test.c " ) ;
2013-12-30 17:45:28 +01:00
tokenizer . simplifyTokenList2 ( ) ;
2009-06-16 22:01:04 +02:00
// Check for memory leaks..
CheckMemoryLeakStructMember checkMemoryLeakStructMember ( & tokenizer , & settings , this ) ;
checkMemoryLeakStructMember . check ( ) ;
}
2019-01-12 15:45:25 +01:00
void run ( ) OVERRIDE {
2015-11-19 17:33:52 +01:00
LOAD_LIB_2 ( settings . library , " std.cfg " ) ;
LOAD_LIB_2 ( settings . library , " posix.cfg " ) ;
2009-07-19 16:51:31 +02:00
// testing that errors are detected
TEST_CASE ( err ) ;
// handle / bail out when "goto" is found
TEST_CASE ( goto_ ) ;
// Don't report errors if the struct is returned
2011-01-22 13:40:19 +01:00
TEST_CASE ( ret1 ) ;
TEST_CASE ( ret2 ) ;
2009-07-19 16:51:31 +02:00
// assignments
2011-02-04 20:41:35 +01:00
TEST_CASE ( assign1 ) ;
TEST_CASE ( assign2 ) ;
2011-08-08 19:58:25 +02:00
TEST_CASE ( assign3 ) ;
2009-07-19 16:51:31 +02:00
// Failed allocation
TEST_CASE ( failedAllocation ) ;
2009-07-22 08:30:51 +02:00
2011-07-21 13:33:20 +02:00
TEST_CASE ( function1 ) ; // Deallocating in function
TEST_CASE ( function2 ) ; // #2848: Taking address in function
2011-08-20 09:17:34 +02:00
TEST_CASE ( function3 ) ; // #3024: kernel list
2011-08-26 19:26:21 +02:00
TEST_CASE ( function4 ) ; // #3038: Deallocating in function
2009-07-23 22:29:31 +02:00
// Handle if-else
TEST_CASE ( ifelse ) ;
2009-09-28 22:58:06 +02:00
2012-06-23 20:15:58 +02:00
// Linked list
TEST_CASE ( linkedlist ) ;
2009-09-28 22:58:06 +02:00
// struct variable is a global variable
TEST_CASE ( globalvar ) ;
2011-05-11 18:19:14 +02:00
// local struct variable
2013-04-26 16:11:57 +02:00
TEST_CASE ( localvars ) ;
2013-09-21 18:10:29 +02:00
2019-01-09 20:38:32 +01:00
// struct variable is a reference variable
TEST_CASE ( refvar ) ;
2013-09-21 18:10:29 +02:00
// Segmentation fault in CheckMemoryLeakStructMember
TEST_CASE ( trac5030 ) ;
2014-01-03 23:23:06 +01:00
TEST_CASE ( varid ) ; // #5201: Analysis confused by (variable).attribute notation
2014-05-08 20:51:18 +02:00
TEST_CASE ( varid_2 ) ; // #5315: Analysis confused by ((variable).attribute) notation
2015-11-19 16:10:00 +01:00
TEST_CASE ( customAllocation ) ;
2009-06-16 22:01:04 +02:00
}
2014-11-20 14:20:09 +01:00
void err ( ) {
2009-06-16 22:01:04 +02:00
check ( " static void foo() \n "
" { \n "
2009-07-19 16:51:31 +02:00
" struct ABC *abc = malloc(sizeof(struct ABC)); \n "
" abc->a = malloc(10); \n "
" free(abc); \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2009-07-19 16:51:31 +02:00
ASSERT_EQUALS ( " [test.cpp:5]: (error) Memory leak: abc.a \n " , errout . str ( ) ) ;
check ( " static void foo() \n "
" { \n "
" struct ABC *abc = malloc(sizeof(struct ABC)); \n "
" abc->a = malloc(10); \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2009-07-19 16:51:31 +02:00
ASSERT_EQUALS ( " [test.cpp:5]: (error) Memory leak: abc.a \n " , errout . str ( ) ) ;
check ( " static ABC * foo() \n "
" { \n "
" ABC *abc = malloc(sizeof(ABC)); \n "
" abc->a = malloc(10); \n "
" abc->b = malloc(10); \n "
" if (abc->b == 0) \n "
" { \n "
" return 0; \n "
" } \n "
" return abc; \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2009-07-19 16:51:31 +02:00
ASSERT_EQUALS ( " [test.cpp:8]: (error) Memory leak: abc.a \n " , errout . str ( ) ) ;
2009-07-20 14:39:24 +02:00
check ( " static void foo(int a) \n "
" { \n "
" ABC *abc = malloc(sizeof(ABC)); \n "
" abc->a = malloc(10); \n "
" if (a == 1) \n "
" { \n "
" free(abc->a); \n "
" return; \n "
" } \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2009-07-20 14:39:24 +02:00
ASSERT_EQUALS ( " [test.cpp:10]: (error) Memory leak: abc.a \n " , errout . str ( ) ) ;
2009-07-19 16:51:31 +02:00
}
2014-11-20 14:20:09 +01:00
void goto_ ( ) {
2009-07-19 16:51:31 +02:00
check ( " static void foo() \n "
" { \n "
" struct ABC *abc = malloc(sizeof(struct ABC)); \n "
" abc->a = malloc(10); \n "
" if (abc->a) \n "
" { goto out; } \n "
" free(abc); \n "
" return; \n "
" out: \n "
" free(abc->a); \n "
" free(abc); \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2009-09-28 22:41:45 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-07-19 16:51:31 +02:00
}
2014-11-20 14:20:09 +01:00
void ret1 ( ) {
2009-07-19 16:51:31 +02:00
check ( " static ABC * foo() \n "
" { \n "
" struct ABC *abc = malloc(sizeof(struct ABC)); \n "
" abc->a = malloc(10); \n "
" return abc; \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2009-07-19 16:51:31 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " static void foo(struct ABC *abc) \n "
" { \n "
" abc->a = malloc(10); \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2009-07-19 16:51:31 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2016-01-31 10:08:00 +01:00
// #7302
check ( " void* foo() { \n "
" struct ABC abc; \n "
" abc.a = malloc(10); \n "
" return abc.a; \n "
" } " , false ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " void* foo() { \n "
" struct ABC abc; \n "
" abc.a = malloc(10); \n "
" return abc.b; \n "
" } " , false ) ;
ASSERT_EQUALS ( " [test.c:4]: (error) Memory leak: abc.a \n " , errout . str ( ) ) ;
2009-07-19 16:51:31 +02:00
}
2014-11-20 14:20:09 +01:00
void ret2 ( ) {
2011-01-22 13:40:19 +01:00
check ( " static ABC * foo() \n "
" { \n "
" struct ABC *abc = malloc(sizeof(struct ABC)); \n "
" abc->a = malloc(10); \n "
" return &abc->self; \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2011-01-22 13:40:19 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void assign1 ( ) {
2009-07-19 16:51:31 +02:00
check ( " static void foo() \n "
" { \n "
" struct ABC *abc = abc1; \n "
" abc->a = malloc(10); \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2009-07-19 16:51:31 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " static void foo() \n "
" { \n "
" struct ABC *abc; \n "
" abc1 = abc = malloc(sizeof(ABC)); \n "
" abc->a = malloc(10); \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2009-07-19 16:51:31 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " static void foo() \n "
" { \n "
" struct msn_entry *ptr; \n "
" ptr = malloc(sizeof(struct msn_entry)); \n "
" ptr->msn = malloc(100); \n "
" back = ptr; \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2009-07-19 16:51:31 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void assign2 ( ) {
2011-02-04 20:41:35 +01:00
check ( " static void foo() { \n "
" struct ABC *abc = malloc(123); \n "
2011-08-08 19:58:25 +02:00
" abc->a = abc->b = malloc(10); \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2011-02-04 20:41:35 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void assign3 ( ) {
2011-08-08 19:58:25 +02:00
check ( " void f(struct s *f1) { \n "
" struct s f2; \n "
" f2.a = malloc(100); \n "
" *f1 = f2; \n "
2016-02-02 09:18:58 +01:00
" } " , false ) ;
2014-02-02 00:10:26 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2011-08-08 19:58:25 +02:00
}
2014-11-20 14:20:09 +01:00
void failedAllocation ( ) {
2009-07-19 16:51:31 +02:00
check ( " static struct ABC * foo() \n "
" { \n "
" struct ABC *abc = malloc(sizeof(struct ABC)); \n "
" abc->a = malloc(10); \n "
" if (!abc->a) \n "
" { \n "
" free(abc); \n "
" return 0; \n "
" } \n "
" return abc; \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2009-07-19 16:51:31 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-06-16 22:01:04 +02:00
}
2009-07-22 08:30:51 +02:00
2014-11-20 14:20:09 +01:00
void function1 ( ) {
2009-07-22 08:30:51 +02:00
// Not found function => assume that the function may deallocate
check ( " static void foo() \n "
" { \n "
" struct ABC *abc = malloc(sizeof(struct ABC)); \n "
" abc->a = malloc(10); \n "
" func(abc); \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2009-07-22 08:30:51 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-07-29 11:38:20 +02:00
check ( " static void foo() \n "
" { \n "
" struct ABC *abc = malloc(sizeof(struct ABC)); \n "
" abclist.push_back(abc); \n "
" abc->a = malloc(10); \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2009-07-29 11:38:20 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-07-22 08:30:51 +02:00
}
2009-07-23 22:29:31 +02:00
2011-07-21 13:33:20 +02:00
// #2848: Taking address in function 'assign'
2014-11-20 14:20:09 +01:00
void function2 ( ) {
2011-07-21 13:33:20 +02:00
check ( " void f() { \n "
" A a = { 0 }; \n "
" a.foo = (char *) malloc(10); \n "
" assign(&a); \n "
2016-02-02 09:18:58 +01:00
" } " , false ) ;
2014-02-02 00:10:26 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2011-07-21 13:33:20 +02:00
}
2011-08-20 09:17:34 +02:00
// #3024: kernel list
2014-11-20 14:20:09 +01:00
void function3 ( ) {
2011-08-20 09:17:34 +02:00
check ( " void f() { \n "
2015-11-19 18:51:32 +01:00
" struct ABC *abc = malloc(100); \n "
" abc.a = (char *) malloc(10); \n "
2011-08-20 09:17:34 +02:00
" list_add_tail(&abc->list, head); \n "
2016-02-02 09:18:58 +01:00
" } " , false ) ;
2011-08-20 09:17:34 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2011-08-26 19:26:21 +02:00
// #3038: deallocating in function
2014-11-20 14:20:09 +01:00
void function4 ( ) {
2011-08-26 19:26:21 +02:00
check ( " void a(char *p) { char *x = p; free(x); } \n "
" void b() { \n "
" struct ABC abc; \n "
" abc.a = (char *) malloc(10); \n "
" a(abc.a); \n "
2016-02-02 09:18:58 +01:00
" } " , false ) ;
2014-02-02 00:10:26 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2011-08-26 19:26:21 +02:00
}
2014-11-20 14:20:09 +01:00
void ifelse ( ) {
2009-07-23 22:29:31 +02:00
check ( " static void foo() \n "
" { \n "
" struct ABC *abc = malloc(sizeof(struct ABC)); \n "
" if (x) "
" { \n "
" abc->a = malloc(10); \n "
" } \n "
" else \n "
" { \n "
" free(abc); \n "
" return; \n "
" } \n "
" free(abc->a); \n "
" free(abc); \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2009-07-24 09:05:40 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2009-07-23 22:29:31 +02:00
}
2009-09-28 22:58:06 +02:00
2014-11-20 14:20:09 +01:00
void linkedlist ( ) {
2012-06-23 20:20:11 +02:00
// #3904 - false positive when linked list is used
2012-06-23 20:15:58 +02:00
check ( " static void foo() { \n "
" struct ABC *abc = malloc(sizeof(struct ABC)); \n "
" abc->next = malloc(sizeof(struct ABC)); \n "
" abc->next->next = NULL; \n "
" \n "
" while (abc) { \n "
" struct ABC *next = abc->next; \n "
" free(abc); \n "
" abc = next; \n "
" } \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void globalvar ( ) {
2009-09-28 22:58:06 +02:00
check ( " struct ABC *abc; \n "
" \n "
" static void foo() \n "
" { \n "
" abc = malloc(sizeof(struct ABC)); \n "
" abc->a = malloc(10); \n "
" return; \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2009-09-28 22:58:06 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2011-05-11 18:19:14 +02:00
2013-04-26 16:11:57 +02:00
// Ticket #933 Leaks with struct members not detected
2014-11-20 14:20:09 +01:00
void localvars ( ) {
2013-04-30 06:44:50 +02:00
// Test error case
2015-11-19 16:10:00 +01:00
const char code1 [ ] = " struct A { \n "
" FILE* f; \n "
" char* c; \n "
" void* m; \n "
" }; \n "
" \n "
" void func() { \n "
" struct A a; \n "
" a.f = fopen( \" test \" , \" r \" ); \n "
" a.c = new char[12]; \n "
" a.m = malloc(12); \n "
" } " ;
2016-01-31 10:08:00 +01:00
check ( code1 , true ) ;
2015-11-19 16:10:00 +01:00
ASSERT_EQUALS ( " [test.cpp:12]: (error) Memory leak: a.f \n "
" [test.cpp:12]: (error) Memory leak: a.c \n "
" [test.cpp:12]: (error) Memory leak: a.m \n " , errout . str ( ) ) ;
2016-01-31 10:08:00 +01:00
check ( code1 , false ) ;
2013-04-26 16:11:57 +02:00
ASSERT_EQUALS ( " [test.c:12]: (error) Memory leak: a.f \n "
" [test.c:12]: (error) Memory leak: a.m \n " , errout . str ( ) ) ;
// Test OK case
2015-11-19 16:10:00 +01:00
const char code2 [ ] = " struct A { \n "
" FILE* f; \n "
" char* c; \n "
" void* m; \n "
" }; \n "
" \n "
" void func() { \n "
" struct A a; \n "
" a.f = fopen( \" test \" , \" r \" ); \n "
" a.c = new char[12]; \n "
" a.m = malloc(12); \n "
" fclose(a.f); \n "
" delete [] a.c; \n "
" free(a.m); \n "
" } " ;
2016-01-31 10:08:00 +01:00
check ( code2 , true ) ;
2015-11-19 16:10:00 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2016-01-31 10:08:00 +01:00
check ( code2 , false ) ;
2015-11-19 16:10:00 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
// Test unknown struct. In C++, it might have a destructor
const char code3 [ ] = " void func() { \n "
" struct A a; \n "
" a.f = fopen( \" test \" , \" r \" ); \n "
" } " ;
2016-01-31 10:08:00 +01:00
check ( code3 , true ) ;
2015-11-19 16:10:00 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2016-01-31 10:08:00 +01:00
check ( code3 , false ) ;
2015-11-19 16:10:00 +01:00
ASSERT_EQUALS ( " [test.c:4]: (error) Memory leak: a.f \n " , errout . str ( ) ) ;
// Test struct with destructor
const char code4 [ ] = " struct A { \n "
" FILE* f; \n "
" ~A(); \n "
" }; \n "
" void func() { \n "
" struct A a; \n "
" a.f = fopen( \" test \" , \" r \" ); \n "
" } " ;
2016-01-31 10:08:00 +01:00
check ( code4 , true ) ;
2014-02-02 00:10:26 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2011-05-11 18:19:14 +02:00
}
2013-09-21 18:10:29 +02:00
2019-01-09 20:38:32 +01:00
void refvar ( ) { // #8116
check ( " struct Test \n "
" { \n "
" int* data; \n "
" }; \n "
" \n "
" void foo(Test* x) \n "
" { \n "
" Test& y = *x; \n "
" y.data = malloc(10); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2013-09-21 18:10:29 +02:00
// don't crash
2014-11-20 14:20:09 +01:00
void trac5030 ( ) {
2013-09-21 18:10:29 +02:00
check ( " bool bob( char const **column_ptrs ) { \n "
" unique_ptr<char[]>otherbuffer{new char[otherbufsize+1]}; \n "
" char *const oldbuffer = otherbuffer.get(); \n "
" int const oldbufsize = otherbufsize; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-01-03 23:23:06 +01:00
2014-11-20 14:20:09 +01:00
void varid ( ) { // #5201
2014-01-03 23:23:06 +01:00
check ( " struct S { \n "
" void *state_check_buff; \n "
" }; \n "
" void f() { \n "
" S s; \n "
" (s).state_check_buff = (void* )malloc(1); \n "
" if (s.state_check_buff == 0) \n "
" return; \n "
2016-01-31 10:08:00 +01:00
" } " , false ) ;
2014-01-03 23:23:06 +01:00
ASSERT_EQUALS ( " [test.c:9]: (error) Memory leak: s.state_check_buff \n " , errout . str ( ) ) ;
}
2014-05-08 20:51:18 +02:00
2014-11-20 14:20:09 +01:00
void varid_2 ( ) { // #5315
2014-05-08 20:51:18 +02:00
check ( " typedef struct foo { char *realm; } foo; \n "
" void build_principal() { \n "
" foo f; \n "
" ((f)->realm) = strdup(realm); \n "
" if(f->realm == NULL) {} \n "
2016-01-31 10:08:00 +01:00
" } " , false ) ;
2014-05-08 20:51:18 +02:00
ASSERT_EQUALS ( " [test.c:6]: (error) Memory leak: f.realm \n " , errout . str ( ) ) ;
}
2015-11-19 16:10:00 +01:00
void customAllocation ( ) { // #4770
check ( " char *myalloc(void) { \n "
" return malloc(100); \n "
" } \n "
" void func() { \n "
" struct ABC abc; \n "
" abc.a = myalloc(); \n "
2016-01-31 10:08:00 +01:00
" } " , false ) ;
2015-11-19 16:10:00 +01:00
ASSERT_EQUALS ( " [test.c:7]: (error) Memory leak: abc.a \n " , errout . str ( ) ) ;
}
2009-06-16 22:01:04 +02:00
} ;
2015-10-07 14:30:01 +02:00
REGISTER_TEST ( TestMemleakStructMember )
2009-06-16 22:01:04 +02:00
2010-11-12 21:09:34 +01:00
2011-10-13 20:53:06 +02:00
class TestMemleakNoVar : public TestFixture {
2010-11-12 21:09:34 +01:00
public :
2014-11-20 14:20:09 +01:00
TestMemleakNoVar ( ) : TestFixture ( " TestMemleakNoVar " ) {
2013-08-07 16:27:37 +02:00
}
2010-11-12 21:09:34 +01:00
private :
2014-03-24 09:59:05 +01:00
Settings settings ;
2014-11-20 14:20:09 +01:00
void check ( const char code [ ] ) {
2010-12-01 18:00:55 +01:00
// Clear the error buffer..
errout . str ( " " ) ;
2014-03-24 09:59:05 +01:00
// Tokenize..
Tokenizer tokenizer ( & settings , this ) ;
std : : istringstream istr ( code ) ;
tokenizer . tokenize ( istr , " test.cpp " ) ;
tokenizer . simplifyTokenList2 ( ) ;
// Check for memory leaks..
CheckMemoryLeakNoVar checkMemoryLeakNoVar ( & tokenizer , & settings , this ) ;
checkMemoryLeakNoVar . check ( ) ;
}
2019-01-12 15:45:25 +01:00
void run ( ) OVERRIDE {
2015-01-04 11:07:53 +01:00
settings . inconclusive = true ;
2019-04-12 10:41:53 +02:00
settings . libraries . push_back ( " posix " ) ;
2015-01-04 11:07:53 +01:00
settings . addEnabled ( " warning " ) ;
2010-12-01 18:00:55 +01:00
2015-11-18 22:09:27 +01:00
LOAD_LIB_2 ( settings . library , " std.cfg " ) ;
2015-11-19 17:33:52 +01:00
LOAD_LIB_2 ( settings . library , " posix.cfg " ) ;
2014-02-05 08:18:39 +01:00
2010-11-12 21:09:34 +01:00
// pass allocated memory to function..
TEST_CASE ( functionParameter ) ;
2015-01-04 11:07:53 +01:00
2012-03-14 23:45:20 +01:00
// never use leakable resource
2014-01-03 10:12:32 +01:00
TEST_CASE ( missingAssignment ) ;
2015-01-04 11:07:53 +01:00
// pass allocated memory to function using a smart pointer
TEST_CASE ( smartPointerFunctionParam ) ;
2018-04-05 06:47:59 +02:00
TEST_CASE ( resourceLeak ) ;
2019-02-03 12:15:05 +01:00
// Test getAllocationType for subfunction
TEST_CASE ( getAllocationType ) ;
2010-11-12 21:09:34 +01:00
}
2014-11-20 14:20:09 +01:00
void functionParameter ( ) {
2010-11-12 21:09:34 +01:00
// standard function..
check ( " void x() { \n "
" strcpy(a, strdup(p)); \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2010-11-12 21:09:34 +01:00
ASSERT_EQUALS ( " [test.cpp:2]: (error) Allocation with strdup, strcpy doesn't release it. \n " , errout . str ( ) ) ;
2011-11-11 09:07:02 +01:00
check ( " char *x() { \n "
" char *ret = strcpy(malloc(10), \" abc \" ); \n "
" return ret; \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2011-11-11 09:07:02 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2011-01-02 08:32:51 +01:00
check ( " void x() { \n "
" free(malloc(10)); \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2011-01-02 08:32:51 +01:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2010-11-12 21:09:34 +01:00
// user function..
check ( " void set_error(const char *msg) { \n "
" } \n "
" \n "
" void x() { \n "
" set_error(strdup(p)); \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2015-07-24 08:30:38 +02:00
TODO_ASSERT_EQUALS ( " [test.cpp:5]: (error) Allocation with strdup, set_error doesn't release it. \n " , " " , errout . str ( ) ) ;
2011-11-07 22:50:57 +01:00
check ( " void f() \n "
" { \n "
" int fd; \n "
" fd = mkstemp(strdup( \" /tmp/file.XXXXXXXX \" )); \n "
" close(fd); \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2011-11-11 09:07:02 +01:00
TODO_ASSERT_EQUALS ( " [test.cpp:4]: (error) Allocation with strdup, mkstemp doesn't release it. \n " , " " , errout . str ( ) ) ;
2014-01-28 14:30:36 +01:00
check ( " void f() \n "
" { \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 ( ) ) ;
check ( " void f() \n "
" { \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 ( ) ) ;
2014-02-05 18:49:34 +01:00
2014-01-28 14:30:36 +01:00
check ( " void f() \n "
" { \n "
" 42, strcmp(strdup(a), b); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (error) Allocation with strdup, strcmp doesn't release it. \n " , errout . str ( ) ) ;
2010-11-12 21:09:34 +01:00
}
2012-03-14 23:45:20 +01:00
2014-11-20 14:20:09 +01:00
void missingAssignment ( ) {
2012-03-14 23:45:20 +01:00
check ( " void x() \n "
" { \n "
" malloc(10); \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2015-07-31 13:52:21 +02:00
ASSERT_EQUALS ( " [test.cpp:3]: (error) Return value of allocation function 'malloc' is not stored. \n " , errout . str ( ) ) ;
2014-01-03 10:12:32 +01:00
check ( " void x() \n "
" { \n "
2015-11-19 17:33:52 +01:00
" calloc(10, 1); \n "
2014-01-03 10:12:32 +01:00
" } " ) ;
2015-07-31 13:52:21 +02:00
ASSERT_EQUALS ( " [test.cpp:3]: (error) Return value of allocation function 'calloc' is not stored. \n " , errout . str ( ) ) ;
2014-01-03 10:12:32 +01:00
check ( " void x() \n "
" { \n "
" strdup( \" Test \" ); \n "
" } " ) ;
2015-07-31 13:52:21 +02:00
ASSERT_EQUALS ( " [test.cpp:3]: (error) Return value of allocation function 'strdup' is not stored. \n " , errout . str ( ) ) ;
2014-01-03 10:12:32 +01:00
check ( " void x() \n "
" { \n "
" (char*) malloc(10); \n "
" } " ) ;
2015-07-31 13:52:21 +02:00
ASSERT_EQUALS ( " [test.cpp:3]: (error) Return value of allocation function 'malloc' is not stored. \n " , errout . str ( ) ) ;
2014-01-03 10:12:32 +01:00
check ( " void x() \n "
" { \n "
" char* ptr = malloc(10); \n "
" foo(ptr); \n "
" free(ptr); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2014-05-21 13:45:36 +02:00
check ( " char** x(const char* str) { \n "
" char* ptr[] = { malloc(10), malloc(5), strdup(str) }; \n "
" return ptr; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2014-01-03 10:12:32 +01:00
check ( " void x() \n "
" { \n "
" 42,malloc(42); \n "
" } " ) ;
2015-07-31 13:52:21 +02:00
ASSERT_EQUALS ( " [test.cpp:3]: (error) Return value of allocation function 'malloc' is not stored. \n " , errout . str ( ) ) ;
2012-03-14 23:45:20 +01:00
check ( " void *f() \n "
" { \n "
" return malloc(10); \n "
" } \n "
" void x() \n "
" { \n "
" f(); \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2015-07-31 13:52:21 +02:00
ASSERT_EQUALS ( " [test.cpp:7]: (error) Return value of allocation function 'f' is not stored. \n " , errout . str ( ) ) ;
2015-01-31 17:27:43 +01:00
2018-11-12 11:28:26 +01:00
check ( " void f() \n " // #8100
" { \n "
" auto lambda = [](){return malloc(10);}; \n "
" } \n "
" void x() \n "
" { \n "
" f(); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2019-04-22 17:37:41 +02:00
check ( " void *f() { \n " // #8848
" struct S { void *alloc() { return malloc(10); } }; \n "
" } \n "
" void x() \n "
" { \n "
" f(); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-01-31 17:27:43 +01:00
check ( " void x() \n "
" { \n "
" if(!malloc(5)) fail(); \n "
" } " ) ;
2015-07-31 13:52:21 +02:00
ASSERT_EQUALS ( " [test.cpp:3]: (error) Return value of allocation function 'malloc' is not stored. \n " , errout . str ( ) ) ;
2015-01-31 20:34:06 +01:00
check ( " FOO* factory() { \n "
" FOO* foo = new (std::nothrow) FOO; \n "
" return foo; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-06-19 23:44:43 +02:00
// Ticket #6536
check ( " struct S { S(int) {} }; \n "
" void foo(int i) { \n "
" S socket(i); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-11-10 14:19:25 +01:00
// Ticket #6693
check ( " struct CTest { \n "
" void Initialise(); \n "
" void malloc(); \n "
" }; \n "
" void CTest::Initialise() { \n "
" malloc(); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-12-05 18:43:29 +01:00
2016-01-25 10:33:11 +01:00
check ( " void foo() { \n " // #7348 - cast
" p = (::X*)malloc(42); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-12-05 18:43:29 +01:00
// #7182 "crash: CheckMemoryLeak::functionReturnType()"
check ( " template<typename... Ts> auto unary_right_comma (Ts... ts) { return (ts , ...); } \n "
" template<typename T, typename... Ts> auto binary_left_comma (T x, Ts... ts) { return (x , ... , ts); } \n "
" int main() { \n "
" unary_right_comma (a); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-03-14 23:45:20 +01:00
}
2015-01-04 11:07:53 +01:00
void smartPointerFunctionParam ( ) {
check ( " void x() { \n "
" f(shared_ptr<int>(new int(42)), g()); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (warning, inconclusive) Unsafe allocation. If g() throws, memory could be leaked. Use make_shared<int>() instead. \n " , errout . str ( ) ) ;
check ( " void x() { \n "
" h(12, f(shared_ptr<int>(new int(42)), g())); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (warning, inconclusive) Unsafe allocation. If g() throws, memory could be leaked. Use make_shared<int>() instead. \n " , errout . str ( ) ) ;
check ( " void x() { \n "
" f(unique_ptr<int>(new int(42)), g()); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (warning, inconclusive) Unsafe allocation. If g() throws, memory could be leaked. Use make_unique<int>() instead. \n " , errout . str ( ) ) ;
check ( " void x() { \n "
" f(g(), shared_ptr<int>(new int(42))); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (warning, inconclusive) Unsafe allocation. If g() throws, memory could be leaked. Use make_shared<int>() instead. \n " , errout . str ( ) ) ;
check ( " void x() { \n "
" f(g(), unique_ptr<int>(new int(42))); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (warning, inconclusive) Unsafe allocation. If g() throws, memory could be leaked. Use make_unique<int>() instead. \n " , errout . str ( ) ) ;
check ( " void x() { \n "
" f(shared_ptr<char>(new char), make_unique<int>(32)); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (warning, inconclusive) Unsafe allocation. If make_unique<int>() throws, memory could be leaked. Use make_shared<char>() instead. \n " , errout . str ( ) ) ;
check ( " void x() { \n "
" f(g(124), h( \" test \" , 234), shared_ptr<char>(new char)); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (warning, inconclusive) Unsafe allocation. If h() throws, memory could be leaked. Use make_shared<char>() instead. \n " , errout . str ( ) ) ;
2015-11-19 15:29:15 +01:00
check ( " void x() { \n "
" f(shared_ptr<std::string>(new std::string( \" \" )), g<std::string>()); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (warning, inconclusive) Unsafe allocation. If g<std::string>() throws, memory could be leaked. Use make_shared<std::string>() instead. \n " , errout . str ( ) ) ;
2015-01-04 11:07:53 +01:00
check ( " void g(int x) throw() { } \n "
" void x() { \n "
" f(g(124), shared_ptr<char>(new char)); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " void __declspec(nothrow) g(int x) { } \n "
" void x() { \n "
" f(g(124), shared_ptr<char>(new char)); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2018-04-05 06:47:59 +02:00
void resourceLeak ( ) {
check ( " void foo() { \n "
" fopen( \" file.txt \" , \" r \" ); \n "
" } \n " ) ;
ASSERT_EQUALS ( " [test.cpp:2]: (error) Return value of allocation function 'fopen' is not stored. \n " , errout . str ( ) ) ;
check ( " struct Holder { \n "
" Holder(FILE* f) : file(f) {} \n "
" ~Holder() { fclose(file); } \n "
" FILE* file; \n "
" }; \n "
" void foo() { \n "
" Holder h ( fopen( \" file.txt \" , \" r \" )); \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " struct Holder { \n "
" Holder(FILE* f) : file(f) {} \n "
" ~Holder() { fclose(file); } \n "
" FILE* file; \n "
" }; \n "
" void foo() { \n "
" Holder ( fopen( \" file.txt \" , \" r \" )); \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " struct Holder { \n "
" Holder(FILE* f) : file(f) {} \n "
" ~Holder() { fclose(file); } \n "
" FILE* file; \n "
" }; \n "
" void foo() { \n "
" Holder h { fopen( \" file.txt \" , \" r \" )}; \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " struct Holder { \n "
" Holder(FILE* f) : file(f) {} \n "
" ~Holder() { fclose(file); } \n "
" FILE* file; \n "
" }; \n "
" void foo() { \n "
" Holder h = fopen( \" file.txt \" , \" r \" ); \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " struct Holder { \n "
" Holder(FILE* f) : file(f) {} \n "
" ~Holder() { fclose(file); } \n "
" FILE* file; \n "
" }; \n "
" void foo() { \n "
" Holder { fopen( \" file.txt \" , \" r \" )}; \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " struct Holder { \n "
" Holder(int i, FILE* f) : file(f) {} \n "
" ~Holder() { fclose(file); } \n "
" FILE* file; \n "
" }; \n "
" void foo() { \n "
" Holder { 0, fopen( \" file.txt \" , \" r \" )}; \n "
" } \n " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2019-02-03 12:15:05 +01:00
void getAllocationType ( ) {
// #7845
check ( " class Thing { Thing(); }; \n "
" Thing * makeThing() { Thing *thing = new Thing; return thing; } \n "
" \n "
" void f() { \n "
" makeThing(); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2010-11-12 21:09:34 +01:00
} ;
2013-06-30 19:44:12 +02:00
REGISTER_TEST ( TestMemleakNoVar )
2014-02-06 09:22:07 +01:00