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