forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			1003 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			1003 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C++
		
	
	
	
| // RUN: %clang_analyze_cc1 %s -std=c++14 \
 | |
| // RUN:   -verify=expected,tracking \
 | |
| // RUN:   -analyzer-config track-conditions=true \
 | |
| // RUN:   -analyzer-output=text \
 | |
| // RUN:   -analyzer-checker=core
 | |
| 
 | |
| // RUN: not %clang_analyze_cc1 -std=c++14 -verify %s \
 | |
| // RUN:   -analyzer-checker=core \
 | |
| // RUN:   -analyzer-config track-conditions=false \
 | |
| // RUN:   -analyzer-config track-conditions-debug=true \
 | |
| // RUN:   2>&1 | FileCheck %s -check-prefix=CHECK-INVALID-DEBUG
 | |
| 
 | |
| // CHECK-INVALID-DEBUG: (frontend): invalid input for analyzer-config option
 | |
| // CHECK-INVALID-DEBUG-SAME:        'track-conditions-debug', that expects
 | |
| // CHECK-INVALID-DEBUG-SAME:        'track-conditions' to also be enabled
 | |
| //
 | |
| // RUN: %clang_analyze_cc1 %s -std=c++14 \
 | |
| // RUN:   -verify=expected,tracking,debug \
 | |
| // RUN:   -analyzer-config track-conditions=true \
 | |
| // RUN:   -analyzer-config track-conditions-debug=true \
 | |
| // RUN:   -analyzer-output=text \
 | |
| // RUN:   -analyzer-checker=core
 | |
| 
 | |
| // RUN: %clang_analyze_cc1 %s -std=c++14 -verify \
 | |
| // RUN:   -analyzer-output=text \
 | |
| // RUN:   -analyzer-config track-conditions=false \
 | |
| // RUN:   -analyzer-checker=core
 | |
| 
 | |
