xref: /llvm-project/clang/test/Analysis/track-control-dependency-conditions.cpp (revision fd8e5762f86f0a602ec08eea5c4c86927faba6dc)
1 // RUN: %clang_analyze_cc1 %s -std=c++17 \
2 // RUN:   -verify=expected,tracking \
3 // RUN:   -analyzer-config track-conditions=true \
4 // RUN:   -analyzer-output=text \
5 // RUN:   -analyzer-checker=core
6 
7 // RUN: not %clang_analyze_cc1 -std=c++17 -verify %s \
8 // RUN:   -analyzer-checker=core \
9 // RUN:   -analyzer-config track-conditions=false \
10 // RUN:   -analyzer-config track-conditions-debug=true \
11 // RUN:   2>&1 | FileCheck %s -check-prefix=CHECK-INVALID-DEBUG
12 
13 // CHECK-INVALID-DEBUG: (frontend): invalid input for analyzer-config option
14 // CHECK-INVALID-DEBUG-SAME:        'track-conditions-debug', that expects
15 // CHECK-INVALID-DEBUG-SAME:        'track-conditions' to also be enabled
16 //
17 // RUN: %clang_analyze_cc1 %s -std=c++17 \
18 // RUN:   -verify=expected,tracking,debug \
19 // RUN:   -analyzer-config track-conditions=true \
20 // RUN:   -analyzer-config track-conditions-debug=true \
21 // RUN:   -analyzer-output=text \
22 // RUN:   -analyzer-checker=core
23 
24 // RUN: %clang_analyze_cc1 %s -std=c++17 -verify \
25 // RUN:   -analyzer-output=text \
26 // RUN:   -analyzer-config track-conditions=false \
27 // RUN:   -analyzer-checker=core
28 
29 namespace example_1 {
30 int flag;
31 bool coin();
32 
foo()33 void foo() {
34   flag = coin(); // tracking-note-re{{{{^}}Value assigned to 'flag', which participates in a condition later{{$}}}}
35 }
36 
test()37 void test() {
38   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
39   flag = 1;
40 
41   foo(); // TODO: Add nodes here about flag's value being invalidated.
42   if (flag) // expected-note-re   {{{{^}}Assuming 'flag' is 0{{$}}}}
43             // expected-note-re@-1{{{{^}}Taking false branch{{$}}}}
44     x = new int;
45 
46   foo(); // tracking-note-re{{{{^}}Calling 'foo'{{$}}}}
47          // tracking-note-re@-1{{{{^}}Returning from 'foo'{{$}}}}
48 
49   if (flag) // expected-note-re   {{{{^}}Assuming 'flag' is not equal to 0{{$}}}}
50             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
51             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
52 
53     *x = 5; // expected-warning{{Dereference of null pointer}}
54             // expected-note@-1{{Dereference of null pointer}}
55 }
56 } // end of namespace example_1
57 
58 namespace example_2 {
59 int flag;
60 bool coin();
61 
foo()62 void foo() {
63   flag = coin(); // tracking-note-re{{{{^}}Value assigned to 'flag', which participates in a condition later{{$}}}}
64 }
65 
test()66 void test() {
67   int *x = 0;
68   flag = 1;
69 
70   foo();
71   if (flag) // expected-note-re   {{{{^}}Assuming 'flag' is 0{{$}}}}
72             // expected-note-re@-1{{{{^}}Taking false branch{{$}}}}
73     x = new int;
74 
75   x = 0; // expected-note-re{{{{^}}Null pointer value stored to 'x'{{$}}}}
76 
77   foo(); // tracking-note-re{{{{^}}Calling 'foo'{{$}}}}
78          // tracking-note-re@-1{{{{^}}Returning from 'foo'{{$}}}}
79 
80   if (flag) // expected-note-re   {{{{^}}Assuming 'flag' is not equal to 0{{$}}}}
81             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
82             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
83 
84     *x = 5; // expected-warning{{Dereference of null pointer}}
85             // expected-note@-1{{Dereference of null pointer}}
86 }
87 } // end of namespace example_2
88 
89 namespace global_variable_invalidation {
90 int flag;
91 bool coin();
92 
foo()93 void foo() {
94   // coin() could write bar, do it's invalidated.
95   flag = coin(); // tracking-note-re{{{{^}}Value assigned to 'flag', which participates in a condition later{{$}}}}
96                  // tracking-note-re@-1{{{{^}}Value assigned to 'bar', which participates in a condition later{{$}}}}
97 }
98 
99 int bar;
100 
test()101 void test() {
102   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
103   flag = 1;
104 
105   foo(); // tracking-note-re{{{{^}}Calling 'foo'{{$}}}}
106          // tracking-note-re@-1{{{{^}}Returning from 'foo'{{$}}}}
107 
108   if (bar) // expected-note-re   {{{{^}}Assuming 'bar' is not equal to 0{{$}}}}
109            // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
110            // debug-note-re@-2{{{{^}}Tracking condition 'bar'{{$}}}}
111     if (flag) // expected-note-re   {{{{^}}Assuming 'flag' is not equal to 0{{$}}}}
112               // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
113               // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
114 
115       *x = 5; // expected-warning{{Dereference of null pointer}}
116               // expected-note@-1{{Dereference of null pointer}}
117 }
118 } // end of namespace global_variable_invalidation
119 
120 namespace variable_declaration_in_condition {
121 bool coin();
122 
foo()123 bool foo() {
124   return coin();
125 }
126 
127 int bar;
128 
test()129 void test() {
130   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
131 
132   if (int flag = foo()) // debug-note-re{{{{^}}Tracking condition 'flag'{{$}}}}
133                         // expected-note-re@-1{{{{^}}Assuming 'flag' is not equal to 0{{$}}}}
134                         // expected-note-re@-2{{{{^}}Taking true branch{{$}}}}
135 
136     *x = 5; // expected-warning{{Dereference of null pointer}}
137             // expected-note@-1{{Dereference of null pointer}}
138 }
139 } // end of namespace variable_declaration_in_condition
140 
141 namespace conversion_to_bool {
142 bool coin();
143 
144 struct ConvertsToBool {
operator boolconversion_to_bool::ConvertsToBool145   operator bool() const { return coin(); }
146 };
147 
test()148 void test() {
149   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
150 
151   if (ConvertsToBool())
152     // expected-note-re@-1{{{{^}}Assuming the condition is true{{$}}}}
153     // expected-note-re@-2{{{{^}}Taking true branch{{$}}}}
154     *x = 5; // expected-warning{{Dereference of null pointer}}
155             // expected-note@-1{{Dereference of null pointer}}
156 }
157 
158 } // namespace conversion_to_bool
159 
160 namespace note_from_different_but_not_nested_stackframe {
161 
nullptrDeref(int * ptr,bool True)162 void nullptrDeref(int *ptr, bool True) {
163   if (True) // expected-note-re{{{{^}}'True' is true{{$}}}}
164             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
165             // debug-note-re@-2{{{{^}}Tracking condition 'True'{{$}}}}
166     *ptr = 5;
167   // expected-note@-1{{Dereference of null pointer (loaded from variable 'ptr')}}
168   // expected-warning@-2{{Dereference of null pointer (loaded from variable 'ptr')}}
169 }
170 
f()171 void f() {
172   int *ptr = nullptr;
173   // expected-note-re@-1{{{{^}}'ptr' initialized to a null pointer value{{$}}}}
174   bool True = true;
175   nullptrDeref(ptr, True);
176   // expected-note-re@-1{{{{^}}Passing null pointer value via 1st parameter 'ptr'{{$}}}}
177   // expected-note-re@-2{{{{^}}Calling 'nullptrDeref'{{$}}}}
178 }
179 
180 } // end of namespace note_from_different_but_not_nested_stackframe
181 
182 namespace important_returning_pointer_loaded_from {
183 bool coin();
184 
185 int *getIntPtr();
186 
storeValue(int ** i)187 void storeValue(int **i) {
188   *i = getIntPtr();
189 }
190 
conjurePointer()191 int *conjurePointer() {
192   int *i;
193   storeValue(&i);
194   return i;
195 }
196 
f(int * ptr)197 void f(int *ptr) {
198   if (ptr) // expected-note-re{{{{^}}Assuming 'ptr' is null{{$}}}}
199            // expected-note-re@-1{{{{^}}Taking false branch{{$}}}}
200     ;
201   if (!conjurePointer())
202     // expected-note-re@-1{{{{^}}Assuming the condition is true{{$}}}}
203     // expected-note-re@-2{{{{^}}Taking true branch{{$}}}}
204     *ptr = 5; // expected-warning{{Dereference of null pointer}}
205               // expected-note@-1{{Dereference of null pointer}}
206 }
207 } // end of namespace important_returning_pointer_loaded_from
208 
209 namespace unimportant_returning_pointer_loaded_from {
210 bool coin();
211 
212 int *getIntPtr();
213 
conjurePointer()214 int *conjurePointer() {
215   int *i = getIntPtr();
216   return i;
217 }
218 
f(int * ptr)219 void f(int *ptr) {
220   if (ptr) // expected-note-re{{{{^}}Assuming 'ptr' is null{{$}}}}
221            // expected-note-re@-1{{{{^}}Taking false branch{{$}}}}
222     ;
223   if (!conjurePointer())
224     // expected-note-re@-1{{{{^}}Assuming the condition is true{{$}}}}
225     // expected-note-re@-2{{{{^}}Taking true branch{{$}}}}
226     *ptr = 5; // expected-warning{{Dereference of null pointer}}
227               // expected-note@-1{{Dereference of null pointer}}
228 }
229 } // end of namespace unimportant_returning_pointer_loaded_from
230 
231 namespace unimportant_returning_pointer_loaded_from_through_cast {
232 
233 void *conjure();
234 
cast(void * P)235 int *cast(void *P) {
236   return static_cast<int *>(P);
237 }
238 
f()239 void f() {
240   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
241 
242   if (cast(conjure()))
243     // expected-note-re@-1{{{{^}}Assuming the condition is false{{$}}}}
244     // expected-note-re@-2{{{{^}}Taking false branch{{$}}}}
245     return;
246   *x = 5; // expected-warning{{Dereference of null pointer}}
247           // expected-note@-1{{Dereference of null pointer}}
248 }
249 
250 } // end of namespace unimportant_returning_pointer_loaded_from_through_cast
251 
252 namespace unimportant_returning_value_note {
253 bool coin();
254 
flipCoin()255 bool flipCoin() { return coin(); }
256 
i(int * ptr)257 void i(int *ptr) {
258   if (ptr) // expected-note-re{{{{^}}Assuming 'ptr' is null{{$}}}}
259            // expected-note-re@-1{{{{^}}Taking false branch{{$}}}}
260     ;
261   if (!flipCoin())
262     // expected-note-re@-1{{{{^}}Assuming the condition is true{{$}}}}
263     // expected-note-re@-2{{{{^}}Taking true branch{{$}}}}
264     *ptr = 5; // expected-warning{{Dereference of null pointer}}
265               // expected-note@-1{{Dereference of null pointer}}
266 }
267 } // end of namespace unimportant_returning_value_note
268 
269 namespace important_returning_value_note {
270 bool coin();
271 
flipCoin()272 bool flipCoin() {
273   if (coin())
274     return true;
275   return coin();
276 }
277 
i(int * ptr)278 void i(int *ptr) {
279   if (ptr) // expected-note-re{{{{^}}Assuming 'ptr' is null{{$}}}}
280            // expected-note-re@-1{{{{^}}Taking false branch{{$}}}}
281     ;
282   if (!flipCoin())
283     // expected-note-re@-1{{{{^}}Assuming the condition is true{{$}}}}
284     // expected-note-re@-2{{{{^}}Taking true branch{{$}}}}
285     *ptr = 5; // expected-warning{{Dereference of null pointer}}
286               // expected-note@-1{{Dereference of null pointer}}
287 }
288 } // end of namespace important_returning_value_note
289 
290 namespace important_returning_value_note_in_linear_function {
291 bool coin();
292 int flag;
293 
294 struct super_complicated_template_hackery {
295   static constexpr bool value = false;
296 };
297 
flipCoin()298 void flipCoin() {
299   if (super_complicated_template_hackery::value)
300     // tracking-note-re@-1{{{{^}}'value' is false{{$}}}}
301     // tracking-note-re@-2{{{{^}}Taking false branch{{$}}}}
302     return;
303   flag = false; // tracking-note-re{{{{^}}The value 0 is assigned to 'flag', which participates in a condition later{{$}}}}
304 }
305 
i(int * ptr)306 void i(int *ptr) {
307   flag = true;
308   if (ptr) // expected-note-re{{{{^}}Assuming 'ptr' is null{{$}}}}
309            // expected-note-re@-1{{{{^}}Taking false branch{{$}}}}
310     ;
311   flipCoin();
312   // tracking-note-re@-1{{{{^}}Calling 'flipCoin'{{$}}}}
313   // tracking-note-re@-2{{{{^}}Returning from 'flipCoin'{{$}}}}
314   if (!flag)
315     // debug-note-re@-1{{{{^}}Tracking condition '!flag'{{$}}}}
316     // expected-note-re@-2{{{{^}}'flag' is 0{{$}}}}
317     // expected-note-re@-3{{{{^}}Taking true branch{{$}}}}
318     *ptr = 5; // expected-warning{{Dereference of null pointer}}
319               // expected-note@-1{{Dereference of null pointer}}
320 }
321 } // end of namespace important_returning_value_note_in_linear_function
322 
323 namespace tracked_condition_is_only_initialized {
324 int getInt();
325 
f()326 void f() {
327   int flag = getInt();
328   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
329   if (flag) // expected-note-re{{{{^}}Assuming 'flag' is not equal to 0{{$}}}}
330             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
331             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
332     *x = 5; // expected-warning{{Dereference of null pointer}}
333             // expected-note@-1{{Dereference of null pointer}}
334 }
335 } // end of namespace tracked_condition_is_only_initialized
336 
337 namespace tracked_condition_written_in_same_stackframe {
338 int flag;
339 int getInt();
340 
f(int y)341 void f(int y) {
342   y = 1;
343   flag = y;
344 
345   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
346   if (flag) // expected-note-re{{{{^}}'flag' is 1{{$}}}}
347             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
348             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
349     *x = 5; // expected-warning{{Dereference of null pointer}}
350             // expected-note@-1{{Dereference of null pointer}}
351 }
352 } // end of namespace tracked_condition_written_in_same_stackframe
353 
354 namespace tracked_condition_written_in_nested_stackframe {
355 int flag;
356 int getInt();
357 
foo()358 void foo() {
359   int y;
360   y = 1;
361   flag = y; // tracking-note-re{{{{^}}The value 1 is assigned to 'flag', which participates in a condition later{{$}}}}
362 }
363 
f(int y)364 void f(int y) {
365   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
366 
367   foo(); // tracking-note-re{{{{^}}Calling 'foo'{{$}}}}
368          // tracking-note-re@-1{{{{^}}Returning from 'foo'{{$}}}}
369 
370   if (flag) // expected-note-re{{{{^}}'flag' is 1{{$}}}}
371             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
372             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
373     *x = 5; // expected-warning{{Dereference of null pointer}}
374             // expected-note@-1{{Dereference of null pointer}}
375 }
376 } // end of namespace tracked_condition_written_in_nested_stackframe
377 
378 namespace condition_written_in_nested_stackframe_before_assignment {
379 int flag = 0;
380 int getInt();
381 
foo()382 void foo() {
383   flag = getInt(); // tracking-note-re{{{{^}}Value assigned to 'flag', which participates in a condition later{{$}}}}
384 }
385 
f()386 void f() {
387   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
388   int y = 0;
389 
390   foo(); // tracking-note-re{{{{^}}Calling 'foo'{{$}}}}
391          // tracking-note-re@-1{{{{^}}Returning from 'foo'{{$}}}}
392   y = flag;
393 
394   if (y)    // expected-note-re{{{{^}}Assuming 'y' is not equal to 0{{$}}}}
395             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
396             // debug-note-re@-2{{{{^}}Tracking condition 'y'{{$}}}}
397     *x = 5; // expected-warning{{Dereference of null pointer}}
398             // expected-note@-1{{Dereference of null pointer}}
399 }
400 } // end of namespace condition_written_in_nested_stackframe_before_assignment
401 
402 namespace dont_explain_foreach_loops {
403 
404 struct Iterator {
405   int *pos;
operator !=dont_explain_foreach_loops::Iterator406   bool operator!=(Iterator other) const {
407     return pos && other.pos && pos != other.pos;
408   }
409   int operator*();
410   Iterator operator++();
411 };
412 
413 struct Container {
414   Iterator begin();
415   Iterator end();
416 };
417 
f(Container Cont)418 void f(Container Cont) {
419   int flag = 0;
420   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
421   for (int i : Cont)
422     if (i) // expected-note-re   {{{{^}}Assuming 'i' is not equal to 0{{$}}}}
423            // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
424            // debug-note-re@-2{{{{^}}Tracking condition 'i'{{$}}}}
425       flag = i;
426 
427   if (flag) // expected-note-re{{{{^}}'flag' is not equal to 0{{$}}}}
428             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
429             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
430     *x = 5; // expected-warning{{Dereference of null pointer}}
431             // expected-note@-1{{Dereference of null pointer}}
432 }
433 } // end of namespace dont_explain_foreach_loops
434 
435 namespace condition_lambda_capture_by_reference_last_write {
436 int getInt();
437 
438 [[noreturn]] void halt();
439 
f(int flag)440 void f(int flag) {
441   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
442 
443   auto lambda = [&flag]() {
444     flag = getInt(); // tracking-note-re{{{{^}}Value assigned to 'flag', which participates in a condition later{{$}}}}
445   };
446 
447   lambda(); // tracking-note-re{{{{^}}Calling 'operator()'{{$}}}}
448             // tracking-note-re@-1{{{{^}}Returning from 'operator()'{{$}}}}
449 
450   if (flag) // expected-note-re{{{{^}}Assuming 'flag' is not equal to 0{{$}}}}
451             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
452             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
453     *x = 5; // expected-warning{{Dereference of null pointer}}
454             // expected-note@-1{{Dereference of null pointer}}
455 }
456 } // end of namespace condition_lambda_capture_by_reference_last_write
457 
458 namespace condition_lambda_capture_by_value_assumption {
459 int getInt();
460 
461 [[noreturn]] void halt();
462 
bar(int & flag)463 void bar(int &flag) {
464   flag = getInt(); // tracking-note-re{{{{^}}Value assigned to 'flag', which participates in a condition later{{$}}}}
465 }
466 
f(int flag)467 void f(int flag) {
468   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
469 
470   auto lambda = [flag]() {
471     if (!flag) // tracking-note-re{{{{^}}Assuming 'flag' is not equal to 0, which participates in a condition later{{$}}}}
472                // tracking-note-re@-1{{{{^}}Taking false branch{{$}}}}
473       halt();
474   };
475 
476   bar(flag); // tracking-note-re{{{{^}}Calling 'bar'{{$}}}}
477              // tracking-note-re@-1{{{{^}}Returning from 'bar'{{$}}}}
478   lambda();  // tracking-note-re{{{{^}}Calling 'operator()'{{$}}}}
479              // tracking-note-re@-1{{{{^}}Returning from 'operator()'{{$}}}}
480 
481   if (flag) // expected-note-re{{{{^}}Assuming 'flag' is not equal to 0{{$}}}}
482             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
483             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
484     *x = 5; // expected-warning{{Dereference of null pointer}}
485             // expected-note@-1{{Dereference of null pointer}}
486 }
487 } // end of namespace condition_lambda_capture_by_value_assumption
488 
489 namespace condition_lambda_capture_by_reference_assumption {
490 int getInt();
491 
492 [[noreturn]] void halt();
493 
bar(int & flag)494 void bar(int &flag) {
495   flag = getInt(); // tracking-note-re{{{{^}}Value assigned to 'flag', which participates in a condition later{{$}}}}
496 }
497 
f(int flag)498 void f(int flag) {
499   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
500 
501   auto lambda = [&flag]() {
502     if (!flag) // tracking-note-re{{{{^}}Assuming 'flag' is not equal to 0, which participates in a condition later{{$}}}}
503                // tracking-note-re@-1{{{{^}}Taking false branch{{$}}}}
504       halt();
505   };
506 
507   bar(flag); // tracking-note-re{{{{^}}Calling 'bar'{{$}}}}
508              // tracking-note-re@-1{{{{^}}Returning from 'bar'{{$}}}}
509   lambda();  // tracking-note-re{{{{^}}Calling 'operator()'{{$}}}}
510              // tracking-note-re@-1{{{{^}}Returning from 'operator()'{{$}}}}
511 
512   if (flag) // expected-note-re{{{{^}}'flag' is not equal to 0{{$}}}}
513             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
514             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
515     *x = 5; // expected-warning{{Dereference of null pointer}}
516             // expected-note@-1{{Dereference of null pointer}}
517 }
518 } // end of namespace condition_lambda_capture_by_reference_assumption
519 
520 namespace collapse_point_not_in_condition_bool {
521 
522 [[noreturn]] void halt();
523 
check(bool b)524 void check(bool b) {
525   if (!b) // tracking-note-re{{{{^}}Assuming 'b' is true, which participates in a condition later{{$}}}}
526           // tracking-note-re@-1{{{{^}}Taking false branch{{$}}}}
527     halt();
528 }
529 
f(bool flag)530 void f(bool flag) {
531   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
532 
533   check(flag); // tracking-note-re{{{{^}}Calling 'check'{{$}}}}
534                 // tracking-note-re@-1{{{{^}}Returning from 'check'{{$}}}}
535 
536   if (flag) // expected-note-re{{{{^}}'flag' is true{{$}}}}
537             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
538             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
539     *x = 5; // expected-warning{{Dereference of null pointer}}
540             // expected-note@-1{{Dereference of null pointer}}
541 }
542 } // end of namespace collapse_point_not_in_condition_bool
543 
544 namespace collapse_point_not_in_condition {
545 
546 [[noreturn]] void halt();
547 
assert(int b)548 void assert(int b) {
549   if (!b) // tracking-note-re{{{{^}}Assuming 'b' is not equal to 0, which participates in a condition later{{$}}}}
550           // tracking-note-re@-1{{{{^}}Taking false branch{{$}}}}
551     halt();
552 }
553 
f(int flag)554 void f(int flag) {
555   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
556 
557   assert(flag); // tracking-note-re{{{{^}}Calling 'assert'{{$}}}}
558                 // tracking-note-re@-1{{{{^}}Returning from 'assert'{{$}}}}
559 
560   if (flag) // expected-note-re{{{{^}}'flag' is not equal to 0{{$}}}}
561             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
562             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
563     *x = 5; // expected-warning{{Dereference of null pointer}}
564             // expected-note@-1{{Dereference of null pointer}}
565 }
566 
567 } // end of namespace collapse_point_not_in_condition
568 
569 namespace unimportant_write_before_collapse_point {
570 
571 [[noreturn]] void halt();
572 
assert(int b)573 void assert(int b) {
574   if (!b) // tracking-note-re{{{{^}}Assuming 'b' is not equal to 0, which participates in a condition later{{$}}}}
575           // tracking-note-re@-1{{{{^}}Taking false branch{{$}}}}
576     halt();
577 }
578 int getInt();
579 
f(int flag)580 void f(int flag) {
581   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
582 
583   flag = getInt();
584   assert(flag); // tracking-note-re{{{{^}}Calling 'assert'{{$}}}}
585                 // tracking-note-re@-1{{{{^}}Returning from 'assert'{{$}}}}
586 
587   if (flag) // expected-note-re{{{{^}}'flag' is not equal to 0{{$}}}}
588             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
589             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
590     *x = 5; // expected-warning{{Dereference of null pointer}}
591             // expected-note@-1{{Dereference of null pointer}}
592 }
593 
594 } // end of namespace unimportant_write_before_collapse_point
595 
596 namespace dont_crash_on_nonlogical_binary_operator {
597 
f6(int x)598 void f6(int x) {
599   int a[20];
600   if (x == 25) {} // expected-note{{Assuming 'x' is equal to 25}}
601                   // expected-note@-1{{Taking true branch}}
602   if (a[x] == 123) {} // expected-warning{{The left operand of '==' is a garbage value due to array index out of bounds}}
603                       // expected-note@-1{{The left operand of '==' is a garbage value due to array index out of bounds}}
604 }
605 
606 } // end of namespace dont_crash_on_nonlogical_binary_operator
607 
608 namespace collapse_point_not_in_condition_binary_op {
609 
610 [[noreturn]] void halt();
611 
check(int b)612 void check(int b) {
613   if (b == 1) // tracking-note-re{{{{^}}Assuming 'b' is not equal to 1, which participates in a condition later{{$}}}}
614               // tracking-note-re@-1{{{{^}}Taking false branch{{$}}}}
615     halt();
616 }
617 
f(int flag)618 void f(int flag) {
619   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
620 
621   check(flag); // tracking-note-re{{{{^}}Calling 'check'{{$}}}}
622                // tracking-note-re@-1{{{{^}}Returning from 'check'{{$}}}}
623 
624   if (flag) // expected-note-re{{{{^}}Assuming 'flag' is not equal to 0{{$}}}}
625             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
626             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
627     *x = 5; // expected-warning{{Dereference of null pointer}}
628             // expected-note@-1{{Dereference of null pointer}}
629 }
630 
631 } // end of namespace collapse_point_not_in_condition_binary_op
632 
633 namespace collapse_point_not_in_condition_as_field {
634 
635 [[noreturn]] void halt();
636 struct IntWrapper {
637   int b;
638   IntWrapper();
639 
checkcollapse_point_not_in_condition_as_field::IntWrapper640   void check() {
641     if (!b) // tracking-note-re{{{{^}}Assuming field 'b' is not equal to 0, which participates in a condition later{{$}}}}
642             // tracking-note-re@-1{{{{^}}Taking false branch{{$}}}}
643       halt();
644     return;
645   }
646 };
647 
f(IntWrapper i)648 void f(IntWrapper i) {
649   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
650 
651   i.check(); // tracking-note-re{{{{^}}Calling 'IntWrapper::check'{{$}}}}
652              // tracking-note-re@-1{{{{^}}Returning from 'IntWrapper::check'{{$}}}}
653   if (i.b)   // expected-note-re{{{{^}}Field 'b' is not equal to 0{{$}}}}
654              // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
655              // debug-note-re@-2{{{{^}}Tracking condition 'i.b'{{$}}}}
656     *x = 5;  // expected-warning{{Dereference of null pointer}}
657              // expected-note@-1{{Dereference of null pointer}}
658 }
659 
660 } // end of namespace collapse_point_not_in_condition_as_field
661 
662 namespace assignemnt_in_condition_in_nested_stackframe {
663 int flag;
664 
665 bool coin();
666 
667 [[noreturn]] void halt();
668 
foo()669 void foo() {
670   if ((flag = coin()))
671     // tracking-note-re@-1{{{{^}}Value assigned to 'flag', which participates in a condition later{{$}}}}
672     // tracking-note-re@-2{{{{^}}Assuming 'flag' is not equal to 0, which participates in a condition later{{$}}}}
673     // tracking-note-re@-3{{{{^}}Taking true branch{{$}}}}
674     return;
675   halt();
676   return;
677 }
678 
f()679 void f() {
680   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
681 
682   foo();    // tracking-note-re{{{{^}}Calling 'foo'{{$}}}}
683             // tracking-note-re@-1{{{{^}}Returning from 'foo'{{$}}}}
684   if (flag) // expected-note-re{{{{^}}'flag' is not equal to 0{{$}}}}
685             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
686             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
687     *x = 5; // expected-warning{{Dereference of null pointer}}
688             // expected-note@-1{{Dereference of null pointer}}
689 }
690 } // end of namespace assignemnt_in_condition_in_nested_stackframe
691 
692 namespace condition_variable_less {
693 int flag;
694 
695 bool coin();
696 
697 [[noreturn]] void halt();
698 
foo()699 void foo() {
700   if (flag > 0)
701     // tracking-note-re@-1{{{{^}}Assuming 'flag' is > 0, which participates in a condition later{{$}}}}
702     // tracking-note-re@-2{{{{^}}Taking true branch{{$}}}}
703     return;
704   halt();
705   return;
706 }
707 
f()708 void f() {
709   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
710 
711   foo();    // tracking-note-re{{{{^}}Calling 'foo'{{$}}}}
712             // tracking-note-re@-1{{{{^}}Returning from 'foo'{{$}}}}
713   if (flag) // expected-note-re{{{{^}}'flag' is not equal to 0{{$}}}}
714             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
715             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
716     *x = 5; // expected-warning{{Dereference of null pointer}}
717             // expected-note@-1{{Dereference of null pointer}}
718 }
719 } // end of namespace condition_variable_less
720 
721 namespace dont_track_assertlike_conditions {
722 
723 extern void __assert_fail(__const char *__assertion, __const char *__file,
724                           unsigned int __line, __const char *__function)
725     __attribute__((__noreturn__));
726 #define assert(expr) \
727   ((expr) ? (void)(0) : __assert_fail(#expr, __FILE__, __LINE__, __func__))
728 
729 int getInt();
730 
731 int cond1;
732 
bar()733 void bar() {
734   cond1 = getInt();
735 }
736 
f(int flag)737 void f(int flag) {
738   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
739 
740   flag = getInt();
741 
742   bar();
743   assert(cond1); // expected-note-re{{{{^}}Assuming 'cond1' is not equal to 0{{$}}}}
744                  // expected-note-re@-1{{{{^}}'?' condition is true{{$}}}}
745 
746   if (flag) // expected-note-re{{{{^}}Assuming 'flag' is not equal to 0{{$}}}}
747             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
748             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
749     *x = 5; // expected-warning{{Dereference of null pointer}}
750             // expected-note@-1{{Dereference of null pointer}}
751 }
752 
753 #undef assert
754 } // end of namespace dont_track_assertlike_conditions
755 
756 namespace dont_track_assertlike_and_conditions {
757 
758 extern void __assert_fail(__const char *__assertion, __const char *__file,
759                           unsigned int __line, __const char *__function)
760     __attribute__((__noreturn__));
761 #define assert(expr) \
762   ((expr) ? (void)(0) : __assert_fail(#expr, __FILE__, __LINE__, __func__))
763 
764 int getInt();
765 
766 int cond1;
767 int cond2;
768 
bar()769 void bar() {
770   cond1 = getInt();
771   cond2 = getInt();
772 }
773 
f(int flag)774 void f(int flag) {
775   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
776 
777   flag = getInt();
778 
779   bar();
780   assert(cond1 && cond2);
781   // expected-note-re@-1{{{{^}}Assuming 'cond1' is not equal to 0{{$}}}}
782   // expected-note-re@-2{{{{^}}Assuming 'cond2' is not equal to 0{{$}}}}
783   // expected-note-re@-3{{{{^}}'?' condition is true{{$}}}}
784   // expected-note-re@-4{{{{^}}Left side of '&&' is true{{$}}}}
785 
786   if (flag) // expected-note-re{{{{^}}Assuming 'flag' is not equal to 0{{$}}}}
787             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
788             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
789     *x = 5; // expected-warning{{Dereference of null pointer}}
790             // expected-note@-1{{Dereference of null pointer}}
791 }
792 
793 #undef assert
794 } // end of namespace dont_track_assertlike_and_conditions
795 
796 namespace dont_track_assertlike_or_conditions {
797 
798 extern void __assert_fail(__const char *__assertion, __const char *__file,
799                           unsigned int __line, __const char *__function)
800     __attribute__((__noreturn__));
801 #define assert(expr) \
802   ((expr) ? (void)(0) : __assert_fail(#expr, __FILE__, __LINE__, __func__))
803 
804 int getInt();
805 
806 int cond1;
807 int cond2;
808 
bar()809 void bar() {
810   cond1 = getInt();
811   cond2 = getInt();
812 }
813 
f(int flag)814 void f(int flag) {
815   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
816 
817   flag = getInt();
818 
819   bar();
820   assert(cond1 || cond2);
821   // expected-note-re@-1{{{{^}}Assuming 'cond1' is not equal to 0{{$}}}}
822   // expected-note-re@-2{{{{^}}Left side of '||' is true{{$}}}}
823 
824   if (flag) // expected-note-re{{{{^}}Assuming 'flag' is not equal to 0{{$}}}}
825             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
826             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
827     *x = 5; // expected-warning{{Dereference of null pointer}}
828             // expected-note@-1{{Dereference of null pointer}}
829 }
830 
831 #undef assert
832 } // end of namespace dont_track_assertlike_or_conditions
833 
834 namespace dont_track_assert2like_conditions {
835 
836 extern void __assert_fail(__const char *__assertion, __const char *__file,
837                           unsigned int __line, __const char *__function)
838     __attribute__((__noreturn__));
839 #define assert(expr)                                      \
840   do {                                                    \
841     if (!(expr))                                          \
842       __assert_fail(#expr, __FILE__, __LINE__, __func__); \
843   } while (0)
844 
845 int getInt();
846 
847 int cond1;
848 
bar()849 void bar() {
850   cond1 = getInt();
851 }
852 
f(int flag)853 void f(int flag) {
854   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
855 
856   flag = getInt();
857 
858   bar();
859   assert(cond1); // expected-note-re{{{{^}}Assuming 'cond1' is not equal to 0{{$}}}}
860                  // expected-note-re@-1{{{{^}}Taking false branch{{$}}}}
861                  // expected-note-re@-2{{{{^}}Loop condition is false.  Exiting loop{{$}}}}
862 
863   if (flag) // expected-note-re{{{{^}}Assuming 'flag' is not equal to 0{{$}}}}
864             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
865             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
866     *x = 5; // expected-warning{{Dereference of null pointer}}
867             // expected-note@-1{{Dereference of null pointer}}
868 }
869 
870 #undef assert
871 } // end of namespace dont_track_assert2like_conditions
872 
873 namespace dont_track_assert2like_and_conditions {
874 
875 extern void __assert_fail(__const char *__assertion, __const char *__file,
876                           unsigned int __line, __const char *__function)
877     __attribute__((__noreturn__));
878 #define assert(expr)                                      \
879   do {                                                    \
880     if (!(expr))                                          \
881       __assert_fail(#expr, __FILE__, __LINE__, __func__); \
882   } while (0)
883 
884 int getInt();
885 
886 int cond1;
887 int cond2;
888 
bar()889 void bar() {
890   cond1 = getInt();
891   cond2 = getInt();
892 }
893 
f(int flag)894 void f(int flag) {
895   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
896 
897   flag = getInt();
898 
899   bar();
900   assert(cond1 && cond2);
901   // expected-note-re@-1{{{{^}}Assuming 'cond1' is not equal to 0{{$}}}}
902   // expected-note-re@-2{{{{^}}Left side of '&&' is true{{$}}}}
903   // expected-note-re@-3{{{{^}}Assuming the condition is false{{$}}}}
904   // expected-note-re@-4{{{{^}}Taking false branch{{$}}}}
905   // expected-note-re@-5{{{{^}}Loop condition is false.  Exiting loop{{$}}}}
906 
907   if (flag) // expected-note-re{{{{^}}Assuming 'flag' is not equal to 0{{$}}}}
908             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
909             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
910     *x = 5; // expected-warning{{Dereference of null pointer}}
911             // expected-note@-1{{Dereference of null pointer}}
912 }
913 
914 #undef assert
915 } // end of namespace dont_track_assert2like_and_conditions
916 
917 namespace dont_track_assert2like_or_conditions {
918 
919 extern void __assert_fail(__const char *__assertion, __const char *__file,
920                           unsigned int __line, __const char *__function)
921     __attribute__((__noreturn__));
922 #define assert(expr)                                      \
923   do {                                                    \
924     if (!(expr))                                          \
925       __assert_fail(#expr, __FILE__, __LINE__, __func__); \
926   } while (0)
927 
928 int getInt();
929 
930 int cond1;
931 int cond2;
932 
bar()933 void bar() {
934   cond1 = getInt();
935   cond2 = getInt();
936 }
937 
f(int flag)938 void f(int flag) {
939   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
940 
941   flag = getInt();
942 
943   bar();
944   assert(cond1 || cond2);
945   // expected-note-re@-1{{{{^}}Assuming 'cond1' is not equal to 0{{$}}}}
946   // expected-note-re@-2{{{{^}}Left side of '||' is true{{$}}}}
947   // expected-note-re@-3{{{{^}}Taking false branch{{$}}}}
948   // expected-note-re@-4{{{{^}}Loop condition is false.  Exiting loop{{$}}}}
949 
950   if (flag) // expected-note-re{{{{^}}Assuming 'flag' is not equal to 0{{$}}}}
951             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
952             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
953     *x = 5; // expected-warning{{Dereference of null pointer}}
954             // expected-note@-1{{Dereference of null pointer}}
955 }
956 
957 #undef assert
958 } // end of namespace dont_track_assert2like_or_conditions
959 
960 namespace only_track_the_evaluated_condition {
961 
962 bool coin();
963 
bar(int & flag)964 void bar(int &flag) {
965   flag = coin(); // tracking-note-re{{{{^}}Value assigned to 'flag', which participates in a condition later{{$}}}}
966 }
967 
bar2(int & flag2)968 void bar2(int &flag2) {
969   flag2 = coin();
970 }
971 
f(int * x)972 void f(int *x) {
973   if (x) // expected-note-re{{{{^}}Assuming 'x' is null{{$}}}}
974          // debug-note-re@-1{{{{^}}Tracking condition 'x'{{$}}}}
975          // expected-note-re@-2{{{{^}}Taking false branch{{$}}}}
976     return;
977 
978   int flag, flag2;
979   bar(flag); // tracking-note-re{{{{^}}Calling 'bar'{{$}}}}
980              // tracking-note-re@-1{{{{^}}Returning from 'bar'{{$}}}}
981   bar2(flag2);
982 
983   if (flag && flag2) // expected-note-re   {{{{^}}Assuming 'flag' is 0{{$}}}}
984                      // expected-note-re@-1{{{{^}}Left side of '&&' is false{{$}}}}
985                      // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
986     return;
987 
988   *x = 5; // expected-warning{{Dereference of null pointer}}
989           // expected-note@-1{{Dereference of null pointer}}
990 }
991 
992 } // end of namespace only_track_the_evaluated_condition
993 
994 namespace operator_call_in_condition_point {
995 
996 struct Error {
operator booloperator_call_in_condition_point::Error997   explicit operator bool() {
998     return true;
999   }
1000 };
1001 
1002 Error couldFail();
1003 
f(int * x)1004 void f(int *x) {
1005   x = nullptr;              // expected-note {{Null pointer value stored to 'x'}}
1006   if (auto e = couldFail()) // expected-note {{Taking true branch}}
1007     *x = 5;                 // expected-warning {{Dereference of null pointer (loaded from variable 'x') [core.NullDereference]}}
1008                             // expected-note@-1 {{Dereference}}
1009 }
1010 
1011 } // namespace operator_call_in_condition_point
1012 
1013 namespace cxx17_ifinit__operator_call_in_condition_point {
1014 
1015 struct Error {
operator boolcxx17_ifinit__operator_call_in_condition_point::Error1016   explicit operator bool() {
1017     return true;
1018   }
1019 };
1020 
1021 Error couldFail();
1022 
f(int * x)1023 void f(int *x) {
1024   x = nullptr;              // expected-note {{Null pointer value stored to 'x'}}
1025   if (auto e = couldFail(); e) // expected-note {{Taking true branch}}
1026     *x = 5;                 // expected-warning {{Dereference of null pointer (loaded from variable 'x') [core.NullDereference]}}
1027                             // expected-note@-1 {{Dereference}}
1028 }
1029 
1030 } // namespace cxx17_ifinit__operator_call_in_condition_point
1031 
1032 namespace funcion_call_in_condition_point {
1033 
alwaysTrue()1034 int alwaysTrue() {
1035   return true;
1036 }
1037 
f(int * x)1038 void f(int *x) {
1039   x = nullptr;      // expected-note {{Null pointer value stored to 'x'}}
1040   if (alwaysTrue()) // expected-note {{Taking true branch}}
1041     *x = 5;         // expected-warning {{Dereference of null pointer (loaded from variable 'x') [core.NullDereference]}}
1042                     // expected-note@-1 {{Dereference}}
1043 }
1044 
1045 } // namespace funcion_call_in_condition_point
1046 
1047 namespace funcion_call_negated_in_condition_point {
1048 
alwaysFalse()1049 int alwaysFalse() {
1050   return false;
1051 }
1052 
f(int * x)1053 void f(int *x) {
1054   x = nullptr;        // expected-note {{Null pointer value stored to 'x'}}
1055   if (!alwaysFalse()) // expected-note {{Taking true branch}}
1056     *x = 5;           // expected-warning {{Dereference of null pointer (loaded from variable 'x') [core.NullDereference]}}
1057                       // expected-note@-1 {{Dereference}}
1058 }
1059 
1060 } // namespace funcion_call_negated_in_condition_point
1061 
1062 namespace funcion_call_part_of_logical_expr_in_condition_point {
1063 
alwaysFalse()1064 int alwaysFalse() {
1065   return false;
1066 }
1067 
f(int * x)1068 void f(int *x) {
1069   x = nullptr;        // expected-note {{Null pointer value stored to 'x'}}
1070   if (!alwaysFalse() && true) // expected-note {{Taking true branch}}
1071                               // expected-note@-1 {{Left side of '&&' is true}}
1072     *x = 5;           // expected-warning {{Dereference of null pointer (loaded from variable 'x') [core.NullDereference]}}
1073                       // expected-note@-1 {{Dereference}}
1074 }
1075 
1076 } // namespace funcion_call_part_of_logical_expr_in_condition_point
1077