1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-store region -analyzer-ipa=inlining -cfg-add-implicit-dtors -Wno-null-dereference -verify %s
2 
3 void clang_analyzer_eval(bool);
4 
5 class A {
6 public:
7   ~A() {
8     int *x = 0;
9     *x = 3; // expected-warning{{Dereference of null pointer}}
10   }
11 };
12 
13 int main() {
14   A a;
15 }
16 
17 
18 typedef __typeof(sizeof(int)) size_t;
19 void *malloc(size_t);
20 void free(void *);
21 
22 class SmartPointer {
23   void *X;
24 public:
25   SmartPointer(void *x) : X(x) {}
26   ~SmartPointer() {
27     free(X);
28   }
29 };
30 
31 void testSmartPointer() {
32   char *mem = (char*)malloc(4);
33   {
34     SmartPointer Deleter(mem);
35     // destructor called here
36   }
37   *mem = 0; // expected-warning{{Use of memory after it is freed}}
38 }
39 
40 
41 void doSomething();
42 void testSmartPointer2() {
43   char *mem = (char*)malloc(4);
44   {
45     SmartPointer Deleter(mem);
46     // Remove dead bindings...
47     doSomething();
48     // destructor called here
49   }
50   *mem = 0; // expected-warning{{Use of memory after it is freed}}
51 }
52 
53 
54 class Subclass : public SmartPointer {
55 public:
56   Subclass(void *x) : SmartPointer(x) {}
57 };
58 
59 void testSubclassSmartPointer() {
60   char *mem = (char*)malloc(4);
61   {
62     Subclass Deleter(mem);
63     // Remove dead bindings...
64     doSomething();
65     // destructor called here
66   }
67   *mem = 0; // expected-warning{{Use of memory after it is freed}}
68 }
69 
70 
71 class MultipleInheritance : public Subclass, public SmartPointer {
72 public:
73   MultipleInheritance(void *a, void *b) : Subclass(a), SmartPointer(b) {}
74 };
75 
76 void testMultipleInheritance1() {
77   char *mem = (char*)malloc(4);
78   {
79     MultipleInheritance Deleter(mem, 0);
80     // Remove dead bindings...
81     doSomething();
82     // destructor called here
83   }
84   *mem = 0; // expected-warning{{Use of memory after it is freed}}
85 }
86 
87 void testMultipleInheritance2() {
88   char *mem = (char*)malloc(4);
89   {
90     MultipleInheritance Deleter(0, mem);
91     // Remove dead bindings...
92     doSomething();
93     // destructor called here
94   }
95   *mem = 0; // expected-warning{{Use of memory after it is freed}}
96 }
97 
98 void testMultipleInheritance3() {
99   char *mem = (char*)malloc(4);
100   {
101     MultipleInheritance Deleter(mem, mem);
102     // Remove dead bindings...
103     doSomething();
104     // destructor called here
105     // expected-warning@27 {{Attempt to free released memory}}
106   }
107 }
108 
109 
110 class SmartPointerMember {
111   SmartPointer P;
112 public:
113   SmartPointerMember(void *x) : P(x) {}
114 };
115 
116 void testSmartPointerMember() {
117   char *mem = (char*)malloc(4);
118   {
119     SmartPointerMember Deleter(mem);
120     // Remove dead bindings...
121     doSomething();
122     // destructor called here
123   }
124   *mem = 0; // expected-warning{{Use of memory after it is freed}}
125 }
126 
127 
128 struct IntWrapper {
129   IntWrapper() : x(0) {}
130   ~IntWrapper();
131   int *x;
132 };
133 
134 void testArrayInvalidation() {
135   int i = 42;
136   int j = 42;
137 
138   {
139     IntWrapper arr[2];
140 
141     // There should be no undefined value warnings here.
142     // Eventually these should be TRUE as well, but right now
143     // we can't handle array constructors.
144     clang_analyzer_eval(arr[0].x == 0); // expected-warning{{UNKNOWN}}
145     clang_analyzer_eval(arr[1].x == 0); // expected-warning{{UNKNOWN}}
146 
147     arr[0].x = &i;
148     arr[1].x = &j;
149     clang_analyzer_eval(*arr[0].x == 42); // expected-warning{{TRUE}}
150     clang_analyzer_eval(*arr[1].x == 42); // expected-warning{{TRUE}}
151   }
152 
153   // The destructors should have invalidated i and j.
154   clang_analyzer_eval(i == 42); // expected-warning{{UNKNOWN}}
155   clang_analyzer_eval(j == 42); // expected-warning{{UNKNOWN}}
156 }
157 
158 
159 
160 // Don't crash on a default argument inside an initializer.
161 struct DefaultArg {
162   DefaultArg(int x = 0) {}
163   ~DefaultArg();
164 };
165 
166 struct InheritsDefaultArg : DefaultArg {
167   InheritsDefaultArg() {}
168   virtual ~InheritsDefaultArg();
169 };
170 
171 void testDefaultArg() {
172   InheritsDefaultArg a;
173   // Force a bug to be emitted.
174   *(char *)0 = 1; // expected-warning{{Dereference of null pointer}}
175 }
176 
177 
178 namespace DestructorVirtualCalls {
179   class A {
180   public:
181     int *out1, *out2, *out3;
182 
183     virtual int get() { return 1; }
184 
185     ~A() {
186       *out1 = get();
187     }
188   };
189 
190   class B : public A {
191   public:
192     virtual int get() { return 2; }
193 
194     ~B() {
195       *out2 = get();
196     }
197   };
198 
199   class C : public B {
200   public:
201     virtual int get() { return 3; }
202 
203     ~C() {
204       *out3 = get();
205     }
206   };
207 
208   void test() {
209     int a, b, c;
210 
211     // New scope for the C object.
212     {
213       C obj;
214       clang_analyzer_eval(obj.get() == 3); // expected-warning{{TRUE}}
215 
216       // Sanity check for devirtualization.
217       A *base = &obj;
218       clang_analyzer_eval(base->get() == 3); // expected-warning{{TRUE}}
219 
220       obj.out1 = &a;
221       obj.out2 = &b;
222       obj.out3 = &c;
223     }
224 
225     clang_analyzer_eval(a == 1); // expected-warning{{TRUE}}
226     clang_analyzer_eval(b == 2); // expected-warning{{TRUE}}
227     clang_analyzer_eval(c == 3); // expected-warning{{TRUE}}
228   }
229 }
230