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