1*0a6a1f1dSLionel Sambuc // RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=destructors,cfg-temporary-dtors=true -Wno-null-dereference -verify %s
2f4a2713aSLionel Sambuc
3f4a2713aSLionel Sambuc void clang_analyzer_eval(bool);
4f4a2713aSLionel Sambuc void clang_analyzer_checkInlined(bool);
5f4a2713aSLionel Sambuc
6f4a2713aSLionel Sambuc class A {
7f4a2713aSLionel Sambuc public:
~A()8f4a2713aSLionel Sambuc ~A() {
9f4a2713aSLionel Sambuc int *x = 0;
10f4a2713aSLionel Sambuc *x = 3; // expected-warning{{Dereference of null pointer}}
11f4a2713aSLionel Sambuc }
12f4a2713aSLionel Sambuc };
13f4a2713aSLionel Sambuc
main()14f4a2713aSLionel Sambuc int main() {
15f4a2713aSLionel Sambuc A a;
16f4a2713aSLionel Sambuc }
17f4a2713aSLionel Sambuc
18f4a2713aSLionel Sambuc
19f4a2713aSLionel Sambuc typedef __typeof(sizeof(int)) size_t;
20f4a2713aSLionel Sambuc void *malloc(size_t);
21f4a2713aSLionel Sambuc void free(void *);
22f4a2713aSLionel Sambuc
23f4a2713aSLionel Sambuc class SmartPointer {
24f4a2713aSLionel Sambuc void *X;
25f4a2713aSLionel Sambuc public:
SmartPointer(void * x)26f4a2713aSLionel Sambuc SmartPointer(void *x) : X(x) {}
~SmartPointer()27f4a2713aSLionel Sambuc ~SmartPointer() {
28f4a2713aSLionel Sambuc free(X);
29f4a2713aSLionel Sambuc }
30f4a2713aSLionel Sambuc };
31f4a2713aSLionel Sambuc
testSmartPointer()32f4a2713aSLionel Sambuc void testSmartPointer() {
33f4a2713aSLionel Sambuc char *mem = (char*)malloc(4);
34f4a2713aSLionel Sambuc {
35f4a2713aSLionel Sambuc SmartPointer Deleter(mem);
36f4a2713aSLionel Sambuc // destructor called here
37f4a2713aSLionel Sambuc }
38f4a2713aSLionel Sambuc *mem = 0; // expected-warning{{Use of memory after it is freed}}
39f4a2713aSLionel Sambuc }
40f4a2713aSLionel Sambuc
41f4a2713aSLionel Sambuc
42f4a2713aSLionel Sambuc void doSomething();
testSmartPointer2()43f4a2713aSLionel Sambuc void testSmartPointer2() {
44f4a2713aSLionel Sambuc char *mem = (char*)malloc(4);
45f4a2713aSLionel Sambuc {
46f4a2713aSLionel Sambuc SmartPointer Deleter(mem);
47f4a2713aSLionel Sambuc // Remove dead bindings...
48f4a2713aSLionel Sambuc doSomething();
49f4a2713aSLionel Sambuc // destructor called here
50f4a2713aSLionel Sambuc }
51f4a2713aSLionel Sambuc *mem = 0; // expected-warning{{Use of memory after it is freed}}
52f4a2713aSLionel Sambuc }
53f4a2713aSLionel Sambuc
54f4a2713aSLionel Sambuc
55f4a2713aSLionel Sambuc class Subclass : public SmartPointer {
56f4a2713aSLionel Sambuc public:
Subclass(void * x)57f4a2713aSLionel Sambuc Subclass(void *x) : SmartPointer(x) {}
58f4a2713aSLionel Sambuc };
59f4a2713aSLionel Sambuc
testSubclassSmartPointer()60f4a2713aSLionel Sambuc void testSubclassSmartPointer() {
61f4a2713aSLionel Sambuc char *mem = (char*)malloc(4);
62f4a2713aSLionel Sambuc {
63f4a2713aSLionel Sambuc Subclass Deleter(mem);
64f4a2713aSLionel Sambuc // Remove dead bindings...
65f4a2713aSLionel Sambuc doSomething();
66f4a2713aSLionel Sambuc // destructor called here
67f4a2713aSLionel Sambuc }
68f4a2713aSLionel Sambuc *mem = 0; // expected-warning{{Use of memory after it is freed}}
69f4a2713aSLionel Sambuc }
70f4a2713aSLionel Sambuc
71f4a2713aSLionel Sambuc
72f4a2713aSLionel Sambuc class MultipleInheritance : public Subclass, public SmartPointer {
73f4a2713aSLionel Sambuc public:
MultipleInheritance(void * a,void * b)74f4a2713aSLionel Sambuc MultipleInheritance(void *a, void *b) : Subclass(a), SmartPointer(b) {}
75f4a2713aSLionel Sambuc };
76f4a2713aSLionel Sambuc
testMultipleInheritance1()77f4a2713aSLionel Sambuc void testMultipleInheritance1() {
78f4a2713aSLionel Sambuc char *mem = (char*)malloc(4);
79f4a2713aSLionel Sambuc {
80f4a2713aSLionel Sambuc MultipleInheritance Deleter(mem, 0);
81f4a2713aSLionel Sambuc // Remove dead bindings...
82f4a2713aSLionel Sambuc doSomething();
83f4a2713aSLionel Sambuc // destructor called here
84f4a2713aSLionel Sambuc }
85f4a2713aSLionel Sambuc *mem = 0; // expected-warning{{Use of memory after it is freed}}
86f4a2713aSLionel Sambuc }
87f4a2713aSLionel Sambuc
testMultipleInheritance2()88f4a2713aSLionel Sambuc void testMultipleInheritance2() {
89f4a2713aSLionel Sambuc char *mem = (char*)malloc(4);
90f4a2713aSLionel Sambuc {
91f4a2713aSLionel Sambuc MultipleInheritance Deleter(0, mem);
92f4a2713aSLionel Sambuc // Remove dead bindings...
93f4a2713aSLionel Sambuc doSomething();
94f4a2713aSLionel Sambuc // destructor called here
95f4a2713aSLionel Sambuc }
96f4a2713aSLionel Sambuc *mem = 0; // expected-warning{{Use of memory after it is freed}}
97f4a2713aSLionel Sambuc }
98f4a2713aSLionel Sambuc
testMultipleInheritance3()99f4a2713aSLionel Sambuc void testMultipleInheritance3() {
100f4a2713aSLionel Sambuc char *mem = (char*)malloc(4);
101f4a2713aSLionel Sambuc {
102f4a2713aSLionel Sambuc MultipleInheritance Deleter(mem, mem);
103f4a2713aSLionel Sambuc // Remove dead bindings...
104f4a2713aSLionel Sambuc doSomething();
105f4a2713aSLionel Sambuc // destructor called here
106f4a2713aSLionel Sambuc // expected-warning@28 {{Attempt to free released memory}}
107f4a2713aSLionel Sambuc }
108f4a2713aSLionel Sambuc }
109f4a2713aSLionel Sambuc
110f4a2713aSLionel Sambuc
111f4a2713aSLionel Sambuc class SmartPointerMember {
112f4a2713aSLionel Sambuc SmartPointer P;
113f4a2713aSLionel Sambuc public:
SmartPointerMember(void * x)114f4a2713aSLionel Sambuc SmartPointerMember(void *x) : P(x) {}
115f4a2713aSLionel Sambuc };
116f4a2713aSLionel Sambuc
testSmartPointerMember()117f4a2713aSLionel Sambuc void testSmartPointerMember() {
118f4a2713aSLionel Sambuc char *mem = (char*)malloc(4);
119f4a2713aSLionel Sambuc {
120f4a2713aSLionel Sambuc SmartPointerMember Deleter(mem);
121f4a2713aSLionel Sambuc // Remove dead bindings...
122f4a2713aSLionel Sambuc doSomething();
123f4a2713aSLionel Sambuc // destructor called here
124f4a2713aSLionel Sambuc }
125f4a2713aSLionel Sambuc *mem = 0; // expected-warning{{Use of memory after it is freed}}
126f4a2713aSLionel Sambuc }
127f4a2713aSLionel Sambuc
128f4a2713aSLionel Sambuc
129f4a2713aSLionel Sambuc struct IntWrapper {
IntWrapperIntWrapper130f4a2713aSLionel Sambuc IntWrapper() : x(0) {}
131f4a2713aSLionel Sambuc ~IntWrapper();
132f4a2713aSLionel Sambuc int *x;
133f4a2713aSLionel Sambuc };
134f4a2713aSLionel Sambuc
testArrayInvalidation()135f4a2713aSLionel Sambuc void testArrayInvalidation() {
136f4a2713aSLionel Sambuc int i = 42;
137f4a2713aSLionel Sambuc int j = 42;
138f4a2713aSLionel Sambuc
139f4a2713aSLionel Sambuc {
140f4a2713aSLionel Sambuc IntWrapper arr[2];
141f4a2713aSLionel Sambuc
142f4a2713aSLionel Sambuc // There should be no undefined value warnings here.
143f4a2713aSLionel Sambuc // Eventually these should be TRUE as well, but right now
144f4a2713aSLionel Sambuc // we can't handle array constructors.
145f4a2713aSLionel Sambuc clang_analyzer_eval(arr[0].x == 0); // expected-warning{{UNKNOWN}}
146f4a2713aSLionel Sambuc clang_analyzer_eval(arr[1].x == 0); // expected-warning{{UNKNOWN}}
147f4a2713aSLionel Sambuc
148f4a2713aSLionel Sambuc arr[0].x = &i;
149f4a2713aSLionel Sambuc arr[1].x = &j;
150f4a2713aSLionel Sambuc clang_analyzer_eval(*arr[0].x == 42); // expected-warning{{TRUE}}
151f4a2713aSLionel Sambuc clang_analyzer_eval(*arr[1].x == 42); // expected-warning{{TRUE}}
152f4a2713aSLionel Sambuc }
153f4a2713aSLionel Sambuc
154f4a2713aSLionel Sambuc // The destructors should have invalidated i and j.
155f4a2713aSLionel Sambuc clang_analyzer_eval(i == 42); // expected-warning{{UNKNOWN}}
156f4a2713aSLionel Sambuc clang_analyzer_eval(j == 42); // expected-warning{{UNKNOWN}}
157f4a2713aSLionel Sambuc }
158f4a2713aSLionel Sambuc
159f4a2713aSLionel Sambuc
160f4a2713aSLionel Sambuc
161f4a2713aSLionel Sambuc // Don't crash on a default argument inside an initializer.
162f4a2713aSLionel Sambuc struct DefaultArg {
DefaultArgDefaultArg163f4a2713aSLionel Sambuc DefaultArg(int x = 0) {}
164f4a2713aSLionel Sambuc ~DefaultArg();
165f4a2713aSLionel Sambuc };
166f4a2713aSLionel Sambuc
167f4a2713aSLionel Sambuc struct InheritsDefaultArg : DefaultArg {
InheritsDefaultArgInheritsDefaultArg168f4a2713aSLionel Sambuc InheritsDefaultArg() {}
169f4a2713aSLionel Sambuc virtual ~InheritsDefaultArg();
170f4a2713aSLionel Sambuc };
171f4a2713aSLionel Sambuc
testDefaultArg()172f4a2713aSLionel Sambuc void testDefaultArg() {
173f4a2713aSLionel Sambuc InheritsDefaultArg a;
174f4a2713aSLionel Sambuc // Force a bug to be emitted.
175f4a2713aSLionel Sambuc *(char *)0 = 1; // expected-warning{{Dereference of null pointer}}
176f4a2713aSLionel Sambuc }
177f4a2713aSLionel Sambuc
178f4a2713aSLionel Sambuc
179f4a2713aSLionel Sambuc namespace DestructorVirtualCalls {
180f4a2713aSLionel Sambuc class A {
181f4a2713aSLionel Sambuc public:
182f4a2713aSLionel Sambuc int *out1, *out2, *out3;
183f4a2713aSLionel Sambuc
get()184f4a2713aSLionel Sambuc virtual int get() { return 1; }
185f4a2713aSLionel Sambuc
~A()186f4a2713aSLionel Sambuc ~A() {
187f4a2713aSLionel Sambuc *out1 = get();
188f4a2713aSLionel Sambuc }
189f4a2713aSLionel Sambuc };
190f4a2713aSLionel Sambuc
191f4a2713aSLionel Sambuc class B : public A {
192f4a2713aSLionel Sambuc public:
get()193f4a2713aSLionel Sambuc virtual int get() { return 2; }
194f4a2713aSLionel Sambuc
~B()195f4a2713aSLionel Sambuc ~B() {
196f4a2713aSLionel Sambuc *out2 = get();
197f4a2713aSLionel Sambuc }
198f4a2713aSLionel Sambuc };
199f4a2713aSLionel Sambuc
200f4a2713aSLionel Sambuc class C : public B {
201f4a2713aSLionel Sambuc public:
get()202f4a2713aSLionel Sambuc virtual int get() { return 3; }
203f4a2713aSLionel Sambuc
~C()204f4a2713aSLionel Sambuc ~C() {
205f4a2713aSLionel Sambuc *out3 = get();
206f4a2713aSLionel Sambuc }
207f4a2713aSLionel Sambuc };
208f4a2713aSLionel Sambuc
test()209f4a2713aSLionel Sambuc void test() {
210f4a2713aSLionel Sambuc int a, b, c;
211f4a2713aSLionel Sambuc
212f4a2713aSLionel Sambuc // New scope for the C object.
213f4a2713aSLionel Sambuc {
214f4a2713aSLionel Sambuc C obj;
215f4a2713aSLionel Sambuc clang_analyzer_eval(obj.get() == 3); // expected-warning{{TRUE}}
216f4a2713aSLionel Sambuc
217f4a2713aSLionel Sambuc // Sanity check for devirtualization.
218f4a2713aSLionel Sambuc A *base = &obj;
219f4a2713aSLionel Sambuc clang_analyzer_eval(base->get() == 3); // expected-warning{{TRUE}}
220f4a2713aSLionel Sambuc
221f4a2713aSLionel Sambuc obj.out1 = &a;
222f4a2713aSLionel Sambuc obj.out2 = &b;
223f4a2713aSLionel Sambuc obj.out3 = &c;
224f4a2713aSLionel Sambuc }
225f4a2713aSLionel Sambuc
226f4a2713aSLionel Sambuc clang_analyzer_eval(a == 1); // expected-warning{{TRUE}}
227f4a2713aSLionel Sambuc clang_analyzer_eval(b == 2); // expected-warning{{TRUE}}
228f4a2713aSLionel Sambuc clang_analyzer_eval(c == 3); // expected-warning{{TRUE}}
229f4a2713aSLionel Sambuc }
230f4a2713aSLionel Sambuc }
231f4a2713aSLionel Sambuc
232f4a2713aSLionel Sambuc
233f4a2713aSLionel Sambuc namespace DestructorsShouldNotAffectReturnValues {
234f4a2713aSLionel Sambuc class Dtor {
235f4a2713aSLionel Sambuc public:
~Dtor()236f4a2713aSLionel Sambuc ~Dtor() {
237f4a2713aSLionel Sambuc clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
238f4a2713aSLionel Sambuc }
239f4a2713aSLionel Sambuc };
240f4a2713aSLionel Sambuc
allocate()241f4a2713aSLionel Sambuc void *allocate() {
242f4a2713aSLionel Sambuc Dtor d;
243f4a2713aSLionel Sambuc return malloc(4); // no-warning
244f4a2713aSLionel Sambuc }
245f4a2713aSLionel Sambuc
test()246f4a2713aSLionel Sambuc void test() {
247f4a2713aSLionel Sambuc // At one point we had an issue where the statements inside an
248f4a2713aSLionel Sambuc // inlined destructor kept us from finding the return statement,
249f4a2713aSLionel Sambuc // leading the analyzer to believe that the malloc'd memory had leaked.
250f4a2713aSLionel Sambuc void *p = allocate();
251f4a2713aSLionel Sambuc free(p); // no-warning
252f4a2713aSLionel Sambuc }
253f4a2713aSLionel Sambuc }
254f4a2713aSLionel Sambuc
255f4a2713aSLionel Sambuc namespace MultipleInheritanceVirtualDtors {
256f4a2713aSLionel Sambuc class VirtualDtor {
257f4a2713aSLionel Sambuc protected:
~VirtualDtor()258f4a2713aSLionel Sambuc virtual ~VirtualDtor() {
259f4a2713aSLionel Sambuc clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
260f4a2713aSLionel Sambuc }
261f4a2713aSLionel Sambuc };
262f4a2713aSLionel Sambuc
263f4a2713aSLionel Sambuc class NonVirtualDtor {
264f4a2713aSLionel Sambuc protected:
~NonVirtualDtor()265f4a2713aSLionel Sambuc ~NonVirtualDtor() {
266f4a2713aSLionel Sambuc clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
267f4a2713aSLionel Sambuc }
268f4a2713aSLionel Sambuc };
269f4a2713aSLionel Sambuc
270f4a2713aSLionel Sambuc class SubclassA : public VirtualDtor, public NonVirtualDtor {
271f4a2713aSLionel Sambuc public:
~SubclassA()272f4a2713aSLionel Sambuc virtual ~SubclassA() {}
273f4a2713aSLionel Sambuc };
274f4a2713aSLionel Sambuc class SubclassB : public NonVirtualDtor, public VirtualDtor {
275f4a2713aSLionel Sambuc public:
~SubclassB()276f4a2713aSLionel Sambuc virtual ~SubclassB() {}
277f4a2713aSLionel Sambuc };
278f4a2713aSLionel Sambuc
test()279f4a2713aSLionel Sambuc void test() {
280f4a2713aSLionel Sambuc SubclassA a;
281f4a2713aSLionel Sambuc SubclassB b;
282f4a2713aSLionel Sambuc }
283f4a2713aSLionel Sambuc }
284f4a2713aSLionel Sambuc
285f4a2713aSLionel Sambuc namespace ExplicitDestructorCall {
286f4a2713aSLionel Sambuc class VirtualDtor {
287f4a2713aSLionel Sambuc public:
~VirtualDtor()288f4a2713aSLionel Sambuc virtual ~VirtualDtor() {
289f4a2713aSLionel Sambuc clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
290f4a2713aSLionel Sambuc }
291f4a2713aSLionel Sambuc };
292f4a2713aSLionel Sambuc
293f4a2713aSLionel Sambuc class Subclass : public VirtualDtor {
294f4a2713aSLionel Sambuc public:
~Subclass()295f4a2713aSLionel Sambuc virtual ~Subclass() {
296f4a2713aSLionel Sambuc clang_analyzer_checkInlined(false); // no-warning
297f4a2713aSLionel Sambuc }
298f4a2713aSLionel Sambuc };
299f4a2713aSLionel Sambuc
destroy(Subclass * obj)300f4a2713aSLionel Sambuc void destroy(Subclass *obj) {
301f4a2713aSLionel Sambuc obj->VirtualDtor::~VirtualDtor();
302f4a2713aSLionel Sambuc }
303f4a2713aSLionel Sambuc }
304f4a2713aSLionel Sambuc
305f4a2713aSLionel Sambuc
306f4a2713aSLionel Sambuc namespace MultidimensionalArrays {
testArrayInvalidation()307f4a2713aSLionel Sambuc void testArrayInvalidation() {
308f4a2713aSLionel Sambuc int i = 42;
309f4a2713aSLionel Sambuc int j = 42;
310f4a2713aSLionel Sambuc
311f4a2713aSLionel Sambuc {
312f4a2713aSLionel Sambuc IntWrapper arr[2][2];
313f4a2713aSLionel Sambuc
314f4a2713aSLionel Sambuc // There should be no undefined value warnings here.
315f4a2713aSLionel Sambuc // Eventually these should be TRUE as well, but right now
316f4a2713aSLionel Sambuc // we can't handle array constructors.
317f4a2713aSLionel Sambuc clang_analyzer_eval(arr[0][0].x == 0); // expected-warning{{UNKNOWN}}
318f4a2713aSLionel Sambuc clang_analyzer_eval(arr[1][1].x == 0); // expected-warning{{UNKNOWN}}
319f4a2713aSLionel Sambuc
320f4a2713aSLionel Sambuc arr[0][0].x = &i;
321f4a2713aSLionel Sambuc arr[1][1].x = &j;
322f4a2713aSLionel Sambuc clang_analyzer_eval(*arr[0][0].x == 42); // expected-warning{{TRUE}}
323f4a2713aSLionel Sambuc clang_analyzer_eval(*arr[1][1].x == 42); // expected-warning{{TRUE}}
324f4a2713aSLionel Sambuc }
325f4a2713aSLionel Sambuc
326f4a2713aSLionel Sambuc // The destructors should have invalidated i and j.
327f4a2713aSLionel Sambuc clang_analyzer_eval(i == 42); // expected-warning{{UNKNOWN}}
328f4a2713aSLionel Sambuc clang_analyzer_eval(j == 42); // expected-warning{{UNKNOWN}}
329f4a2713aSLionel Sambuc }
330f4a2713aSLionel Sambuc }
331f4a2713aSLionel Sambuc
332f4a2713aSLionel Sambuc namespace LifetimeExtension {
333f4a2713aSLionel Sambuc struct IntWrapper {
334f4a2713aSLionel Sambuc int x;
IntWrapperLifetimeExtension::IntWrapper335f4a2713aSLionel Sambuc IntWrapper(int y) : x(y) {}
IntWrapperLifetimeExtension::IntWrapper336f4a2713aSLionel Sambuc IntWrapper() {
337f4a2713aSLionel Sambuc extern void use(int);
338f4a2713aSLionel Sambuc use(x); // no-warning
339f4a2713aSLionel Sambuc }
340f4a2713aSLionel Sambuc };
341f4a2713aSLionel Sambuc
342f4a2713aSLionel Sambuc struct DerivedWrapper : public IntWrapper {
DerivedWrapperLifetimeExtension::DerivedWrapper343f4a2713aSLionel Sambuc DerivedWrapper(int y) : IntWrapper(y) {}
344f4a2713aSLionel Sambuc };
345f4a2713aSLionel Sambuc
get()346f4a2713aSLionel Sambuc DerivedWrapper get() {
347f4a2713aSLionel Sambuc return DerivedWrapper(1);
348f4a2713aSLionel Sambuc }
349f4a2713aSLionel Sambuc
test()350f4a2713aSLionel Sambuc void test() {
351f4a2713aSLionel Sambuc const DerivedWrapper &d = get(); // lifetime extended here
352f4a2713aSLionel Sambuc }
353f4a2713aSLionel Sambuc
354f4a2713aSLionel Sambuc
355f4a2713aSLionel Sambuc class SaveOnDestruct {
356f4a2713aSLionel Sambuc public:
357f4a2713aSLionel Sambuc static int lastOutput;
358f4a2713aSLionel Sambuc int value;
359f4a2713aSLionel Sambuc
360f4a2713aSLionel Sambuc SaveOnDestruct();
~SaveOnDestruct()361f4a2713aSLionel Sambuc ~SaveOnDestruct() {
362f4a2713aSLionel Sambuc lastOutput = value;
363f4a2713aSLionel Sambuc }
364f4a2713aSLionel Sambuc };
365f4a2713aSLionel Sambuc
testSimple()366f4a2713aSLionel Sambuc void testSimple() {
367f4a2713aSLionel Sambuc {
368f4a2713aSLionel Sambuc const SaveOnDestruct &obj = SaveOnDestruct();
369f4a2713aSLionel Sambuc if (obj.value != 42)
370f4a2713aSLionel Sambuc return;
371f4a2713aSLionel Sambuc // destructor called here
372f4a2713aSLionel Sambuc }
373f4a2713aSLionel Sambuc
374f4a2713aSLionel Sambuc clang_analyzer_eval(SaveOnDestruct::lastOutput == 42); // expected-warning{{TRUE}}
375f4a2713aSLionel Sambuc }
376f4a2713aSLionel Sambuc
377*0a6a1f1dSLionel Sambuc struct NRCheck {
378*0a6a1f1dSLionel Sambuc bool bool_;
NRCheckLifetimeExtension::NRCheck379*0a6a1f1dSLionel Sambuc NRCheck():bool_(true) {}
380*0a6a1f1dSLionel Sambuc ~NRCheck() __attribute__((noreturn));
operator boolLifetimeExtension::NRCheck381*0a6a1f1dSLionel Sambuc operator bool() const { return bool_; }
382*0a6a1f1dSLionel Sambuc };
383*0a6a1f1dSLionel Sambuc
384*0a6a1f1dSLionel Sambuc struct CheckAutoDestructor {
385*0a6a1f1dSLionel Sambuc bool bool_;
CheckAutoDestructorLifetimeExtension::CheckAutoDestructor386*0a6a1f1dSLionel Sambuc CheckAutoDestructor():bool_(true) {}
operator boolLifetimeExtension::CheckAutoDestructor387*0a6a1f1dSLionel Sambuc operator bool() const { return bool_; }
388*0a6a1f1dSLionel Sambuc };
389*0a6a1f1dSLionel Sambuc
390*0a6a1f1dSLionel Sambuc struct CheckCustomDestructor {
391*0a6a1f1dSLionel Sambuc bool bool_;
CheckCustomDestructorLifetimeExtension::CheckCustomDestructor392*0a6a1f1dSLionel Sambuc CheckCustomDestructor():bool_(true) {}
393*0a6a1f1dSLionel Sambuc ~CheckCustomDestructor();
operator boolLifetimeExtension::CheckCustomDestructor394*0a6a1f1dSLionel Sambuc operator bool() const { return bool_; }
395*0a6a1f1dSLionel Sambuc };
396*0a6a1f1dSLionel Sambuc
testUnnamedNR()397*0a6a1f1dSLionel Sambuc bool testUnnamedNR() {
398*0a6a1f1dSLionel Sambuc if (NRCheck())
399*0a6a1f1dSLionel Sambuc return true;
400*0a6a1f1dSLionel Sambuc return false;
401*0a6a1f1dSLionel Sambuc }
402*0a6a1f1dSLionel Sambuc
testNamedNR()403*0a6a1f1dSLionel Sambuc bool testNamedNR() {
404*0a6a1f1dSLionel Sambuc if (NRCheck c = NRCheck())
405*0a6a1f1dSLionel Sambuc return true;
406*0a6a1f1dSLionel Sambuc return false;
407*0a6a1f1dSLionel Sambuc }
408*0a6a1f1dSLionel Sambuc
testUnnamedAutoDestructor()409*0a6a1f1dSLionel Sambuc bool testUnnamedAutoDestructor() {
410*0a6a1f1dSLionel Sambuc if (CheckAutoDestructor())
411*0a6a1f1dSLionel Sambuc return true;
412*0a6a1f1dSLionel Sambuc return false;
413*0a6a1f1dSLionel Sambuc }
414*0a6a1f1dSLionel Sambuc
testNamedAutoDestructor()415*0a6a1f1dSLionel Sambuc bool testNamedAutoDestructor() {
416*0a6a1f1dSLionel Sambuc if (CheckAutoDestructor c = CheckAutoDestructor())
417*0a6a1f1dSLionel Sambuc return true;
418*0a6a1f1dSLionel Sambuc return false;
419*0a6a1f1dSLionel Sambuc }
420*0a6a1f1dSLionel Sambuc
testUnnamedCustomDestructor()421*0a6a1f1dSLionel Sambuc bool testUnnamedCustomDestructor() {
422*0a6a1f1dSLionel Sambuc if (CheckCustomDestructor())
423*0a6a1f1dSLionel Sambuc return true;
424*0a6a1f1dSLionel Sambuc return false;
425*0a6a1f1dSLionel Sambuc }
426*0a6a1f1dSLionel Sambuc
427*0a6a1f1dSLionel Sambuc // This case used to cause an unexpected "Undefined or garbage value returned
428*0a6a1f1dSLionel Sambuc // to caller" warning
testNamedCustomDestructor()429*0a6a1f1dSLionel Sambuc bool testNamedCustomDestructor() {
430*0a6a1f1dSLionel Sambuc if (CheckCustomDestructor c = CheckCustomDestructor())
431*0a6a1f1dSLionel Sambuc return true;
432*0a6a1f1dSLionel Sambuc return false;
433*0a6a1f1dSLionel Sambuc }
434*0a6a1f1dSLionel Sambuc
testMultipleTemporariesCustomDestructor()435*0a6a1f1dSLionel Sambuc bool testMultipleTemporariesCustomDestructor() {
436*0a6a1f1dSLionel Sambuc if (CheckCustomDestructor c = (CheckCustomDestructor(), CheckCustomDestructor()))
437*0a6a1f1dSLionel Sambuc return true;
438*0a6a1f1dSLionel Sambuc return false;
439*0a6a1f1dSLionel Sambuc }
440*0a6a1f1dSLionel Sambuc
441f4a2713aSLionel Sambuc class VirtualDtorBase {
442f4a2713aSLionel Sambuc public:
443f4a2713aSLionel Sambuc int value;
~VirtualDtorBase()444f4a2713aSLionel Sambuc virtual ~VirtualDtorBase() {}
445f4a2713aSLionel Sambuc };
446f4a2713aSLionel Sambuc
447f4a2713aSLionel Sambuc class SaveOnVirtualDestruct : public VirtualDtorBase {
448f4a2713aSLionel Sambuc public:
449f4a2713aSLionel Sambuc static int lastOutput;
450f4a2713aSLionel Sambuc
451f4a2713aSLionel Sambuc SaveOnVirtualDestruct();
~SaveOnVirtualDestruct()452f4a2713aSLionel Sambuc virtual ~SaveOnVirtualDestruct() {
453f4a2713aSLionel Sambuc lastOutput = value;
454f4a2713aSLionel Sambuc }
455f4a2713aSLionel Sambuc };
456f4a2713aSLionel Sambuc
testVirtual()457f4a2713aSLionel Sambuc void testVirtual() {
458f4a2713aSLionel Sambuc {
459f4a2713aSLionel Sambuc const VirtualDtorBase &obj = SaveOnVirtualDestruct();
460f4a2713aSLionel Sambuc if (obj.value != 42)
461f4a2713aSLionel Sambuc return;
462f4a2713aSLionel Sambuc // destructor called here
463f4a2713aSLionel Sambuc }
464f4a2713aSLionel Sambuc
465f4a2713aSLionel Sambuc clang_analyzer_eval(SaveOnVirtualDestruct::lastOutput == 42); // expected-warning{{TRUE}}
466f4a2713aSLionel Sambuc }
467f4a2713aSLionel Sambuc }
468f4a2713aSLionel Sambuc
469f4a2713aSLionel Sambuc namespace NoReturn {
470f4a2713aSLionel Sambuc struct NR {
471f4a2713aSLionel Sambuc ~NR() __attribute__((noreturn));
472f4a2713aSLionel Sambuc };
473f4a2713aSLionel Sambuc
f(int ** x)474f4a2713aSLionel Sambuc void f(int **x) {
475f4a2713aSLionel Sambuc NR nr;
476f4a2713aSLionel Sambuc }
477f4a2713aSLionel Sambuc
g()478f4a2713aSLionel Sambuc void g() {
479f4a2713aSLionel Sambuc int *x;
480f4a2713aSLionel Sambuc f(&x);
481f4a2713aSLionel Sambuc *x = 47; // no warning
482f4a2713aSLionel Sambuc }
483*0a6a1f1dSLionel Sambuc
g2(int * x)484*0a6a1f1dSLionel Sambuc void g2(int *x) {
485*0a6a1f1dSLionel Sambuc if (! x) NR();
486*0a6a1f1dSLionel Sambuc *x = 47; // no warning
487*0a6a1f1dSLionel Sambuc }
488f4a2713aSLionel Sambuc }
489f4a2713aSLionel Sambuc
490f4a2713aSLionel Sambuc namespace PseudoDtor {
491f4a2713aSLionel Sambuc template <typename T>
destroy(T & obj)492f4a2713aSLionel Sambuc void destroy(T &obj) {
493f4a2713aSLionel Sambuc clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
494f4a2713aSLionel Sambuc obj.~T();
495f4a2713aSLionel Sambuc }
496f4a2713aSLionel Sambuc
test()497f4a2713aSLionel Sambuc void test() {
498f4a2713aSLionel Sambuc int i;
499f4a2713aSLionel Sambuc destroy(i);
500f4a2713aSLionel Sambuc clang_analyzer_eval(true); // expected-warning{{TRUE}}
501f4a2713aSLionel Sambuc }
502f4a2713aSLionel Sambuc }
503f4a2713aSLionel Sambuc
504f4a2713aSLionel Sambuc namespace Incomplete {
505f4a2713aSLionel Sambuc class Foo; // expected-note{{forward declaration}}
f(Foo * foo)506f4a2713aSLionel Sambuc void f(Foo *foo) { delete foo; } // expected-warning{{deleting pointer to incomplete type}}
507f4a2713aSLionel Sambuc }
508