1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator,cplusplus.NewDelete -std=c++11 -verify %s
2 // RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator,cplusplus.NewDelete,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -verify %s
3 
4 #include "Inputs/system-header-simulator-for-malloc.h"
5 
6 //--------------------------------------------------
7 // Check that unix.Malloc catches all types of bugs.
8 //--------------------------------------------------
testMallocDoubleFree()9 void testMallocDoubleFree() {
10   int *p = (int *)malloc(sizeof(int));
11   free(p);
12   free(p); // expected-warning{{Attempt to free released memory}}
13 }
14 
testMallocLeak()15 void testMallocLeak() {
16   int *p = (int *)malloc(sizeof(int));
17 } // expected-warning{{Potential leak of memory pointed to by 'p'}}
18 
testMallocUseAfterFree()19 void testMallocUseAfterFree() {
20   int *p = (int *)malloc(sizeof(int));
21   free(p);
22   int j = *p; // expected-warning{{Use of memory after it is freed}}
23 }
24 
testMallocBadFree()25 void testMallocBadFree() {
26   int i;
27   free(&i); // expected-warning{{Argument to free() is the address of the local variable 'i', which is not memory allocated by malloc()}}
28 }
29 
testMallocOffsetFree()30 void testMallocOffsetFree() {
31   int *p = (int *)malloc(sizeof(int));
32   free(++p); // expected-warning{{Argument to free() is offset by 4 bytes from the start of memory allocated by malloc()}}
33 }
34 
35 //-----------------------------------------------------------------
36 // Check that unix.MismatchedDeallocator catches all types of bugs.
37 //-----------------------------------------------------------------
testMismatchedDeallocator()38 void testMismatchedDeallocator() {
39   int *x = (int *)malloc(sizeof(int));
40   delete x; // expected-warning{{Memory allocated by malloc() should be deallocated by free(), not 'delete'}}
41 }
42 
43 //----------------------------------------------------------------
44 // Check that alpha.cplusplus.NewDelete catches all types of bugs.
45 //----------------------------------------------------------------
testNewDoubleFree()46 void testNewDoubleFree() {
47   int *p = new int;
48   delete p;
49   delete p; // expected-warning{{Attempt to free released memory}}
50 }
51 
testNewLeak()52 void testNewLeak() {
53   int *p = new int;
54 }
55 #ifdef LEAKS
56 // expected-warning@-2 {{Potential leak of memory pointed to by 'p'}}
57 #endif
58 
testNewUseAfterFree()59 void testNewUseAfterFree() {
60   int *p = (int *)operator new(0);
61   delete p;
62   int j = *p; // expected-warning{{Use of memory after it is freed}}
63 }
64 
testNewBadFree()65 void testNewBadFree() {
66   int i;
67   delete &i; // expected-warning{{Argument to 'delete' is the address of the local variable 'i', which is not memory allocated by 'new'}}
68 }
69 
testNewOffsetFree()70 void testNewOffsetFree() {
71   int *p = new int;
72   operator delete(++p); // expected-warning{{Argument to operator delete is offset by 4 bytes from the start of memory allocated by 'new'}}
73 }
74 
75 //----------------------------------------------------------------
76 // Test that we check for free errors on escaped pointers.
77 //----------------------------------------------------------------
78 void changePtr(int **p);
79 static int *globalPtr;
80 void changePointee(int *p);
81 
testMismatchedChangePtrThroughCall()82 void testMismatchedChangePtrThroughCall() {
83   int *p = (int*)malloc(sizeof(int)*4);
84   changePtr(&p);
85   delete p; // no-warning the value of the pointer might have changed
86 }
87 
testMismatchedChangePointeeThroughCall()88 void testMismatchedChangePointeeThroughCall() {
89   int *p = (int*)malloc(sizeof(int)*4);
90   changePointee(p);
91   delete p; // expected-warning{{Memory allocated by malloc() should be deallocated by free(), not 'delete'}}
92 }
93 
testShouldReportDoubleFreeNotMismatched()94 void testShouldReportDoubleFreeNotMismatched() {
95   int *p = (int*)malloc(sizeof(int)*4);
96   globalPtr = p;
97   free(p);
98   delete globalPtr; // expected-warning {{Attempt to free released memory}}
99 }
allocIntArray(unsigned c)100 int *allocIntArray(unsigned c) {
101   return new int[c];
102 }
testMismatchedChangePointeeThroughAssignment()103 void testMismatchedChangePointeeThroughAssignment() {
104   int *arr = allocIntArray(4);
105   globalPtr = arr;
106   delete arr; // expected-warning{{Memory allocated by 'new[]' should be deallocated by 'delete[]', not 'delete'}}
107 }
108