2012-05-26 08:53:46 +02:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2015-01-03 12:14:58 +01:00
* Copyright ( C ) 2007 - 2015 Daniel Marjamäki and Cppcheck team .
2012-05-26 08:53:46 +02: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
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "tokenize.h"
# include "checkleakautovar.h"
# include "testsuite.h"
# include <sstream>
extern std : : ostringstream errout ;
class TestLeakAutoVar : public TestFixture {
public :
2014-11-20 14:20:09 +01:00
TestLeakAutoVar ( ) : TestFixture ( " TestLeakAutoVar " ) {
2013-08-07 16:27:37 +02:00
}
2012-05-26 08:53:46 +02:00
private :
2014-11-20 14:20:09 +01:00
void run ( ) {
2012-05-26 08:53:46 +02:00
// Assign
TEST_CASE ( assign1 ) ;
TEST_CASE ( assign2 ) ;
TEST_CASE ( assign3 ) ;
TEST_CASE ( assign4 ) ;
TEST_CASE ( assign5 ) ;
TEST_CASE ( assign6 ) ;
TEST_CASE ( assign7 ) ;
TEST_CASE ( assign8 ) ;
TEST_CASE ( assign9 ) ;
2012-05-26 21:28:35 +02:00
TEST_CASE ( assign10 ) ;
2012-08-21 17:02:11 +02:00
TEST_CASE ( assign11 ) ; // #3942: x = a(b(p));
2012-10-25 19:41:18 +02:00
TEST_CASE ( assign12 ) ; // #4236: FP. bar(&x);
2012-10-27 16:36:14 +02:00
TEST_CASE ( assign13 ) ; // #4237: FP. char*&ref=p; p=malloc(10); free(ref);
2012-05-26 08:53:46 +02:00
TEST_CASE ( deallocuse1 ) ;
TEST_CASE ( deallocuse2 ) ;
TEST_CASE ( deallocuse3 ) ;
2012-06-11 18:28:31 +02:00
TEST_CASE ( deallocuse4 ) ;
2012-08-12 16:18:07 +02:00
TEST_CASE ( deallocuse5 ) ; // #4018: FP. free(p), p = 0;
2012-08-28 06:38:38 +02:00
TEST_CASE ( deallocuse6 ) ; // #4034: FP. x = p = f();
2015-01-29 21:26:06 +01:00
TEST_CASE ( deallocuse7 ) ; // #6467, #6469, #6473
2012-05-26 08:53:46 +02:00
2012-07-16 17:07:51 +02:00
TEST_CASE ( doublefree1 ) ;
TEST_CASE ( doublefree2 ) ;
2013-07-28 10:26:46 +02:00
TEST_CASE ( doublefree3 ) ; // #4914
2014-05-04 12:02:55 +02:00
TEST_CASE ( doublefree4 ) ; // #5451 - FP when exit is called
2012-06-22 09:10:30 +02:00
2012-05-26 08:53:46 +02:00
// exit
TEST_CASE ( exit1 ) ;
TEST_CASE ( exit2 ) ;
// goto
TEST_CASE ( goto1 ) ;
2012-10-08 17:23:47 +02:00
TEST_CASE ( goto2 ) ;
2012-05-26 08:53:46 +02:00
// if/else
TEST_CASE ( ifelse1 ) ;
TEST_CASE ( ifelse2 ) ;
TEST_CASE ( ifelse3 ) ;
TEST_CASE ( ifelse4 ) ;
2012-05-29 21:10:19 +02:00
TEST_CASE ( ifelse5 ) ;
2012-06-04 21:21:14 +02:00
TEST_CASE ( ifelse6 ) ; // #3370
2014-04-18 18:18:47 +02:00
TEST_CASE ( ifelse7 ) ; // #5576 - if (fd < 0)
2014-09-17 18:37:41 +02:00
TEST_CASE ( ifelse8 ) ; // #5747 - if (fd == -1)
2012-05-26 08:53:46 +02:00
// switch
TEST_CASE ( switch1 ) ;
// loops
TEST_CASE ( loop1 ) ;
// mismatching allocation/deallocation
TEST_CASE ( mismatch_fopen_free ) ;
// Execution reaches a 'return'
TEST_CASE ( return1 ) ;
TEST_CASE ( return2 ) ;
TEST_CASE ( return3 ) ;
2012-06-01 19:08:50 +02:00
TEST_CASE ( return4 ) ;
2012-05-26 08:53:46 +02:00
2012-06-01 19:01:19 +02:00
// General tests: variable type, allocation type, etc
TEST_CASE ( test1 ) ;
2012-06-20 17:09:41 +02:00
TEST_CASE ( test2 ) ;
2012-07-17 16:28:34 +02:00
TEST_CASE ( test3 ) ; // #3954 - reference pointer
2014-06-23 16:05:28 +02:00
TEST_CASE ( test4 ) ; // #5923 - static pointer
2014-10-14 16:40:30 +02:00
TEST_CASE ( test5 ) ; // unknown type
2012-06-01 19:01:19 +02:00
2012-09-22 10:37:27 +02:00
// Execution reaches a 'throw'
TEST_CASE ( throw1 ) ;
2012-05-26 08:53:46 +02:00
// Possible leak => Further configuration is needed for complete analysis
TEST_CASE ( configuration1 ) ;
TEST_CASE ( configuration2 ) ;
TEST_CASE ( configuration3 ) ;
TEST_CASE ( configuration4 ) ;
2012-08-26 11:39:17 +02:00
TEST_CASE ( ptrptr ) ;
2014-09-30 13:02:02 +02:00
TEST_CASE ( nestedAllocation ) ;
2012-05-26 08:53:46 +02:00
}
2015-01-28 13:45:40 +01:00
void check ( const char code [ ] , bool cpp = false ) {
2012-05-26 08:53:46 +02:00
// Clear the error buffer..
errout . str ( " " ) ;
// Tokenize..
Settings settings ;
2013-07-20 17:12:56 +02:00
int id = 0 ;
while ( ! settings . library . ismemory ( + + id ) ) ;
2015-01-28 13:45:40 +01:00
settings . library . setalloc ( " malloc " , id ) ;
settings . library . setdealloc ( " free " , id ) ;
2013-07-20 17:12:56 +02:00
while ( ! settings . library . isresource ( + + id ) ) ;
2015-01-28 13:45:40 +01:00
settings . library . setalloc ( " fopen " , id ) ;
settings . library . setdealloc ( " fclose " , id ) ;
2012-05-26 08:53:46 +02:00
Tokenizer tokenizer ( & settings , this ) ;
std : : istringstream istr ( code ) ;
2015-01-28 13:45:40 +01:00
tokenizer . tokenize ( istr , cpp ? " test.cpp " : " test.c " ) ;
2014-10-14 16:40:30 +02:00
tokenizer . simplifyTokenList2 ( ) ;
// Check for leaks..
CheckLeakAutoVar c ;
settings . checkLibrary = true ;
settings . addEnabled ( " information " ) ;
c . runSimplifiedChecks ( & tokenizer , & settings , this ) ;
}
2014-11-20 14:20:09 +01:00
void assign1 ( ) {
2012-05-26 08:53:46 +02:00
check ( " void f() { \n "
" char *p = malloc(10); \n "
" p = NULL; \n "
" free(p); \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2012-06-30 16:23:10 +02:00
ASSERT_EQUALS ( " [test.c:3]: (error) Memory leak: p \n " , errout . str ( ) ) ;
2012-05-26 08:53:46 +02:00
}
2014-11-20 14:20:09 +01:00
void assign2 ( ) {
2012-05-26 08:53:46 +02:00
check ( " void f() { \n "
" char *p = malloc(10); \n "
" char *q = p; \n "
" free(q); \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2012-05-26 08:53:46 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void assign3 ( ) {
2012-05-26 08:53:46 +02:00
check ( " void f() { \n "
" char *p = malloc(10); \n "
" char *q = p + 1; \n "
" free(q - 1); \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2012-05-26 08:53:46 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void assign4 ( ) {
2012-05-26 08:53:46 +02:00
check ( " void f() { \n "
" char *a = malloc(10); \n "
" a += 10; \n "
" free(a - 10); \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2012-05-26 08:53:46 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void assign5 ( ) {
2012-05-26 08:53:46 +02:00
check ( " void foo() \n "
" { \n "
" char *p = new char[100]; \n "
" list += p; \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2012-05-26 08:53:46 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void assign6 ( ) { // #2806 - FP when there is redundant assignment
2012-05-26 08:53:46 +02:00
check ( " void foo() { \n "
" char *p = malloc(10); \n "
" p = strcpy(p,q); \n "
" free(p); \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2012-05-26 08:53:46 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void assign7 ( ) {
2012-05-26 08:53:46 +02:00
check ( " void foo(struct str *d) { \n "
" struct str *p = malloc(10); \n "
" d->p = p; \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2012-05-26 08:53:46 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void assign8 ( ) { // linux list
2012-05-26 08:53:46 +02:00
check ( " void foo(struct str *d) { \n "
" struct str *p = malloc(10); \n "
" d->p = &p->x; \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2012-05-26 08:53:46 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void assign9 ( ) {
2012-05-26 08:53:46 +02:00
check ( " void foo() { \n "
" char *p = x(); \n "
" free(p); \n "
" p = NULL; \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2012-05-26 08:53:46 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void assign10 ( ) {
2012-05-26 21:28:35 +02:00
check ( " void foo() { \n "
" char *p; \n "
" if (x) { p = malloc(10); } \n "
" if (!x) { p = NULL; } \n "
" free(p); \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2012-05-26 21:28:35 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void assign11 ( ) { // #3942 - FP for x = a(b(p));
2012-08-21 17:02:11 +02:00
check ( " void f() { \n "
" char *p = malloc(10); \n "
" x = a(b(p)); \n "
" } " ) ;
2015-02-03 18:35:52 +01:00
ASSERT_EQUALS ( " [test.c:4]: (information) --check-library: Function b() should have <use>/<leak-ignore> configuration \n " , errout . str ( ) ) ;
2012-08-21 17:02:11 +02:00
}
2014-11-20 14:20:09 +01:00
void assign12 ( ) { // #4236: FP. bar(&x)
2012-10-25 19:41:18 +02:00
check ( " void f() { \n "
" char *p = malloc(10); \n "
" free(p); \n "
" bar(&p); \n "
" free(p); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void assign13 ( ) { // #4237: FP. char *&ref=p; p=malloc(10); free(ref);
2012-10-27 16:36:14 +02:00
check ( " void f() { \n "
" char *p; \n "
" char * &ref = p; \n "
" p = malloc(10); \n "
" free(ref); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void deallocuse1 ( ) {
2012-05-26 08:53:46 +02:00
check ( " void f(char *p) { \n "
" free(p); \n "
" *p = 0; \n "
" } " ) ;
2012-06-30 16:23:10 +02:00
ASSERT_EQUALS ( " [test.c:3]: (error) Dereferencing 'p' after it is deallocated / released \n " , errout . str ( ) ) ;
2012-05-26 08:53:46 +02:00
check ( " void f(char *p) { \n "
" free(p); \n "
" char c = *p; \n "
" } " ) ;
2012-06-30 16:23:10 +02:00
ASSERT_EQUALS ( " [test.c:3]: (error) Dereferencing 'p' after it is deallocated / released \n " , errout . str ( ) ) ;
2012-05-26 08:53:46 +02:00
}
2014-11-20 14:20:09 +01:00
void deallocuse2 ( ) {
2012-05-26 08:53:46 +02:00
check ( " void f(char *p) { \n "
" free(p); \n "
" strcpy(a, p); \n "
" } " ) ;
2013-07-16 18:50:25 +02:00
TODO_ASSERT_EQUALS ( " error (free,use) " , " [test.c:3]: (information) --check-library: Function strcpy() should have <noreturn> configuration \n " , errout . str ( ) ) ;
2012-05-26 08:53:46 +02:00
check ( " void f(char *p) { \n " // #3041 - assigning pointer when it's used
" free(p); \n "
" strcpy(a, p=b()); \n "
" } " ) ;
2013-07-16 18:50:25 +02:00
TODO_ASSERT_EQUALS ( " " , " [test.c:3]: (information) --check-library: Function strcpy() should have <noreturn> configuration \n " , errout . str ( ) ) ;
2012-05-26 08:53:46 +02:00
}
2014-11-20 14:20:09 +01:00
void deallocuse3 ( ) {
2012-05-26 08:53:46 +02:00
check ( " void f(struct str *p) { \n "
" free(p); \n "
" p = p->next; \n "
" } " ) ;
2012-06-30 16:23:10 +02:00
ASSERT_EQUALS ( " [test.c:3]: (error) Dereferencing 'p' after it is deallocated / released \n " , errout . str ( ) ) ;
2012-05-26 08:53:46 +02:00
}
2014-11-20 14:20:09 +01:00
void deallocuse4 ( ) {
2012-06-11 18:28:31 +02:00
check ( " void f(char *p) { \n "
" free(p); \n "
" return p; \n "
" } " ) ;
2012-06-30 16:23:10 +02:00
ASSERT_EQUALS ( " [test.c:3]: (error) Returning/dereferencing 'p' after it is deallocated / released \n " , errout . str ( ) ) ;
2012-06-11 18:28:31 +02:00
}
2014-11-20 14:20:09 +01:00
void deallocuse5 ( ) { // #4018
2012-08-12 16:18:07 +02:00
check ( " void f(char *p) { \n "
" free(p), p = 0; \n "
" *p = 0; \n " // <- Make sure pointer info is reset. It is NOT a freed pointer dereference
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void deallocuse6 ( ) { // #4034
2012-08-28 06:38:38 +02:00
check ( " void f(char *p) { \n "
" free(p); \n "
" x = p = foo(); \n " // <- p is not dereferenced
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2015-01-29 21:26:06 +01:00
void deallocuse7 ( ) { // #6467, #6469, #6473
2015-01-29 10:18:21 +01:00
check ( " struct Foo { int* ptr; }; \n "
" void f(Foo* foo) { \n "
" delete foo->ptr; \n "
" foo->ptr = new Foo; \n "
" } " , true ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " struct Foo { int* ptr; }; \n "
" void f(Foo* foo) { \n "
" delete foo->ptr; \n "
" x = *foo->ptr; \n "
" } " , true ) ;
ASSERT_EQUALS ( " [test.cpp:4]: (error) Dereferencing 'ptr' after it is deallocated / released \n " , errout . str ( ) ) ;
2015-01-29 21:26:06 +01:00
check ( " void parse() { \n "
" struct Buf { \n "
" Buf(uint32_t len) : m_buf(new uint8_t[len]) {} \n "
" ~Buf() { delete[]m_buf; } \n "
" uint8_t *m_buf; \n "
" }; \n "
" } " , true ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " struct Foo { \n "
" Foo(); \n "
" Foo* ptr; \n "
" void func(); \n "
" }; \n "
" void bar(Foo* foo) { \n "
" delete foo->ptr; \n "
" foo->ptr = new Foo; \n "
" foo->ptr->func(); \n "
" } " , true ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-01-29 10:18:21 +01:00
}
2014-11-20 14:20:09 +01:00
void doublefree1 ( ) { // #3895
2012-06-22 09:10:30 +02:00
check ( " void f(char *p) { \n "
" if (x) \n "
" free(p); \n "
" else \n "
" p = 0; \n "
" free(p); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.c:6]: (error) Memory pointed to by 'p' is freed twice. \n " , errout . str ( ) ) ;
2015-01-28 13:45:40 +01:00
check (
" void foo(char *p) { \n "
" free(p); \n "
" free(p); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.c:3]: (error) Memory pointed to by 'p' is freed twice. \n " , errout . str ( ) ) ;
check (
" void foo(char *p, char *r) { \n "
" free(p); \n "
" free(r); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check (
" void foo() { \n "
" free(p); \n "
" free(r); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check (
" void foo(char *p) { \n "
" if (x < 3) free(p); \n "
" else { if (x > 9) free(p); } \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check (
" void foo(char *p) { \n "
" free(p); \n "
" getNext(&p); \n "
" free(p); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check (
" void foo(char *p) { \n "
" free(p); \n "
" bar(); \n "
" free(p); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.c:4]: (error) Memory pointed to by 'p' is freed twice. \n " , errout . str ( ) ) ;
check (
" void foo(char *p) { \n "
" free(p); \n "
" printf( \" Freed memory at location %x \" , p); \n "
" free(p); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.c:4]: (error) Memory pointed to by 'p' is freed twice. \n " , errout . str ( ) ) ;
check (
" void foo(FILE *p) { \n "
" fclose(p); \n "
" fclose(p); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.c:3]: (error) Resource handle 'p' freed twice. \n " , errout . str ( ) ) ;
check (
" void foo(FILE *p, FILE *r) { \n "
" fclose(p); \n "
" fclose(r); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check (
" void foo(FILE *p) { \n "
" if (x < 3) fclose(p); \n "
" else { if (x > 9) fclose(p); } \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check (
" void foo(FILE *p) { \n "
" fclose(p); \n "
" gethandle(&p); \n "
" fclose(p); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check (
" void foo(FILE *p) { \n "
" fclose(p); \n "
" gethandle(); \n "
" fclose(p); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.c:4]: (error) Resource handle 'p' freed twice. \n " , errout . str ( ) ) ;
check (
" void foo(Data* p) { \n "
" free(p->a); \n "
" free(p->b); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check (
" void f() { \n "
" char *p; p = malloc(100); \n "
" if (x) { \n "
" free(p); \n "
" exit(); \n "
" } \n "
" free(p); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check (
" void f() { \n "
" char *p; p = malloc(100); \n "
" if (x) { \n "
" free(p); \n "
" x = 0; \n "
" } \n "
" free(p); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.c:7]: (error) Memory pointed to by 'p' is freed twice. \n " , errout . str ( ) ) ;
check (
" void f() { \n "
" char *p; p = do_something(); \n "
" free(p); \n "
" p = do_something(); \n "
" free(p); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check (
" void foo(char *p) { \n "
" delete p; \n "
" delete p; \n "
" } " , true ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (error) Memory pointed to by 'p' is freed twice. \n " , errout . str ( ) ) ;
check (
" void foo(char *p, char *r) { \n "
" delete p; \n "
" delete r; \n "
" } " , true ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check (
" void foo(P p) { \n "
" delete p.x; \n "
" delete p; \n "
" } " , true ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-01-29 09:50:33 +01:00
check (
" void foo(char **p) { \n "
" delete p[0]; \n "
" delete p[1]; \n "
" } " , true ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-01-28 13:45:40 +01:00
check (
" void foo(char *p) { \n "
" delete p; \n "
" getNext(&p); \n "
" delete p; \n "
" } " , true ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check (
" void foo(char *p) { \n "
" delete p; \n "
" bar(); \n "
" delete p; \n "
" } " , true ) ;
ASSERT_EQUALS ( " [test.cpp:4]: (error) Memory pointed to by 'p' is freed twice. \n " , errout . str ( ) ) ;
check (
" void foo(char *p) { \n "
" delete[] p; \n "
" delete[] p; \n "
" } " , true ) ;
ASSERT_EQUALS ( " [test.cpp:3]: (error) Memory pointed to by 'p' is freed twice. \n " , errout . str ( ) ) ;
check (
" void foo(char *p, char *r) { \n "
" delete[] p; \n "
" delete[] r; \n "
" } " , true ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check (
" void foo(char *p) { \n "
" delete[] p; \n "
" getNext(&p); \n "
" delete[] p; \n "
" } " , true ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check (
" void foo(char *p) { \n "
" delete[] p; \n "
" bar(); \n "
" delete[] p; \n "
" } " , true ) ;
ASSERT_EQUALS ( " [test.cpp:4]: (error) Memory pointed to by 'p' is freed twice. \n " , errout . str ( ) ) ;
check (
" ~LineMarker() { \n "
" delete pxpm; \n "
" } \n "
" LineMarker &operator=(const LineMarker &) { \n "
" delete pxpm; \n "
" pxpm = NULL; \n "
" return *this; \n "
" } " , true ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check (
" void foo() \n "
" { \n "
" int* ptr; ptr = NULL; \n "
" try \n "
" { \n "
" ptr = new int(4); \n "
" } \n "
" catch(...) \n "
" { \n "
" delete ptr; \n "
" throw; \n "
" } \n "
" delete ptr; \n "
" } " , true ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check (
" int foo() \n "
" { \n "
" int* a; a = new int; \n "
" bool doDelete; doDelete = true; \n "
" if (a != 0) \n "
" { \n "
" doDelete = false; \n "
" delete a; \n "
" } \n "
" if(doDelete) \n "
" delete a; \n "
" return 0; \n "
" } " , true ) ;
TODO_ASSERT_EQUALS ( " " , " [test.cpp:11]: (error) Memory pointed to by 'a' is freed twice. \n " , errout . str ( ) ) ;
check (
" void foo(int y) \n "
" { \n "
" char * x; x = NULL; \n "
" while(true) { \n "
" x = new char[100]; \n "
" if (y++ > 100) \n "
" break; \n "
" delete[] x; \n "
" } \n "
" delete[] x; \n "
" } " , true ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check (
" void foo(int y) \n "
" { \n "
" char * x; x = NULL; \n "
" for (int i = 0; i < 10000; i++) { \n "
" x = new char[100]; \n "
" delete[] x; \n "
" } \n "
" delete[] x; \n "
" } " , true ) ;
TODO_ASSERT_EQUALS ( " [test.cpp:8]: (error) Memory pointed to by 'x' is freed twice. \n " , " " , errout . str ( ) ) ;
check (
" void foo(int y) \n "
" { \n "
" char * x; x = NULL; \n "
" while (isRunning()) { \n "
" x = new char[100]; \n "
" delete[] x; \n "
" } \n "
" delete[] x; \n "
" } " , true ) ;
TODO_ASSERT_EQUALS ( " [test.cpp:8]: (error) Memory pointed to by 'x' is freed twice. \n " , " " , errout . str ( ) ) ;
check (
" void foo(int y) \n "
" { \n "
" char * x; x = NULL; \n "
" while (isRunning()) { \n "
" x = malloc(100); \n "
" free(x); \n "
" } \n "
" free(x); \n "
" } " ) ;
TODO_ASSERT_EQUALS ( " [test.c:8]: (error) Memory pointed to by 'x' is freed twice. \n " , " " , errout . str ( ) ) ;
check (
" void foo(int y) \n "
" { \n "
" char * x; x = NULL; \n "
" for (;;) { \n "
" x = new char[100]; \n "
" if (y++ > 100) \n "
" break; \n "
" delete[] x; \n "
" } \n "
" delete[] x; \n "
" } " , true ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check (
" void foo(int y) \n "
" { \n "
" char * x; x = NULL; \n "
" do { \n "
" x = new char[100]; \n "
" if (y++ > 100) \n "
" break; \n "
" delete[] x; \n "
" } while (true); \n "
" delete[] x; \n "
" } " , true ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check (
" void f() \n "
" { \n "
" char *p; p = 0; \n "
" if (x < 100) { \n "
" p = malloc(10); \n "
" free(p); \n "
" } \n "
" free(p); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.c:8]: (error) Memory pointed to by 'p' is freed twice. \n " , errout . str ( ) ) ;
check (
" void MyFunction() \n "
" { \n "
" char* data; data = new char[100]; \n "
" try \n "
" { \n "
" } \n "
" catch(err) \n "
" { \n "
" delete[] data; \n "
" MyThrow(err); \n "
" } \n "
" delete[] data; \n "
" } \n "
" void MyThrow(err) \n "
" { \n "
" throw(err); \n "
" } " , true ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check (
" void MyFunction() \n "
" { \n "
" char* data; data = new char[100]; \n "
" try \n "
" { \n "
" } \n "
" catch(err) \n "
" { \n "
" delete[] data; \n "
" MyExit(err); \n "
" } \n "
" delete[] data; \n "
" } \n "
" void MyExit(err) \n "
" { \n "
" exit(err); \n "
" } " , true ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( // #6252
" struct Wrapper { \n "
" Thing* m_thing; \n "
" Wrapper() : m_thing(0) { \n "
" } \n "
" ~Wrapper() { \n "
" delete m_thing; \n "
" } \n "
" void changeThing() { \n "
" delete m_thing; \n "
" m_thing = new Thing; \n "
" } \n "
" }; " , true ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-06-22 09:10:30 +02:00
}
2014-11-20 14:20:09 +01:00
void doublefree2 ( ) { // #3891
2012-07-16 17:07:51 +02:00
check ( " void *f(int a) { \n "
" char *p = malloc(10); \n "
" if (a == 2) { free(p); return ((void*)1); } \n "
" free(p); \n "
" return 0; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2013-07-28 11:53:49 +02:00
2014-11-20 14:20:09 +01:00
void doublefree3 ( ) { // #4914
2013-07-28 10:26:46 +02:00
check ( " void foo() { \n "
" bool done = false; \n "
" do { \n "
" char *bar = malloc(10) \n "
" if(condition()) { \n "
" free(bar); \n "
" continue; \n "
" } \n "
" done = true; \n "
" free(bar) \n "
" } while(!done); \n "
" return; "
" } "
2013-07-28 11:53:49 +02:00
) ;
2013-07-28 10:26:46 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2014-05-04 12:02:55 +02:00
}
2014-11-20 14:20:09 +01:00
void doublefree4 ( ) { // #5451 - exit
2014-05-04 13:11:21 +02:00
check ( " void f(char *p) { \n "
" if (x) { \n "
" free(p); \n "
" exit(1); \n "
" } \n "
" free(p); \n "
2014-05-04 12:02:55 +02:00
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2013-07-28 10:26:46 +02:00
}
2012-07-16 17:07:51 +02:00
2014-11-20 14:20:09 +01:00
void exit1 ( ) {
2012-05-26 08:53:46 +02:00
check ( " void f() { \n "
" char *p = malloc(10); \n "
" exit(0); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void exit2 ( ) {
2012-05-26 08:53:46 +02:00
check ( " void f() { \n "
" char *p = malloc(10); \n "
" fatal_error(); \n "
" } " ) ;
2013-07-16 18:50:25 +02:00
ASSERT_EQUALS ( " [test.c:3]: (information) --check-library: Function fatal_error() should have <noreturn> configuration \n "
2015-02-03 18:35:52 +01:00
" [test.c:4]: (information) --check-library: Function fatal_error() should have <use>/<leak-ignore> configuration \n " ,
2013-07-16 18:50:25 +02:00
errout . str ( ) ) ;
2012-05-26 08:53:46 +02:00
}
2014-11-20 14:20:09 +01:00
void goto1 ( ) {
2012-05-26 08:53:46 +02:00
check ( " static void f() { \n "
" int err = -ENOMEM; \n "
" char *reg = malloc(100); \n "
" if (err) { \n "
" free(reg); \n "
" } \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void goto2 ( ) { // #4231
2012-10-08 17:23:47 +02:00
check ( " static char * f() { \n "
" x: \n "
" char *p = malloc(100); \n "
" if (err) { \n "
" free(p); \n "
" goto x; \n "
" } \n "
" return p; \n " // no error since there is a goto
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void ifelse1 ( ) {
2012-05-26 08:53:46 +02:00
check ( " int f() { \n "
" char *p = NULL; \n "
" if (x) { p = malloc(10); } \n "
" else { return 0; } \n "
" free(p); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void ifelse2 ( ) {
2012-05-26 08:53:46 +02:00
check ( " int f() { \n "
" char *p = NULL; \n "
" if (x) { p = malloc(10); } \n "
" else { return 0; } \n "
" } " ) ;
2012-06-30 16:23:10 +02:00
ASSERT_EQUALS ( " [test.c:5]: (error) Memory leak: p \n " , errout . str ( ) ) ;
2012-05-26 08:53:46 +02:00
}
2014-11-20 14:20:09 +01:00
void ifelse3 ( ) {
2012-05-26 08:53:46 +02:00
check ( " void f() { \n "
" char *p = malloc(10); \n "
" if (!p) { return; } \n "
" free(p); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " void f() { \n "
" char *p = malloc(10); \n "
" if (p) { } else { return; } \n "
" free(p); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-06-17 07:54:24 +02:00
// #3866 - UNLIKELY
check ( " void f() { \n "
" char *p = malloc(10); \n "
" if (UNLIKELY(!p)) { return; } \n "
" free(p); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-05-26 08:53:46 +02:00
}
2014-11-20 14:20:09 +01:00
void ifelse4 ( ) {
2012-05-26 08:53:46 +02:00
check ( " void f(int x) { \n "
" char *p; \n "
" if (x) { p = malloc(10); } \n "
" if (x) { free(p); } \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " void f(int x) { \n "
" char *p; \n "
" if (x) { p = malloc(10); } \n "
" if (!x) { return; } \n "
" free(p); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void ifelse5 ( ) {
2012-05-29 21:10:19 +02:00
check ( " void f() { \n "
" char *p = malloc(10); \n "
" if (!p && x) { p = malloc(10); } \n "
" free(p); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void ifelse6 ( ) { // #3370
2012-06-04 21:21:14 +02:00
check ( " void f(int x) { \n "
" int *a = malloc(20); \n "
" if (x) \n "
2012-06-06 13:37:56 +02:00
" free(a); \n "
2012-06-04 21:21:14 +02:00
" else \n "
2012-06-06 13:37:56 +02:00
" a = 0; \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2012-06-30 16:23:10 +02:00
ASSERT_EQUALS ( " [test.c:6]: (error) Memory leak: a \n " , errout . str ( ) ) ;
2012-06-04 21:21:14 +02:00
}
2014-11-20 14:20:09 +01:00
void ifelse7 ( ) { // #5576
2014-04-18 18:18:47 +02:00
check ( " void f() { \n "
" int x = malloc(20); \n "
" if (x < 0) \n " // assume negative value indicates its unallocated
" return; \n "
" free(x); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void ifelse8 ( ) { // #5747
2014-09-17 18:37:41 +02:00
check ( " void f() { \n "
" int fd = socket(AF_INET, SOCK_PACKET, 0 ); \n "
" if (fd == -1) \n "
" return; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void switch1 ( ) {
2012-05-26 08:53:46 +02:00
check ( " void f() { \n "
" char *p = 0; \n "
" switch (x) { \n "
" case 123: p = malloc(100); break; \n "
" default: return; \n "
" } \n "
" free(p); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void loop1 ( ) {
2012-05-26 08:53:46 +02:00
// test the handling of { }
check ( " void f() { \n "
" char *p; \n "
" for (i=0;i<5;i++) { } \n "
" if (x) { free(p) } \n "
" else { a = p; } \n "
2013-03-20 15:36:16 +01:00
" } " ) ;
2012-05-26 08:53:46 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void mismatch_fopen_free ( ) {
2012-05-26 08:53:46 +02:00
check ( " void f() { \n "
" FILE*f=fopen(fname,a); \n "
" free(f); \n "
" } " ) ;
2012-06-30 16:23:10 +02:00
ASSERT_EQUALS ( " [test.c:3]: (error) Mismatching allocation and deallocation: f \n " , errout . str ( ) ) ;
2012-05-26 08:53:46 +02:00
}
2014-11-20 14:20:09 +01:00
void return1 ( ) {
2012-05-26 08:53:46 +02:00
check ( " int f() { \n "
" char *p = malloc(100); \n "
" return 123; \n "
" } " ) ;
2012-06-30 16:23:10 +02:00
ASSERT_EQUALS ( " [test.c:3]: (error) Memory leak: p \n " , errout . str ( ) ) ;
2012-05-26 08:53:46 +02:00
}
2014-11-20 14:20:09 +01:00
void return2 ( ) {
2012-05-26 08:53:46 +02:00
check ( " char *f() { \n "
" char *p = malloc(100); \n "
" return p; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void return3 ( ) {
2012-05-26 08:53:46 +02:00
check ( " struct dev * f() { \n "
" struct ABC *abc = malloc(100); \n "
" return &abc->dev; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void return4 ( ) { // ticket #3862
2012-06-04 21:32:11 +02:00
// avoid false positives
2012-06-01 19:08:50 +02:00
check ( " void f(char *p, int x) { \n "
2012-12-26 12:50:59 +01:00
" if (x==12) { \n "
2012-06-01 19:08:50 +02:00
" free(p); \n "
" throw 1; \n "
" } \n "
" free(p); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-06-04 21:32:11 +02:00
check ( " void f(char *p, int x) { \n "
2012-12-26 12:50:59 +01:00
" if (x==12) { \n "
2012-06-04 21:32:11 +02:00
" delete p; \n "
" throw 1; \n "
" } \n "
" delete p; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
check ( " void f(char *p, int x) { \n "
2012-12-26 12:50:59 +01:00
" if (x==12) { \n "
2012-06-04 21:32:11 +02:00
" delete [] p; \n "
" throw 1; \n "
" } \n "
" delete [] p; \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2012-06-01 19:08:50 +02:00
}
2014-11-20 14:20:09 +01:00
void test1 ( ) { // 3809
2012-06-01 19:01:19 +02:00
check ( " void f(double*&p) { \n "
" p = malloc(0x100); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void test2 ( ) { // 3899
2012-06-20 17:09:41 +02:00
check ( " struct Fred { \n "
" char *p; \n "
" void f1() { free(p); } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void test3 ( ) { // 3954 - reference pointer
2012-07-17 16:28:34 +02:00
check ( " void f() { \n "
" char *&p = x(); \n "
" p = malloc(10); \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void test4 ( ) { // 5923 - static pointer
2014-06-23 16:05:28 +02:00
check ( " void f() { \n "
" static char *p; \n "
" if (!p) p = malloc(10); \n "
" if (x) { free(p); p = 0; } \n "
" }; " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void test5 ( ) { // unknown type
2015-01-28 13:45:40 +01:00
check ( " void f() { Fred *p = malloc(10); } " , true ) ;
2014-10-14 16:40:30 +02:00
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
2015-01-28 13:45:40 +01:00
check ( " void f() { Fred *p = malloc(10); } " , false ) ;
2014-10-14 16:40:30 +02:00
ASSERT_EQUALS ( " [test.c:1]: (error) Memory leak: p \n " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void throw1 ( ) { // 3987 - Execution reach a 'throw'
2012-09-22 10:37:27 +02:00
check ( " void f() { \n "
" char *p = malloc(10); \n "
" throw 123; \n "
" } " ) ;
2015-01-22 11:12:26 +01:00
ASSERT_EQUALS ( " [test.c:3]: (error) Memory leak: p \n " , errout . str ( ) ) ;
2012-09-22 10:37:27 +02:00
check ( " void f() { \n "
" char *p; \n "
" try { \n "
" p = malloc(10); \n "
" throw 123; \n "
" } catch (...) { } \n "
" free(p); \n "
" } " ) ;
ASSERT_EQUALS ( " " , errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void configuration1 ( ) {
2012-05-26 08:53:46 +02:00
// Possible leak => configuration is required for complete analysis
// The user should be able to "white list" and "black list" functions.
// possible leak. If the function 'x' deallocates the pointer or
// takes the address, there is no leak.
check ( " void f() { \n "
" char *p = malloc(10); \n "
" x(p); \n "
" } " ) ;
2013-07-16 18:50:25 +02:00
ASSERT_EQUALS ( " [test.c:3]: (information) --check-library: Function x() should have <noreturn> configuration \n "
2015-02-03 18:35:52 +01:00
" [test.c:4]: (information) --check-library: Function x() should have <use>/<leak-ignore> configuration \n " ,
2013-07-16 18:50:25 +02:00
errout . str ( ) ) ;
2012-05-26 08:53:46 +02:00
}
2014-11-20 14:20:09 +01:00
void configuration2 ( ) {
2012-05-26 08:53:46 +02:00
// possible leak. If the function 'x' deallocates the pointer or
// takes the address, there is no leak.
check ( " void f() { \n "
" char *p = malloc(10); \n "
" x(&p); \n "
" } " ) ;
2013-07-16 18:50:25 +02:00
ASSERT_EQUALS ( " [test.c:3]: (information) --check-library: Function x() should have <noreturn> configuration \n "
2015-02-03 18:35:52 +01:00
" [test.c:4]: (information) --check-library: Function x() should have <use>/<leak-ignore> configuration \n " ,
2013-07-16 18:50:25 +02:00
errout . str ( ) ) ;
2012-05-26 08:53:46 +02:00
}
2014-11-20 14:20:09 +01:00
void configuration3 ( ) {
2012-05-26 08:53:46 +02:00
check ( " void f() { \n "
" char *p = malloc(10); \n "
" if (set_data(p)) { } \n "
" } " ) ;
2015-02-03 18:35:52 +01:00
ASSERT_EQUALS ( " [test.c:4]: (information) --check-library: Function set_data() should have <use>/<leak-ignore> configuration \n " , errout . str ( ) ) ;
2012-05-26 08:53:46 +02:00
check ( " void f() { \n "
" char *p = malloc(10); \n "
" if (set_data(p)) { return; } \n "
" } " ) ;
2015-02-03 18:35:52 +01:00
ASSERT_EQUALS ( " [test.c:3]: (information) --check-library: Function set_data() should have <use>/<leak-ignore> configuration \n "
" [test.c:4]: (information) --check-library: Function set_data() should have <use>/<leak-ignore> configuration \n "
2012-05-26 08:53:46 +02:00
, errout . str ( ) ) ;
}
2014-11-20 14:20:09 +01:00
void configuration4 ( ) {
2012-05-26 08:53:46 +02:00
check ( " void f() { \n "
" char *p = malloc(10); \n "
" int ret = set_data(p); \n "
" return ret; \n "
" } " ) ;
2015-02-03 18:35:52 +01:00
ASSERT_EQUALS ( " [test.c:4]: (information) --check-library: Function set_data() should have <use>/<leak-ignore> configuration \n " , errout . str ( ) ) ;
2012-05-26 08:53:46 +02:00
}
2012-08-26 11:39:17 +02:00
2014-11-20 14:20:09 +01:00
void ptrptr ( ) {
2012-08-26 11:39:17 +02:00
check ( " void f() { \n "
" char **p = malloc(10); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.c:3]: (error) Memory leak: p \n " , errout . str ( ) ) ;
}
2014-09-30 13:02:02 +02:00
2014-11-20 14:20:09 +01:00
void nestedAllocation ( ) {
2014-09-30 13:02:02 +02:00
check ( " void QueueDSMCCPacket(unsigned char *data, int length) { \n "
" unsigned char *dataCopy = malloc(length * sizeof(unsigned char)); \n "
" m_dsmccQueue.enqueue(new DSMCCPacket(dataCopy)); \n "
" } " ) ;
2015-02-03 18:35:52 +01:00
ASSERT_EQUALS ( " [test.c:4]: (information) --check-library: Function DSMCCPacket() should have <use>/<leak-ignore> configuration \n " , errout . str ( ) ) ;
2014-09-30 13:02:02 +02:00
check ( " void QueueDSMCCPacket(unsigned char *data, int length) { \n "
" unsigned char *dataCopy = malloc(length * sizeof(unsigned char)); \n "
" m_dsmccQueue.enqueue(new DSMCCPacket(somethingunrelated)); \n "
" } " ) ;
ASSERT_EQUALS ( " [test.c:4]: (error) Memory leak: dataCopy \n " , errout . str ( ) ) ;
}
2012-05-26 08:53:46 +02:00
} ;
REGISTER_TEST ( TestLeakAutoVar )