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 | //-------------------------------------------------- |
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 | |
15 | void testMallocLeak() { |
16 | int *p = (int *)malloc(sizeof(int)); |
17 | } // expected-warning{{Potential leak of memory pointed to by 'p'}} |
18 | |
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 | |
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 | |
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 | //----------------------------------------------------------------- |
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 | //---------------------------------------------------------------- |
46 | void testNewDoubleFree() { |
47 | int *p = new int; |
48 | delete p; |
49 | delete p; // expected-warning{{Attempt to free released memory}} |
50 | } |
51 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | } |
100 | int *allocIntArray(unsigned c) { |
101 | return new int[c]; |
102 | } |
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 | |