| // RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s |
| |
| struct S { |
| int n; |
| }; |
| struct T { |
| S s; |
| }; |
| |
| // &r->s is the address of a field of a symbolic region, so it is symbol-based. |
| // A swapped null check (`nullptr == p`) must build the same constraint as the |
| // usual `p == nullptr`; otherwise the analyzer contradicts itself and reports a |
| // null dereference that cannot happen. |
| int gh206798_swapped(T *r) { |
| S *p = &r->s; |
| if (!p) { |
| } |
| if (nullptr == p) |
| return 0; |
| return p->n; // no-warning: p is known non-null after the check |
| } |
| |
| int gh206798_normal(T *r) { |
| S *p = &r->s; |
| if (!p) { |
| } |
| if (p == nullptr) |
| return 0; |
| return p->n; // no-warning: p is known non-null after the check |
| } |
| |
| // A genuine null dereference must still be flagged in either order. |
| int stillReportsRealBug_swapped(S *p) { |
| if (nullptr == p) |
| return p->n; // expected-warning{{Access to field 'n' results in a dereference of a null pointer (loaded from variable 'p')}} |
| return 0; |
| } |
| |
| int stillReportsRealBug_normal(S *p) { |
| if (p == nullptr) |
| return p->n; // expected-warning{{Access to field 'n' results in a dereference of a null pointer (loaded from variable 'p')}} |
| return 0; |
| } |