| namespace example_1 {
 | |
| int flag;
 | |
| bool coin();
 | |
| 
 | |
| void foo() {
 | |
|   flag = coin(); // tracking-note-re{{{{^}}Value assigned to 'flag', which participates in a condition later{{$}}}}
 | |
| }
 | |
| 
 | |
| void test() {
 | |
|   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
 | |
|   flag = 1;
 | |
| 
 | |
|   foo(); // TODO: Add nodes here about flag's value being invalidated.
 | |
|   if (flag) // expected-note-re   {{{{^}}Assuming 'flag' is 0{{$}}}}
 | |
|             // expected-note-re@-1{{{{^}}Taking false branch{{$}}}}
 | |
|     x = new int;
 | |
| 
 | |
|   foo(); // tracking-note-re{{{{^}}Calling 'foo'{{$}}}}
 | |
|          // tracking-note-re@-1{{{{^}}Returning from 'foo'{{$}}}}
 | |
| 
 | |
|   if (flag) // expected-note-re   {{{{^}}Assuming 'flag' is not equal to 0{{$}}}}
 | |
|             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
 | |
|             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
 | |
| 
 | |
|     *x = 5; // expected-warning{{Dereference of null pointer}}
 | |
|             // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| } // end of namespace example_1
 | |
| 
 | |
| namespace example_2 {
 | |
| int flag;
 | |
| bool coin();
 | |
| 
 | |
| void foo() {
 | |
|   flag = coin(); // tracking-note-re{{{{^}}Value assigned to 'flag', which participates in a condition later{{$}}}}
 | |
| }
 | |
| 
 | |
| void test() {
 | |
|   int *x = 0;
 | |
|   flag = 1;
 | |
| 
 | |
|   foo();
 | |
|   if (flag) // expected-note-re   {{{{^}}Assuming 'flag' is 0{{$}}}}
 | |
|             // expected-note-re@-1{{{{^}}Taking false branch{{$}}}}
 | |
|     x = new int;
 | |
| 
 | |
|   x = 0; // expected-note-re{{{{^}}Null pointer value stored to 'x'{{$}}}}
 | |
| 
 | |
|   foo(); // tracking-note-re{{{{^}}Calling 'foo'{{$}}}}
 | |
|          // tracking-note-re@-1{{{{^}}Returning from 'foo'{{$}}}}
 | |
| 
 | |
|   if (flag) // expected-note-re   {{{{^}}Assuming 'flag' is not equal to 0{{$}}}}
 | |
|             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
 | |
|             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
 | |
| 
 | |
|     *x = 5; // expected-warning{{Dereference of null pointer}}
 | |
|             // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| } // end of namespace example_2
 | |
| 
 | |
| namespace global_variable_invalidation {
 | |
| int flag;
 | |
| bool coin();
 | |
| 
 | |
| void foo() {
 | |
|   // coin() could write bar, do it's invalidated.
 | |
|   flag = coin(); // tracking-note-re{{{{^}}Value assigned to 'flag', which participates in a condition later{{$}}}}
 | |
|                  // tracking-note-re@-1{{{{^}}Value assigned to 'bar', which participates in a condition later{{$}}}}
 | |
| }
 | |
| 
 | |
| int bar;
 | |
| 
 | |
| void test() {
 | |
|   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
 | |
|   flag = 1;
 | |
| 
 | |
|   foo(); // tracking-note-re{{{{^}}Calling 'foo'{{$}}}}
 | |
|          // tracking-note-re@-1{{{{^}}Returning from 'foo'{{$}}}}
 | |
| 
 | |
|   if (bar) // expected-note-re   {{{{^}}Assuming 'bar' is not equal to 0{{$}}}}
 | |
|            // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
 | |
|            // debug-note-re@-2{{{{^}}Tracking condition 'bar'{{$}}}}
 | |
|     if (flag) // expected-note-re   {{{{^}}Assuming 'flag' is not equal to 0{{$}}}}
 | |
|               // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
 | |
|               // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
 | |
| 
 | |
|       *x = 5; // expected-warning{{Dereference of null pointer}}
 | |
|               // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| } // end of namespace global_variable_invalidation
 | |
| 
 | |
| namespace variable_declaration_in_condition {
 | |
| bool coin();
 | |
| 
 | |
| bool foo() {
 | |
|   return coin();
 | |
| }
 | |
| 
 | |
| int bar;
 | |
| 
 | |
| void test() {
 | |
|   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
 | |
| 
 | |
|   if (int flag = foo()) // debug-note-re{{{{^}}Tracking condition 'flag'{{$}}}}
 | |
|                         // expected-note-re@-1{{{{^}}Assuming 'flag' is not equal to 0{{$}}}}
 | |
|                         // expected-note-re@-2{{{{^}}Taking true branch{{$}}}}
 | |
| 
 | |
|     *x = 5; // expected-warning{{Dereference of null pointer}}
 | |
|             // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| } // end of namespace variable_declaration_in_condition
 | |
| 
 | |
| namespace conversion_to_bool {
 | |
| bool coin();
 | |
| 
 | |
| struct ConvertsToBool {
 | |
|   operator bool() const { return coin(); }
 | |
| };
 | |
| 
 | |
| void test() {
 | |
|   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
 | |
| 
 | |
|   if (ConvertsToBool())
 | |
|     // debug-note-re@-1{{{{^}}Tracking condition 'ConvertsToBool()'{{$}}}}
 | |
|     // expected-note-re@-2{{{{^}}Assuming the condition is true{{$}}}}
 | |
|     // expected-note-re@-3{{{{^}}Taking true branch{{$}}}}
 | |
|     *x = 5; // expected-warning{{Dereference of null pointer}}
 | |
|             // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| 
 | |
| } // end of namespace variable_declaration_in_condition
 | |
| 
 | |
| namespace note_from_different_but_not_nested_stackframe {
 | |
| 
 | |
| void nullptrDeref(int *ptr, bool True) {
 | |
|   if (True) // expected-note-re{{{{^}}'True' is true{{$}}}}
 | |
|             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
 | |
|             // debug-note-re@-2{{{{^}}Tracking condition 'True'{{$}}}}
 | |
|     *ptr = 5;
 | |
|   // expected-note@-1{{Dereference of null pointer (loaded from variable 'ptr')}}
 | |
|   // expected-warning@-2{{Dereference of null pointer (loaded from variable 'ptr')}}
 | |
| }
 | |
| 
 | |
| void f() {
 | |
|   int *ptr = nullptr;
 | |
|   // expected-note-re@-1{{{{^}}'ptr' initialized to a null pointer value{{$}}}}
 | |
|   bool True = true;
 | |
|   nullptrDeref(ptr, True);
 | |
|   // expected-note-re@-1{{{{^}}Passing null pointer value via 1st parameter 'ptr'{{$}}}}
 | |
|   // expected-note-re@-2{{{{^}}Calling 'nullptrDeref'{{$}}}}
 | |
| }
 | |
| 
 | |
| } // end of namespace note_from_different_but_not_nested_stackframe
 | |
| 
 | |
| namespace important_returning_pointer_loaded_from {
 | |
| bool coin();
 | |
| 
 | |
| int *getIntPtr();
 | |
| 
 | |
| void storeValue(int **i) {
 | |
|   *i = getIntPtr(); // tracking-note-re{{{{^}}Value assigned to 'i', which participates in a condition later{{$}}}}
 | |
| }
 | |
| 
 | |
| int *conjurePointer() {
 | |
|   int *i;
 | |
|   storeValue(&i); // tracking-note-re{{{{^}}Calling 'storeValue'{{$}}}}
 | |
|                   // tracking-note-re@-1{{{{^}}Returning from 'storeValue'{{$}}}}
 | |
|   return i; // tracking-note-re{{{{^}}Returning pointer (loaded from 'i'), which participates in a condition later{{$}}}}
 | |
| }
 | |
| 
 | |
| void f(int *ptr) {
 | |
|   if (ptr) // expected-note-re{{{{^}}Assuming 'ptr' is null{{$}}}}
 | |
|            // expected-note-re@-1{{{{^}}Taking false branch{{$}}}}
 | |
|     ;
 | |
|   if (!conjurePointer())
 | |
|     // tracking-note-re@-1{{{{^}}Calling 'conjurePointer'{{$}}}}
 | |
|     // tracking-note-re@-2{{{{^}}Returning from 'conjurePointer'{{$}}}}
 | |
|     // debug-note-re@-3{{{{^}}Tracking condition '!conjurePointer()'{{$}}}}
 | |
|     // expected-note-re@-4{{{{^}}Assuming the condition is true{{$}}}}
 | |
|     // expected-note-re@-5{{{{^}}Taking true branch{{$}}}}
 | |
|     *ptr = 5; // expected-warning{{Dereference of null pointer}}
 | |
|               // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| } // end of namespace important_returning_pointer_loaded_from
 | |
| 
 | |
| namespace unimportant_returning_pointer_loaded_from {
 | |
| bool coin();
 | |
| 
 | |
| int *getIntPtr();
 | |
| 
 | |
| int *conjurePointer() {
 | |
|   int *i = getIntPtr();
 | |
|   return i;
 | |
| }
 | |
| 
 | |
| void f(int *ptr) {
 | |
|   if (ptr) // expected-note-re{{{{^}}Assuming 'ptr' is null{{$}}}}
 | |
|            // expected-note-re@-1{{{{^}}Taking false branch{{$}}}}
 | |
|     ;
 | |
|   if (!conjurePointer())
 | |
|     // debug-note-re@-1{{{{^}}Tracking condition '!conjurePointer()'{{$}}}}
 | |
|     // expected-note-re@-2{{{{^}}Assuming the condition is true{{$}}}}
 | |
|     // expected-note-re@-3{{{{^}}Taking true branch{{$}}}}
 | |
|     *ptr = 5; // expected-warning{{Dereference of null pointer}}
 | |
|               // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| } // end of namespace unimportant_returning_pointer_loaded_from
 | |
| 
 | |
| namespace unimportant_returning_pointer_loaded_from_through_cast {
 | |
| 
 | |
| void *conjure();
 | |
| 
 | |
| int *cast(void *P) {
 | |
|   return static_cast<int *>(P);
 | |
| }
 | |
| 
 | |
| void f() {
 | |
|   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
 | |
| 
 | |
|   if (cast(conjure()))
 | |
|     // debug-note-re@-1{{{{^}}Tracking condition 'cast(conjure())'{{$}}}}
 | |
|     // expected-note-re@-2{{{{^}}Assuming the condition is false{{$}}}}
 | |
|     // expected-note-re@-3{{{{^}}Taking false branch{{$}}}}
 | |
|     return;
 | |
|   *x = 5; // expected-warning{{Dereference of null pointer}}
 | |
|           // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| 
 | |
| } // end of namespace unimportant_returning_pointer_loaded_from_through_cast
 | |
| 
 | |
| namespace unimportant_returning_value_note {
 | |
| bool coin();
 | |
| 
 | |
| bool flipCoin() { return coin(); }
 | |
| 
 | |
| void i(int *ptr) {
 | |
|   if (ptr) // expected-note-re{{{{^}}Assuming 'ptr' is null{{$}}}}
 | |
|            // expected-note-re@-1{{{{^}}Taking false branch{{$}}}}
 | |
|     ;
 | |
|   if (!flipCoin())
 | |
|     // debug-note-re@-1{{{{^}}Tracking condition '!flipCoin()'{{$}}}}
 | |
|     // expected-note-re@-2{{{{^}}Assuming the condition is true{{$}}}}
 | |
|     // expected-note-re@-3{{{{^}}Taking true branch{{$}}}}
 | |
|     *ptr = 5; // expected-warning{{Dereference of null pointer}}
 | |
|               // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| } // end of namespace unimportant_returning_value_note
 | |
| 
 | |
| namespace important_returning_value_note {
 | |
| bool coin();
 | |
| 
 | |
| bool flipCoin() {
 | |
|   if (coin()) // tracking-note-re{{{{^}}Assuming the condition is false{{$}}}}
 | |
|               // tracking-note-re@-1{{{{^}}Taking false branch{{$}}}}
 | |
|               // debug-note-re@-2{{{{^}}Tracking condition 'coin()'{{$}}}}
 | |
|     return true;
 | |
|   return coin(); // tracking-note-re{{{{^}}Returning value, which participates in a condition later{{$}}}}
 | |
| }
 | |
| 
 | |
| void i(int *ptr) {
 | |
|   if (ptr) // expected-note-re{{{{^}}Assuming 'ptr' is null{{$}}}}
 | |
|            // expected-note-re@-1{{{{^}}Taking false branch{{$}}}}
 | |
|     ;
 | |
|   if (!flipCoin())
 | |
|     // tracking-note-re@-1{{{{^}}Calling 'flipCoin'{{$}}}}
 | |
|     // tracking-note-re@-2{{{{^}}Returning from 'flipCoin'{{$}}}}
 | |
|     // debug-note-re@-3{{{{^}}Tracking condition '!flipCoin()'{{$}}}}
 | |
|     // expected-note-re@-4{{{{^}}Assuming the condition is true{{$}}}}
 | |
|     // expected-note-re@-5{{{{^}}Taking true branch{{$}}}}
 | |
|     *ptr = 5; // expected-warning{{Dereference of null pointer}}
 | |
|               // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| } // end of namespace important_returning_value_note
 | |
| 
 | |
| namespace important_returning_value_note_in_linear_function {
 | |
| bool coin();
 | |
| 
 | |
| struct super_complicated_template_hackery {
 | |
|   static constexpr bool value = false;
 | |
| };
 | |
| 
 | |
| bool flipCoin() {
 | |
|   if (super_complicated_template_hackery::value)
 | |
|     // tracking-note-re@-1{{{{^}}'value' is false{{$}}}}
 | |
|     // tracking-note-re@-2{{{{^}}Taking false branch{{$}}}}
 | |
|     return true;
 | |
|   return coin(); // tracking-note-re{{{{^}}Returning value, which participates in a condition later{{$}}}}
 | |
| }
 | |
| 
 | |
| void i(int *ptr) {
 | |
|   if (ptr) // expected-note-re{{{{^}}Assuming 'ptr' is null{{$}}}}
 | |
|            // expected-note-re@-1{{{{^}}Taking false branch{{$}}}}
 | |
|     ;
 | |
|   if (!flipCoin())
 | |
|     // tracking-note-re@-1{{{{^}}Calling 'flipCoin'{{$}}}}
 | |
|     // tracking-note-re@-2{{{{^}}Returning from 'flipCoin'{{$}}}}
 | |
|     // debug-note-re@-3{{{{^}}Tracking condition '!flipCoin()'{{$}}}}
 | |
|     // expected-note-re@-4{{{{^}}Assuming the condition is true{{$}}}}
 | |
|     // expected-note-re@-5{{{{^}}Taking true branch{{$}}}}
 | |
|     *ptr = 5; // expected-warning{{Dereference of null pointer}}
 | |
|               // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| } // end of namespace important_returning_value_note_in_linear_function
 | |
| 
 | |
| namespace tracked_condition_is_only_initialized {
 | |
| int getInt();
 | |
| 
 | |
| void f() {
 | |
|   int flag = getInt();
 | |
|   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
 | |
|   if (flag) // expected-note-re{{{{^}}Assuming 'flag' is not equal to 0{{$}}}}
 | |
|             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
 | |
|             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
 | |
|     *x = 5; // expected-warning{{Dereference of null pointer}}
 | |
|             // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| } // end of namespace tracked_condition_is_only_initialized
 | |
| 
 | |
| namespace tracked_condition_written_in_same_stackframe {
 | |
| int flag;
 | |
| int getInt();
 | |
| 
 | |
| void f(int y) {
 | |
|   y = 1;
 | |
|   flag = y;
 | |
| 
 | |
|   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
 | |
|   if (flag) // expected-note-re{{{{^}}'flag' is 1{{$}}}}
 | |
|             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
 | |
|             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
 | |
|     *x = 5; // expected-warning{{Dereference of null pointer}}
 | |
|             // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| } // end of namespace tracked_condition_written_in_same_stackframe
 | |
| 
 | |
| namespace tracked_condition_written_in_nested_stackframe {
 | |
| int flag;
 | |
| int getInt();
 | |
| 
 | |
| void foo() {
 | |
|   int y;
 | |
|   y = 1;
 | |
|   flag = y; // tracking-note-re{{{{^}}The value 1 is assigned to 'flag', which participates in a condition later{{$}}}}
 | |
| }
 | |
| 
 | |
| void f(int y) {
 | |
|   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
 | |
| 
 | |
|   foo(); // tracking-note-re{{{{^}}Calling 'foo'{{$}}}}
 | |
|          // tracking-note-re@-1{{{{^}}Returning from 'foo'{{$}}}}
 | |
| 
 | |
|   if (flag) // expected-note-re{{{{^}}'flag' is 1{{$}}}}
 | |
|             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
 | |
|             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
 | |
|     *x = 5; // expected-warning{{Dereference of null pointer}}
 | |
|             // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| } // end of namespace tracked_condition_written_in_nested_stackframe
 | |
| 
 | |
| namespace condition_written_in_nested_stackframe_before_assignment {
 | |
| int flag = 0;
 | |
| int getInt();
 | |
| 
 | |
| void foo() {
 | |
|   flag = getInt(); // tracking-note-re{{{{^}}Value assigned to 'flag', which participates in a condition later{{$}}}}
 | |
| }
 | |
| 
 | |
| void f() {
 | |
|   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
 | |
|   int y = 0;
 | |
| 
 | |
|   foo(); // tracking-note-re{{{{^}}Calling 'foo'{{$}}}}
 | |
|          // tracking-note-re@-1{{{{^}}Returning from 'foo'{{$}}}}
 | |
|   y = flag;
 | |
| 
 | |
|   if (y)    // expected-note-re{{{{^}}Assuming 'y' is not equal to 0{{$}}}}
 | |
|             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
 | |
|             // debug-note-re@-2{{{{^}}Tracking condition 'y'{{$}}}}
 | |
|     *x = 5; // expected-warning{{Dereference of null pointer}}
 | |
|             // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| } // end of namespace condition_written_in_nested_stackframe_before_assignment
 | |
| 
 | |
| namespace dont_explain_foreach_loops {
 | |
| 
 | |
| struct Iterator {
 | |
|   int *pos;
 | |
|   bool operator!=(Iterator other) const {
 | |
|     return pos && other.pos && pos != other.pos;
 | |
|   }
 | |
|   int operator*();
 | |
|   Iterator operator++();
 | |
| };
 | |
| 
 | |
| struct Container {
 | |
|   Iterator begin();
 | |
|   Iterator end();
 | |
| };
 | |
| 
 | |
| void f(Container Cont) {
 | |
|   int flag = 0;
 | |
|   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
 | |
|   for (int i : Cont)
 | |
|     if (i) // expected-note-re   {{{{^}}Assuming 'i' is not equal to 0{{$}}}}
 | |
|            // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
 | |
|            // debug-note-re@-2{{{{^}}Tracking condition 'i'{{$}}}}
 | |
|       flag = i;
 | |
| 
 | |
|   if (flag) // expected-note-re{{{{^}}'flag' is not equal to 0{{$}}}}
 | |
|             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
 | |
|             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
 | |
|     *x = 5; // expected-warning{{Dereference of null pointer}}
 | |
|             // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| } // end of namespace dont_explain_foreach_loops
 | |
| 
 | |
| namespace condition_lambda_capture_by_reference_last_write {
 | |
| int getInt();
 | |
| 
 | |
| [[noreturn]] void halt();
 | |
| 
 | |
| void f(int flag) {
 | |
|   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
 | |
| 
 | |
|   auto lambda = [&flag]() {
 | |
|     flag = getInt(); // tracking-note-re{{{{^}}Value assigned to 'flag', which participates in a condition later{{$}}}}
 | |
|   };
 | |
| 
 | |
|   lambda(); // tracking-note-re{{{{^}}Calling 'operator()'{{$}}}}
 | |
|             // tracking-note-re@-1{{{{^}}Returning from 'operator()'{{$}}}}
 | |
| 
 | |
|   if (flag) // expected-note-re{{{{^}}Assuming 'flag' is not equal to 0{{$}}}}
 | |
|             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
 | |
|             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
 | |
|     *x = 5; // expected-warning{{Dereference of null pointer}}
 | |
|             // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| } // end of namespace condition_lambda_capture_by_reference_last_write
 | |
| 
 | |
| namespace condition_lambda_capture_by_value_assumption {
 | |
| int getInt();
 | |
| 
 | |
| [[noreturn]] void halt();
 | |
| 
 | |
| void bar(int &flag) {
 | |
|   flag = getInt(); // tracking-note-re{{{{^}}Value assigned to 'flag', which participates in a condition later{{$}}}}
 | |
| }
 | |
| 
 | |
| void f(int flag) {
 | |
|   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
 | |
| 
 | |
|   auto lambda = [flag]() {
 | |
|     if (!flag) // tracking-note-re{{{{^}}Assuming 'flag' is not equal to 0, which participates in a condition later{{$}}}}
 | |
|                // tracking-note-re@-1{{{{^}}Taking false branch{{$}}}}
 | |
|       halt();
 | |
|   };
 | |
| 
 | |
|   bar(flag); // tracking-note-re{{{{^}}Calling 'bar'{{$}}}}
 | |
|              // tracking-note-re@-1{{{{^}}Returning from 'bar'{{$}}}}
 | |
|   lambda();  // tracking-note-re{{{{^}}Calling 'operator()'{{$}}}}
 | |
|              // tracking-note-re@-1{{{{^}}Returning from 'operator()'{{$}}}}
 | |
| 
 | |
|   if (flag) // expected-note-re{{{{^}}Assuming 'flag' is not equal to 0{{$}}}}
 | |
|             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
 | |
|             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
 | |
|     *x = 5; // expected-warning{{Dereference of null pointer}}
 | |
|             // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| } // end of namespace condition_lambda_capture_by_value_assumption
 | |
| 
 | |
| namespace condition_lambda_capture_by_reference_assumption {
 | |
| int getInt();
 | |
| 
 | |
| [[noreturn]] void halt();
 | |
| 
 | |
| void bar(int &flag) {
 | |
|   flag = getInt(); // tracking-note-re{{{{^}}Value assigned to 'flag', which participates in a condition later{{$}}}}
 | |
| }
 | |
| 
 | |
| void f(int flag) {
 | |
|   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
 | |
| 
 | |
|   auto lambda = [&flag]() {
 | |
|     if (!flag) // tracking-note-re{{{{^}}Assuming 'flag' is not equal to 0, which participates in a condition later{{$}}}}
 | |
|                // tracking-note-re@-1{{{{^}}Taking false branch{{$}}}}
 | |
|       halt();
 | |
|   };
 | |
| 
 | |
|   bar(flag); // tracking-note-re{{{{^}}Calling 'bar'{{$}}}}
 | |
|              // tracking-note-re@-1{{{{^}}Returning from 'bar'{{$}}}}
 | |
|   lambda();  // tracking-note-re{{{{^}}Calling 'operator()'{{$}}}}
 | |
|              // tracking-note-re@-1{{{{^}}Returning from 'operator()'{{$}}}}
 | |
| 
 | |
|   if (flag) // expected-note-re{{{{^}}'flag' is not equal to 0{{$}}}}
 | |
|             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
 | |
|             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
 | |
|     *x = 5; // expected-warning{{Dereference of null pointer}}
 | |
|             // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| } // end of namespace condition_lambda_capture_by_reference_assumption
 | |
| 
 | |
| namespace collapse_point_not_in_condition_bool {
 | |
| 
 | |
| [[noreturn]] void halt();
 | |
| 
 | |
| void check(bool b) {
 | |
|   if (!b) // tracking-note-re{{{{^}}Assuming 'b' is true, which participates in a condition later{{$}}}}
 | |
|           // tracking-note-re@-1{{{{^}}Taking false branch{{$}}}}
 | |
|     halt();
 | |
| }
 | |
| 
 | |
| void f(bool flag) {
 | |
|   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
 | |
| 
 | |
|   check(flag); // tracking-note-re{{{{^}}Calling 'check'{{$}}}}
 | |
|                 // tracking-note-re@-1{{{{^}}Returning from 'check'{{$}}}}
 | |
| 
 | |
|   if (flag) // expected-note-re{{{{^}}'flag' is true{{$}}}}
 | |
|             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
 | |
|             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
 | |
|     *x = 5; // expected-warning{{Dereference of null pointer}}
 | |
|             // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| } // end of namespace collapse_point_not_in_condition_bool
 | |
| 
 | |
| namespace collapse_point_not_in_condition {
 | |
| 
 | |
| [[noreturn]] void halt();
 | |
| 
 | |
| void assert(int b) {
 | |
|   if (!b) // tracking-note-re{{{{^}}Assuming 'b' is not equal to 0, which participates in a condition later{{$}}}}
 | |
|           // tracking-note-re@-1{{{{^}}Taking false branch{{$}}}}
 | |
|     halt();
 | |
| }
 | |
| 
 | |
| void f(int flag) {
 | |
|   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
 | |
| 
 | |
|   assert(flag); // tracking-note-re{{{{^}}Calling 'assert'{{$}}}}
 | |
|                 // tracking-note-re@-1{{{{^}}Returning from 'assert'{{$}}}}
 | |
| 
 | |
|   if (flag) // expected-note-re{{{{^}}'flag' is not equal to 0{{$}}}}
 | |
|             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
 | |
|             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
 | |
|     *x = 5; // expected-warning{{Dereference of null pointer}}
 | |
|             // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| 
 | |
| } // end of namespace collapse_point_not_in_condition
 | |
| 
 | |
| namespace unimportant_write_before_collapse_point {
 | |
| 
 | |
| [[noreturn]] void halt();
 | |
| 
 | |
| void assert(int b) {
 | |
|   if (!b) // tracking-note-re{{{{^}}Assuming 'b' is not equal to 0, which participates in a condition later{{$}}}}
 | |
|           // tracking-note-re@-1{{{{^}}Taking false branch{{$}}}}
 | |
|     halt();
 | |
| }
 | |
| int getInt();
 | |
| 
 | |
| void f(int flag) {
 | |
|   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
 | |
| 
 | |
|   flag = getInt();
 | |
|   assert(flag); // tracking-note-re{{{{^}}Calling 'assert'{{$}}}}
 | |
|                 // tracking-note-re@-1{{{{^}}Returning from 'assert'{{$}}}}
 | |
| 
 | |
|   if (flag) // expected-note-re{{{{^}}'flag' is not equal to 0{{$}}}}
 | |
|             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
 | |
|             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
 | |
|     *x = 5; // expected-warning{{Dereference of null pointer}}
 | |
|             // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| 
 | |
| } // end of namespace unimportant_write_before_collapse_point
 | |
| 
 | |
| namespace dont_crash_on_nonlogical_binary_operator {
 | |
| 
 | |
| void f6(int x) {
 | |
|   int a[20];
 | |
|   if (x == 25) {} // expected-note{{Assuming 'x' is equal to 25}}
 | |
|                   // expected-note@-1{{Taking true branch}}
 | |
|   if (a[x] == 123) {} // expected-warning{{The left operand of '==' is a garbage value due to array index out of bounds}}
 | |
|                       // expected-note@-1{{The left operand of '==' is a garbage value due to array index out of bounds}}
 | |
| }
 | |
| 
 | |
| } // end of namespace dont_crash_on_nonlogical_binary_operator
 | |
| 
 | |
| namespace collapse_point_not_in_condition_binary_op {
 | |
| 
 | |
| [[noreturn]] void halt();
 | |
| 
 | |
| void check(int b) {
 | |
|   if (b == 1) // tracking-note-re{{{{^}}Assuming 'b' is not equal to 1, which participates in a condition later{{$}}}}
 | |
|               // tracking-note-re@-1{{{{^}}Taking false branch{{$}}}}
 | |
|     halt();
 | |
| }
 | |
| 
 | |
| void f(int flag) {
 | |
|   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
 | |
| 
 | |
|   check(flag); // tracking-note-re{{{{^}}Calling 'check'{{$}}}}
 | |
|                // tracking-note-re@-1{{{{^}}Returning from 'check'{{$}}}}
 | |
| 
 | |
|   if (flag) // expected-note-re{{{{^}}Assuming 'flag' is not equal to 0{{$}}}}
 | |
|             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
 | |
|             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
 | |
|     *x = 5; // expected-warning{{Dereference of null pointer}}
 | |
|             // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| 
 | |
| } // end of namespace collapse_point_not_in_condition_binary_op
 | |
| 
 | |
| namespace collapse_point_not_in_condition_as_field {
 | |
| 
 | |
| [[noreturn]] void halt();
 | |
| struct IntWrapper {
 | |
|   int b;
 | |
|   IntWrapper();
 | |
| 
 | |
|   void check() {
 | |
|     if (!b) // tracking-note-re{{{{^}}Assuming field 'b' is not equal to 0, which participates in a condition later{{$}}}}
 | |
|             // tracking-note-re@-1{{{{^}}Taking false branch{{$}}}}
 | |
|       halt();
 | |
|     return;
 | |
|   }
 | |
| };
 | |
| 
 | |
| void f(IntWrapper i) {
 | |
|   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
 | |
| 
 | |
|   i.check(); // tracking-note-re{{{{^}}Calling 'IntWrapper::check'{{$}}}}
 | |
|              // tracking-note-re@-1{{{{^}}Returning from 'IntWrapper::check'{{$}}}}
 | |
|   if (i.b)   // expected-note-re{{{{^}}Field 'b' is not equal to 0{{$}}}}
 | |
|              // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
 | |
|              // debug-note-re@-2{{{{^}}Tracking condition 'i.b'{{$}}}}
 | |
|     *x = 5;  // expected-warning{{Dereference of null pointer}}
 | |
|              // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| 
 | |
| } // end of namespace collapse_point_not_in_condition_as_field
 | |
| 
 | |
| namespace assignemnt_in_condition_in_nested_stackframe {
 | |
| int flag;
 | |
| 
 | |
| bool coin();
 | |
| 
 | |
| [[noreturn]] void halt();
 | |
| 
 | |
| void foo() {
 | |
|   if ((flag = coin()))
 | |
|     // tracking-note-re@-1{{{{^}}Value assigned to 'flag', which participates in a condition later{{$}}}}
 | |
|     // tracking-note-re@-2{{{{^}}Assuming 'flag' is not equal to 0, which participates in a condition later{{$}}}}
 | |
|     // tracking-note-re@-3{{{{^}}Taking true branch{{$}}}}
 | |
|     return;
 | |
|   halt();
 | |
|   return;
 | |
| }
 | |
| 
 | |
| void f() {
 | |
|   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
 | |
| 
 | |
|   foo();    // tracking-note-re{{{{^}}Calling 'foo'{{$}}}}
 | |
|             // tracking-note-re@-1{{{{^}}Returning from 'foo'{{$}}}}
 | |
|   if (flag) // expected-note-re{{{{^}}'flag' is not equal to 0{{$}}}}
 | |
|             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
 | |
|             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
 | |
|     *x = 5; // expected-warning{{Dereference of null pointer}}
 | |
|             // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| } // end of namespace assignemnt_in_condition_in_nested_stackframe
 | |
| 
 | |
| namespace condition_variable_less {
 | |
| int flag;
 | |
| 
 | |
| bool coin();
 | |
| 
 | |
| [[noreturn]] void halt();
 | |
| 
 | |
| void foo() {
 | |
|   if (flag > 0)
 | |
|     // tracking-note-re@-1{{{{^}}Assuming 'flag' is > 0, which participates in a condition later{{$}}}}
 | |
|     // tracking-note-re@-2{{{{^}}Taking true branch{{$}}}}
 | |
|     return;
 | |
|   halt();
 | |
|   return;
 | |
| }
 | |
| 
 | |
| void f() {
 | |
|   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
 | |
| 
 | |
|   foo();    // tracking-note-re{{{{^}}Calling 'foo'{{$}}}}
 | |
|             // tracking-note-re@-1{{{{^}}Returning from 'foo'{{$}}}}
 | |
|   if (flag) // expected-note-re{{{{^}}'flag' is not equal to 0{{$}}}}
 | |
|             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
 | |
|             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
 | |
|     *x = 5; // expected-warning{{Dereference of null pointer}}
 | |
|             // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| } // end of namespace condition_variable_less
 | |
| 
 | |
| namespace dont_track_assertlike_conditions {
 | |
| 
 | |
| extern void __assert_fail(__const char *__assertion, __const char *__file,
 | |
|                           unsigned int __line, __const char *__function)
 | |
|     __attribute__((__noreturn__));
 | |
| #define assert(expr) \
 | |
|   ((expr) ? (void)(0) : __assert_fail(#expr, __FILE__, __LINE__, __func__))
 | |
| 
 | |
| int getInt();
 | |
| 
 | |
| int cond1;
 | |
| 
 | |
| void bar() {
 | |
|   cond1 = getInt();
 | |
| }
 | |
| 
 | |
| void f(int flag) {
 | |
|   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
 | |
| 
 | |
|   flag = getInt();
 | |
| 
 | |
|   bar();
 | |
|   assert(cond1); // expected-note-re{{{{^}}Assuming 'cond1' is not equal to 0{{$}}}}
 | |
|                  // expected-note-re@-1{{{{^}}'?' condition is true{{$}}}}
 | |
| 
 | |
|   if (flag) // expected-note-re{{{{^}}Assuming 'flag' is not equal to 0{{$}}}}
 | |
|             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
 | |
|             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
 | |
|     *x = 5; // expected-warning{{Dereference of null pointer}}
 | |
|             // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| 
 | |
| #undef assert
 | |
| } // end of namespace dont_track_assertlike_conditions
 | |
| 
 | |
| namespace dont_track_assertlike_and_conditions {
 | |
| 
 | |
| extern void __assert_fail(__const char *__assertion, __const char *__file,
 | |
|                           unsigned int __line, __const char *__function)
 | |
|     __attribute__((__noreturn__));
 | |
| #define assert(expr) \
 | |
|   ((expr) ? (void)(0) : __assert_fail(#expr, __FILE__, __LINE__, __func__))
 | |
| 
 | |
| int getInt();
 | |
| 
 | |
| int cond1;
 | |
| int cond2;
 | |
| 
 | |
| void bar() {
 | |
|   cond1 = getInt();
 | |
|   cond2 = getInt();
 | |
| }
 | |
| 
 | |
| void f(int flag) {
 | |
|   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
 | |
| 
 | |
|   flag = getInt();
 | |
| 
 | |
|   bar();
 | |
|   assert(cond1 && cond2);
 | |
|   // expected-note-re@-1{{{{^}}Assuming 'cond1' is not equal to 0{{$}}}}
 | |
|   // expected-note-re@-2{{{{^}}Assuming 'cond2' is not equal to 0{{$}}}}
 | |
|   // expected-note-re@-3{{{{^}}'?' condition is true{{$}}}}
 | |
|   // expected-note-re@-4{{{{^}}Left side of '&&' is true{{$}}}}
 | |
| 
 | |
|   if (flag) // expected-note-re{{{{^}}Assuming 'flag' is not equal to 0{{$}}}}
 | |
|             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
 | |
|             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
 | |
|     *x = 5; // expected-warning{{Dereference of null pointer}}
 | |
|             // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| 
 | |
| #undef assert
 | |
| } // end of namespace dont_track_assertlike_and_conditions
 | |
| 
 | |
| namespace dont_track_assertlike_or_conditions {
 | |
| 
 | |
| extern void __assert_fail(__const char *__assertion, __const char *__file,
 | |
|                           unsigned int __line, __const char *__function)
 | |
|     __attribute__((__noreturn__));
 | |
| #define assert(expr) \
 | |
|   ((expr) ? (void)(0) : __assert_fail(#expr, __FILE__, __LINE__, __func__))
 | |
| 
 | |
| int getInt();
 | |
| 
 | |
| int cond1;
 | |
| int cond2;
 | |
| 
 | |
| void bar() {
 | |
|   cond1 = getInt();
 | |
|   cond2 = getInt();
 | |
| }
 | |
| 
 | |
| void f(int flag) {
 | |
|   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
 | |
| 
 | |
|   flag = getInt();
 | |
| 
 | |
|   bar();
 | |
|   assert(cond1 || cond2);
 | |
|   // expected-note-re@-1{{{{^}}Assuming 'cond1' is not equal to 0{{$}}}}
 | |
|   // expected-note-re@-2{{{{^}}Left side of '||' is true{{$}}}}
 | |
| 
 | |
|   if (flag) // expected-note-re{{{{^}}Assuming 'flag' is not equal to 0{{$}}}}
 | |
|             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
 | |
|             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
 | |
|     *x = 5; // expected-warning{{Dereference of null pointer}}
 | |
|             // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| 
 | |
| #undef assert
 | |
| } // end of namespace dont_track_assertlike_or_conditions
 | |
| 
 | |
| namespace dont_track_assert2like_conditions {
 | |
| 
 | |
| extern void __assert_fail(__const char *__assertion, __const char *__file,
 | |
|                           unsigned int __line, __const char *__function)
 | |
|     __attribute__((__noreturn__));
 | |
| #define assert(expr)                                      \
 | |
|   do {                                                    \
 | |
|     if (!(expr))                                          \
 | |
|       __assert_fail(#expr, __FILE__, __LINE__, __func__); \
 | |
|   } while (0)
 | |
| 
 | |
| int getInt();
 | |
| 
 | |
| int cond1;
 | |
| 
 | |
| void bar() {
 | |
|   cond1 = getInt();
 | |
| }
 | |
| 
 | |
| void f(int flag) {
 | |
|   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
 | |
| 
 | |
|   flag = getInt();
 | |
| 
 | |
|   bar();
 | |
|   assert(cond1); // expected-note-re{{{{^}}Assuming 'cond1' is not equal to 0{{$}}}}
 | |
|                  // expected-note-re@-1{{{{^}}Taking false branch{{$}}}}
 | |
|                  // expected-note-re@-2{{{{^}}Loop condition is false.  Exiting loop{{$}}}}
 | |
| 
 | |
|   if (flag) // expected-note-re{{{{^}}Assuming 'flag' is not equal to 0{{$}}}}
 | |
|             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
 | |
|             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
 | |
|     *x = 5; // expected-warning{{Dereference of null pointer}}
 | |
|             // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| 
 | |
| #undef assert
 | |
| } // end of namespace dont_track_assert2like_conditions
 | |
| 
 | |
| namespace dont_track_assert2like_and_conditions {
 | |
| 
 | |
| extern void __assert_fail(__const char *__assertion, __const char *__file,
 | |
|                           unsigned int __line, __const char *__function)
 | |
|     __attribute__((__noreturn__));
 | |
| #define assert(expr)                                      \
 | |
|   do {                                                    \
 | |
|     if (!(expr))                                          \
 | |
|       __assert_fail(#expr, __FILE__, __LINE__, __func__); \
 | |
|   } while (0)
 | |
| 
 | |
| int getInt();
 | |
| 
 | |
| int cond1;
 | |
| int cond2;
 | |
| 
 | |
| void bar() {
 | |
|   cond1 = getInt();
 | |
|   cond2 = getInt();
 | |
| }
 | |
| 
 | |
| void f(int flag) {
 | |
|   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
 | |
| 
 | |
|   flag = getInt();
 | |
| 
 | |
|   bar();
 | |
|   assert(cond1 && cond2);
 | |
|   // expected-note-re@-1{{{{^}}Assuming 'cond1' is not equal to 0{{$}}}}
 | |
|   // expected-note-re@-2{{{{^}}Left side of '&&' is true{{$}}}}
 | |
|   // expected-note-re@-3{{{{^}}Assuming the condition is false{{$}}}}
 | |
|   // expected-note-re@-4{{{{^}}Taking false branch{{$}}}}
 | |
|   // expected-note-re@-5{{{{^}}Loop condition is false.  Exiting loop{{$}}}}
 | |
| 
 | |
|   if (flag) // expected-note-re{{{{^}}Assuming 'flag' is not equal to 0{{$}}}}
 | |
|             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
 | |
|             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
 | |
|     *x = 5; // expected-warning{{Dereference of null pointer}}
 | |
|             // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| 
 | |
| #undef assert
 | |
| } // end of namespace dont_track_assert2like_and_conditions
 | |
| 
 | |
| namespace dont_track_assert2like_or_conditions {
 | |
| 
 | |
| extern void __assert_fail(__const char *__assertion, __const char *__file,
 | |
|                           unsigned int __line, __const char *__function)
 | |
|     __attribute__((__noreturn__));
 | |
| #define assert(expr)                                      \
 | |
|   do {                                                    \
 | |
|     if (!(expr))                                          \
 | |
|       __assert_fail(#expr, __FILE__, __LINE__, __func__); \
 | |
|   } while (0)
 | |
| 
 | |
| int getInt();
 | |
| 
 | |
| int cond1;
 | |
| int cond2;
 | |
| 
 | |
| void bar() {
 | |
|   cond1 = getInt();
 | |
|   cond2 = getInt();
 | |
| }
 | |
| 
 | |
| void f(int flag) {
 | |
|   int *x = 0; // expected-note-re{{{{^}}'x' initialized to a null pointer value{{$}}}}
 | |
| 
 | |
|   flag = getInt();
 | |
| 
 | |
|   bar();
 | |
|   assert(cond1 || cond2);
 | |
|   // expected-note-re@-1{{{{^}}Assuming 'cond1' is not equal to 0{{$}}}}
 | |
|   // expected-note-re@-2{{{{^}}Left side of '||' is true{{$}}}}
 | |
|   // expected-note-re@-3{{{{^}}Taking false branch{{$}}}}
 | |
|   // expected-note-re@-4{{{{^}}Loop condition is false.  Exiting loop{{$}}}}
 | |
| 
 | |
|   if (flag) // expected-note-re{{{{^}}Assuming 'flag' is not equal to 0{{$}}}}
 | |
|             // expected-note-re@-1{{{{^}}Taking true branch{{$}}}}
 | |
|             // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
 | |
|     *x = 5; // expected-warning{{Dereference of null pointer}}
 | |
|             // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| 
 | |
| #undef assert
 | |
| } // end of namespace dont_track_assert2like_or_conditions
 | |
| 
 | |
| namespace only_track_the_evaluated_condition {
 | |
| 
 | |
| bool coin();
 | |
| 
 | |
| void bar(int &flag) {
 | |
|   flag = coin(); // tracking-note-re{{{{^}}Value assigned to 'flag', which participates in a condition later{{$}}}}
 | |
| }
 | |
| 
 | |
| void bar2(int &flag2) {
 | |
|   flag2 = coin();
 | |
| }
 | |
| 
 | |
| void f(int *x) {
 | |
|   if (x) // expected-note-re{{{{^}}Assuming 'x' is null{{$}}}}
 | |
|          // debug-note-re@-1{{{{^}}Tracking condition 'x'{{$}}}}
 | |
|          // expected-note-re@-2{{{{^}}Taking false branch{{$}}}}
 | |
|     return;
 | |
| 
 | |
|   int flag, flag2;
 | |
|   bar(flag); // tracking-note-re{{{{^}}Calling 'bar'{{$}}}}
 | |
|              // tracking-note-re@-1{{{{^}}Returning from 'bar'{{$}}}}
 | |
|   bar2(flag2);
 | |
| 
 | |
|   if (flag && flag2) // expected-note-re   {{{{^}}Assuming 'flag' is 0{{$}}}}
 | |
|                      // expected-note-re@-1{{{{^}}Left side of '&&' is false{{$}}}}
 | |
|                      // debug-note-re@-2{{{{^}}Tracking condition 'flag'{{$}}}}
 | |
|     return;
 | |
| 
 | |
|   *x = 5; // expected-warning{{Dereference of null pointer}}
 | |
|           // expected-note@-1{{Dereference of null pointer}}
 | |
| }
 | |
| 
 | |
| } // end of namespace only_track_the_evaluated_condition
 |