1 // RUN: %clang_analyze_cc1 -analyzer-checker=core,optin.cplusplus.UninitializedObject \
2 // RUN:   -analyzer-config optin.cplusplus.UninitializedObject:Pedantic=true -DPEDANTIC \
3 // RUN:   -analyzer-config optin.cplusplus.UninitializedObject:IgnoreGuardedFields=true \
4 // RUN:   -std=c++11 -verify  %s
5 
6 //===----------------------------------------------------------------------===//
7 // Helper functions for tests.
8 //===----------------------------------------------------------------------===//
9 
10 [[noreturn]] void halt();
11 
assert(int b)12 void assert(int b) {
13   if (!b)
14     halt();
15 }
16 
17 int rand();
18 
19 //===----------------------------------------------------------------------===//
20 // Tests for fields properly guarded by asserts.
21 //===----------------------------------------------------------------------===//
22 
23 class NoUnguardedFieldsTest {
24 public:
25   enum Kind {
26     V,
27     A
28   };
29 
30 private:
31   int Volume, Area;
32   Kind K;
33 
34 public:
NoUnguardedFieldsTest(Kind K)35   NoUnguardedFieldsTest(Kind K) : K(K) {
36     switch (K) {
37     case V:
38       Volume = 0;
39       break;
40     case A:
41       Area = 0;
42       break;
43     }
44   }
45 
operator -()46   void operator-() {
47     assert(K == Kind::A);
48     (void)Area;
49   }
50 
operator +()51   void operator+() {
52     assert(K == Kind::V);
53     (void)Volume;
54   }
55 };
56 
fNoUnguardedFieldsTest()57 void fNoUnguardedFieldsTest() {
58   NoUnguardedFieldsTest T1(NoUnguardedFieldsTest::Kind::A);
59   NoUnguardedFieldsTest T2(NoUnguardedFieldsTest::Kind::V);
60 }
61 
62 class NoUngardedFieldsNoReturnFuncCalledTest {
63 public:
64   enum Kind {
65     V,
66     A
67   };
68 
69 private:
70   int Volume, Area;
71   Kind K;
72 
73 public:
NoUngardedFieldsNoReturnFuncCalledTest(Kind K)74   NoUngardedFieldsNoReturnFuncCalledTest(Kind K) : K(K) {
75     switch (K) {
76     case V:
77       Volume = 0;
78       break;
79     case A:
80       Area = 0;
81       break;
82     }
83   }
84 
operator -()85   void operator-() {
86     halt();
87     (void)Area;
88   }
89 
operator +()90   void operator+() {
91     halt();
92     (void)Volume;
93   }
94 };
95 
fNoUngardedFieldsNoReturnFuncCalledTest()96 void fNoUngardedFieldsNoReturnFuncCalledTest() {
97   NoUngardedFieldsNoReturnFuncCalledTest
98     T1(NoUngardedFieldsNoReturnFuncCalledTest::Kind::A);
99   NoUngardedFieldsNoReturnFuncCalledTest
100     T2(NoUngardedFieldsNoReturnFuncCalledTest::Kind::V);
101 }
102 
103 class NoUnguardedFieldsWithUndefMethodTest {
104 public:
105   enum Kind {
106     V,
107     A
108   };
109 
110 private:
111   int Volume, Area;
112   Kind K;
113 
114 public:
NoUnguardedFieldsWithUndefMethodTest(Kind K)115   NoUnguardedFieldsWithUndefMethodTest(Kind K) : K(K) {
116     switch (K) {
117     case V:
118       Volume = 0;
119       break;
120     case A:
121       Area = 0;
122       break;
123     }
124   }
125 
operator -()126   void operator-() {
127     assert(K == Kind::A);
128     (void)Area;
129   }
130 
operator +()131   void operator+() {
132     assert(K == Kind::V);
133     (void)Volume;
134   }
135 
136   // We're checking method definitions for guards, so this is a no-crash test
137   // whether we handle methods without definitions.
138   void methodWithoutDefinition();
139 };
140 
fNoUnguardedFieldsWithUndefMethodTest()141 void fNoUnguardedFieldsWithUndefMethodTest() {
142   NoUnguardedFieldsWithUndefMethodTest
143       T1(NoUnguardedFieldsWithUndefMethodTest::Kind::A);
144   NoUnguardedFieldsWithUndefMethodTest
145       T2(NoUnguardedFieldsWithUndefMethodTest::Kind::V);
146 }
147 
148 class UnguardedFieldThroughMethodTest {
149 public:
150   enum Kind {
151     V,
152     A
153   };
154 
155 private:
156   int Volume, Area; // expected-note {{uninitialized field 'this->Volume'}}
157   Kind K;
158 
159 public:
UnguardedFieldThroughMethodTest(Kind K)160   UnguardedFieldThroughMethodTest(Kind K) : K(K) {
161     switch (K) {
162     case V:
163       Volume = 0;
164       break;
165     case A:
166       Area = 0; // expected-warning {{1 uninitialized field}}
167       break;
168     }
169   }
170 
operator -()171   void operator-() {
172     assert(K == Kind::A);
173     (void)Area;
174   }
175 
operator +()176   void operator+() {
177     (void)Volume;
178   }
179 };
180 
fUnguardedFieldThroughMethodTest()181 void fUnguardedFieldThroughMethodTest() {
182   UnguardedFieldThroughMethodTest T1(UnguardedFieldThroughMethodTest::Kind::A);
183 }
184 
185 class UnguardedPublicFieldsTest {
186 public:
187   enum Kind {
188     V,
189     A
190   };
191 
192 public:
193   // Note that fields are public.
194   int Volume, Area; // expected-note {{uninitialized field 'this->Volume'}}
195   Kind K;
196 
197 public:
UnguardedPublicFieldsTest(Kind K)198   UnguardedPublicFieldsTest(Kind K) : K(K) {
199     switch (K) {
200     case V:
201       Volume = 0;
202       break;
203     case A:
204       Area = 0; // expected-warning {{1 uninitialized field}}
205       break;
206     }
207   }
208 
operator -()209   void operator-() {
210     assert(K == Kind::A);
211     (void)Area;
212   }
213 
operator +()214   void operator+() {
215     assert(K == Kind::V);
216     (void)Volume;
217   }
218 };
219 
fUnguardedPublicFieldsTest()220 void fUnguardedPublicFieldsTest() {
221   UnguardedPublicFieldsTest T1(UnguardedPublicFieldsTest::Kind::A);
222 }
223 
224 //===----------------------------------------------------------------------===//
225 // Highlights of some false negatives due to syntactic checking.
226 //===----------------------------------------------------------------------===//
227 
228 class UnguardedFalseNegativeTest1 {
229 public:
230   enum Kind {
231     V,
232     A
233   };
234 
235 private:
236   int Volume, Area;
237   Kind K;
238 
239 public:
UnguardedFalseNegativeTest1(Kind K)240   UnguardedFalseNegativeTest1(Kind K) : K(K) {
241     switch (K) {
242     case V:
243       Volume = 0;
244       break;
245     case A:
246       Area = 0;
247       break;
248     }
249   }
250 
operator -()251   void operator-() {
252     if (rand())
253       assert(K == Kind::A);
254     (void)Area;
255   }
256 
operator +()257   void operator+() {
258     if (rand())
259       assert(K == Kind::V);
260     (void)Volume;
261   }
262 };
263 
fUnguardedFalseNegativeTest1()264 void fUnguardedFalseNegativeTest1() {
265   UnguardedFalseNegativeTest1 T1(UnguardedFalseNegativeTest1::Kind::A);
266 }
267 
268 class UnguardedFalseNegativeTest2 {
269 public:
270   enum Kind {
271     V,
272     A
273   };
274 
275 private:
276   int Volume, Area;
277   Kind K;
278 
279 public:
UnguardedFalseNegativeTest2(Kind K)280   UnguardedFalseNegativeTest2(Kind K) : K(K) {
281     switch (K) {
282     case V:
283       Volume = 0;
284       break;
285     case A:
286       Area = 0;
287       break;
288     }
289   }
290 
operator -()291   void operator-() {
292     assert(rand());
293     (void)Area;
294   }
295 
operator +()296   void operator+() {
297     assert(rand());
298     (void)Volume;
299   }
300 };
301 
fUnguardedFalseNegativeTest2()302 void fUnguardedFalseNegativeTest2() {
303   UnguardedFalseNegativeTest2 T1(UnguardedFalseNegativeTest2::Kind::A);
304 }
305 
306 //===----------------------------------------------------------------------===//
307 // Tests for other guards. These won't be as thorough, as other guards are
308 // matched the same way as asserts, so if they are recognized, they are expected
309 // to work as well as asserts do.
310 //
311 // None of these tests expect warnings, since the flag works correctly if these
312 // fields are regarded properly guarded.
313 //===----------------------------------------------------------------------===//
314 
315 class IfGuardedFieldsTest {
316 public:
317   enum Kind {
318     V,
319     A
320   };
321 
322 private:
323   int Volume, Area;
324   Kind K;
325 
326 public:
IfGuardedFieldsTest(Kind K)327   IfGuardedFieldsTest(Kind K) : K(K) {
328     switch (K) {
329     case V:
330       Volume = 0;
331       break;
332     case A:
333       Area = 0;
334       break;
335     }
336   }
337 
operator -()338   void operator-() {
339     if (K != Kind::A)
340       return;
341     (void)Area;
342   }
343 
operator +()344   void operator+() {
345     if (K != Kind::V)
346       return;
347     (void)Volume;
348   }
349 };
350 
fIfGuardedFieldsTest()351 void fIfGuardedFieldsTest() {
352   IfGuardedFieldsTest T1(IfGuardedFieldsTest::Kind::A);
353   IfGuardedFieldsTest T2(IfGuardedFieldsTest::Kind::V);
354 }
355 
356 class SwitchGuardedFieldsTest {
357 public:
358   enum Kind {
359     V,
360     A
361   };
362 
363 private:
364   int Volume, Area;
365   Kind K;
366 
367 public:
SwitchGuardedFieldsTest(Kind K)368   SwitchGuardedFieldsTest(Kind K) : K(K) {
369     switch (K) {
370     case V:
371       Volume = 0;
372       break;
373     case A:
374       Area = 0;
375       break;
376     }
377   }
378 
operator -()379   int operator-() {
380     switch (K) {
381     case Kind::A:
382       return Area;
383     case Kind::V:
384       return -1;
385     }
386   }
387 
operator +()388   int operator+() {
389     switch (K) {
390     case Kind::A:
391       return Area;
392     case Kind::V:
393       return -1;
394     }
395   }
396 };
397 
fSwitchGuardedFieldsTest()398 void fSwitchGuardedFieldsTest() {
399   SwitchGuardedFieldsTest T1(SwitchGuardedFieldsTest::Kind::A);
400   SwitchGuardedFieldsTest T2(SwitchGuardedFieldsTest::Kind::V);
401 }
402 
403 class ConditionalOperatorGuardedFieldsTest {
404 public:
405   enum Kind {
406     V,
407     A
408   };
409 
410 private:
411   int Volume, Area;
412   Kind K;
413 
414 public:
ConditionalOperatorGuardedFieldsTest(Kind K)415   ConditionalOperatorGuardedFieldsTest(Kind K) : K(K) {
416     switch (K) {
417     case V:
418       Volume = 0;
419       break;
420     case A:
421       Area = 0;
422       break;
423     }
424   }
425 
operator -()426   int operator-() {
427     return K == Kind::A ? Area : -1;
428   }
429 
operator +()430   int operator+() {
431     return K == Kind::V ? Volume : -1;
432   }
433 };
434 
fConditionalOperatorGuardedFieldsTest()435 void fConditionalOperatorGuardedFieldsTest() {
436   ConditionalOperatorGuardedFieldsTest
437       T1(ConditionalOperatorGuardedFieldsTest::Kind::A);
438   ConditionalOperatorGuardedFieldsTest
439       T2(ConditionalOperatorGuardedFieldsTest::Kind::V);
440 }
441