xref: /llvm-project/clang/test/Analysis/dtor-array.cpp (revision 2fb3bec932ede7704724abb71e8270e0b4c201f6)
1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config c++-inlining=destructors -verify -std=c++11 %s
2 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config c++-inlining=destructors -verify -std=c++17 %s
3 
4 using size_t =  __typeof(sizeof(int));
5 
6 void clang_analyzer_eval(bool);
7 void clang_analyzer_checkInlined(bool);
8 void clang_analyzer_warnIfReached();
9 void clang_analyzer_explain(int);
10 
11 int a, b, c, d;
12 
13 struct InlineDtor {
14   static int cnt;
15   static int dtorCalled;
~InlineDtorInlineDtor16   ~InlineDtor() {
17     switch (dtorCalled % 4) {
18     case 0:
19       a = cnt++;
20       break;
21     case 1:
22       b = cnt++;
23       break;
24     case 2:
25       c = cnt++;
26       break;
27     case 3:
28       d = cnt++;
29       break;
30     }
31 
32     ++dtorCalled;
33   }
34 };
35 
36 int InlineDtor::cnt = 0;
37 int InlineDtor::dtorCalled = 0;
38 
foo()39 void foo() {
40   InlineDtor::cnt = 0;
41   InlineDtor::dtorCalled = 0;
42   InlineDtor arr[4];
43 }
44 
testAutoDtor()45 void testAutoDtor() {
46   foo();
47 
48   clang_analyzer_eval(a == 0); // expected-warning {{TRUE}}
49   clang_analyzer_eval(b == 1); // expected-warning {{TRUE}}
50   clang_analyzer_eval(c == 2); // expected-warning {{TRUE}}
51   clang_analyzer_eval(d == 3); // expected-warning {{TRUE}}
52 }
53 
testDeleteDtor()54 void testDeleteDtor() {
55   InlineDtor::cnt = 10;
56   InlineDtor::dtorCalled = 0;
57 
58   InlineDtor *arr = new InlineDtor[4];
59   delete[] arr;
60 
61   clang_analyzer_eval(a == 10); // expected-warning {{TRUE}}
62   clang_analyzer_eval(b == 11); // expected-warning {{TRUE}}
63   clang_analyzer_eval(c == 12); // expected-warning {{TRUE}}
64   clang_analyzer_eval(d == 13); // expected-warning {{TRUE}}
65 }
66 
67 struct MemberDtor {
68   InlineDtor arr[4];
69 };
70 
testMemberDtor()71 void testMemberDtor() {
72   InlineDtor::cnt = 5;
73   InlineDtor::dtorCalled = 0;
74 
75   MemberDtor *MD = new MemberDtor{};
76   delete MD;
77 
78   clang_analyzer_eval(a == 5); // expected-warning {{TRUE}}
79   clang_analyzer_eval(b == 6); // expected-warning {{TRUE}}
80   clang_analyzer_eval(c == 7); // expected-warning {{TRUE}}
81   clang_analyzer_eval(d == 8); // expected-warning {{TRUE}}
82 }
83 
84 struct MultipleMemberDtor
85 {
86   InlineDtor arr[4];
87   InlineDtor arr2[4];
88 };
89 
testMultipleMemberDtor()90 void testMultipleMemberDtor() {
91   InlineDtor::cnt = 30;
92   InlineDtor::dtorCalled = 0;
93 
94   MultipleMemberDtor *MD = new MultipleMemberDtor{};
95   delete MD;
96 
97   clang_analyzer_eval(a == 34); // expected-warning {{TRUE}}
98   clang_analyzer_eval(b == 35); // expected-warning {{TRUE}}
99   clang_analyzer_eval(c == 36); // expected-warning {{TRUE}}
100   clang_analyzer_eval(d == 37); // expected-warning {{TRUE}}
101 }
102 
103 int EvalOrderArr[4];
104 
105 struct EvalOrder
106 {
107   int ctor = 0;
108   static int dtorCalled;
109   static int ctorCalled;
110 
EvalOrderEvalOrder111   EvalOrder() { ctor = ctorCalled++; };
112 
~EvalOrderEvalOrder113   ~EvalOrder() { EvalOrderArr[ctor] = dtorCalled++; }
114 };
115 
116 int EvalOrder::ctorCalled = 0;
117 int EvalOrder::dtorCalled = 0;
118 
dtorEvaluationOrder()119 void dtorEvaluationOrder() {
120   EvalOrder::ctorCalled = 0;
121   EvalOrder::dtorCalled = 0;
122 
123   EvalOrder* eptr = new EvalOrder[4];
124   delete[] eptr;
125 
126   clang_analyzer_eval(EvalOrder::dtorCalled == 4); // expected-warning {{TRUE}}
127   clang_analyzer_eval(EvalOrder::dtorCalled == EvalOrder::ctorCalled); // expected-warning {{TRUE}}
128 
129   clang_analyzer_eval(EvalOrderArr[0] == 3); // expected-warning {{TRUE}}
130   clang_analyzer_eval(EvalOrderArr[1] == 2); // expected-warning {{TRUE}}
131   clang_analyzer_eval(EvalOrderArr[2] == 1); // expected-warning {{TRUE}}
132   clang_analyzer_eval(EvalOrderArr[3] == 0); // expected-warning {{TRUE}}
133 }
134 
135 struct EmptyDtor {
~EmptyDtorEmptyDtor136   ~EmptyDtor(){};
137 };
138 
139 struct DefaultDtor {
140   ~DefaultDtor() = default;
141 };
142 
143 // This function used to fail on an assertion.
no_crash()144 void no_crash() {
145   EmptyDtor* eptr = new EmptyDtor[4];
146   delete[] eptr;
147   clang_analyzer_warnIfReached();  // expected-warning{{REACHABLE}}
148 
149   DefaultDtor* dptr = new DefaultDtor[4];
150   delete[] dptr;
151   clang_analyzer_warnIfReached();  // expected-warning{{REACHABLE}}
152 }
153 
154 // This snippet used to crash.
155 namespace crash2
156 {
157   template <class _Tp> class unique_ptr {
158   typedef _Tp *pointer;
159   pointer __ptr_;
160 
161 public:
unique_ptr(pointer __p)162   unique_ptr(pointer __p) : __ptr_(__p) {}
~unique_ptr()163   ~unique_ptr() { reset(); }
get()164   pointer get() { return __ptr_;}
reset()165   void reset() {}
166 };
167 
168 struct S;
169 
170 S *makeS();
171 int bar(S *x, S *y);
172 
foo()173 void foo() {
174   unique_ptr<S> x(makeS()), y(makeS());
175   bar(x.get(), y.get());
176 }
177 
bar()178 void bar() {
179   foo();
180   clang_analyzer_warnIfReached();  // expected-warning{{REACHABLE}}
181 }
182 
183 } // namespace crash2
184 
185 // This snippet used to crash.
186 namespace crash3
187 {
188 struct InlineDtor {
~InlineDtorcrash3::InlineDtor189   ~InlineDtor() {}
190 };
191 struct MultipleMemberDtor
192 {
193   InlineDtor arr[4];
194   InlineDtor arr2[4];
195 };
196 
foo()197 void foo(){
198   auto *arr = new MultipleMemberDtor[4];
199   delete[] arr;
200   clang_analyzer_warnIfReached();  // expected-warning{{REACHABLE}}
201 }
202 } // namespace crash3
203 
204 namespace crash4 {
205 struct a {
206   a *b;
207 };
208 struct c {
209   a d;
210   c();
~ccrash4::c211   ~c() {
212     for (a e = d;; e = *e.b)
213       ;
214   }
215 };
f()216 void f() {
217   c g;
218   clang_analyzer_warnIfReached();  // expected-warning{{REACHABLE}}
219 }
220 
221 } // namespace crash4
222 
223 namespace crash5 {
224 namespace std {
225 template <class _Tp> class unique_ptr {
226   _Tp *__ptr_;
227 public:
unique_ptr(_Tp * __p)228   unique_ptr(_Tp *__p) : __ptr_(__p) {}
~unique_ptr()229   ~unique_ptr() {}
230 };
231 } // namespace std
232 
SSL_use_certificate(int * arg)233 int SSL_use_certificate(int *arg) {
234   std::unique_ptr<int> free_x509(arg);
235   {
236     if (SSL_use_certificate(arg)) {
237       return 0;
238     }
239   }
240   clang_analyzer_warnIfReached();  // expected-warning{{REACHABLE}}
241   return 1;
242 }
243 
244 } // namespace crash5
245 
zeroLength()246 void zeroLength(){
247   InlineDtor::dtorCalled = 0;
248 
249   auto *arr = new InlineDtor[0];
250   delete[] arr;
251 
252   auto *arr2 = new InlineDtor[2][0][2];
253   delete[] arr2;
254 
255   auto *arr3 = new InlineDtor[0][2][2];
256   delete[] arr3;
257 
258   auto *arr4 = new InlineDtor[2][2][0];
259   delete[] arr4;
260 
261   clang_analyzer_eval(InlineDtor::dtorCalled == 0); // expected-warning {{TRUE}}
262 }
263 
264 
evalOrderPrep()265 void evalOrderPrep() {
266   EvalOrderArr[0] = 0;
267   EvalOrderArr[1] = 0;
268   EvalOrderArr[2] = 0;
269   EvalOrderArr[3] = 0;
270 
271   EvalOrder::ctorCalled = 0;
272   EvalOrder::dtorCalled = 0;
273 }
274 
multidimensionalPrep()275 void multidimensionalPrep(){
276   EvalOrder::ctorCalled = 0;
277   EvalOrder::dtorCalled = 0;
278 
279   EvalOrder arr[2][2];
280 }
281 
multidimensional()282 void multidimensional(){
283   evalOrderPrep();
284   multidimensionalPrep();
285 
286   clang_analyzer_eval(EvalOrder::dtorCalled == 4); // expected-warning {{TRUE}}
287   clang_analyzer_eval(EvalOrder::dtorCalled == EvalOrder::ctorCalled); // expected-warning {{TRUE}}
288 
289   clang_analyzer_eval(EvalOrderArr[0] == 3); // expected-warning {{TRUE}}
290   clang_analyzer_eval(EvalOrderArr[1] == 2); // expected-warning {{TRUE}}
291   clang_analyzer_eval(EvalOrderArr[2] == 1); // expected-warning {{TRUE}}
292   clang_analyzer_eval(EvalOrderArr[3] == 0); // expected-warning {{TRUE}}
293 }
294 
multidimensionalHeap()295 void multidimensionalHeap() {
296   evalOrderPrep();
297 
298   auto* eptr = new EvalOrder[2][2];
299   delete[] eptr;
300 
301   clang_analyzer_eval(EvalOrder::dtorCalled == 4); // expected-warning {{TRUE}}
302   clang_analyzer_eval(EvalOrder::dtorCalled == EvalOrder::ctorCalled); // expected-warning {{TRUE}}
303 
304   clang_analyzer_eval(EvalOrderArr[0] == 3); // expected-warning {{TRUE}}
305   clang_analyzer_eval(EvalOrderArr[1] == 2); // expected-warning {{TRUE}}
306   clang_analyzer_eval(EvalOrderArr[2] == 1); // expected-warning {{TRUE}}
307   clang_analyzer_eval(EvalOrderArr[3] == 0); // expected-warning {{TRUE}}
308 }
309 
310 struct MultiWrapper{
311   EvalOrder arr[2][2];
312 };
313 
multidimensionalMember()314 void multidimensionalMember(){
315   evalOrderPrep();
316 
317   auto* mptr = new MultiWrapper;
318   delete mptr;
319 
320   clang_analyzer_eval(EvalOrder::dtorCalled == 4); // expected-warning {{TRUE}}
321   clang_analyzer_eval(EvalOrder::dtorCalled == EvalOrder::ctorCalled); // expected-warning {{TRUE}}
322 
323   clang_analyzer_eval(EvalOrderArr[0] == 3); // expected-warning {{TRUE}}
324   clang_analyzer_eval(EvalOrderArr[1] == 2); // expected-warning {{TRUE}}
325   clang_analyzer_eval(EvalOrderArr[2] == 1); // expected-warning {{TRUE}}
326   clang_analyzer_eval(EvalOrderArr[3] == 0); // expected-warning {{TRUE}}
327 }
328 
329 void *memset(void *, int, size_t);
330 void clang_analyzer_dumpElementCount(InlineDtor *);
331 
nonConstantRegionExtent()332 void nonConstantRegionExtent(){
333 
334   InlineDtor::dtorCalled = 0;
335 
336   int x = 3;
337   memset(&x, 1, sizeof(x));
338 
339   InlineDtor *arr = new InlineDtor[x];
340   clang_analyzer_dumpElementCount(arr); // expected-warning {{conj_$0}}
341   delete [] arr;
342 
343   //FIXME: This should be TRUE but memset also sets this
344   // region to a conjured symbol.
345   clang_analyzer_eval(InlineDtor::dtorCalled == 0); // expected-warning {{TRUE}} expected-warning {{FALSE}}
346 }
347 
348 namespace crash6 {
349 
350 struct NonTrivialItem {
351   ~NonTrivialItem();
352 };
353 
354 struct WeirdVec {
clearcrash6::WeirdVec355   void clear() {
356     delete[] data;
357     size = 0;
358   }
359   NonTrivialItem *data;
360   unsigned size;
361 };
362 
top(int j)363 void top(int j) {
364   WeirdVec *p = new WeirdVec;
365 
366   p[j].size = 0;
367   delete[] p->data; // no-crash
368 }
369 
370 template <typename T>
make_unknown()371 T make_unknown() {
372   return reinterpret_cast<T>(static_cast<int>(0.404));
373 }
374 
directUnknownSymbol()375 void directUnknownSymbol() {
376   delete[] make_unknown<NonTrivialItem*>(); // no-crash
377 }
378 
379 }
380